aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/devinet.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2008-06-19 19:15:47 -0400
committerDavid S. Miller <davem@davemloft.net>2008-06-19 19:15:47 -0400
commit0187bdfb05674147774ca79a79942537f3ad54bd (patch)
tree43980261ce9e2b6ef76356dbbbc7efe3dbb60a02 /net/ipv4/devinet.c
parent2e3216cd54b142ba605e87522e15f42e0c4e3996 (diff)
net: Disable LRO on devices that are forwarding
Large Receive Offload (LRO) is only appropriate for packets that are destined for the host, and should be disabled if received packets may be forwarded. It can also confuse the GSO on output. Add dev_disable_lro() function which uses the appropriate ethtool ops to disable LRO if enabled. Add calls to dev_disable_lro() in br_add_if() and functions that enable IPv4 and IPv6 forwarding. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/devinet.c')
-rw-r--r--net/ipv4/devinet.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index f8c0b0aea93a..9de2514946ca 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -168,6 +168,8 @@ static struct in_device *inetdev_init(struct net_device *dev)
168 in_dev->dev = dev; 168 in_dev->dev = dev;
169 if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL) 169 if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
170 goto out_kfree; 170 goto out_kfree;
171 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
172 dev_disable_lro(dev);
171 /* Reference in_dev->dev */ 173 /* Reference in_dev->dev */
172 dev_hold(dev); 174 dev_hold(dev);
173 /* Account for reference dev->ip_ptr (below) */ 175 /* Account for reference dev->ip_ptr (below) */
@@ -1241,6 +1243,8 @@ static void inet_forward_change(struct net *net)
1241 read_lock(&dev_base_lock); 1243 read_lock(&dev_base_lock);
1242 for_each_netdev(net, dev) { 1244 for_each_netdev(net, dev) {
1243 struct in_device *in_dev; 1245 struct in_device *in_dev;
1246 if (on)
1247 dev_disable_lro(dev);
1244 rcu_read_lock(); 1248 rcu_read_lock();
1245 in_dev = __in_dev_get_rcu(dev); 1249 in_dev = __in_dev_get_rcu(dev);
1246 if (in_dev) 1250 if (in_dev)
@@ -1248,8 +1252,6 @@ static void inet_forward_change(struct net *net)
1248 rcu_read_unlock(); 1252 rcu_read_unlock();
1249 } 1253 }
1250 read_unlock(&dev_base_lock); 1254 read_unlock(&dev_base_lock);
1251
1252 rt_cache_flush(0);
1253} 1255}
1254 1256
1255static int devinet_conf_proc(ctl_table *ctl, int write, 1257static int devinet_conf_proc(ctl_table *ctl, int write,
@@ -1335,10 +1337,19 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
1335 if (write && *valp != val) { 1337 if (write && *valp != val) {
1336 struct net *net = ctl->extra2; 1338 struct net *net = ctl->extra2;
1337 1339
1338 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) 1340 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
1339 inet_forward_change(net); 1341 rtnl_lock();
1340 else if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) 1342 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
1343 inet_forward_change(net);
1344 } else if (*valp) {
1345 struct ipv4_devconf *cnf = ctl->extra1;
1346 struct in_device *idev =
1347 container_of(cnf, struct in_device, cnf);
1348 dev_disable_lro(idev->dev);
1349 }
1350 rtnl_unlock();
1341 rt_cache_flush(0); 1351 rt_cache_flush(0);
1352 }
1342 } 1353 }
1343 1354
1344 return ret; 1355 return ret;