diff options
-rw-r--r-- | acinclude.m4 | 1 | ||||
-rw-r--r-- | datapath/datapath.c | 41 | ||||
-rw-r--r-- | datapath/datapath.h | 4 | ||||
-rw-r--r-- | datapath/linux/compat/include/linux/netdevice.h | 19 | ||||
-rw-r--r-- | datapath/vport-internal_dev.c | 16 |
5 files changed, 80 insertions, 1 deletions
diff --git a/acinclude.m4 b/acinclude.m4 index e77a9f688..94bfe9446 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -469,6 +469,7 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [udp_offload.*uoff], [OVS_DEFINE([HAVE_UDP_OFFLOAD_ARG_UOFF])]) OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [gro_remcsum]) + OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [IFF_PHONY_HEADROOM]) OVS_GREP_IFELSE([$KSRC/include/linux/netfilter.h], [nf_hook_state]) OVS_GREP_IFELSE([$KSRC/include/linux/netfilter.h], [nf_register_net_hook]) diff --git a/datapath/datapath.c b/datapath/datapath.c index 9ce611ffd..3d2385e20 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -1953,6 +1953,29 @@ static struct vport *lookup_vport(struct net *net, return ERR_PTR(-EINVAL); } +/* Called with ovs_mutex */ +static void update_headroom(struct datapath *dp) +{ + unsigned dev_headroom, max_headroom = 0; + struct net_device *dev; + struct vport *vport; + int i; + + for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) { + hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) { + dev = vport->dev; + dev_headroom = netdev_get_fwd_headroom(dev); + if (dev_headroom > max_headroom) + max_headroom = dev_headroom; + } + } + + dp->max_headroom = max_headroom; + for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) + hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) + netdev_set_rx_headroom(vport->dev, max_headroom); +} + static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) { struct nlattr **a = info->attrs; @@ -2019,6 +2042,12 @@ restart: err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, info->snd_seq, 0, OVS_VPORT_CMD_NEW); BUG_ON(err < 0); + + if (netdev_get_fwd_headroom(vport->dev) > dp->max_headroom) + update_headroom(dp); + else + netdev_set_rx_headroom(vport->dev, dp->max_headroom); + ovs_unlock(); ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info); @@ -2083,8 +2112,10 @@ exit_unlock_free: static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info) { + bool must_update_headroom = false; struct nlattr **a = info->attrs; struct sk_buff *reply; + struct datapath *dp; struct vport *vport; int err; @@ -2106,7 +2137,17 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info) err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, info->snd_seq, 0, OVS_VPORT_CMD_DEL); BUG_ON(err < 0); + + /* the vport deletion may trigger dp headroom update */ + dp = vport->dp; + if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom) + must_update_headroom = true; + netdev_reset_rx_headroom(vport->dev); ovs_dp_detach_port(vport); + + if (must_update_headroom) + update_headroom(dp); + ovs_unlock(); ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info); diff --git a/datapath/datapath.h b/datapath/datapath.h index f1607ab22..22bbaac4b 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -69,6 +69,8 @@ struct dp_stats_percpu { * ovs_mutex and RCU. * @stats_percpu: Per-CPU datapath statistics. * @net: Reference to net namespace. + * @max_headroom: the maximum headroom of all vports in this datapath; it will + * be used by all the internal vports in this dp. * * Context: See the comment on locking at the top of datapath.c for additional * locking information. @@ -90,6 +92,8 @@ struct datapath { possible_net_t net; u32 user_features; + + u32 max_headroom; }; /** diff --git a/datapath/linux/compat/include/linux/netdevice.h b/datapath/linux/compat/include/linux/netdevice.h index 8bb5947de..235851bd5 100644 --- a/datapath/linux/compat/include/linux/netdevice.h +++ b/datapath/linux/compat/include/linux/netdevice.h @@ -262,4 +262,23 @@ int ovs_dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb); #define NETDEV_OFFLOAD_PUSH_GENEVE 0x001D #endif +#ifndef HAVE_IFF_PHONY_HEADROOM + +#define IFF_PHONY_HEADROOM 0 +static inline unsigned netdev_get_fwd_headroom(struct net_device *dev) +{ + return 0; +} + +static inline void netdev_set_rx_headroom(struct net_device *dev, int new_hr) +{ +} + +/* set the device rx headroom to the dev's default */ +static inline void netdev_reset_rx_headroom(struct net_device *dev) +{ +} + +#endif + #endif /* __LINUX_NETDEVICE_WRAPPER_H */ diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c index ec76398a7..2ce3c3a18 100644 --- a/datapath/vport-internal_dev.c +++ b/datapath/vport-internal_dev.c @@ -138,6 +138,13 @@ internal_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) return stats; } +#ifdef HAVE_IFF_PHONY_HEADROOM +static void internal_set_rx_headroom(struct net_device *dev, int new_hr) +{ + dev->needed_headroom = new_hr; +} +#endif + static const struct net_device_ops internal_dev_netdev_ops = { .ndo_open = internal_dev_open, .ndo_stop = internal_dev_stop, @@ -145,6 +152,9 @@ static const struct net_device_ops internal_dev_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = internal_dev_change_mtu, .ndo_get_stats64 = internal_get_stats, +#ifdef HAVE_IFF_PHONY_HEADROOM + .ndo_set_rx_headroom = internal_set_rx_headroom, +#endif }; static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { @@ -158,7 +168,8 @@ static void do_setup(struct net_device *netdev) netdev->netdev_ops = &internal_dev_netdev_ops; netdev->priv_flags &= ~IFF_TX_SKB_SHARING; - netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_OPENVSWITCH; + netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_OPENVSWITCH | + IFF_PHONY_HEADROOM; netdev->destructor = internal_dev_destructor; netdev->ethtool_ops = &internal_dev_ethtool_ops; netdev->rtnl_link_ops = &internal_dev_link_ops; @@ -200,6 +211,9 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) goto error_free_netdev; } +#ifdef HAVE_IFF_PHONY_HEADROOM + vport->dev->needed_headroom = vport->dp->max_headroom; +#endif dev_net_set(vport->dev, ovs_dp_get_net(vport->dp)); internal_dev = internal_dev_priv(vport->dev); internal_dev->vport = vport; |