aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_fdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge/br_fdb.c')
-rw-r--r--net/bridge/br_fdb.c258
1 files changed, 207 insertions, 51 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index d9576e6de2b8..8117900af4de 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -23,11 +23,12 @@
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/atomic.h> 24#include <linux/atomic.h>
25#include <asm/unaligned.h> 25#include <asm/unaligned.h>
26#include <linux/if_vlan.h>
26#include "br_private.h" 27#include "br_private.h"
27 28
28static struct kmem_cache *br_fdb_cache __read_mostly; 29static struct kmem_cache *br_fdb_cache __read_mostly;
29static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, 30static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
30 const unsigned char *addr); 31 const unsigned char *addr, u16 vid);
31static void fdb_notify(struct net_bridge *br, 32static void fdb_notify(struct net_bridge *br,
32 const struct net_bridge_fdb_entry *, int); 33 const struct net_bridge_fdb_entry *, int);
33 34
@@ -67,11 +68,11 @@ static inline int has_expired(const struct net_bridge *br,
67 time_before_eq(fdb->updated + hold_time(br), jiffies); 68 time_before_eq(fdb->updated + hold_time(br), jiffies);
68} 69}
69 70
70static inline int br_mac_hash(const unsigned char *mac) 71static inline int br_mac_hash(const unsigned char *mac, __u16 vid)
71{ 72{
72 /* use 1 byte of OUI cnd 3 bytes of NIC */ 73 /* use 1 byte of OUI and 3 bytes of NIC */
73 u32 key = get_unaligned((u32 *)(mac + 2)); 74 u32 key = get_unaligned((u32 *)(mac + 2));
74 return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1); 75 return jhash_2words(key, vid, fdb_salt) & (BR_HASH_SIZE - 1);
75} 76}
76 77
77static void fdb_rcu_free(struct rcu_head *head) 78static void fdb_rcu_free(struct rcu_head *head)
@@ -91,6 +92,7 @@ static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
91void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) 92void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
92{ 93{
93 struct net_bridge *br = p->br; 94 struct net_bridge *br = p->br;
95 bool no_vlan = (nbp_get_vlan_info(p) == NULL) ? true : false;
94 int i; 96 int i;
95 97
96 spin_lock_bh(&br->hash_lock); 98 spin_lock_bh(&br->hash_lock);
@@ -105,10 +107,12 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
105 if (f->dst == p && f->is_local) { 107 if (f->dst == p && f->is_local) {
106 /* maybe another port has same hw addr? */ 108 /* maybe another port has same hw addr? */
107 struct net_bridge_port *op; 109 struct net_bridge_port *op;
110 u16 vid = f->vlan_id;
108 list_for_each_entry(op, &br->port_list, list) { 111 list_for_each_entry(op, &br->port_list, list) {
109 if (op != p && 112 if (op != p &&
110 ether_addr_equal(op->dev->dev_addr, 113 ether_addr_equal(op->dev->dev_addr,
111 f->addr.addr)) { 114 f->addr.addr) &&
115 nbp_vlan_find(op, vid)) {
112 f->dst = op; 116 f->dst = op;
113 goto insert; 117 goto insert;
114 } 118 }
@@ -116,27 +120,55 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
116 120
117 /* delete old one */ 121 /* delete old one */
118 fdb_delete(br, f); 122 fdb_delete(br, f);
119 goto insert; 123insert:
124 /* insert new address, may fail if invalid
125 * address or dup.
126 */
127 fdb_insert(br, p, newaddr, vid);
128
129 /* if this port has no vlan information
130 * configured, we can safely be done at
131 * this point.
132 */
133 if (no_vlan)
134 goto done;
120 } 135 }
121 } 136 }
122 } 137 }
123 insert:
124 /* insert new address, may fail if invalid address or dup. */
125 fdb_insert(br, p, newaddr);
126 138
139done:
127 spin_unlock_bh(&br->hash_lock); 140 spin_unlock_bh(&br->hash_lock);
128} 141}
129 142
130void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr) 143void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
131{ 144{
132 struct net_bridge_fdb_entry *f; 145 struct net_bridge_fdb_entry *f;
146 struct net_port_vlans *pv;
147 u16 vid = 0;
133 148
134 /* If old entry was unassociated with any port, then delete it. */ 149 /* If old entry was unassociated with any port, then delete it. */
135 f = __br_fdb_get(br, br->dev->dev_addr); 150 f = __br_fdb_get(br, br->dev->dev_addr, 0);
136 if (f && f->is_local && !f->dst) 151 if (f && f->is_local && !f->dst)
137 fdb_delete(br, f); 152 fdb_delete(br, f);
138 153
139 fdb_insert(br, NULL, newaddr); 154 fdb_insert(br, NULL, newaddr, 0);
155
156 /* Now remove and add entries for every VLAN configured on the
157 * bridge. This function runs under RTNL so the bitmap will not
158 * change from under us.
159 */
160 pv = br_get_vlan_info(br);
161 if (!pv)
162 return;
163
164 for (vid = find_next_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN, vid);
165 vid < BR_VLAN_BITMAP_LEN;
166 vid = find_next_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN, vid+1)) {
167 f = __br_fdb_get(br, br->dev->dev_addr, vid);
168 if (f && f->is_local && !f->dst)
169 fdb_delete(br, f);
170 fdb_insert(br, NULL, newaddr, vid);
171 }
140} 172}
141 173
142void br_fdb_cleanup(unsigned long _data) 174void br_fdb_cleanup(unsigned long _data)
@@ -231,13 +263,16 @@ void br_fdb_delete_by_port(struct net_bridge *br,
231 263
232/* No locking or refcounting, assumes caller has rcu_read_lock */ 264/* No locking or refcounting, assumes caller has rcu_read_lock */
233struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, 265struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
234 const unsigned char *addr) 266 const unsigned char *addr,
267 __u16 vid)
235{ 268{
236 struct hlist_node *h; 269 struct hlist_node *h;
237 struct net_bridge_fdb_entry *fdb; 270 struct net_bridge_fdb_entry *fdb;
238 271
239 hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) { 272 hlist_for_each_entry_rcu(fdb, h,
240 if (ether_addr_equal(fdb->addr.addr, addr)) { 273 &br->hash[br_mac_hash(addr, vid)], hlist) {
274 if (ether_addr_equal(fdb->addr.addr, addr) &&
275 fdb->vlan_id == vid) {
241 if (unlikely(has_expired(br, fdb))) 276 if (unlikely(has_expired(br, fdb)))
242 break; 277 break;
243 return fdb; 278 return fdb;
@@ -261,7 +296,7 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
261 if (!port) 296 if (!port)
262 ret = 0; 297 ret = 0;
263 else { 298 else {
264 fdb = __br_fdb_get(port->br, addr); 299 fdb = __br_fdb_get(port->br, addr, 0);
265 ret = fdb && fdb->dst && fdb->dst->dev != dev && 300 ret = fdb && fdb->dst && fdb->dst->dev != dev &&
266 fdb->dst->state == BR_STATE_FORWARDING; 301 fdb->dst->state == BR_STATE_FORWARDING;
267 } 302 }
@@ -325,26 +360,30 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
325} 360}
326 361
327static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head, 362static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
328 const unsigned char *addr) 363 const unsigned char *addr,
364 __u16 vid)
329{ 365{
330 struct hlist_node *h; 366 struct hlist_node *h;
331 struct net_bridge_fdb_entry *fdb; 367 struct net_bridge_fdb_entry *fdb;
332 368
333 hlist_for_each_entry(fdb, h, head, hlist) { 369 hlist_for_each_entry(fdb, h, head, hlist) {
334 if (ether_addr_equal(fdb->addr.addr, addr)) 370 if (ether_addr_equal(fdb->addr.addr, addr) &&
371 fdb->vlan_id == vid)
335 return fdb; 372 return fdb;
336 } 373 }
337 return NULL; 374 return NULL;
338} 375}
339 376
340static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head, 377static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head,
341 const unsigned char *addr) 378 const unsigned char *addr,
379 __u16 vid)
342{ 380{
343 struct hlist_node *h; 381 struct hlist_node *h;
344 struct net_bridge_fdb_entry *fdb; 382 struct net_bridge_fdb_entry *fdb;
345 383
346 hlist_for_each_entry_rcu(fdb, h, head, hlist) { 384 hlist_for_each_entry_rcu(fdb, h, head, hlist) {
347 if (ether_addr_equal(fdb->addr.addr, addr)) 385 if (ether_addr_equal(fdb->addr.addr, addr) &&
386 fdb->vlan_id == vid)
348 return fdb; 387 return fdb;
349 } 388 }
350 return NULL; 389 return NULL;
@@ -352,7 +391,8 @@ static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head,
352 391
353static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, 392static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
354 struct net_bridge_port *source, 393 struct net_bridge_port *source,
355 const unsigned char *addr) 394 const unsigned char *addr,
395 __u16 vid)
356{ 396{
357 struct net_bridge_fdb_entry *fdb; 397 struct net_bridge_fdb_entry *fdb;
358 398
@@ -360,6 +400,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
360 if (fdb) { 400 if (fdb) {
361 memcpy(fdb->addr.addr, addr, ETH_ALEN); 401 memcpy(fdb->addr.addr, addr, ETH_ALEN);
362 fdb->dst = source; 402 fdb->dst = source;
403 fdb->vlan_id = vid;
363 fdb->is_local = 0; 404 fdb->is_local = 0;
364 fdb->is_static = 0; 405 fdb->is_static = 0;
365 fdb->updated = fdb->used = jiffies; 406 fdb->updated = fdb->used = jiffies;
@@ -369,15 +410,15 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
369} 410}
370 411
371static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, 412static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
372 const unsigned char *addr) 413 const unsigned char *addr, u16 vid)
373{ 414{
374 struct hlist_head *head = &br->hash[br_mac_hash(addr)]; 415 struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
375 struct net_bridge_fdb_entry *fdb; 416 struct net_bridge_fdb_entry *fdb;
376 417
377 if (!is_valid_ether_addr(addr)) 418 if (!is_valid_ether_addr(addr))
378 return -EINVAL; 419 return -EINVAL;
379 420
380 fdb = fdb_find(head, addr); 421 fdb = fdb_find(head, addr, vid);
381 if (fdb) { 422 if (fdb) {
382 /* it is okay to have multiple ports with same 423 /* it is okay to have multiple ports with same
383 * address, just use the first one. 424 * address, just use the first one.
@@ -390,7 +431,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
390 fdb_delete(br, fdb); 431 fdb_delete(br, fdb);
391 } 432 }
392 433
393 fdb = fdb_create(head, source, addr); 434 fdb = fdb_create(head, source, addr, vid);
394 if (!fdb) 435 if (!fdb)
395 return -ENOMEM; 436 return -ENOMEM;
396 437
@@ -401,20 +442,20 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
401 442
402/* Add entry for local address of interface */ 443/* Add entry for local address of interface */
403int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source, 444int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
404 const unsigned char *addr) 445 const unsigned char *addr, u16 vid)
405{ 446{
406 int ret; 447 int ret;
407 448
408 spin_lock_bh(&br->hash_lock); 449 spin_lock_bh(&br->hash_lock);
409 ret = fdb_insert(br, source, addr); 450 ret = fdb_insert(br, source, addr, vid);
410 spin_unlock_bh(&br->hash_lock); 451 spin_unlock_bh(&br->hash_lock);
411 return ret; 452 return ret;
412} 453}
413 454
414void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, 455void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
415 const unsigned char *addr) 456 const unsigned char *addr, u16 vid)
416{ 457{
417 struct hlist_head *head = &br->hash[br_mac_hash(addr)]; 458 struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
418 struct net_bridge_fdb_entry *fdb; 459 struct net_bridge_fdb_entry *fdb;
419 460
420 /* some users want to always flood. */ 461 /* some users want to always flood. */
@@ -426,7 +467,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
426 source->state == BR_STATE_FORWARDING)) 467 source->state == BR_STATE_FORWARDING))
427 return; 468 return;
428 469
429 fdb = fdb_find_rcu(head, addr); 470 fdb = fdb_find_rcu(head, addr, vid);
430 if (likely(fdb)) { 471 if (likely(fdb)) {
431 /* attempt to update an entry for a local interface */ 472 /* attempt to update an entry for a local interface */
432 if (unlikely(fdb->is_local)) { 473 if (unlikely(fdb->is_local)) {
@@ -441,8 +482,8 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
441 } 482 }
442 } else { 483 } else {
443 spin_lock(&br->hash_lock); 484 spin_lock(&br->hash_lock);
444 if (likely(!fdb_find(head, addr))) { 485 if (likely(!fdb_find(head, addr, vid))) {
445 fdb = fdb_create(head, source, addr); 486 fdb = fdb_create(head, source, addr, vid);
446 if (fdb) 487 if (fdb)
447 fdb_notify(br, fdb, RTM_NEWNEIGH); 488 fdb_notify(br, fdb, RTM_NEWNEIGH);
448 } 489 }
@@ -495,6 +536,10 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
495 ci.ndm_refcnt = 0; 536 ci.ndm_refcnt = 0;
496 if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) 537 if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
497 goto nla_put_failure; 538 goto nla_put_failure;
539
540 if (nla_put(skb, NDA_VLAN, sizeof(u16), &fdb->vlan_id))
541 goto nla_put_failure;
542
498 return nlmsg_end(skb, nlh); 543 return nlmsg_end(skb, nlh);
499 544
500nla_put_failure: 545nla_put_failure:
@@ -506,6 +551,7 @@ static inline size_t fdb_nlmsg_size(void)
506{ 551{
507 return NLMSG_ALIGN(sizeof(struct ndmsg)) 552 return NLMSG_ALIGN(sizeof(struct ndmsg))
508 + nla_total_size(ETH_ALEN) /* NDA_LLADDR */ 553 + nla_total_size(ETH_ALEN) /* NDA_LLADDR */
554 + nla_total_size(sizeof(u16)) /* NDA_VLAN */
509 + nla_total_size(sizeof(struct nda_cacheinfo)); 555 + nla_total_size(sizeof(struct nda_cacheinfo));
510} 556}
511 557
@@ -571,18 +617,18 @@ out:
571 617
572/* Update (create or replace) forwarding database entry */ 618/* Update (create or replace) forwarding database entry */
573static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr, 619static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
574 __u16 state, __u16 flags) 620 __u16 state, __u16 flags, __u16 vid)
575{ 621{
576 struct net_bridge *br = source->br; 622 struct net_bridge *br = source->br;
577 struct hlist_head *head = &br->hash[br_mac_hash(addr)]; 623 struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
578 struct net_bridge_fdb_entry *fdb; 624 struct net_bridge_fdb_entry *fdb;
579 625
580 fdb = fdb_find(head, addr); 626 fdb = fdb_find(head, addr, vid);
581 if (fdb == NULL) { 627 if (fdb == NULL) {
582 if (!(flags & NLM_F_CREATE)) 628 if (!(flags & NLM_F_CREATE))
583 return -ENOENT; 629 return -ENOENT;
584 630
585 fdb = fdb_create(head, source, addr); 631 fdb = fdb_create(head, source, addr, vid);
586 if (!fdb) 632 if (!fdb)
587 return -ENOMEM; 633 return -ENOMEM;
588 fdb_notify(br, fdb, RTM_NEWNEIGH); 634 fdb_notify(br, fdb, RTM_NEWNEIGH);
@@ -607,6 +653,25 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
607 return 0; 653 return 0;
608} 654}
609 655
656static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge_port *p,
657 const unsigned char *addr, u16 nlh_flags, u16 vid)
658{
659 int err = 0;
660
661 if (ndm->ndm_flags & NTF_USE) {
662 rcu_read_lock();
663 br_fdb_update(p->br, p, addr, vid);
664 rcu_read_unlock();
665 } else {
666 spin_lock_bh(&p->br->hash_lock);
667 err = fdb_add_entry(p, addr, ndm->ndm_state,
668 nlh_flags, vid);
669 spin_unlock_bh(&p->br->hash_lock);
670 }
671
672 return err;
673}
674
610/* Add new permanent fdb entry with RTM_NEWNEIGH */ 675/* Add new permanent fdb entry with RTM_NEWNEIGH */
611int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], 676int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
612 struct net_device *dev, 677 struct net_device *dev,
@@ -614,12 +679,29 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
614{ 679{
615 struct net_bridge_port *p; 680 struct net_bridge_port *p;
616 int err = 0; 681 int err = 0;
682 struct net_port_vlans *pv;
683 unsigned short vid = VLAN_N_VID;
617 684
618 if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) { 685 if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
619 pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state); 686 pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
620 return -EINVAL; 687 return -EINVAL;
621 } 688 }
622 689
690 if (tb[NDA_VLAN]) {
691 if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
692 pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n");
693 return -EINVAL;
694 }
695
696 vid = nla_get_u16(tb[NDA_VLAN]);
697
698 if (vid >= VLAN_N_VID) {
699 pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n",
700 vid);
701 return -EINVAL;
702 }
703 }
704
623 p = br_port_get_rtnl(dev); 705 p = br_port_get_rtnl(dev);
624 if (p == NULL) { 706 if (p == NULL) {
625 pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n", 707 pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n",
@@ -627,40 +709,90 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
627 return -EINVAL; 709 return -EINVAL;
628 } 710 }
629 711
630 if (ndm->ndm_flags & NTF_USE) { 712 pv = nbp_get_vlan_info(p);
631 rcu_read_lock(); 713 if (vid != VLAN_N_VID) {
632 br_fdb_update(p->br, p, addr); 714 if (!pv || !test_bit(vid, pv->vlan_bitmap)) {
633 rcu_read_unlock(); 715 pr_info("bridge: RTM_NEWNEIGH with unconfigured "
716 "vlan %d on port %s\n", vid, dev->name);
717 return -EINVAL;
718 }
719
720 /* VID was specified, so use it. */
721 err = __br_fdb_add(ndm, p, addr, nlh_flags, vid);
634 } else { 722 } else {
635 spin_lock_bh(&p->br->hash_lock); 723 if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
636 err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags); 724 err = __br_fdb_add(ndm, p, addr, nlh_flags, 0);
637 spin_unlock_bh(&p->br->hash_lock); 725 goto out;
726 }
727
728 /* We have vlans configured on this port and user didn't
729 * specify a VLAN. To be nice, add/update entry for every
730 * vlan on this port.
731 */
732 vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN);
733 while (vid < BR_VLAN_BITMAP_LEN) {
734 err = __br_fdb_add(ndm, p, addr, nlh_flags, vid);
735 if (err)
736 goto out;
737 vid = find_next_bit(pv->vlan_bitmap,
738 BR_VLAN_BITMAP_LEN, vid+1);
739 }
638 } 740 }
639 741
742out:
640 return err; 743 return err;
641} 744}
642 745
643static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr) 746int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr,
747 u16 vlan)
644{ 748{
645 struct net_bridge *br = p->br; 749 struct hlist_head *head = &br->hash[br_mac_hash(addr, vlan)];
646 struct hlist_head *head = &br->hash[br_mac_hash(addr)];
647 struct net_bridge_fdb_entry *fdb; 750 struct net_bridge_fdb_entry *fdb;
648 751
649 fdb = fdb_find(head, addr); 752 fdb = fdb_find(head, addr, vlan);
650 if (!fdb) 753 if (!fdb)
651 return -ENOENT; 754 return -ENOENT;
652 755
653 fdb_delete(p->br, fdb); 756 fdb_delete(br, fdb);
654 return 0; 757 return 0;
655} 758}
656 759
760static int __br_fdb_delete(struct net_bridge_port *p,
761 const unsigned char *addr, u16 vid)
762{
763 int err;
764
765 spin_lock_bh(&p->br->hash_lock);
766 err = fdb_delete_by_addr(p->br, addr, vid);
767 spin_unlock_bh(&p->br->hash_lock);
768
769 return err;
770}
771
657/* Remove neighbor entry with RTM_DELNEIGH */ 772/* Remove neighbor entry with RTM_DELNEIGH */
658int br_fdb_delete(struct ndmsg *ndm, struct net_device *dev, 773int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
774 struct net_device *dev,
659 const unsigned char *addr) 775 const unsigned char *addr)
660{ 776{
661 struct net_bridge_port *p; 777 struct net_bridge_port *p;
662 int err; 778 int err;
779 struct net_port_vlans *pv;
780 unsigned short vid = VLAN_N_VID;
781
782 if (tb[NDA_VLAN]) {
783 if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
784 pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n");
785 return -EINVAL;
786 }
787
788 vid = nla_get_u16(tb[NDA_VLAN]);
663 789
790 if (vid >= VLAN_N_VID) {
791 pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n",
792 vid);
793 return -EINVAL;
794 }
795 }
664 p = br_port_get_rtnl(dev); 796 p = br_port_get_rtnl(dev);
665 if (p == NULL) { 797 if (p == NULL) {
666 pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n", 798 pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n",
@@ -668,9 +800,33 @@ int br_fdb_delete(struct ndmsg *ndm, struct net_device *dev,
668 return -EINVAL; 800 return -EINVAL;
669 } 801 }
670 802
671 spin_lock_bh(&p->br->hash_lock); 803 pv = nbp_get_vlan_info(p);
672 err = fdb_delete_by_addr(p, addr); 804 if (vid != VLAN_N_VID) {
673 spin_unlock_bh(&p->br->hash_lock); 805 if (!pv || !test_bit(vid, pv->vlan_bitmap)) {
806 pr_info("bridge: RTM_DELNEIGH with unconfigured "
807 "vlan %d on port %s\n", vid, dev->name);
808 return -EINVAL;
809 }
810
811 err = __br_fdb_delete(p, addr, vid);
812 } else {
813 if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
814 err = __br_fdb_delete(p, addr, 0);
815 goto out;
816 }
674 817
818 /* We have vlans configured on this port and user didn't
819 * specify a VLAN. To be nice, add/update entry for every
820 * vlan on this port.
821 */
822 err = -ENOENT;
823 vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN);
824 while (vid < BR_VLAN_BITMAP_LEN) {
825 err &= __br_fdb_delete(p, addr, vid);
826 vid = find_next_bit(pv->vlan_bitmap,
827 BR_VLAN_BITMAP_LEN, vid+1);
828 }
829 }
830out:
675 return err; 831 return err;
676} 832}