Commit edb5e46fc03d0a45f2b41e3717631f7af7e9fc19

Authored by Stephen Hemminger
Committed by David S. Miller
1 parent 0e5eabac49

[BRIDGE]: limited ethtool support

Add limited ethtool support to bridge to allow disabling
features.

Note: if underlying device does not support a feature (like checksum
offload), then the bridge device won't inherit it.

Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 3 changed files with 67 additions and 3 deletions Side-by-side Diff

net/bridge/br_device.c
... ... @@ -16,6 +16,7 @@
16 16 #include <linux/kernel.h>
17 17 #include <linux/netdevice.h>
18 18 #include <linux/etherdevice.h>
  19 +#include <linux/ethtool.h>
19 20  
20 21 #include <asm/uaccess.h>
21 22 #include "br_private.h"
... ... @@ -106,6 +107,64 @@
106 107 return err;
107 108 }
108 109  
  110 +static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
  111 +{
  112 + strcpy(info->driver, "bridge");
  113 + strcpy(info->version, BR_VERSION);
  114 + strcpy(info->fw_version, "N/A");
  115 + strcpy(info->bus_info, "N/A");
  116 +}
  117 +
  118 +static int br_set_sg(struct net_device *dev, u32 data)
  119 +{
  120 + struct net_bridge *br = netdev_priv(dev);
  121 +
  122 + if (data)
  123 + br->feature_mask |= NETIF_F_SG;
  124 + else
  125 + br->feature_mask &= ~NETIF_F_SG;
  126 +
  127 + br_features_recompute(br);
  128 + return 0;
  129 +}
  130 +
  131 +static int br_set_tso(struct net_device *dev, u32 data)
  132 +{
  133 + struct net_bridge *br = netdev_priv(dev);
  134 +
  135 + if (data)
  136 + br->feature_mask |= NETIF_F_TSO;
  137 + else
  138 + br->feature_mask &= ~NETIF_F_TSO;
  139 +
  140 + br_features_recompute(br);
  141 + return 0;
  142 +}
  143 +
  144 +static int br_set_tx_csum(struct net_device *dev, u32 data)
  145 +{
  146 + struct net_bridge *br = netdev_priv(dev);
  147 +
  148 + if (data)
  149 + br->feature_mask |= NETIF_F_IP_CSUM;
  150 + else
  151 + br->feature_mask &= ~NETIF_F_IP_CSUM;
  152 +
  153 + br_features_recompute(br);
  154 + return 0;
  155 +}
  156 +
  157 +static struct ethtool_ops br_ethtool_ops = {
  158 + .get_drvinfo = br_getinfo,
  159 + .get_link = ethtool_op_get_link,
  160 + .get_sg = ethtool_op_get_sg,
  161 + .set_sg = br_set_sg,
  162 + .get_tx_csum = ethtool_op_get_tx_csum,
  163 + .set_tx_csum = br_set_tx_csum,
  164 + .get_tso = ethtool_op_get_tso,
  165 + .set_tso = br_set_tso,
  166 +};
  167 +
109 168 void br_dev_setup(struct net_device *dev)
110 169 {
111 170 memset(dev->dev_addr, 0, ETH_ALEN);
112 171  
... ... @@ -120,9 +179,13 @@
120 179 dev->change_mtu = br_change_mtu;
121 180 dev->destructor = free_netdev;
122 181 SET_MODULE_OWNER(dev);
  182 + SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
123 183 dev->stop = br_dev_stop;
124 184 dev->tx_queue_len = 0;
125 185 dev->set_mac_address = br_set_mac_address;
126 186 dev->priv_flags = IFF_EBRIDGE;
  187 +
  188 + dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
  189 + | NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_IP_CSUM;
127 190 }
... ... @@ -182,6 +182,7 @@
182 182 br->bridge_id.prio[1] = 0x00;
183 183 memset(br->bridge_id.addr, 0, ETH_ALEN);
184 184  
  185 + br->feature_mask = dev->features;
185 186 br->stp_enabled = 0;
186 187 br->designated_root = br->bridge_id;
187 188 br->root_path_cost = 0;
... ... @@ -349,9 +350,8 @@
349 350 struct net_bridge_port *p;
350 351 unsigned long features, checksum;
351 352  
352   - features = NETIF_F_SG | NETIF_F_FRAGLIST
353   - | NETIF_F_HIGHDMA | NETIF_F_TSO;
354   - checksum = NETIF_F_IP_CSUM; /* least commmon subset */
  353 + features = br->feature_mask &~ NETIF_F_IP_CSUM;
  354 + checksum = br->feature_mask & NETIF_F_IP_CSUM;
355 355  
356 356 list_for_each_entry(p, &br->port_list, list) {
357 357 if (!(p->dev->features
net/bridge/br_private.h
... ... @@ -93,6 +93,7 @@
93 93 spinlock_t hash_lock;
94 94 struct hlist_head hash[BR_HASH_SIZE];
95 95 struct list_head age_list;
  96 + unsigned long feature_mask;
96 97  
97 98 /* STP */
98 99 bridge_id designated_root;