diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2005-12-21 22:00:58 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-01-03 16:11:03 -0500 |
commit | edb5e46fc03d0a45f2b41e3717631f7af7e9fc19 (patch) | |
tree | ede6a4e9dcdf52ff48ea2a11ac0188822b097715 /net | |
parent | 0e5eabac4995e128f06b90df64b93604625de6de (diff) |
[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>
Diffstat (limited to 'net')
-rw-r--r-- | net/bridge/br_device.c | 63 | ||||
-rw-r--r-- | net/bridge/br_if.c | 6 | ||||
-rw-r--r-- | net/bridge/br_private.h | 1 |
3 files changed, 67 insertions, 3 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index f7a66abf5def..0b33a7b3a00c 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/netdevice.h> | 17 | #include <linux/netdevice.h> |
18 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
19 | #include <linux/ethtool.h> | ||
19 | 20 | ||
20 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
21 | #include "br_private.h" | 22 | #include "br_private.h" |
@@ -106,6 +107,64 @@ static int br_set_mac_address(struct net_device *dev, void *p) | |||
106 | return err; | 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 | void br_dev_setup(struct net_device *dev) | 168 | void br_dev_setup(struct net_device *dev) |
110 | { | 169 | { |
111 | memset(dev->dev_addr, 0, ETH_ALEN); | 170 | memset(dev->dev_addr, 0, ETH_ALEN); |
@@ -120,8 +179,12 @@ void br_dev_setup(struct net_device *dev) | |||
120 | dev->change_mtu = br_change_mtu; | 179 | dev->change_mtu = br_change_mtu; |
121 | dev->destructor = free_netdev; | 180 | dev->destructor = free_netdev; |
122 | SET_MODULE_OWNER(dev); | 181 | SET_MODULE_OWNER(dev); |
182 | SET_ETHTOOL_OPS(dev, &br_ethtool_ops); | ||
123 | dev->stop = br_dev_stop; | 183 | dev->stop = br_dev_stop; |
124 | dev->tx_queue_len = 0; | 184 | dev->tx_queue_len = 0; |
125 | dev->set_mac_address = br_set_mac_address; | 185 | dev->set_mac_address = br_set_mac_address; |
126 | dev->priv_flags = IFF_EBRIDGE; | 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 | } |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index e6b8bb51d613..11321197338e 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -182,6 +182,7 @@ static struct net_device *new_bridge_dev(const char *name) | |||
182 | br->bridge_id.prio[1] = 0x00; | 182 | br->bridge_id.prio[1] = 0x00; |
183 | memset(br->bridge_id.addr, 0, ETH_ALEN); | 183 | memset(br->bridge_id.addr, 0, ETH_ALEN); |
184 | 184 | ||
185 | br->feature_mask = dev->features; | ||
185 | br->stp_enabled = 0; | 186 | br->stp_enabled = 0; |
186 | br->designated_root = br->bridge_id; | 187 | br->designated_root = br->bridge_id; |
187 | br->root_path_cost = 0; | 188 | br->root_path_cost = 0; |
@@ -349,9 +350,8 @@ void br_features_recompute(struct net_bridge *br) | |||
349 | struct net_bridge_port *p; | 350 | struct net_bridge_port *p; |
350 | unsigned long features, checksum; | 351 | unsigned long features, checksum; |
351 | 352 | ||
352 | features = NETIF_F_SG | NETIF_F_FRAGLIST | 353 | features = br->feature_mask &~ NETIF_F_IP_CSUM; |
353 | | NETIF_F_HIGHDMA | NETIF_F_TSO; | 354 | checksum = br->feature_mask & NETIF_F_IP_CSUM; |
354 | checksum = NETIF_F_IP_CSUM; /* least commmon subset */ | ||
355 | 355 | ||
356 | list_for_each_entry(p, &br->port_list, list) { | 356 | list_for_each_entry(p, &br->port_list, list) { |
357 | if (!(p->dev->features | 357 | if (!(p->dev->features |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 7ad53c2aa684..db7b26b8de96 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -93,6 +93,7 @@ struct net_bridge | |||
93 | spinlock_t hash_lock; | 93 | spinlock_t hash_lock; |
94 | struct hlist_head hash[BR_HASH_SIZE]; | 94 | struct hlist_head hash[BR_HASH_SIZE]; |
95 | struct list_head age_list; | 95 | struct list_head age_list; |
96 | unsigned long feature_mask; | ||
96 | 97 | ||
97 | /* STP */ | 98 | /* STP */ |
98 | bridge_id designated_root; | 99 | bridge_id designated_root; |