aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2016-02-26 04:45:39 -0500
committerDavid S. Miller <davem@davemloft.net>2016-03-01 15:54:30 -0500
commit3a927bc7cf9d0fbe8f4a8189dd5f8440228f64e7 (patch)
tree31a903a08d2f40e2c2026ef955be2d86bdecf777 /net
parent45493d47c3db862263583400c1f721f13f2a0610 (diff)
ovs: propagate per dp max headroom to all vports
This patch implements bookkeeping support to compute the maximum headroom for all the devices in each datapath. When said value changes, the underlying devs are notified via the ndo_set_rx_headroom method. This also increases the internal vports xmit performance. Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/openvswitch/datapath.c40
-rw-r--r--net/openvswitch/datapath.h4
-rw-r--r--net/openvswitch/vport-internal_dev.c10
3 files changed, 53 insertions, 1 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index c4e8455d5d56..e6a7d494df24 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -1908,6 +1908,29 @@ static struct vport *lookup_vport(struct net *net,
1908 return ERR_PTR(-EINVAL); 1908 return ERR_PTR(-EINVAL);
1909} 1909}
1910 1910
1911/* Called with ovs_mutex */
1912static void update_headroom(struct datapath *dp)
1913{
1914 unsigned dev_headroom, max_headroom = 0;
1915 struct net_device *dev;
1916 struct vport *vport;
1917 int i;
1918
1919 for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
1920 hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) {
1921 dev = vport->dev;
1922 dev_headroom = netdev_get_fwd_headroom(dev);
1923 if (dev_headroom > max_headroom)
1924 max_headroom = dev_headroom;
1925 }
1926 }
1927
1928 dp->max_headroom = max_headroom;
1929 for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++)
1930 hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node)
1931 netdev_set_rx_headroom(vport->dev, max_headroom);
1932}
1933
1911static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) 1934static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
1912{ 1935{
1913 struct nlattr **a = info->attrs; 1936 struct nlattr **a = info->attrs;
@@ -1973,6 +1996,12 @@ restart:
1973 1996
1974 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, 1997 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
1975 info->snd_seq, 0, OVS_VPORT_CMD_NEW); 1998 info->snd_seq, 0, OVS_VPORT_CMD_NEW);
1999
2000 if (netdev_get_fwd_headroom(vport->dev) > dp->max_headroom)
2001 update_headroom(dp);
2002 else
2003 netdev_set_rx_headroom(vport->dev, dp->max_headroom);
2004
1976 BUG_ON(err < 0); 2005 BUG_ON(err < 0);
1977 ovs_unlock(); 2006 ovs_unlock();
1978 2007
@@ -2039,8 +2068,10 @@ exit_unlock_free:
2039 2068
2040static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info) 2069static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
2041{ 2070{
2071 bool must_update_headroom = false;
2042 struct nlattr **a = info->attrs; 2072 struct nlattr **a = info->attrs;
2043 struct sk_buff *reply; 2073 struct sk_buff *reply;
2074 struct datapath *dp;
2044 struct vport *vport; 2075 struct vport *vport;
2045 int err; 2076 int err;
2046 2077
@@ -2062,7 +2093,16 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
2062 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, 2093 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
2063 info->snd_seq, 0, OVS_VPORT_CMD_DEL); 2094 info->snd_seq, 0, OVS_VPORT_CMD_DEL);
2064 BUG_ON(err < 0); 2095 BUG_ON(err < 0);
2096
2097 /* the vport deletion may trigger dp headroom update */
2098 dp = vport->dp;
2099 if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
2100 must_update_headroom = true;
2101 netdev_reset_rx_headroom(vport->dev);
2065 ovs_dp_detach_port(vport); 2102 ovs_dp_detach_port(vport);
2103
2104 if (must_update_headroom)
2105 update_headroom(dp);
2066 ovs_unlock(); 2106 ovs_unlock();
2067 2107
2068 ovs_notify(&dp_vport_genl_family, reply, info); 2108 ovs_notify(&dp_vport_genl_family, reply, info);
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index 67bdecd9fdc1..427e39a045cf 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -68,6 +68,8 @@ struct dp_stats_percpu {
68 * ovs_mutex and RCU. 68 * ovs_mutex and RCU.
69 * @stats_percpu: Per-CPU datapath statistics. 69 * @stats_percpu: Per-CPU datapath statistics.
70 * @net: Reference to net namespace. 70 * @net: Reference to net namespace.
71 * @max_headroom: the maximum headroom of all vports in this datapath; it will
72 * be used by all the internal vports in this dp.
71 * 73 *
72 * Context: See the comment on locking at the top of datapath.c for additional 74 * Context: See the comment on locking at the top of datapath.c for additional
73 * locking information. 75 * locking information.
@@ -89,6 +91,8 @@ struct datapath {
89 possible_net_t net; 91 possible_net_t net;
90 92
91 u32 user_features; 93 u32 user_features;
94
95 u32 max_headroom;
92}; 96};
93 97
94/** 98/**
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c
index ec76398a792f..83a5534abd31 100644
--- a/net/openvswitch/vport-internal_dev.c
+++ b/net/openvswitch/vport-internal_dev.c
@@ -138,6 +138,11 @@ internal_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
138 return stats; 138 return stats;
139} 139}
140 140
141void internal_set_rx_headroom(struct net_device *dev, int new_hr)
142{
143 dev->needed_headroom = new_hr;
144}
145
141static const struct net_device_ops internal_dev_netdev_ops = { 146static const struct net_device_ops internal_dev_netdev_ops = {
142 .ndo_open = internal_dev_open, 147 .ndo_open = internal_dev_open,
143 .ndo_stop = internal_dev_stop, 148 .ndo_stop = internal_dev_stop,
@@ -145,6 +150,7 @@ static const struct net_device_ops internal_dev_netdev_ops = {
145 .ndo_set_mac_address = eth_mac_addr, 150 .ndo_set_mac_address = eth_mac_addr,
146 .ndo_change_mtu = internal_dev_change_mtu, 151 .ndo_change_mtu = internal_dev_change_mtu,
147 .ndo_get_stats64 = internal_get_stats, 152 .ndo_get_stats64 = internal_get_stats,
153 .ndo_set_rx_headroom = internal_set_rx_headroom,
148}; 154};
149 155
150static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { 156static struct rtnl_link_ops internal_dev_link_ops __read_mostly = {
@@ -158,7 +164,8 @@ static void do_setup(struct net_device *netdev)
158 netdev->netdev_ops = &internal_dev_netdev_ops; 164 netdev->netdev_ops = &internal_dev_netdev_ops;
159 165
160 netdev->priv_flags &= ~IFF_TX_SKB_SHARING; 166 netdev->priv_flags &= ~IFF_TX_SKB_SHARING;
161 netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_OPENVSWITCH; 167 netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_OPENVSWITCH |
168 IFF_PHONY_HEADROOM;
162 netdev->destructor = internal_dev_destructor; 169 netdev->destructor = internal_dev_destructor;
163 netdev->ethtool_ops = &internal_dev_ethtool_ops; 170 netdev->ethtool_ops = &internal_dev_ethtool_ops;
164 netdev->rtnl_link_ops = &internal_dev_link_ops; 171 netdev->rtnl_link_ops = &internal_dev_link_ops;
@@ -199,6 +206,7 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
199 err = -ENOMEM; 206 err = -ENOMEM;
200 goto error_free_netdev; 207 goto error_free_netdev;
201 } 208 }
209 vport->dev->needed_headroom = vport->dp->max_headroom;
202 210
203 dev_net_set(vport->dev, ovs_dp_get_net(vport->dp)); 211 dev_net_set(vport->dev, ovs_dp_get_net(vport->dp));
204 internal_dev = internal_dev_priv(vport->dev); 212 internal_dev = internal_dev_priv(vport->dev);