Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Stephen Hemminger and committed by
David S. Miller
edb5e46f 0e5eabac

+67 -3
+63
net/bridge/br_device.c
··· 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" ··· 107 106 return err; 108 107 } 109 108 109 + static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) 110 + { 111 + strcpy(info->driver, "bridge"); 112 + strcpy(info->version, BR_VERSION); 113 + strcpy(info->fw_version, "N/A"); 114 + strcpy(info->bus_info, "N/A"); 115 + } 116 + 117 + static int br_set_sg(struct net_device *dev, u32 data) 118 + { 119 + struct net_bridge *br = netdev_priv(dev); 120 + 121 + if (data) 122 + br->feature_mask |= NETIF_F_SG; 123 + else 124 + br->feature_mask &= ~NETIF_F_SG; 125 + 126 + br_features_recompute(br); 127 + return 0; 128 + } 129 + 130 + static int br_set_tso(struct net_device *dev, u32 data) 131 + { 132 + struct net_bridge *br = netdev_priv(dev); 133 + 134 + if (data) 135 + br->feature_mask |= NETIF_F_TSO; 136 + else 137 + br->feature_mask &= ~NETIF_F_TSO; 138 + 139 + br_features_recompute(br); 140 + return 0; 141 + } 142 + 143 + static int br_set_tx_csum(struct net_device *dev, u32 data) 144 + { 145 + struct net_bridge *br = netdev_priv(dev); 146 + 147 + if (data) 148 + br->feature_mask |= NETIF_F_IP_CSUM; 149 + else 150 + br->feature_mask &= ~NETIF_F_IP_CSUM; 151 + 152 + br_features_recompute(br); 153 + return 0; 154 + } 155 + 156 + static struct ethtool_ops br_ethtool_ops = { 157 + .get_drvinfo = br_getinfo, 158 + .get_link = ethtool_op_get_link, 159 + .get_sg = ethtool_op_get_sg, 160 + .set_sg = br_set_sg, 161 + .get_tx_csum = ethtool_op_get_tx_csum, 162 + .set_tx_csum = br_set_tx_csum, 163 + .get_tso = ethtool_op_get_tso, 164 + .set_tso = br_set_tso, 165 + }; 166 + 110 167 void br_dev_setup(struct net_device *dev) 111 168 { 112 169 memset(dev->dev_addr, 0, ETH_ALEN); ··· 179 120 dev->change_mtu = br_change_mtu; 180 121 dev->destructor = free_netdev; 181 122 SET_MODULE_OWNER(dev); 123 + SET_ETHTOOL_OPS(dev, &br_ethtool_ops); 182 124 dev->stop = br_dev_stop; 183 125 dev->tx_queue_len = 0; 184 126 dev->set_mac_address = br_set_mac_address; 185 127 dev->priv_flags = IFF_EBRIDGE; 128 + 129 + dev->features = NETIF_F_SG | NETIF_F_FRAGLIST 130 + | NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_IP_CSUM; 186 131 }
+3 -3
net/bridge/br_if.c
··· 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; ··· 350 349 struct net_bridge_port *p; 351 350 unsigned long features, checksum; 352 351 353 - features = NETIF_F_SG | NETIF_F_FRAGLIST 354 - | NETIF_F_HIGHDMA | NETIF_F_TSO; 355 - checksum = NETIF_F_IP_CSUM; /* least commmon subset */ 352 + features = br->feature_mask &~ NETIF_F_IP_CSUM; 353 + checksum = br->feature_mask & NETIF_F_IP_CSUM; 356 354 357 355 list_for_each_entry(p, &br->port_list, list) { 358 356 if (!(p->dev->features
+1
net/bridge/br_private.h
··· 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;