aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_fdb.c148
-rw-r--r--net/bridge/br_private.h6
2 files changed, 134 insertions, 20 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 276a52254606..4b75ad43aa85 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -505,6 +505,10 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
505 ci.ndm_refcnt = 0; 505 ci.ndm_refcnt = 0;
506 if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) 506 if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
507 goto nla_put_failure; 507 goto nla_put_failure;
508
509 if (nla_put(skb, NDA_VLAN, sizeof(u16), &fdb->vlan_id))
510 goto nla_put_failure;
511
508 return nlmsg_end(skb, nlh); 512 return nlmsg_end(skb, nlh);
509 513
510nla_put_failure: 514nla_put_failure:
@@ -516,6 +520,7 @@ static inline size_t fdb_nlmsg_size(void)
516{ 520{
517 return NLMSG_ALIGN(sizeof(struct ndmsg)) 521 return NLMSG_ALIGN(sizeof(struct ndmsg))
518 + nla_total_size(ETH_ALEN) /* NDA_LLADDR */ 522 + nla_total_size(ETH_ALEN) /* NDA_LLADDR */
523 + nla_total_size(sizeof(u16)) /* NDA_VLAN */
519 + nla_total_size(sizeof(struct nda_cacheinfo)); 524 + nla_total_size(sizeof(struct nda_cacheinfo));
520} 525}
521 526
@@ -617,6 +622,25 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
617 return 0; 622 return 0;
618} 623}
619 624
625static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge_port *p,
626 const unsigned char *addr, u16 nlh_flags, u16 vid)
627{
628 int err = 0;
629
630 if (ndm->ndm_flags & NTF_USE) {
631 rcu_read_lock();
632 br_fdb_update(p->br, p, addr, vid);
633 rcu_read_unlock();
634 } else {
635 spin_lock_bh(&p->br->hash_lock);
636 err = fdb_add_entry(p, addr, ndm->ndm_state,
637 nlh_flags, vid);
638 spin_unlock_bh(&p->br->hash_lock);
639 }
640
641 return err;
642}
643
620/* Add new permanent fdb entry with RTM_NEWNEIGH */ 644/* Add new permanent fdb entry with RTM_NEWNEIGH */
621int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], 645int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
622 struct net_device *dev, 646 struct net_device *dev,
@@ -624,12 +648,29 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
624{ 648{
625 struct net_bridge_port *p; 649 struct net_bridge_port *p;
626 int err = 0; 650 int err = 0;
651 struct net_port_vlans *pv;
652 unsigned short vid = VLAN_N_VID;
627 653
628 if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) { 654 if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
629 pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state); 655 pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
630 return -EINVAL; 656 return -EINVAL;
631 } 657 }
632 658
659 if (tb[NDA_VLAN]) {
660 if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
661 pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n");
662 return -EINVAL;
663 }
664
665 vid = nla_get_u16(tb[NDA_VLAN]);
666
667 if (vid >= VLAN_N_VID) {
668 pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n",
669 vid);
670 return -EINVAL;
671 }
672 }
673
633 p = br_port_get_rtnl(dev); 674 p = br_port_get_rtnl(dev);
634 if (p == NULL) { 675 if (p == NULL) {
635 pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n", 676 pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n",
@@ -637,41 +678,90 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
637 return -EINVAL; 678 return -EINVAL;
638 } 679 }
639 680
640 if (ndm->ndm_flags & NTF_USE) { 681 pv = nbp_get_vlan_info(p);
641 rcu_read_lock(); 682 if (vid != VLAN_N_VID) {
642 br_fdb_update(p->br, p, addr, 0); 683 if (!pv || !test_bit(vid, pv->vlan_bitmap)) {
643 rcu_read_unlock(); 684 pr_info("bridge: RTM_NEWNEIGH with unconfigured "
685 "vlan %d on port %s\n", vid, dev->name);
686 return -EINVAL;
687 }
688
689 /* VID was specified, so use it. */
690 err = __br_fdb_add(ndm, p, addr, nlh_flags, vid);
644 } else { 691 } else {
645 spin_lock_bh(&p->br->hash_lock); 692 if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
646 err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags, 693 err = __br_fdb_add(ndm, p, addr, nlh_flags, 0);
647 0); 694 goto out;
648 spin_unlock_bh(&p->br->hash_lock); 695 }
696
697 /* We have vlans configured on this port and user didn't
698 * specify a VLAN. To be nice, add/update entry for every
699 * vlan on this port.
700 */
701 vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN);
702 while (vid < BR_VLAN_BITMAP_LEN) {
703 err = __br_fdb_add(ndm, p, addr, nlh_flags, vid);
704 if (err)
705 goto out;
706 vid = find_next_bit(pv->vlan_bitmap,
707 BR_VLAN_BITMAP_LEN, vid+1);
708 }
649 } 709 }
650 710
711out:
651 return err; 712 return err;
652} 713}
653 714
654static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr) 715static int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr,
716 u16 vlan)
655{ 717{
656 struct net_bridge *br = p->br; 718 struct hlist_head *head = &br->hash[br_mac_hash(addr, vlan)];
657 struct hlist_head *head = &br->hash[br_mac_hash(addr, 0)];
658 struct net_bridge_fdb_entry *fdb; 719 struct net_bridge_fdb_entry *fdb;
659 720
660 fdb = fdb_find(head, addr, 0); 721 fdb = fdb_find(head, addr, vlan);
661 if (!fdb) 722 if (!fdb)
662 return -ENOENT; 723 return -ENOENT;
663 724
664 fdb_delete(p->br, fdb); 725 fdb_delete(br, fdb);
665 return 0; 726 return 0;
666} 727}
667 728
729static int __br_fdb_delete(struct net_bridge_port *p,
730 const unsigned char *addr, u16 vid)
731{
732 int err;
733
734 spin_lock_bh(&p->br->hash_lock);
735 err = fdb_delete_by_addr(p->br, addr, vid);
736 spin_unlock_bh(&p->br->hash_lock);
737
738 return err;
739}
740
668/* Remove neighbor entry with RTM_DELNEIGH */ 741/* Remove neighbor entry with RTM_DELNEIGH */
669int br_fdb_delete(struct ndmsg *ndm, struct net_device *dev, 742int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
743 struct net_device *dev,
670 const unsigned char *addr) 744 const unsigned char *addr)
671{ 745{
672 struct net_bridge_port *p; 746 struct net_bridge_port *p;
673 int err; 747 int err;
748 struct net_port_vlans *pv;
749 unsigned short vid = VLAN_N_VID;
674 750
751 if (tb[NDA_VLAN]) {
752 if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
753 pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n");
754 return -EINVAL;
755 }
756
757 vid = nla_get_u16(tb[NDA_VLAN]);
758
759 if (vid >= VLAN_N_VID) {
760 pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n",
761 vid);
762 return -EINVAL;
763 }
764 }
675 p = br_port_get_rtnl(dev); 765 p = br_port_get_rtnl(dev);
676 if (p == NULL) { 766 if (p == NULL) {
677 pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n", 767 pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n",
@@ -679,9 +769,33 @@ int br_fdb_delete(struct ndmsg *ndm, struct net_device *dev,
679 return -EINVAL; 769 return -EINVAL;
680 } 770 }
681 771
682 spin_lock_bh(&p->br->hash_lock); 772 pv = nbp_get_vlan_info(p);
683 err = fdb_delete_by_addr(p, addr); 773 if (vid != VLAN_N_VID) {
684 spin_unlock_bh(&p->br->hash_lock); 774 if (!pv || !test_bit(vid, pv->vlan_bitmap)) {
775 pr_info("bridge: RTM_DELNEIGH with unconfigured "
776 "vlan %d on port %s\n", vid, dev->name);
777 return -EINVAL;
778 }
685 779
780 err = __br_fdb_delete(p, addr, vid);
781 } else {
782 if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
783 err = __br_fdb_delete(p, addr, 0);
784 goto out;
785 }
786
787 /* We have vlans configured on this port and user didn't
788 * specify a VLAN. To be nice, add/update entry for every
789 * vlan on this port.
790 */
791 err = -ENOENT;
792 vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN);
793 while (vid < BR_VLAN_BITMAP_LEN) {
794 err &= __br_fdb_delete(p, addr, vid);
795 vid = find_next_bit(pv->vlan_bitmap,
796 BR_VLAN_BITMAP_LEN, vid+1);
797 }
798 }
799out:
686 return err; 800 return err;
687} 801}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 22915c8e9961..799dbb37e5a2 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -388,7 +388,7 @@ extern void br_fdb_update(struct net_bridge *br,
388 const unsigned char *addr, 388 const unsigned char *addr,
389 u16 vid); 389 u16 vid);
390 390
391extern int br_fdb_delete(struct ndmsg *ndm, 391extern int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
392 struct net_device *dev, 392 struct net_device *dev,
393 const unsigned char *addr); 393 const unsigned char *addr);
394extern int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], 394extern int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[],
@@ -577,13 +577,13 @@ extern void nbp_vlan_flush(struct net_bridge_port *port);
577static inline struct net_port_vlans *br_get_vlan_info( 577static inline struct net_port_vlans *br_get_vlan_info(
578 const struct net_bridge *br) 578 const struct net_bridge *br)
579{ 579{
580 return rcu_dereference(br->vlan_info); 580 return rcu_dereference_rtnl(br->vlan_info);
581} 581}
582 582
583static inline struct net_port_vlans *nbp_get_vlan_info( 583static inline struct net_port_vlans *nbp_get_vlan_info(
584 const struct net_bridge_port *p) 584 const struct net_bridge_port *p)
585{ 585{
586 return rcu_dereference(p->vlan_info); 586 return rcu_dereference_rtnl(p->vlan_info);
587} 587}
588 588
589/* Since bridge now depends on 8021Q module, but the time bridge sees the 589/* Since bridge now depends on 8021Q module, but the time bridge sees the