Blame view
net/8021q/vlan_dev.c
18.9 KB
1da177e4c
|
1 2 3 4 5 |
/* -*- linux-c -*- * INET 802.1Q VLAN * Ethernet-type device handling. * * Authors: Ben Greear <greearb@candelatech.com> |
ad712087f
|
6 |
* Please send support related email to: netdev@vger.kernel.org |
1da177e4c
|
7 |
* VLAN Home Page: http://www.candelatech.com/~greear/vlan.html |
122952fc2
|
8 |
* |
1da177e4c
|
9 10 11 12 13 14 |
* Fixes: Mar 22 2001: Martin Bokaemper <mbokaemper@unispherenetworks.com> * - reset skb->pkt_type on incoming packets when MAC was changed * - see that changed MAC is saddr for outgoing packets * Oct 20, 2001: Ard van Breeman: * - Fix MC-list, finally. * - Flush MC-list on VLAN destroy. |
122952fc2
|
15 |
* |
1da177e4c
|
16 17 18 19 20 21 22 23 |
* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include <linux/module.h> |
5a0e3ad6a
|
24 |
#include <linux/slab.h> |
1da177e4c
|
25 26 27 |
#include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> |
75b8846ac
|
28 |
#include <linux/ethtool.h> |
1da177e4c
|
29 30 31 32 33 |
#include <net/arp.h> #include "vlan.h" #include "vlanproc.h" #include <linux/if_vlan.h> |
1da177e4c
|
34 35 36 37 38 39 40 41 42 43 44 |
/* * Rebuild the Ethernet MAC header. This is called after an ARP * (or in future other address resolution) has completed on this * sk_buff. We now let ARP fill in the other fields. * * This routine CANNOT use cached dst->neigh! * Really, it is used only when dst->neigh is wrong. * * TODO: This needs a checkup, I'm ignorant here. --BLG */ |
ef3eb3e59
|
45 |
static int vlan_dev_rebuild_header(struct sk_buff *skb) |
1da177e4c
|
46 47 48 49 50 51 |
{ struct net_device *dev = skb->dev; struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); switch (veth->h_vlan_encapsulated_proto) { #ifdef CONFIG_INET |
606780404
|
52 |
case htons(ETH_P_IP): |
1da177e4c
|
53 54 55 |
/* TODO: Confirm this will work with VLAN headers... */ return arp_find(veth->h_dest, skb); |
122952fc2
|
56 |
#endif |
1da177e4c
|
57 |
default: |
40f98e1af
|
58 59 60 |
pr_debug("%s: unable to resolve type %X addresses. ", dev->name, ntohs(veth->h_vlan_encapsulated_proto)); |
122952fc2
|
61 |
|
1da177e4c
|
62 63 |
memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); break; |
3ff50b799
|
64 |
} |
1da177e4c
|
65 66 67 |
return 0; } |
9bb8582ef
|
68 |
static inline u16 |
2029cc2c8
|
69 |
vlan_dev_get_egress_qos_mask(struct net_device *dev, struct sk_buff *skb) |
1da177e4c
|
70 |
{ |
2029cc2c8
|
71 |
struct vlan_priority_tci_mapping *mp; |
1da177e4c
|
72 |
|
2029cc2c8
|
73 |
mp = vlan_dev_info(dev)->egress_priority_map[(skb->priority & 0xF)]; |
1da177e4c
|
74 75 |
while (mp) { if (mp->priority == skb->priority) { |
2029cc2c8
|
76 77 78 |
return mp->vlan_qos; /* This should already be shifted * to mask correctly with the * VLAN's TCI */ |
1da177e4c
|
79 80 81 82 83 84 85 |
} mp = mp->next; } return 0; } /* |
122952fc2
|
86 |
* Create the VLAN header for an arbitrary protocol layer |
1da177e4c
|
87 88 89 90 91 92 93 |
* * saddr=NULL means use device source address * daddr=NULL means leave destination address (eg unresolved arp) * * This is called when the SKB is moving down the stack towards the * physical devices. */ |
ef3eb3e59
|
94 95 96 97 |
static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *daddr, const void *saddr, unsigned int len) |
1da177e4c
|
98 99 |
{ struct vlan_hdr *vhdr; |
1349fe9a6
|
100 |
unsigned int vhdrlen = 0; |
9bb8582ef
|
101 |
u16 vlan_tci = 0; |
1349fe9a6
|
102 |
int rc; |
1da177e4c
|
103 |
|
1349fe9a6
|
104 |
if (!(vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR)) { |
1da177e4c
|
105 |
vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN); |
9bb8582ef
|
106 107 |
vlan_tci = vlan_dev_info(dev)->vlan_id; vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); |
9bb8582ef
|
108 |
vhdr->h_vlan_TCI = htons(vlan_tci); |
1da177e4c
|
109 110 |
/* |
bf9ae5386
|
111 112 |
* Set the protocol type. For a packet of type ETH_P_802_3/2 we * put the length in here instead. |
1da177e4c
|
113 |
*/ |
bf9ae5386
|
114 |
if (type != ETH_P_802_3 && type != ETH_P_802_2) |
1da177e4c
|
115 |
vhdr->h_vlan_encapsulated_proto = htons(type); |
2029cc2c8
|
116 |
else |
1da177e4c
|
117 |
vhdr->h_vlan_encapsulated_proto = htons(len); |
279e172a5
|
118 119 |
skb->protocol = htons(ETH_P_8021Q); |
1349fe9a6
|
120 121 |
type = ETH_P_8021Q; vhdrlen = VLAN_HLEN; |
1da177e4c
|
122 123 124 125 126 |
} /* Before delegating work to the lower layer, enter our MAC-address */ if (saddr == NULL) saddr = dev->dev_addr; |
1349fe9a6
|
127 |
/* Now make the underlying real hard header */ |
9dfebcc64
|
128 |
dev = vlan_dev_info(dev)->real_dev; |
1349fe9a6
|
129 130 131 |
rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen); if (rc > 0) rc += vhdrlen; |
1da177e4c
|
132 133 |
return rc; } |
6fef4c0c8
|
134 135 |
static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) |
1da177e4c
|
136 |
{ |
1da177e4c
|
137 |
struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); |
1a123a316
|
138 139 |
unsigned int len; int ret; |
55b01e868
|
140 |
|
1da177e4c
|
141 142 143 144 145 |
/* Handle non-VLAN frames if they are sent to us, for example by DHCP. * * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs... */ |
6ab3b487d
|
146 |
if (veth->h_vlan_proto != htons(ETH_P_8021Q) || |
d80aa31bb
|
147 |
vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR) { |
9bb8582ef
|
148 |
u16 vlan_tci; |
9bb8582ef
|
149 150 |
vlan_tci = vlan_dev_info(dev)->vlan_id; vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); |
636e19a34
|
151 |
skb = __vlan_hwaccel_put_tag(skb, vlan_tci); |
1da177e4c
|
152 |
} |
8a83a00b0
|
153 |
skb_set_dev(skb, vlan_dev_info(dev)->real_dev); |
1a123a316
|
154 155 |
len = skb->len; ret = dev_queue_xmit(skb); |
2d6c9ffcc
|
156 |
if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { |
4af429d29
|
157 158 159 160 161 162 |
struct vlan_pcpu_stats *stats; stats = this_cpu_ptr(vlan_dev_info(dev)->vlan_pcpu_stats); u64_stats_update_begin(&stats->syncp); stats->tx_packets++; stats->tx_bytes += len; |
307f73df2
|
163 |
u64_stats_update_end(&stats->syncp); |
4af429d29
|
164 165 166 |
} else { this_cpu_inc(vlan_dev_info(dev)->vlan_pcpu_stats->tx_dropped); } |
1a123a316
|
167 |
|
cbbef5e18
|
168 |
return ret; |
1da177e4c
|
169 |
} |
ef3eb3e59
|
170 |
static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) |
1da177e4c
|
171 172 173 174 |
{ /* TODO: gotta make sure the underlying layer can handle it, * maybe an IFF_VLAN_CAPABLE flag for devices? */ |
9dfebcc64
|
175 |
if (vlan_dev_info(dev)->real_dev->mtu < new_mtu) |
1da177e4c
|
176 177 178 179 180 181 |
return -ERANGE; dev->mtu = new_mtu; return 0; } |
c17d8874f
|
182 |
void vlan_dev_set_ingress_priority(const struct net_device *dev, |
9bb8582ef
|
183 |
u32 skb_prio, u16 vlan_prio) |
1da177e4c
|
184 |
{ |
9dfebcc64
|
185 |
struct vlan_dev_info *vlan = vlan_dev_info(dev); |
b020cb488
|
186 187 188 189 190 191 192 |
if (vlan->ingress_priority_map[vlan_prio & 0x7] && !skb_prio) vlan->nr_ingress_mappings--; else if (!vlan->ingress_priority_map[vlan_prio & 0x7] && skb_prio) vlan->nr_ingress_mappings++; vlan->ingress_priority_map[vlan_prio & 0x7] = skb_prio; |
1da177e4c
|
193 |
} |
c17d8874f
|
194 |
int vlan_dev_set_egress_priority(const struct net_device *dev, |
9bb8582ef
|
195 |
u32 skb_prio, u16 vlan_prio) |
1da177e4c
|
196 |
{ |
9dfebcc64
|
197 |
struct vlan_dev_info *vlan = vlan_dev_info(dev); |
1da177e4c
|
198 199 |
struct vlan_priority_tci_mapping *mp = NULL; struct vlan_priority_tci_mapping *np; |
05423b241
|
200 |
u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK; |
122952fc2
|
201 |
|
c17d8874f
|
202 |
/* See if a priority mapping exists.. */ |
b020cb488
|
203 |
mp = vlan->egress_priority_map[skb_prio & 0xF]; |
c17d8874f
|
204 205 |
while (mp) { if (mp->priority == skb_prio) { |
b020cb488
|
206 207 208 209 210 |
if (mp->vlan_qos && !vlan_qos) vlan->nr_egress_mappings--; else if (!mp->vlan_qos && vlan_qos) vlan->nr_egress_mappings++; mp->vlan_qos = vlan_qos; |
c17d8874f
|
211 |
return 0; |
1da177e4c
|
212 |
} |
c17d8874f
|
213 |
mp = mp->next; |
1da177e4c
|
214 |
} |
c17d8874f
|
215 216 |
/* Create a new mapping then. */ |
b020cb488
|
217 |
mp = vlan->egress_priority_map[skb_prio & 0xF]; |
c17d8874f
|
218 219 220 221 222 223 |
np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL); if (!np) return -ENOBUFS; np->next = mp; np->priority = skb_prio; |
b020cb488
|
224 225 226 227 |
np->vlan_qos = vlan_qos; vlan->egress_priority_map[skb_prio & 0xF] = np; if (vlan_qos) vlan->nr_egress_mappings++; |
c17d8874f
|
228 |
return 0; |
1da177e4c
|
229 |
} |
a4bf3af4a
|
230 |
/* Flags are defined in the vlan_flags enum in include/linux/if_vlan.h file. */ |
b3ce0325f
|
231 |
int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask) |
1da177e4c
|
232 |
{ |
b3ce0325f
|
233 234 |
struct vlan_dev_info *vlan = vlan_dev_info(dev); u32 old_flags = vlan->flags; |
5e7565930
|
235 236 |
if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | VLAN_FLAG_LOOSE_BINDING)) |
b3ce0325f
|
237 238 239 |
return -EINVAL; vlan->flags = (old_flags & ~mask) | (flags & mask); |
70c03b49b
|
240 241 242 243 244 245 246 |
if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_GVRP) { if (vlan->flags & VLAN_FLAG_GVRP) vlan_gvrp_request_join(dev); else vlan_gvrp_request_leave(dev); } |
b3ce0325f
|
247 |
return 0; |
1da177e4c
|
248 |
} |
c17d8874f
|
249 |
void vlan_dev_get_realdev_name(const struct net_device *dev, char *result) |
1da177e4c
|
250 |
{ |
9dfebcc64
|
251 |
strncpy(result, vlan_dev_info(dev)->real_dev->name, 23); |
1da177e4c
|
252 |
} |
ef3eb3e59
|
253 |
static int vlan_dev_open(struct net_device *dev) |
1da177e4c
|
254 |
{ |
9dfebcc64
|
255 |
struct vlan_dev_info *vlan = vlan_dev_info(dev); |
8c979c26a
|
256 257 |
struct net_device *real_dev = vlan->real_dev; int err; |
5e7565930
|
258 259 |
if (!(real_dev->flags & IFF_UP) && !(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) |
1da177e4c
|
260 |
return -ENETDOWN; |
8c979c26a
|
261 |
if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { |
a748ee242
|
262 |
err = dev_uc_add(real_dev, dev->dev_addr); |
8c979c26a
|
263 |
if (err < 0) |
89146504c
|
264 |
goto out; |
8c979c26a
|
265 |
} |
8c979c26a
|
266 |
|
89146504c
|
267 268 269 270 271 272 273 274 275 276 277 278 |
if (dev->flags & IFF_ALLMULTI) { err = dev_set_allmulti(real_dev, 1); if (err < 0) goto del_unicast; } if (dev->flags & IFF_PROMISC) { err = dev_set_promiscuity(real_dev, 1); if (err < 0) goto clear_allmulti; } memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN); |
6c78dcbd4
|
279 |
|
70c03b49b
|
280 281 |
if (vlan->flags & VLAN_FLAG_GVRP) vlan_gvrp_request_join(dev); |
0ac820eeb
|
282 283 |
if (netif_carrier_ok(real_dev)) netif_carrier_on(dev); |
1da177e4c
|
284 |
return 0; |
89146504c
|
285 286 287 288 289 290 |
clear_allmulti: if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(real_dev, -1); del_unicast: if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) |
a748ee242
|
291 |
dev_uc_del(real_dev, dev->dev_addr); |
89146504c
|
292 |
out: |
adc667e84
|
293 |
netif_carrier_off(dev); |
89146504c
|
294 |
return err; |
1da177e4c
|
295 |
} |
ef3eb3e59
|
296 |
static int vlan_dev_stop(struct net_device *dev) |
1da177e4c
|
297 |
{ |
70c03b49b
|
298 299 |
struct vlan_dev_info *vlan = vlan_dev_info(dev); struct net_device *real_dev = vlan->real_dev; |
56addd6ee
|
300 |
dev_mc_unsync(real_dev, dev); |
a748ee242
|
301 |
dev_uc_unsync(real_dev, dev); |
6c78dcbd4
|
302 303 304 305 |
if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(real_dev, -1); if (dev->flags & IFF_PROMISC) dev_set_promiscuity(real_dev, -1); |
8c979c26a
|
306 |
if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) |
a748ee242
|
307 |
dev_uc_del(real_dev, dev->dev_addr); |
8c979c26a
|
308 |
|
adc667e84
|
309 |
netif_carrier_off(dev); |
1da177e4c
|
310 311 |
return 0; } |
ef3eb3e59
|
312 |
static int vlan_dev_set_mac_address(struct net_device *dev, void *p) |
39aaac114
|
313 |
{ |
9dfebcc64
|
314 |
struct net_device *real_dev = vlan_dev_info(dev)->real_dev; |
39aaac114
|
315 316 317 318 319 320 321 322 323 324 |
struct sockaddr *addr = p; int err; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; if (!(dev->flags & IFF_UP)) goto out; if (compare_ether_addr(addr->sa_data, real_dev->dev_addr)) { |
a748ee242
|
325 |
err = dev_uc_add(real_dev, addr->sa_data); |
39aaac114
|
326 327 328 329 330 |
if (err < 0) return err; } if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) |
a748ee242
|
331 |
dev_uc_del(real_dev, dev->dev_addr); |
39aaac114
|
332 333 334 335 336 |
out: memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); return 0; } |
ef3eb3e59
|
337 |
static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
1da177e4c
|
338 |
{ |
9dfebcc64
|
339 |
struct net_device *real_dev = vlan_dev_info(dev)->real_dev; |
656299f70
|
340 |
const struct net_device_ops *ops = real_dev->netdev_ops; |
1da177e4c
|
341 342 343 344 345 |
struct ifreq ifrr; int err = -EOPNOTSUPP; strncpy(ifrr.ifr_name, real_dev->name, IFNAMSIZ); ifrr.ifr_ifru = ifr->ifr_ifru; |
2029cc2c8
|
346 |
switch (cmd) { |
1da177e4c
|
347 348 349 |
case SIOCGMIIPHY: case SIOCGMIIREG: case SIOCSMIIREG: |
656299f70
|
350 351 |
if (netif_device_present(real_dev) && ops->ndo_do_ioctl) err = ops->ndo_do_ioctl(real_dev, &ifrr, cmd); |
1da177e4c
|
352 |
break; |
1da177e4c
|
353 |
} |
122952fc2
|
354 |
if (!err) |
1da177e4c
|
355 356 357 358 |
ifr->ifr_ifru = ifrr.ifr_ifru; return err; } |
cc883d16c
|
359 360 361 362 363 364 365 |
static int vlan_dev_neigh_setup(struct net_device *dev, struct neigh_parms *pa) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; const struct net_device_ops *ops = real_dev->netdev_ops; int err = 0; if (netif_device_present(real_dev) && ops->ndo_neigh_setup) |
9d40bbda5
|
366 |
err = ops->ndo_neigh_setup(real_dev, pa); |
cc883d16c
|
367 368 369 |
return err; } |
b85daa532
|
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) static int vlan_dev_fcoe_ddp_setup(struct net_device *dev, u16 xid, struct scatterlist *sgl, unsigned int sgc) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; const struct net_device_ops *ops = real_dev->netdev_ops; int rc = 0; if (ops->ndo_fcoe_ddp_setup) rc = ops->ndo_fcoe_ddp_setup(real_dev, xid, sgl, sgc); return rc; } static int vlan_dev_fcoe_ddp_done(struct net_device *dev, u16 xid) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; const struct net_device_ops *ops = real_dev->netdev_ops; int len = 0; if (ops->ndo_fcoe_ddp_done) len = ops->ndo_fcoe_ddp_done(real_dev, xid); return len; } |
0af46d997
|
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
static int vlan_dev_fcoe_enable(struct net_device *dev) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; const struct net_device_ops *ops = real_dev->netdev_ops; int rc = -EINVAL; if (ops->ndo_fcoe_enable) rc = ops->ndo_fcoe_enable(real_dev); return rc; } static int vlan_dev_fcoe_disable(struct net_device *dev) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; const struct net_device_ops *ops = real_dev->netdev_ops; int rc = -EINVAL; if (ops->ndo_fcoe_disable) rc = ops->ndo_fcoe_disable(real_dev); return rc; } |
d65347994
|
417 418 419 420 421 422 423 424 425 426 427 |
static int vlan_dev_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; const struct net_device_ops *ops = real_dev->netdev_ops; int rc = -EINVAL; if (ops->ndo_fcoe_get_wwn) rc = ops->ndo_fcoe_get_wwn(real_dev, wwn, type); return rc; } |
4ea09c9ca
|
428 429 430 431 432 433 434 435 436 437 438 439 440 |
static int vlan_dev_fcoe_ddp_target(struct net_device *dev, u16 xid, struct scatterlist *sgl, unsigned int sgc) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; const struct net_device_ops *ops = real_dev->netdev_ops; int rc = 0; if (ops->ndo_fcoe_ddp_target) rc = ops->ndo_fcoe_ddp_target(real_dev, xid, sgl, sgc); return rc; } |
b85daa532
|
441 |
#endif |
ef3eb3e59
|
442 |
static void vlan_dev_change_rx_flags(struct net_device *dev, int change) |
6c78dcbd4
|
443 |
{ |
9dfebcc64
|
444 |
struct net_device *real_dev = vlan_dev_info(dev)->real_dev; |
6c78dcbd4
|
445 446 447 448 449 450 |
if (change & IFF_ALLMULTI) dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1); if (change & IFF_PROMISC) dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1); } |
e83a2ea85
|
451 |
static void vlan_dev_set_rx_mode(struct net_device *vlan_dev) |
1da177e4c
|
452 |
{ |
9dfebcc64
|
453 |
dev_mc_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev); |
a748ee242
|
454 |
dev_uc_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev); |
1da177e4c
|
455 |
} |
ef3eb3e59
|
456 457 458 459 460 461 462 |
/* * vlan network devices have devices nesting below it, and are a special * "super class" of normal network devices; split their locks off into a * separate class since they always nest. */ static struct lock_class_key vlan_netdev_xmit_lock_key; |
cf508b121
|
463 |
static struct lock_class_key vlan_netdev_addr_lock_key; |
ef3eb3e59
|
464 |
|
e8a0464cc
|
465 466 467 |
static void vlan_dev_set_lockdep_one(struct net_device *dev, struct netdev_queue *txq, void *_subclass) |
c773e847e
|
468 469 |
{ lockdep_set_class_and_subclass(&txq->_xmit_lock, |
e8a0464cc
|
470 471 |
&vlan_netdev_xmit_lock_key, *(int *)_subclass); |
c773e847e
|
472 473 474 475 |
} static void vlan_dev_set_lockdep_class(struct net_device *dev, int subclass) { |
cf508b121
|
476 477 478 |
lockdep_set_class_and_subclass(&dev->addr_list_lock, &vlan_netdev_addr_lock_key, subclass); |
e8a0464cc
|
479 |
netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, &subclass); |
c773e847e
|
480 |
} |
ef3eb3e59
|
481 482 483 484 485 |
static const struct header_ops vlan_header_ops = { .create = vlan_dev_hard_header, .rebuild = vlan_dev_rebuild_header, .parse = eth_header_parse, }; |
213b15ca8
|
486 |
static const struct net_device_ops vlan_netdev_ops; |
f7d1b9f5a
|
487 |
|
ef3eb3e59
|
488 489 |
static int vlan_dev_init(struct net_device *dev) { |
9dfebcc64
|
490 |
struct net_device *real_dev = vlan_dev_info(dev)->real_dev; |
ef3eb3e59
|
491 |
int subclass = 0; |
adc667e84
|
492 |
netif_carrier_off(dev); |
ef3eb3e59
|
493 |
/* IFF_BROADCAST|IFF_MULTICAST; ??? */ |
194dbcc8a
|
494 495 |
dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_MASTER | IFF_SLAVE); |
ef3eb3e59
|
496 497 498 499 |
dev->iflink = real_dev->ifindex; dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))) | (1<<__LINK_STATE_PRESENT); |
f0a619ccf
|
500 |
dev->hw_features = NETIF_F_ALL_TX_OFFLOADS; |
8a0427bb6
|
501 |
dev->features |= real_dev->vlan_features | NETIF_F_LLTX; |
1ae4be22f
|
502 |
dev->gso_max_size = real_dev->gso_max_size; |
5fb135705
|
503 |
|
ef3eb3e59
|
504 505 506 507 508 509 510 |
/* ipv6 shared card related stuff */ dev->dev_id = real_dev->dev_id; if (is_zero_ether_addr(dev->dev_addr)) memcpy(dev->dev_addr, real_dev->dev_addr, dev->addr_len); if (is_zero_ether_addr(dev->broadcast)) memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len); |
b85daa532
|
511 512 513 |
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) dev->fcoe_ddp_xid = real_dev->fcoe_ddp_xid; #endif |
d870bfb9d
|
514 |
dev->needed_headroom = real_dev->needed_headroom; |
ef3eb3e59
|
515 516 517 |
if (real_dev->features & NETIF_F_HW_VLAN_TX) { dev->header_ops = real_dev->header_ops; dev->hard_header_len = real_dev->hard_header_len; |
ef3eb3e59
|
518 519 520 |
} else { dev->header_ops = &vlan_header_ops; dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; |
ef3eb3e59
|
521 |
} |
213b15ca8
|
522 |
dev->netdev_ops = &vlan_netdev_ops; |
636e19a34
|
523 |
|
26a25239d
|
524 |
if (is_vlan_dev(real_dev)) |
ef3eb3e59
|
525 |
subclass = 1; |
c773e847e
|
526 |
vlan_dev_set_lockdep_class(dev, subclass); |
9793241fe
|
527 |
|
4af429d29
|
528 529 |
vlan_dev_info(dev)->vlan_pcpu_stats = alloc_percpu(struct vlan_pcpu_stats); if (!vlan_dev_info(dev)->vlan_pcpu_stats) |
9793241fe
|
530 |
return -ENOMEM; |
ef3eb3e59
|
531 532 |
return 0; } |
23556323b
|
533 534 535 536 537 |
static void vlan_dev_uninit(struct net_device *dev) { struct vlan_priority_tci_mapping *pm; struct vlan_dev_info *vlan = vlan_dev_info(dev); int i; |
4af429d29
|
538 539 |
free_percpu(vlan->vlan_pcpu_stats); vlan->vlan_pcpu_stats = NULL; |
23556323b
|
540 541 542 543 544 545 546 |
for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { while ((pm = vlan->egress_priority_map[i]) != NULL) { vlan->egress_priority_map[i] = pm->next; kfree(pm); } } } |
8a0427bb6
|
547 548 549 |
static u32 vlan_dev_fix_features(struct net_device *dev, u32 features) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; |
f0a619ccf
|
550 551 |
features &= real_dev->features; features &= real_dev->vlan_features; |
8a0427bb6
|
552 553 |
if (dev_ethtool_get_rx_csum(real_dev)) features |= NETIF_F_RXCSUM; |
f0a619ccf
|
554 |
features |= NETIF_F_LLTX; |
8a0427bb6
|
555 556 557 |
return features; } |
b30200616
|
558 559 560 561 |
static int vlan_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { const struct vlan_dev_info *vlan = vlan_dev_info(dev); |
b1b67dd45
|
562 |
return dev_ethtool_get_settings(vlan->real_dev, cmd); |
b30200616
|
563 564 565 566 567 568 569 570 571 |
} static void vlan_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strcpy(info->driver, vlan_fullname); strcpy(info->version, vlan_version); strcpy(info->fw_version, "N/A"); } |
28172739f
|
572 |
static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) |
9793241fe
|
573 |
{ |
9793241fe
|
574 |
|
4af429d29
|
575 576 577 |
if (vlan_dev_info(dev)->vlan_pcpu_stats) { struct vlan_pcpu_stats *p; u32 rx_errors = 0, tx_dropped = 0; |
9793241fe
|
578 579 580 |
int i; for_each_possible_cpu(i) { |
4af429d29
|
581 |
u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes; |
9618e2ffd
|
582 |
unsigned int start; |
4af429d29
|
583 |
p = per_cpu_ptr(vlan_dev_info(dev)->vlan_pcpu_stats, i); |
9618e2ffd
|
584 585 586 587 588 |
do { start = u64_stats_fetch_begin_bh(&p->syncp); rxpackets = p->rx_packets; rxbytes = p->rx_bytes; rxmulticast = p->rx_multicast; |
4af429d29
|
589 590 |
txpackets = p->tx_packets; txbytes = p->tx_bytes; |
9618e2ffd
|
591 |
} while (u64_stats_fetch_retry_bh(&p->syncp, start)); |
4af429d29
|
592 593 594 595 596 597 598 599 600 |
stats->rx_packets += rxpackets; stats->rx_bytes += rxbytes; stats->multicast += rxmulticast; stats->tx_packets += txpackets; stats->tx_bytes += txbytes; /* rx_errors & tx_dropped are u32 */ rx_errors += p->rx_errors; tx_dropped += p->tx_dropped; |
9793241fe
|
601 |
} |
4af429d29
|
602 603 |
stats->rx_errors = rx_errors; stats->tx_dropped = tx_dropped; |
9793241fe
|
604 605 606 |
} return stats; } |
75b8846ac
|
607 |
static const struct ethtool_ops vlan_ethtool_ops = { |
b30200616
|
608 609 |
.get_settings = vlan_ethtool_get_settings, .get_drvinfo = vlan_ethtool_get_drvinfo, |
75b8846ac
|
610 |
.get_link = ethtool_op_get_link, |
75b8846ac
|
611 |
}; |
656299f70
|
612 613 614 615 616 617 |
static const struct net_device_ops vlan_netdev_ops = { .ndo_change_mtu = vlan_dev_change_mtu, .ndo_init = vlan_dev_init, .ndo_uninit = vlan_dev_uninit, .ndo_open = vlan_dev_open, .ndo_stop = vlan_dev_stop, |
669d3e0ba
|
618 619 620 621 622 623 624 625 |
.ndo_start_xmit = vlan_dev_hard_start_xmit, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = vlan_dev_set_mac_address, .ndo_set_rx_mode = vlan_dev_set_rx_mode, .ndo_set_multicast_list = vlan_dev_set_rx_mode, .ndo_change_rx_flags = vlan_dev_change_rx_flags, .ndo_do_ioctl = vlan_dev_ioctl, .ndo_neigh_setup = vlan_dev_neigh_setup, |
9618e2ffd
|
626 |
.ndo_get_stats64 = vlan_dev_get_stats64, |
669d3e0ba
|
627 628 629 630 631 632 |
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, .ndo_fcoe_enable = vlan_dev_fcoe_enable, .ndo_fcoe_disable = vlan_dev_fcoe_disable, .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, |
4ea09c9ca
|
633 |
.ndo_fcoe_ddp_target = vlan_dev_fcoe_ddp_target, |
669d3e0ba
|
634 |
#endif |
8a0427bb6
|
635 |
.ndo_fix_features = vlan_dev_fix_features, |
669d3e0ba
|
636 |
}; |
ef3eb3e59
|
637 638 639 640 641 |
void vlan_setup(struct net_device *dev) { ether_setup(dev); dev->priv_flags |= IFF_802_1Q_VLAN; |
93f154b59
|
642 |
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; |
ef3eb3e59
|
643 |
dev->tx_queue_len = 0; |
656299f70
|
644 |
dev->netdev_ops = &vlan_netdev_ops; |
ef3eb3e59
|
645 |
dev->destructor = free_netdev; |
75b8846ac
|
646 |
dev->ethtool_ops = &vlan_ethtool_ops; |
ef3eb3e59
|
647 648 649 |
memset(dev->broadcast, 0, ETH_ALEN); } |