if_vlan.c (152882) | if_vlan.c (155051) |
---|---|
1/*- 2 * Copyright 1998 Massachusetts Institute of Technology 3 * 4 * Permission to use, copy, modify, and distribute this software and 5 * its documentation for any purpose and without fee is hereby 6 * granted, provided that both the above copyright notice and this 7 * permission notice appear in all copies, that both the above 8 * copyright notice and this permission notice appear in all --- 12 unchanged lines hidden (view full) --- 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * | 1/*- 2 * Copyright 1998 Massachusetts Institute of Technology 3 * 4 * Permission to use, copy, modify, and distribute this software and 5 * its documentation for any purpose and without fee is hereby 6 * granted, provided that both the above copyright notice and this 7 * permission notice appear in all copies, that both the above 8 * copyright notice and this permission notice appear in all --- 12 unchanged lines hidden (view full) --- 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * |
29 * $FreeBSD: head/sys/net/if_vlan.c 152882 2005-11-28 12:46:35Z glebius $ | 29 * $FreeBSD: head/sys/net/if_vlan.c 155051 2006-01-30 13:45:15Z glebius $ |
30 */ 31 32/* 33 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. 34 * Might be extended some day to also handle IEEE 802.1p priority 35 * tagging. This is sort of sneaky in the implementation, since 36 * we need to pretend to be enough of an Ethernet implementation 37 * to make arp work. The way we do this is by telling everyone 38 * that we are an Ethernet, and then catch the packets that 39 * ether_output() left on our output queue when it calls 40 * if_start(), rewrite them for use by the real outgoing interface, 41 * and ask it to send them. 42 */ 43 44#include "opt_inet.h" | 30 */ 31 32/* 33 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. 34 * Might be extended some day to also handle IEEE 802.1p priority 35 * tagging. This is sort of sneaky in the implementation, since 36 * we need to pretend to be enough of an Ethernet implementation 37 * to make arp work. The way we do this is by telling everyone 38 * that we are an Ethernet, and then catch the packets that 39 * ether_output() left on our output queue when it calls 40 * if_start(), rewrite them for use by the real outgoing interface, 41 * and ask it to send them. 42 */ 43 44#include "opt_inet.h" |
45#include "opt_vlan.h" |
|
45 46#include <sys/param.h> 47#include <sys/kernel.h> | 46 47#include <sys/param.h> 48#include <sys/kernel.h> |
49#include <sys/lock.h> |
|
48#include <sys/malloc.h> 49#include <sys/mbuf.h> 50#include <sys/module.h> | 50#include <sys/malloc.h> 51#include <sys/mbuf.h> 52#include <sys/module.h> |
53#include <sys/rwlock.h> |
|
51#include <sys/queue.h> 52#include <sys/socket.h> 53#include <sys/sockio.h> 54#include <sys/sysctl.h> 55#include <sys/systm.h> 56 57#include <net/bpf.h> 58#include <net/ethernet.h> --- 5 unchanged lines hidden (view full) --- 64#include <net/if_vlan_var.h> 65 66#ifdef INET 67#include <netinet/in.h> 68#include <netinet/if_ether.h> 69#endif 70 71#define VLANNAME "vlan" | 54#include <sys/queue.h> 55#include <sys/socket.h> 56#include <sys/sockio.h> 57#include <sys/sysctl.h> 58#include <sys/systm.h> 59 60#include <net/bpf.h> 61#include <net/ethernet.h> --- 5 unchanged lines hidden (view full) --- 67#include <net/if_vlan_var.h> 68 69#ifdef INET 70#include <netinet/in.h> 71#include <netinet/if_ether.h> 72#endif 73 74#define VLANNAME "vlan" |
75#define VLAN_DEF_HWIDTH 4 |
|
72 | 76 |
77LIST_HEAD(ifvlanhead, ifvlan); 78 79struct ifvlantrunk { 80 struct ifnet *parent; /* parent interface of this trunk */ 81 struct rwlock rw; 82#ifdef VLAN_ARRAY 83 struct ifvlan *vlans[EVL_VLID_MASK+1]; /* static table */ 84#else 85 struct ifvlanhead *hash; /* dynamic hash-list table */ 86 uint16_t hmask; 87 uint16_t hwidth; 88#endif 89 int refcnt; 90 LIST_ENTRY(ifvlantrunk) trunk_entry; 91}; 92static LIST_HEAD(, ifvlantrunk) trunk_list; 93 |
|
73struct vlan_mc_entry { 74 struct ether_addr mc_addr; 75 SLIST_ENTRY(vlan_mc_entry) mc_entries; 76}; 77 78struct ifvlan { | 94struct vlan_mc_entry { 95 struct ether_addr mc_addr; 96 SLIST_ENTRY(vlan_mc_entry) mc_entries; 97}; 98 99struct ifvlan { |
100 struct ifvlantrunk *ifv_trunk; |
|
79 struct ifnet *ifv_ifp; | 101 struct ifnet *ifv_ifp; |
80 struct ifnet *ifv_p; /* parent inteface of this vlan */ | 102#define TRUNK(ifv) ((ifv)->ifv_trunk) 103#define PARENT(ifv) ((ifv)->ifv_trunk->parent) |
81 int ifv_pflags; /* special flags we have set on parent */ 82 struct ifv_linkmib { 83 int ifvm_parent; 84 int ifvm_encaplen; /* encapsulation length */ 85 int ifvm_mtufudge; /* MTU fudged by this much */ 86 int ifvm_mintu; /* min transmission unit */ | 104 int ifv_pflags; /* special flags we have set on parent */ 105 struct ifv_linkmib { 106 int ifvm_parent; 107 int ifvm_encaplen; /* encapsulation length */ 108 int ifvm_mtufudge; /* MTU fudged by this much */ 109 int ifvm_mintu; /* min transmission unit */ |
87 u_int16_t ifvm_proto; /* encapsulation ethertype */ 88 u_int16_t ifvm_tag; /* tag to apply on packets leaving if */ | 110 uint16_t ifvm_proto; /* encapsulation ethertype */ 111 uint16_t ifvm_tag; /* tag to apply on packets leaving if */ |
89 } ifv_mib; | 112 } ifv_mib; |
90 SLIST_HEAD(__vlan_mchead, vlan_mc_entry) vlan_mc_listhead; | 113 SLIST_HEAD(__vlan_mchead, vlan_mc_entry) vlan_mc_listhead; |
91 LIST_ENTRY(ifvlan) ifv_list; 92}; 93#define ifv_tag ifv_mib.ifvm_tag 94#define ifv_encaplen ifv_mib.ifvm_encaplen 95#define ifv_mtufudge ifv_mib.ifvm_mtufudge 96#define ifv_mintu ifv_mib.ifvm_mintu 97 | 114 LIST_ENTRY(ifvlan) ifv_list; 115}; 116#define ifv_tag ifv_mib.ifvm_tag 117#define ifv_encaplen ifv_mib.ifvm_encaplen 118#define ifv_mtufudge ifv_mib.ifvm_mtufudge 119#define ifv_mintu ifv_mib.ifvm_mintu 120 |
98/* Special flags we should propagate to parent */ | 121/* Special flags we should propagate to parent. */ |
99static struct { 100 int flag; 101 int (*func)(struct ifnet *, int); 102} vlan_pflags[] = { 103 {IFF_PROMISC, ifpromisc}, 104 {IFF_ALLMULTI, if_allmulti}, 105 {0, NULL} 106}; 107 108SYSCTL_DECL(_net_link); 109SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN"); 110SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency"); 111 112static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface"); | 122static struct { 123 int flag; 124 int (*func)(struct ifnet *, int); 125} vlan_pflags[] = { 126 {IFF_PROMISC, ifpromisc}, 127 {IFF_ALLMULTI, if_allmulti}, 128 {0, NULL} 129}; 130 131SYSCTL_DECL(_net_link); 132SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN"); 133SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency"); 134 135static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface"); |
113static LIST_HEAD(, ifvlan) ifv_list; | |
114 115/* | 136 137/* |
116 * Locking: one lock is used to guard both the ifv_list and modification 117 * to vlan data structures. We are rather conservative here; probably 118 * more than necessary. | 138 * We have a global mutex, that is used to serialize configuration 139 * changes and isn't used in normal packet delivery. 140 * 141 * We also have a per-trunk rwlock, that is locked shared on packet 142 * processing and exclusive when configuration is changed. 143 * 144 * The VLAN_ARRAY substitutes the dynamic hash with a static array 145 * with 4096 entries. In theory this can give a boots in processing, 146 * however on practice it does not. Probably this is because array 147 * is too big to fit into CPU cache. |
119 */ 120static struct mtx ifv_mtx; | 148 */ 149static struct mtx ifv_mtx; |
121#define VLAN_LOCK_INIT() mtx_init(&ifv_mtx, VLANNAME, NULL, MTX_DEF) | 150#define VLAN_LOCK_INIT() mtx_init(&ifv_mtx, "vlan_global", NULL, MTX_DEF) |
122#define VLAN_LOCK_DESTROY() mtx_destroy(&ifv_mtx) 123#define VLAN_LOCK_ASSERT() mtx_assert(&ifv_mtx, MA_OWNED) | 151#define VLAN_LOCK_DESTROY() mtx_destroy(&ifv_mtx) 152#define VLAN_LOCK_ASSERT() mtx_assert(&ifv_mtx, MA_OWNED) |
124#define VLAN_LOCK() mtx_lock(&ifv_mtx) 125#define VLAN_UNLOCK() mtx_unlock(&ifv_mtx) | 153#define VLAN_LOCK() mtx_lock(&ifv_mtx) 154#define VLAN_UNLOCK() mtx_unlock(&ifv_mtx) 155#define TRUNK_LOCK_INIT(trunk) rw_init(&(trunk)->rw, VLANNAME) 156#define TRUNK_LOCK_DESTROY(trunk) rw_destroy(&(trunk)->rw) 157#define TRUNK_LOCK(trunk) rw_wlock(&(trunk)->rw) 158#define TRUNK_UNLOCK(trunk) rw_wunlock(&(trunk)->rw) 159#define TRUNK_LOCK_ASSERT(trunk) rw_assert(&(trunk)->rw, RA_WLOCKED) 160#define TRUNK_RLOCK(trunk) rw_rlock(&(trunk)->rw) 161#define TRUNK_RUNLOCK(trunk) rw_runlock(&(trunk)->rw) 162#define TRUNK_LOCK_RASSERT(trunk) rw_assert(&(trunk)->rw, RA_RLOCKED) |
126 | 163 |
164#ifndef VLAN_ARRAY 165static void vlan_inithash(struct ifvlantrunk *trunk); 166static void vlan_freehash(struct ifvlantrunk *trunk); 167static int vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv); 168static int vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv); 169static void vlan_growhash(struct ifvlantrunk *trunk, int howmuch); 170static __inline struct ifvlan * vlan_gethash(struct ifvlantrunk *trunk, 171 uint16_t tag); 172#endif 173static void trunk_destroy(struct ifvlantrunk *trunk); 174 |
|
127static void vlan_start(struct ifnet *ifp); 128static void vlan_ifinit(void *foo); 129static void vlan_input(struct ifnet *ifp, struct mbuf *m); 130static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); 131static int vlan_setflag(struct ifnet *ifp, int flag, int status, 132 int (*func)(struct ifnet *, int)); 133static int vlan_setflags(struct ifnet *ifp, int status); 134static int vlan_setmulti(struct ifnet *ifp); 135static int vlan_unconfig(struct ifnet *ifp); | 175static void vlan_start(struct ifnet *ifp); 176static void vlan_ifinit(void *foo); 177static void vlan_input(struct ifnet *ifp, struct mbuf *m); 178static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); 179static int vlan_setflag(struct ifnet *ifp, int flag, int status, 180 int (*func)(struct ifnet *, int)); 181static int vlan_setflags(struct ifnet *ifp, int status); 182static int vlan_setmulti(struct ifnet *ifp); 183static int vlan_unconfig(struct ifnet *ifp); |
136static int vlan_config(struct ifvlan *ifv, struct ifnet *p); | 184static int vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag); |
137static void vlan_link_state(struct ifnet *ifp, int link); | 185static void vlan_link_state(struct ifnet *ifp, int link); |
186static void vlan_capabilities(struct ifvlan *ifv); 187static void vlan_trunk_capabilities(struct ifnet *ifp); |
|
138 139static struct ifnet *vlan_clone_match_ethertag(struct if_clone *, 140 const char *, int *); 141static int vlan_clone_match(struct if_clone *, const char *); 142static int vlan_clone_create(struct if_clone *, char *, size_t); 143static int vlan_clone_destroy(struct if_clone *, struct ifnet *); 144 145static struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL, 146 IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy); 147 | 188 189static struct ifnet *vlan_clone_match_ethertag(struct if_clone *, 190 const char *, int *); 191static int vlan_clone_match(struct if_clone *, const char *); 192static int vlan_clone_create(struct if_clone *, char *, size_t); 193static int vlan_clone_destroy(struct if_clone *, struct ifnet *); 194 195static struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL, 196 IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy); 197 |
198#ifndef VLAN_ARRAY 199#define HASH(n, m) ((((n) >> 8) ^ ((n) >> 4) ^ (n)) & (m)) 200static void 201vlan_inithash(struct ifvlantrunk *trunk) 202{ 203 int i, n; 204 205 /* 206 * The trunk must not be locked here since we call malloc(M_WAITOK). 207 * It is OK in case this function is called before the trunk struct 208 * gets hooked up and becomes visible from other threads. 209 */ 210 211 KASSERT(trunk->hwidth == 0 && trunk->hash == NULL, 212 ("%s: hash already initialized", __func__)); 213 214 trunk->hwidth = VLAN_DEF_HWIDTH; 215 n = 1 << trunk->hwidth; 216 trunk->hmask = n - 1; 217 trunk->hash = malloc(sizeof(struct ifvlanhead) * n, M_VLAN, M_WAITOK); 218 for (i = 0; i < n; i++) 219 LIST_INIT(&trunk->hash[i]); 220} 221 222static void 223vlan_freehash(struct ifvlantrunk *trunk) 224{ 225#ifdef INVARIANTS 226 int i; 227 228 TRUNK_LOCK_ASSERT(trunk); /* XXX just unhook trunk first? */ 229 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); 230 for (i = 0; i < (1 << trunk->hwidth); i++) 231 KASSERT(LIST_EMPTY(&trunk->hash[i]), 232 ("%s: hash table not empty", __func__)); 233#endif 234 free(trunk->hash, M_VLAN); 235 trunk->hash = NULL; 236 trunk->hwidth = trunk->hmask = 0; 237} 238 239static int 240vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv) 241{ 242 int i, b; 243 struct ifvlan *ifv2; 244 245 TRUNK_LOCK_ASSERT(trunk); 246 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); 247 248 b = 1 << trunk->hwidth; 249 i = HASH(ifv->ifv_tag, trunk->hmask); 250 LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) 251 if (ifv->ifv_tag == ifv2->ifv_tag) 252 return (EEXIST); 253 254 /* 255 * Grow the hash when the number of vlans exceeds half of the number of 256 * hash buckets squared. This will make the average linked-list length 257 * buckets/2. 258 */ 259 if (trunk->refcnt > (b * b) / 2) { 260 vlan_growhash(trunk, 1); 261 i = HASH(ifv->ifv_tag, trunk->hmask); 262 } 263 LIST_INSERT_HEAD(&trunk->hash[i], ifv, ifv_list); 264 trunk->refcnt++; 265 266 return (0); 267} 268 269static int 270vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv) 271{ 272 int i, b; 273 struct ifvlan *ifv2; 274 275 TRUNK_LOCK_ASSERT(trunk); 276 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); 277 278 b = 1 << trunk->hwidth; 279 i = HASH(ifv->ifv_tag, trunk->hmask); 280 LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) 281 if (ifv2 == ifv) { 282 trunk->refcnt--; 283 LIST_REMOVE(ifv2, ifv_list); 284 if (trunk->refcnt < (b * b) / 2) 285 vlan_growhash(trunk, -1); 286 return (0); 287 } 288 289 panic("%s: vlan not found\n", __func__); 290 return (ENOENT); /*NOTREACHED*/ 291} 292 |
|
148/* | 293/* |
294 * Grow the hash larger or smaller if memory permits. 295 */ 296static void 297vlan_growhash(struct ifvlantrunk *trunk, int howmuch) 298{ 299 300 struct ifvlan *ifv; 301 struct ifvlanhead *hash2; 302 int hwidth2, i, j, n, n2; 303 304 TRUNK_LOCK_ASSERT(trunk); 305 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); 306 307 if (howmuch == 0) { 308 /* Harmless yet obvious coding error */ 309 printf("%s: howmuch is 0\n", __func__); 310 return; 311 } 312 313 hwidth2 = trunk->hwidth + howmuch; 314 n = 1 << trunk->hwidth; 315 n2 = 1 << hwidth2; 316 /* Do not shrink the table below the default */ 317 if (hwidth2 < VLAN_DEF_HWIDTH) 318 return; 319 320 /* M_NOWAIT because we're called with trunk mutex held */ 321 hash2 = malloc(sizeof(struct ifvlanhead) * n2, M_VLAN, M_NOWAIT); 322 if (hash2 == NULL) { 323 printf("%s: out of memory -- hash size not changed\n", 324 __func__); 325 return; /* We can live with the old hash table */ 326 } 327 for (j = 0; j < n2; j++) 328 LIST_INIT(&hash2[j]); 329 for (i = 0; i < n; i++) 330 while (!LIST_EMPTY(&trunk->hash[i])) { 331 ifv = LIST_FIRST(&trunk->hash[i]); 332 LIST_REMOVE(ifv, ifv_list); 333 j = HASH(ifv->ifv_tag, n2 - 1); 334 LIST_INSERT_HEAD(&hash2[j], ifv, ifv_list); 335 } 336 free(trunk->hash, M_VLAN); 337 trunk->hash = hash2; 338 trunk->hwidth = hwidth2; 339 trunk->hmask = n2 - 1; 340} 341 342static __inline struct ifvlan * 343vlan_gethash(struct ifvlantrunk *trunk, uint16_t tag) 344{ 345 struct ifvlan *ifv; 346 347 TRUNK_LOCK_RASSERT(trunk); 348 349 LIST_FOREACH(ifv, &trunk->hash[HASH(tag, trunk->hmask)], ifv_list) 350 if (ifv->ifv_tag == tag) 351 return (ifv); 352 return (NULL); 353} 354 355#if 0 356/* Debugging code to view the hashtables. */ 357static void 358vlan_dumphash(struct ifvlantrunk *trunk) 359{ 360 int i; 361 struct ifvlan *ifv; 362 363 for (i = 0; i < (1 << trunk->hwidth); i++) { 364 printf("%d: ", i); 365 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) 366 printf("%s ", ifv->ifv_ifp->if_xname); 367 printf("\n"); 368 } 369} 370#endif /* 0 */ 371#endif /* !VLAN_ARRAY */ 372 373static void 374trunk_destroy(struct ifvlantrunk *trunk) 375{ 376 VLAN_LOCK_ASSERT(); 377 378 TRUNK_LOCK(trunk); 379#ifndef VLAN_ARRAY 380 vlan_freehash(trunk); 381#endif 382 TRUNK_LOCK_DESTROY(trunk); 383 LIST_REMOVE(trunk, trunk_entry); 384 trunk->parent->if_vlantrunk = NULL; 385 free(trunk, M_VLAN); 386} 387 388/* |
|
149 * Program our multicast filter. What we're actually doing is 150 * programming the multicast filter of the parent. This has the 151 * side effect of causing the parent interface to receive multicast 152 * traffic that it doesn't really want, which ends up being discarded 153 * later by the upper protocol layers. Unfortunately, there's no way 154 * to avoid this: there really is only one physical interface. 155 * 156 * XXX: There is a possible race here if more than one thread is --- 8 unchanged lines hidden (view full) --- 165 struct vlan_mc_entry *mc = NULL; 166 struct sockaddr_dl sdl; 167 int error; 168 169 /*VLAN_LOCK_ASSERT();*/ 170 171 /* Find the parent. */ 172 sc = ifp->if_softc; | 389 * Program our multicast filter. What we're actually doing is 390 * programming the multicast filter of the parent. This has the 391 * side effect of causing the parent interface to receive multicast 392 * traffic that it doesn't really want, which ends up being discarded 393 * later by the upper protocol layers. Unfortunately, there's no way 394 * to avoid this: there really is only one physical interface. 395 * 396 * XXX: There is a possible race here if more than one thread is --- 8 unchanged lines hidden (view full) --- 405 struct vlan_mc_entry *mc = NULL; 406 struct sockaddr_dl sdl; 407 int error; 408 409 /*VLAN_LOCK_ASSERT();*/ 410 411 /* Find the parent. */ 412 sc = ifp->if_softc; |
173 ifp_p = sc->ifv_p; | 413 ifp_p = PARENT(sc); |
174 | 414 |
175 /* 176 * If we don't have a parent, just remember the membership for 177 * when we do. 178 */ 179 if (ifp_p == NULL) 180 return (0); 181 | |
182 bzero((char *)&sdl, sizeof(sdl)); 183 sdl.sdl_len = sizeof(sdl); 184 sdl.sdl_family = AF_LINK; 185 sdl.sdl_index = ifp_p->if_index; 186 sdl.sdl_type = IFT_ETHER; 187 sdl.sdl_alen = ETHER_ADDR_LEN; 188 189 /* First, remove any existing filter entries. */ --- 28 unchanged lines hidden (view full) --- 218} 219 220/* 221 * VLAN support can be loaded as a module. The only place in the 222 * system that's intimately aware of this is ether_input. We hook 223 * into this code through vlan_input_p which is defined there and 224 * set here. Noone else in the system should be aware of this so 225 * we use an explicit reference here. | 415 bzero((char *)&sdl, sizeof(sdl)); 416 sdl.sdl_len = sizeof(sdl); 417 sdl.sdl_family = AF_LINK; 418 sdl.sdl_index = ifp_p->if_index; 419 sdl.sdl_type = IFT_ETHER; 420 sdl.sdl_alen = ETHER_ADDR_LEN; 421 422 /* First, remove any existing filter entries. */ --- 28 unchanged lines hidden (view full) --- 451} 452 453/* 454 * VLAN support can be loaded as a module. The only place in the 455 * system that's intimately aware of this is ether_input. We hook 456 * into this code through vlan_input_p which is defined there and 457 * set here. Noone else in the system should be aware of this so 458 * we use an explicit reference here. |
226 * 227 * NB: Noone should ever need to check if vlan_input_p is null or 228 * not. This is because interfaces have a count of the number 229 * of active vlans (if_nvlans) and this should never be bumped 230 * except by vlan_config--which is in this module so therefore 231 * the module must be loaded and vlan_input_p must be non-NULL. | |
232 */ 233extern void (*vlan_input_p)(struct ifnet *, struct mbuf *); 234 235/* For if_link_state_change() eyes only... */ 236extern void (*vlan_link_state_p)(struct ifnet *, int); 237 238static int 239vlan_modevent(module_t mod, int type, void *data) 240{ 241 242 switch (type) { 243 case MOD_LOAD: | 459 */ 460extern void (*vlan_input_p)(struct ifnet *, struct mbuf *); 461 462/* For if_link_state_change() eyes only... */ 463extern void (*vlan_link_state_p)(struct ifnet *, int); 464 465static int 466vlan_modevent(module_t mod, int type, void *data) 467{ 468 469 switch (type) { 470 case MOD_LOAD: |
244 LIST_INIT(&ifv_list); | 471 LIST_INIT(&trunk_list); |
245 VLAN_LOCK_INIT(); 246 vlan_input_p = vlan_input; 247 vlan_link_state_p = vlan_link_state; | 472 VLAN_LOCK_INIT(); 473 vlan_input_p = vlan_input; 474 vlan_link_state_p = vlan_link_state; |
475 vlan_trunk_cap_p = vlan_trunk_capabilities; |
|
248 if_clone_attach(&vlan_cloner); 249 break; 250 case MOD_UNLOAD: | 476 if_clone_attach(&vlan_cloner); 477 break; 478 case MOD_UNLOAD: |
479 { 480 struct ifvlantrunk *trunk, *trunk1; 481 |
|
251 if_clone_detach(&vlan_cloner); 252 vlan_input_p = NULL; 253 vlan_link_state_p = NULL; | 482 if_clone_detach(&vlan_cloner); 483 vlan_input_p = NULL; 484 vlan_link_state_p = NULL; |
485 vlan_trunk_cap_p = NULL; 486 VLAN_LOCK(); 487 LIST_FOREACH_SAFE(trunk, &trunk_list, trunk_entry, trunk1) 488 trunk_destroy(trunk); 489 VLAN_UNLOCK(); |
|
254 VLAN_LOCK_DESTROY(); 255 break; | 490 VLAN_LOCK_DESTROY(); 491 break; |
492 } |
|
256 default: 257 return (EOPNOTSUPP); 258 } 259 return (0); 260} 261 262static moduledata_t vlan_mod = { 263 "if_vlan", --- 128 unchanged lines hidden (view full) --- 392 ifp->if_ioctl = vlan_ioctl; 393 ifp->if_snd.ifq_maxlen = ifqmaxlen; 394 ether_ifattach(ifp, eaddr); 395 /* Now undo some of the damage... */ 396 ifp->if_baudrate = 0; 397 ifp->if_type = IFT_L2VLAN; 398 ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN; 399 | 493 default: 494 return (EOPNOTSUPP); 495 } 496 return (0); 497} 498 499static moduledata_t vlan_mod = { 500 "if_vlan", --- 128 unchanged lines hidden (view full) --- 629 ifp->if_ioctl = vlan_ioctl; 630 ifp->if_snd.ifq_maxlen = ifqmaxlen; 631 ether_ifattach(ifp, eaddr); 632 /* Now undo some of the damage... */ 633 ifp->if_baudrate = 0; 634 ifp->if_type = IFT_L2VLAN; 635 ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN; 636 |
400 VLAN_LOCK(); 401 LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list); 402 VLAN_UNLOCK(); 403 | |
404 if (ethertag) { | 637 if (ethertag) { |
405 VLAN_LOCK(); 406 error = vlan_config(ifv, p); | 638 error = vlan_config(ifv, p, tag); |
407 if (error != 0) { 408 /* 409 * Since we've partialy failed, we need to back 410 * out all the way, otherwise userland could get 411 * confused. Thus, we destroy the interface. 412 */ | 639 if (error != 0) { 640 /* 641 * Since we've partialy failed, we need to back 642 * out all the way, otherwise userland could get 643 * confused. Thus, we destroy the interface. 644 */ |
413 LIST_REMOVE(ifv, ifv_list); | |
414 vlan_unconfig(ifp); | 645 vlan_unconfig(ifp); |
415 VLAN_UNLOCK(); | |
416 ether_ifdetach(ifp); 417 if_free_type(ifp, IFT_ETHER); 418 free(ifv, M_VLAN); 419 420 return (error); 421 } | 646 ether_ifdetach(ifp); 647 if_free_type(ifp, IFT_ETHER); 648 free(ifv, M_VLAN); 649 650 return (error); 651 } |
422 ifv->ifv_tag = tag; | |
423 ifp->if_drv_flags |= IFF_DRV_RUNNING; | 652 ifp->if_drv_flags |= IFF_DRV_RUNNING; |
424 VLAN_UNLOCK(); | |
425 426 /* Update flags on the parent, if necessary. */ 427 vlan_setflags(ifp, 1); 428 } 429 430 return (0); 431} 432 433static int 434vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) 435{ 436 int unit; 437 struct ifvlan *ifv = ifp->if_softc; 438 439 unit = ifp->if_dunit; 440 | 653 654 /* Update flags on the parent, if necessary. */ 655 vlan_setflags(ifp, 1); 656 } 657 658 return (0); 659} 660 661static int 662vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) 663{ 664 int unit; 665 struct ifvlan *ifv = ifp->if_softc; 666 667 unit = ifp->if_dunit; 668 |
441 VLAN_LOCK(); 442 LIST_REMOVE(ifv, ifv_list); | |
443 vlan_unconfig(ifp); | 669 vlan_unconfig(ifp); |
444 VLAN_UNLOCK(); | |
445 446 ether_ifdetach(ifp); 447 if_free_type(ifp, IFT_ETHER); 448 449 free(ifv, M_VLAN); 450 451 ifc_free_unit(ifc, unit); 452 --- 17 unchanged lines hidden (view full) --- 470 * not called, the queue would never get emptied and 471 * interface would stall forever. 472 */ 473static void 474vlan_start(struct ifnet *ifp) 475{ 476 struct ifvlan *ifv; 477 struct ifnet *p; | 670 671 ether_ifdetach(ifp); 672 if_free_type(ifp, IFT_ETHER); 673 674 free(ifv, M_VLAN); 675 676 ifc_free_unit(ifc, unit); 677 --- 17 unchanged lines hidden (view full) --- 695 * not called, the queue would never get emptied and 696 * interface would stall forever. 697 */ 698static void 699vlan_start(struct ifnet *ifp) 700{ 701 struct ifvlan *ifv; 702 struct ifnet *p; |
478 struct ether_vlan_header *evl; | |
479 struct mbuf *m; 480 int error; 481 482 ifv = ifp->if_softc; | 703 struct mbuf *m; 704 int error; 705 706 ifv = ifp->if_softc; |
483 p = ifv->ifv_p; | 707 p = PARENT(ifv); |
484 485 for (;;) { 486 IF_DEQUEUE(&ifp->if_snd, m); 487 if (m == 0) 488 break; 489 BPF_MTAP(ifp, m); 490 491 /* --- 10 unchanged lines hidden (view full) --- 502 /* 503 * If underlying interface can do VLAN tag insertion itself, 504 * just pass the packet along. However, we need some way to 505 * tell the interface where the packet came from so that it 506 * knows how to find the VLAN tag to use, so we attach a 507 * packet tag that holds it. 508 */ 509 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) { | 708 709 for (;;) { 710 IF_DEQUEUE(&ifp->if_snd, m); 711 if (m == 0) 712 break; 713 BPF_MTAP(ifp, m); 714 715 /* --- 10 unchanged lines hidden (view full) --- 726 /* 727 * If underlying interface can do VLAN tag insertion itself, 728 * just pass the packet along. However, we need some way to 729 * tell the interface where the packet came from so that it 730 * knows how to find the VLAN tag to use, so we attach a 731 * packet tag that holds it. 732 */ 733 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) { |
510 struct m_tag *mtag = m_tag_alloc(MTAG_VLAN, 511 MTAG_VLAN_TAG, 512 sizeof(u_int), 513 M_NOWAIT); | 734 struct m_tag *mtag = (struct m_tag *) 735 uma_zalloc(zone_mtag_vlan, M_NOWAIT); |
514 if (mtag == NULL) { 515 ifp->if_oerrors++; 516 m_freem(m); 517 continue; 518 } 519 VLAN_TAG_VALUE(mtag) = ifv->ifv_tag; 520 m_tag_prepend(m, mtag); 521 m->m_flags |= M_VLANTAG; 522 } else { | 736 if (mtag == NULL) { 737 ifp->if_oerrors++; 738 m_freem(m); 739 continue; 740 } 741 VLAN_TAG_VALUE(mtag) = ifv->ifv_tag; 742 m_tag_prepend(m, mtag); 743 m->m_flags |= M_VLANTAG; 744 } else { |
745 struct ether_vlan_header *evl; 746 |
|
523 M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT); 524 if (m == NULL) { 525 if_printf(ifp, 526 "unable to prepend VLAN header\n"); 527 ifp->if_oerrors++; 528 continue; 529 } 530 /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ --- 34 unchanged lines hidden (view full) --- 565 else 566 ifp->if_oerrors++; 567 } 568} 569 570static void 571vlan_input(struct ifnet *ifp, struct mbuf *m) 572{ | 747 M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT); 748 if (m == NULL) { 749 if_printf(ifp, 750 "unable to prepend VLAN header\n"); 751 ifp->if_oerrors++; 752 continue; 753 } 754 /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ --- 34 unchanged lines hidden (view full) --- 789 else 790 ifp->if_oerrors++; 791 } 792} 793 794static void 795vlan_input(struct ifnet *ifp, struct mbuf *m) 796{ |
573 struct ether_vlan_header *evl; | 797 struct ifvlantrunk *trunk = ifp->if_vlantrunk; |
574 struct ifvlan *ifv; 575 struct m_tag *mtag; | 798 struct ifvlan *ifv; 799 struct m_tag *mtag; |
576 u_int tag; | 800 uint16_t tag; |
577 | 801 |
802 KASSERT(trunk != NULL, ("%s: no trunk", __func__)); 803 |
|
578 if (m->m_flags & M_VLANTAG) { 579 /* 580 * Packet is tagged, but m contains a normal 581 * Ethernet frame; the tag is stored out-of-band. 582 */ 583 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL); 584 KASSERT(mtag != NULL, 585 ("%s: M_VLANTAG without m_tag", __func__)); 586 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag)); 587 m_tag_delete(m, mtag); 588 m->m_flags &= ~M_VLANTAG; 589 } else { | 804 if (m->m_flags & M_VLANTAG) { 805 /* 806 * Packet is tagged, but m contains a normal 807 * Ethernet frame; the tag is stored out-of-band. 808 */ 809 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL); 810 KASSERT(mtag != NULL, 811 ("%s: M_VLANTAG without m_tag", __func__)); 812 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag)); 813 m_tag_delete(m, mtag); 814 m->m_flags &= ~M_VLANTAG; 815 } else { |
816 struct ether_vlan_header *evl; 817 |
|
590 /* 591 * Packet is tagged in-band as specified by 802.1q. 592 */ 593 mtag = NULL; 594 switch (ifp->if_type) { 595 case IFT_ETHER: 596 if (m->m_len < sizeof(*evl) && 597 (m = m_pullup(m, sizeof(*evl))) == NULL) { --- 10 unchanged lines hidden (view full) --- 608 /* 609 * Restore the original ethertype. We'll remove 610 * the encapsulation after we've found the vlan 611 * interface corresponding to the tag. 612 */ 613 evl->evl_encap_proto = evl->evl_proto; 614 break; 615 default: | 818 /* 819 * Packet is tagged in-band as specified by 802.1q. 820 */ 821 mtag = NULL; 822 switch (ifp->if_type) { 823 case IFT_ETHER: 824 if (m->m_len < sizeof(*evl) && 825 (m = m_pullup(m, sizeof(*evl))) == NULL) { --- 10 unchanged lines hidden (view full) --- 836 /* 837 * Restore the original ethertype. We'll remove 838 * the encapsulation after we've found the vlan 839 * interface corresponding to the tag. 840 */ 841 evl->evl_encap_proto = evl->evl_proto; 842 break; 843 default: |
616 tag = (u_int) -1; | 844 tag = (uint16_t) -1; |
617#ifdef INVARIANTS 618 panic("%s: unsupported if_type (%u)", 619 __func__, ifp->if_type); 620#endif 621 break; 622 } 623 } 624 | 845#ifdef INVARIANTS 846 panic("%s: unsupported if_type (%u)", 847 __func__, ifp->if_type); 848#endif 849 break; 850 } 851 } 852 |
625 VLAN_LOCK(); 626 LIST_FOREACH(ifv, &ifv_list, ifv_list) 627 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag) 628 break; 629 | 853 /* 854 * In VLAN_ARRAY case we proceed completely lockless. 855 */ 856#ifdef VLAN_ARRAY 857 ifv = trunk->vlans[tag]; |
630 if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) { | 858 if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) { |
631 VLAN_UNLOCK(); | |
632 m_freem(m); 633 ifp->if_noproto++; | 859 m_freem(m); 860 ifp->if_noproto++; |
634#ifdef DEBUG 635 printf("%s: tag %d, no interface\n", __func__, tag); 636#endif | |
637 return; 638 } | 861 return; 862 } |
639 VLAN_UNLOCK(); /* XXX extend below? */ 640#ifdef DEBUG 641 printf("%s: tag %d, parent %s\n", __func__, tag, ifv->ifv_p->if_xname); | 863#else 864 TRUNK_RLOCK(trunk); 865 ifv = vlan_gethash(trunk, tag); 866 if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) { 867 TRUNK_RUNLOCK(trunk); 868 m_freem(m); 869 ifp->if_noproto++; 870 return; 871 } 872 TRUNK_RUNLOCK(trunk); |
642#endif 643 644 if (mtag == NULL) { 645 /* 646 * Packet had an in-line encapsulation header; 647 * remove it. The original header has already 648 * been fixed up above. 649 */ --- 6 unchanged lines hidden (view full) --- 656 m->m_pkthdr.rcvif = ifv->ifv_ifp; 657 ifv->ifv_ifp->if_ipackets++; 658 659 /* Pass it back through the parent's input routine. */ 660 (*ifp->if_input)(ifv->ifv_ifp, m); 661} 662 663static int | 873#endif 874 875 if (mtag == NULL) { 876 /* 877 * Packet had an in-line encapsulation header; 878 * remove it. The original header has already 879 * been fixed up above. 880 */ --- 6 unchanged lines hidden (view full) --- 887 m->m_pkthdr.rcvif = ifv->ifv_ifp; 888 ifv->ifv_ifp->if_ipackets++; 889 890 /* Pass it back through the parent's input routine. */ 891 (*ifp->if_input)(ifv->ifv_ifp, m); 892} 893 894static int |
664vlan_config(struct ifvlan *ifv, struct ifnet *p) | 895vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag) |
665{ | 896{ |
897 struct ifvlantrunk *trunk; |
|
666 struct ifnet *ifp; | 898 struct ifnet *ifp; |
899 int error = 0; |
|
667 | 900 |
668 VLAN_LOCK_ASSERT(); 669 | 901 /* VID numbers 0x0 and 0xFFF are reserved */ 902 if (tag == 0 || tag == 0xFFF) 903 return (EINVAL); |
670 if (p->if_type != IFT_ETHER) 671 return (EPROTONOSUPPORT); | 904 if (p->if_type != IFT_ETHER) 905 return (EPROTONOSUPPORT); |
672 if (ifv->ifv_p) | 906 if (ifv->ifv_trunk) |
673 return (EBUSY); 674 | 907 return (EBUSY); 908 |
909 if (p->if_vlantrunk == NULL) { 910 trunk = malloc(sizeof(struct ifvlantrunk), 911 M_VLAN, M_WAITOK | M_ZERO); 912 VLAN_LOCK(); 913 if (p->if_vlantrunk != NULL) { 914 /* A race that that is very unlikely to be hit. */ 915 free(trunk, M_VLAN); 916 goto exists; 917 } 918#ifndef VLAN_ARRAY 919 vlan_inithash(trunk); 920#endif 921 TRUNK_LOCK_INIT(trunk); 922 LIST_INSERT_HEAD(&trunk_list, trunk, trunk_entry); 923 TRUNK_LOCK(trunk); 924 p->if_vlantrunk = trunk; 925 trunk->parent = p; 926 } else { 927 VLAN_LOCK(); 928exists: 929 trunk = p->if_vlantrunk; 930 TRUNK_LOCK(trunk); 931 } 932 933 ifv->ifv_tag = tag; 934#ifdef VLAN_ARRAY 935 if (trunk->vlans[tag] != NULL) 936 error = EEXIST; 937#else 938 error = vlan_inshash(trunk, ifv); 939#endif 940 if (error) 941 goto done; 942 |
|
675 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; 676 ifv->ifv_mintu = ETHERMIN; 677 ifv->ifv_pflags = 0; 678 679 /* | 943 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; 944 ifv->ifv_mintu = ETHERMIN; 945 ifv->ifv_pflags = 0; 946 947 /* |
680 * The active VLAN counter on the parent is used 681 * at various places to see if there is a vlan(4) 682 * attached to this physical interface. 683 */ 684 p->if_nvlans++; 685 686 /* | |
687 * If the parent supports the VLAN_MTU capability, 688 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames, 689 * use it. 690 */ 691 if (p->if_capenable & IFCAP_VLAN_MTU) { 692 /* 693 * No need to fudge the MTU since the parent can 694 * handle extended frames. --- 5 unchanged lines hidden (view full) --- 700 * makes us incompatible with strictly compliant 701 * 802.1Q implementations, but allows us to use 702 * the feature with other NetBSD implementations, 703 * which might still be useful. 704 */ 705 ifv->ifv_mtufudge = ifv->ifv_encaplen; 706 } 707 | 948 * If the parent supports the VLAN_MTU capability, 949 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames, 950 * use it. 951 */ 952 if (p->if_capenable & IFCAP_VLAN_MTU) { 953 /* 954 * No need to fudge the MTU since the parent can 955 * handle extended frames. --- 5 unchanged lines hidden (view full) --- 961 * makes us incompatible with strictly compliant 962 * 802.1Q implementations, but allows us to use 963 * the feature with other NetBSD implementations, 964 * which might still be useful. 965 */ 966 ifv->ifv_mtufudge = ifv->ifv_encaplen; 967 } 968 |
708 ifv->ifv_p = p; | 969 ifv->ifv_trunk = trunk; |
709 ifp = ifv->ifv_ifp; 710 ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge; | 970 ifp = ifv->ifv_ifp; 971 ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge; |
711 ifv->ifv_ifp->if_baudrate = p->if_baudrate; | 972 ifp->if_baudrate = p->if_baudrate; |
712 /* 713 * Copy only a selected subset of flags from the parent. 714 * Other flags are none of our business. 715 */ 716#define VLAN_COPY_FLAGS \ 717 (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT) 718 ifp->if_flags &= ~VLAN_COPY_FLAGS; 719 ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS; 720#undef VLAN_COPY_FLAGS 721 722 ifp->if_link_state = p->if_link_state; 723 | 973 /* 974 * Copy only a selected subset of flags from the parent. 975 * Other flags are none of our business. 976 */ 977#define VLAN_COPY_FLAGS \ 978 (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT) 979 ifp->if_flags &= ~VLAN_COPY_FLAGS; 980 ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS; 981#undef VLAN_COPY_FLAGS 982 983 ifp->if_link_state = p->if_link_state; 984 |
724#if 0 725 /* 726 * Not ready yet. We need notification from the parent 727 * when hw checksumming flags in its if_capenable change. 728 * Flags set in if_capabilities only are useless. 729 */ 730 /* 731 * If the parent interface can do hardware-assisted 732 * VLAN encapsulation, then propagate its hardware- 733 * assisted checksumming flags. 734 */ 735 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) 736 ifp->if_capabilities |= p->if_capabilities & IFCAP_HWCSUM; 737#endif | 985 vlan_capabilities(ifv); |
738 739 /* 740 * Set up our ``Ethernet address'' to reflect the underlying 741 * physical interface's. 742 */ 743 bcopy(IF_LLADDR(p), IF_LLADDR(ifp), ETHER_ADDR_LEN); 744 745 /* 746 * Configure multicast addresses that may already be 747 * joined on the vlan device. 748 */ 749 (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */ 750 | 986 987 /* 988 * Set up our ``Ethernet address'' to reflect the underlying 989 * physical interface's. 990 */ 991 bcopy(IF_LLADDR(p), IF_LLADDR(ifp), ETHER_ADDR_LEN); 992 993 /* 994 * Configure multicast addresses that may already be 995 * joined on the vlan device. 996 */ 997 (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */ 998 |
751 return (0); | 999#ifdef VLAN_ARRAY 1000 atomic_store_rel_ptr((uintptr_t *)&trunk->vlans[tag], (uintptr_t)ifv); 1001 trunk->refcnt++; 1002#endif 1003done: 1004 TRUNK_UNLOCK(trunk); 1005 VLAN_UNLOCK(); 1006 1007 return (error); |
752} 753 754static int 755vlan_unconfig(struct ifnet *ifp) 756{ | 1008} 1009 1010static int 1011vlan_unconfig(struct ifnet *ifp) 1012{ |
1013 struct ifvlantrunk *trunk; |
|
757 struct vlan_mc_entry *mc; 758 struct ifvlan *ifv; | 1014 struct vlan_mc_entry *mc; 1015 struct ifvlan *ifv; |
759 struct ifnet *p; | |
760 int error; 761 | 1016 int error; 1017 |
762 VLAN_LOCK_ASSERT(); | 1018 VLAN_LOCK(); |
763 764 ifv = ifp->if_softc; | 1019 1020 ifv = ifp->if_softc; |
765 p = ifv->ifv_p; | 1021 trunk = ifv->ifv_trunk; |
766 | 1022 |
767 if (p) { | 1023 if (trunk) { |
768 struct sockaddr_dl sdl; | 1024 struct sockaddr_dl sdl; |
1025 struct ifnet *p = trunk->parent; |
|
769 | 1026 |
1027 TRUNK_LOCK(trunk); 1028#ifdef VLAN_ARRAY 1029 atomic_store_rel_ptr((uintptr_t *)&trunk->vlans[ifv->ifv_tag], 1030 (uintptr_t)NULL); 1031 trunk->refcnt--; 1032#endif 1033 |
|
770 /* 771 * Since the interface is being unconfigured, we need to 772 * empty the list of multicast groups that we may have joined 773 * while we were alive from the parent's list. 774 */ 775 bzero((char *)&sdl, sizeof(sdl)); 776 sdl.sdl_len = sizeof(sdl); 777 sdl.sdl_family = AF_LINK; --- 8 unchanged lines hidden (view full) --- 786 error = if_delmulti(p, (struct sockaddr *)&sdl); 787 if (error) 788 return (error); 789 SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); 790 free(mc, M_VLAN); 791 } 792 793 vlan_setflags(ifp, 0); /* clear special flags on parent */ | 1034 /* 1035 * Since the interface is being unconfigured, we need to 1036 * empty the list of multicast groups that we may have joined 1037 * while we were alive from the parent's list. 1038 */ 1039 bzero((char *)&sdl, sizeof(sdl)); 1040 sdl.sdl_len = sizeof(sdl); 1041 sdl.sdl_family = AF_LINK; --- 8 unchanged lines hidden (view full) --- 1050 error = if_delmulti(p, (struct sockaddr *)&sdl); 1051 if (error) 1052 return (error); 1053 SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); 1054 free(mc, M_VLAN); 1055 } 1056 1057 vlan_setflags(ifp, 0); /* clear special flags on parent */ |
794 p->if_nvlans--; | 1058#ifndef VLAN_ARRAY 1059 vlan_remhash(trunk, ifv); 1060#endif 1061 ifv->ifv_trunk = NULL; 1062 1063 /* 1064 * Check if we were the last. 1065 */ 1066 if (trunk->refcnt == 0) { 1067 atomic_store_rel_ptr((uintptr_t *) 1068 &trunk->parent->if_vlantrunk, 1069 (uintptr_t)NULL); 1070 /* 1071 * XXXGL: If some ithread has already entered 1072 * vlan_input() and is now blocked on the trunk 1073 * lock, then it should preempt us right after 1074 * unlock and finish its work. Then we will acquire 1075 * lock again in trunk_destroy(). 1076 * XXX: not true in case of VLAN_ARRAY 1077 */ 1078 TRUNK_UNLOCK(trunk); 1079 trunk_destroy(trunk); 1080 } else 1081 TRUNK_UNLOCK(trunk); |
795 } 796 797 /* Disconnect from parent. */ 798 if (ifv->ifv_pflags) 799 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__); | 1082 } 1083 1084 /* Disconnect from parent. */ 1085 if (ifv->ifv_pflags) 1086 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__); |
800 ifv->ifv_p = NULL; | |
801 ifv->ifv_ifp->if_mtu = ETHERMTU; /* XXX why not 0? */ 802 ifv->ifv_ifp->if_link_state = LINK_STATE_UNKNOWN; 803 804 /* Clear our MAC address. */ 805 bzero(IF_LLADDR(ifv->ifv_ifp), ETHER_ADDR_LEN); 806 | 1087 ifv->ifv_ifp->if_mtu = ETHERMTU; /* XXX why not 0? */ 1088 ifv->ifv_ifp->if_link_state = LINK_STATE_UNKNOWN; 1089 1090 /* Clear our MAC address. */ 1091 bzero(IF_LLADDR(ifv->ifv_ifp), ETHER_ADDR_LEN); 1092 |
1093 VLAN_UNLOCK(); 1094 |
|
807 return (0); 808} 809 810/* Handle a reference counted flag that should be set on the parent as well */ 811static int 812vlan_setflag(struct ifnet *ifp, int flag, int status, 813 int (*func)(struct ifnet *, int)) 814{ --- 11 unchanged lines hidden (view full) --- 826 * we want it to be. If it is, flip it. We record parent's 827 * status in ifv_pflags so that we won't clear parent's flag 828 * we haven't set. In fact, we don't clear or set parent's 829 * flags directly, but get or release references to them. 830 * That's why we can be sure that recorded flags still are 831 * in accord with actual parent's flags. 832 */ 833 if (status != (ifv->ifv_pflags & flag)) { | 1095 return (0); 1096} 1097 1098/* Handle a reference counted flag that should be set on the parent as well */ 1099static int 1100vlan_setflag(struct ifnet *ifp, int flag, int status, 1101 int (*func)(struct ifnet *, int)) 1102{ --- 11 unchanged lines hidden (view full) --- 1114 * we want it to be. If it is, flip it. We record parent's 1115 * status in ifv_pflags so that we won't clear parent's flag 1116 * we haven't set. In fact, we don't clear or set parent's 1117 * flags directly, but get or release references to them. 1118 * That's why we can be sure that recorded flags still are 1119 * in accord with actual parent's flags. 1120 */ 1121 if (status != (ifv->ifv_pflags & flag)) { |
834 error = (*func)(ifv->ifv_p, status); | 1122 error = (*func)(PARENT(ifv), status); |
835 if (error) 836 return (error); 837 ifv->ifv_pflags &= ~flag; 838 ifv->ifv_pflags |= status; 839 } 840 return (0); 841} 842 --- 15 unchanged lines hidden (view full) --- 858 } 859 return (0); 860} 861 862/* Inform all vlans that their parent has changed link state */ 863static void 864vlan_link_state(struct ifnet *ifp, int link) 865{ | 1123 if (error) 1124 return (error); 1125 ifv->ifv_pflags &= ~flag; 1126 ifv->ifv_pflags |= status; 1127 } 1128 return (0); 1129} 1130 --- 15 unchanged lines hidden (view full) --- 1146 } 1147 return (0); 1148} 1149 1150/* Inform all vlans that their parent has changed link state */ 1151static void 1152vlan_link_state(struct ifnet *ifp, int link) 1153{ |
1154 struct ifvlantrunk *trunk = ifp->if_vlantrunk; |
|
866 struct ifvlan *ifv; | 1155 struct ifvlan *ifv; |
1156 int i; |
|
867 | 1157 |
868 VLAN_LOCK(); 869 LIST_FOREACH(ifv, &ifv_list, ifv_list) { 870 if (ifv->ifv_p == ifp) | 1158 TRUNK_LOCK(trunk); 1159#ifdef VLAN_ARRAY 1160 for (i = 0; i < EVL_VLID_MASK+1; i++) 1161 if (trunk->vlans[i] != NULL) { 1162 ifv = trunk->vlans[i]; 1163#else 1164 for (i = 0; i < (1 << trunk->hwidth); i++) { 1165 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) 1166#endif |
871 if_link_state_change(ifv->ifv_ifp, | 1167 if_link_state_change(ifv->ifv_ifp, |
872 ifv->ifv_p->if_link_state); | 1168 trunk->parent->if_link_state); |
873 } | 1169 } |
874 VLAN_UNLOCK(); | 1170 TRUNK_UNLOCK(trunk); |
875} 876 | 1171} 1172 |
1173static void 1174vlan_capabilities(struct ifvlan *ifv) 1175{ 1176 struct ifnet *p = PARENT(ifv); 1177 struct ifnet *ifp = ifv->ifv_ifp; 1178 1179 TRUNK_LOCK_ASSERT(TRUNK(ifv)); 1180 1181 /* 1182 * If the parent interface can do checksum offloading 1183 * on VLANs, then propagate its hardware-assisted 1184 * checksumming flags. Also assert that checksum 1185 * offloading requires hardware VLAN tagging. 1186 */ 1187 if (p->if_capabilities & IFCAP_VLAN_HWCSUM) 1188 ifp->if_capabilities = p->if_capabilities & IFCAP_HWCSUM; 1189 1190 if (p->if_capenable & IFCAP_VLAN_HWCSUM && 1191 p->if_capenable & IFCAP_VLAN_HWTAGGING) { 1192 ifp->if_capenable = p->if_capenable & IFCAP_HWCSUM; 1193 ifp->if_hwassist = p->if_hwassist; 1194 } else { 1195 ifp->if_capenable = 0; 1196 ifp->if_hwassist = 0; 1197 } 1198} 1199 1200static void 1201vlan_trunk_capabilities(struct ifnet *ifp) 1202{ 1203 struct ifvlantrunk *trunk = ifp->if_vlantrunk; 1204 struct ifvlan *ifv; 1205 int i; 1206 1207 TRUNK_LOCK(trunk); 1208#ifdef VLAN_ARRAY 1209 for (i = 0; i < EVL_VLID_MASK+1; i++) 1210 if (trunk->vlans[i] != NULL) { 1211 ifv = trunk->vlans[i]; 1212#else 1213 for (i = 0; i < (1 << trunk->hwidth); i++) { 1214 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) 1215#endif 1216 vlan_capabilities(ifv); 1217 } 1218 TRUNK_UNLOCK(trunk); 1219} 1220 |
|
877static int 878vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 879{ 880 struct ifaddr *ifa; 881 struct ifnet *p; 882 struct ifreq *ifr; 883 struct ifvlan *ifv; 884 struct vlanreq vlr; --- 25 unchanged lines hidden (view full) --- 910 sa = (struct sockaddr *) &ifr->ifr_data; 911 bcopy(IF_LLADDR(ifp), (caddr_t)sa->sa_data, 912 ETHER_ADDR_LEN); 913 } 914 break; 915 916 case SIOCGIFMEDIA: 917 VLAN_LOCK(); | 1221static int 1222vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1223{ 1224 struct ifaddr *ifa; 1225 struct ifnet *p; 1226 struct ifreq *ifr; 1227 struct ifvlan *ifv; 1228 struct vlanreq vlr; --- 25 unchanged lines hidden (view full) --- 1254 sa = (struct sockaddr *) &ifr->ifr_data; 1255 bcopy(IF_LLADDR(ifp), (caddr_t)sa->sa_data, 1256 ETHER_ADDR_LEN); 1257 } 1258 break; 1259 1260 case SIOCGIFMEDIA: 1261 VLAN_LOCK(); |
918 if (ifv->ifv_p != NULL) { 919 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, | 1262 if (TRUNK(ifv) != NULL) { 1263 error = (*PARENT(ifv)->if_ioctl)(PARENT(ifv), |
920 SIOCGIFMEDIA, data); 921 VLAN_UNLOCK(); 922 /* Limit the result to the parent's current config. */ 923 if (error == 0) { 924 struct ifmediareq *ifmr; 925 926 ifmr = (struct ifmediareq *)data; 927 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) { --- 13 unchanged lines hidden (view full) --- 941 error = EINVAL; 942 break; 943 944 case SIOCSIFMTU: 945 /* 946 * Set the interface MTU. 947 */ 948 VLAN_LOCK(); | 1264 SIOCGIFMEDIA, data); 1265 VLAN_UNLOCK(); 1266 /* Limit the result to the parent's current config. */ 1267 if (error == 0) { 1268 struct ifmediareq *ifmr; 1269 1270 ifmr = (struct ifmediareq *)data; 1271 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) { --- 13 unchanged lines hidden (view full) --- 1285 error = EINVAL; 1286 break; 1287 1288 case SIOCSIFMTU: 1289 /* 1290 * Set the interface MTU. 1291 */ 1292 VLAN_LOCK(); |
949 if (ifv->ifv_p != NULL) { | 1293 if (TRUNK(ifv) != NULL) { |
950 if (ifr->ifr_mtu > | 1294 if (ifr->ifr_mtu > |
951 (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) || | 1295 (PARENT(ifv)->if_mtu - ifv->ifv_mtufudge) || |
952 ifr->ifr_mtu < 953 (ifv->ifv_mintu - ifv->ifv_mtufudge)) 954 error = EINVAL; 955 else 956 ifp->if_mtu = ifr->ifr_mtu; 957 } else 958 error = EINVAL; 959 VLAN_UNLOCK(); --- 20 unchanged lines hidden (view full) --- 980 /* 981 * Don't let the caller set up a VLAN tag with 982 * anything except VLID bits. 983 */ 984 if (vlr.vlr_tag & ~EVL_VLID_MASK) { 985 error = EINVAL; 986 break; 987 } | 1296 ifr->ifr_mtu < 1297 (ifv->ifv_mintu - ifv->ifv_mtufudge)) 1298 error = EINVAL; 1299 else 1300 ifp->if_mtu = ifr->ifr_mtu; 1301 } else 1302 error = EINVAL; 1303 VLAN_UNLOCK(); --- 20 unchanged lines hidden (view full) --- 1324 /* 1325 * Don't let the caller set up a VLAN tag with 1326 * anything except VLID bits. 1327 */ 1328 if (vlr.vlr_tag & ~EVL_VLID_MASK) { 1329 error = EINVAL; 1330 break; 1331 } |
988 VLAN_LOCK(); 989 error = vlan_config(ifv, p); 990 if (error) { 991 VLAN_UNLOCK(); | 1332 error = vlan_config(ifv, p, vlr.vlr_tag); 1333 if (error) |
992 break; | 1334 break; |
993 } 994 ifv->ifv_tag = vlr.vlr_tag; | |
995 ifp->if_drv_flags |= IFF_DRV_RUNNING; | 1335 ifp->if_drv_flags |= IFF_DRV_RUNNING; |
996 VLAN_UNLOCK(); | |
997 998 /* Update flags on the parent, if necessary. */ 999 vlan_setflags(ifp, 1); 1000 break; 1001 1002 case SIOCGETVLAN: 1003 bzero(&vlr, sizeof(vlr)); 1004 VLAN_LOCK(); | 1336 1337 /* Update flags on the parent, if necessary. */ 1338 vlan_setflags(ifp, 1); 1339 break; 1340 1341 case SIOCGETVLAN: 1342 bzero(&vlr, sizeof(vlr)); 1343 VLAN_LOCK(); |
1005 if (ifv->ifv_p) { 1006 strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname, | 1344 if (TRUNK(ifv) != NULL) { 1345 strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname, |
1007 sizeof(vlr.vlr_parent)); 1008 vlr.vlr_tag = ifv->ifv_tag; 1009 } 1010 VLAN_UNLOCK(); 1011 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr)); 1012 break; 1013 1014 case SIOCSIFFLAGS: 1015 /* 1016 * We should propagate selected flags to the parent, 1017 * e.g., promiscuous mode. 1018 */ | 1346 sizeof(vlr.vlr_parent)); 1347 vlr.vlr_tag = ifv->ifv_tag; 1348 } 1349 VLAN_UNLOCK(); 1350 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr)); 1351 break; 1352 1353 case SIOCSIFFLAGS: 1354 /* 1355 * We should propagate selected flags to the parent, 1356 * e.g., promiscuous mode. 1357 */ |
1019 if (ifv->ifv_p != NULL) | 1358 if (TRUNK(ifv) != NULL) |
1020 error = vlan_setflags(ifp, 1); 1021 break; 1022 1023 case SIOCADDMULTI: 1024 case SIOCDELMULTI: | 1359 error = vlan_setflags(ifp, 1); 1360 break; 1361 1362 case SIOCADDMULTI: 1363 case SIOCDELMULTI: |
1025 /*VLAN_LOCK();*/ 1026 error = vlan_setmulti(ifp); 1027 /*VLAN_UNLOCK();*/ | 1364 /* 1365 * If we don't have a parent, just remember the membership for 1366 * when we do. 1367 */ 1368 if (TRUNK(ifv) != NULL) 1369 error = vlan_setmulti(ifp); |
1028 break; | 1370 break; |
1371 |
|
1029 default: 1030 error = EINVAL; 1031 } 1032 1033 return (error); 1034} | 1372 default: 1373 error = EINVAL; 1374 } 1375 1376 return (error); 1377} |