aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c4
-rw-r--r--drivers/net/macvlan.c2
-rw-r--r--drivers/net/vxlan.c3
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/uapi/linux/neighbour.h1
-rw-r--r--net/bridge/br_fdb.c148
-rw-r--r--net/bridge/br_private.h6
-rw-r--r--net/core/rtnetlink.c26
10 files changed, 162 insertions, 35 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 4e2aa47193cb..1c0efcb7920f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7002,7 +7002,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
7002 return err; 7002 return err;
7003} 7003}
7004 7004
7005static int ixgbe_ndo_fdb_del(struct ndmsg *ndm, 7005static int ixgbe_ndo_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
7006 struct net_device *dev, 7006 struct net_device *dev,
7007 const unsigned char *addr) 7007 const unsigned char *addr)
7008{ 7008{
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 937bcc3d3212..5088dc5c3d1a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1959,6 +1959,7 @@ static int mlx4_en_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
1959} 1959}
1960 1960
1961static int mlx4_en_fdb_del(struct ndmsg *ndm, 1961static int mlx4_en_fdb_del(struct ndmsg *ndm,
1962 struct nlattr *tb[],
1962 struct net_device *dev, 1963 struct net_device *dev,
1963 const unsigned char *addr) 1964 const unsigned char *addr)
1964{ 1965{
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index b745194391a1..b95316831587 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -247,8 +247,8 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
247 return 0; 247 return 0;
248} 248}
249 249
250static int qlcnic_fdb_del(struct ndmsg *ndm, struct net_device *netdev, 250static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
251 const unsigned char *addr) 251 struct net_device *netdev, const unsigned char *addr)
252{ 252{
253 struct qlcnic_adapter *adapter = netdev_priv(netdev); 253 struct qlcnic_adapter *adapter = netdev_priv(netdev);
254 int err = -EOPNOTSUPP; 254 int err = -EOPNOTSUPP;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index e4b8078e88a9..defcd8a85744 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -599,7 +599,7 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
599 return err; 599 return err;
600} 600}
601 601
602static int macvlan_fdb_del(struct ndmsg *ndm, 602static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
603 struct net_device *dev, 603 struct net_device *dev,
604 const unsigned char *addr) 604 const unsigned char *addr)
605{ 605{
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 72485b9b9005..9d70421cf3a0 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -393,7 +393,8 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
393} 393}
394 394
395/* Delete entry (via netlink) */ 395/* Delete entry (via netlink) */
396static int vxlan_fdb_delete(struct ndmsg *ndm, struct net_device *dev, 396static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
397 struct net_device *dev,
397 const unsigned char *addr) 398 const unsigned char *addr)
398{ 399{
399 struct vxlan_dev *vxlan = netdev_priv(dev); 400 struct vxlan_dev *vxlan = netdev_priv(dev);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 1964ca66df56..9deb672d999f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -884,7 +884,8 @@ struct netdev_fcoe_hbainfo {
884 * struct net_device *dev, 884 * struct net_device *dev,
885 * const unsigned char *addr, u16 flags) 885 * const unsigned char *addr, u16 flags)
886 * Adds an FDB entry to dev for addr. 886 * Adds an FDB entry to dev for addr.
887 * int (*ndo_fdb_del)(struct ndmsg *ndm, struct net_device *dev, 887 * int (*ndo_fdb_del)(struct ndmsg *ndm, struct nlattr *tb[],
888 * struct net_device *dev,
888 * const unsigned char *addr) 889 * const unsigned char *addr)
889 * Deletes the FDB entry from dev coresponding to addr. 890 * Deletes the FDB entry from dev coresponding to addr.
890 * int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb, 891 * int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb,
@@ -1008,6 +1009,7 @@ struct net_device_ops {
1008 const unsigned char *addr, 1009 const unsigned char *addr,
1009 u16 flags); 1010 u16 flags);
1010 int (*ndo_fdb_del)(struct ndmsg *ndm, 1011 int (*ndo_fdb_del)(struct ndmsg *ndm,
1012 struct nlattr *tb[],
1011 struct net_device *dev, 1013 struct net_device *dev,
1012 const unsigned char *addr); 1014 const unsigned char *addr);
1013 int (*ndo_fdb_dump)(struct sk_buff *skb, 1015 int (*ndo_fdb_dump)(struct sk_buff *skb,
diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
index 275e5d65dcb2..adb068c53c4e 100644
--- a/include/uapi/linux/neighbour.h
+++ b/include/uapi/linux/neighbour.h
@@ -20,6 +20,7 @@ enum {
20 NDA_LLADDR, 20 NDA_LLADDR,
21 NDA_CACHEINFO, 21 NDA_CACHEINFO,
22 NDA_PROBES, 22 NDA_PROBES,
23 NDA_VLAN,
23 __NDA_MAX 24 __NDA_MAX
24}; 25};
25 26
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
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index f3a112ec86d5..d8aa20f6a46e 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2119,13 +2119,17 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2119{ 2119{
2120 struct net *net = sock_net(skb->sk); 2120 struct net *net = sock_net(skb->sk);
2121 struct ndmsg *ndm; 2121 struct ndmsg *ndm;
2122 struct nlattr *llattr; 2122 struct nlattr *tb[NDA_MAX+1];
2123 struct net_device *dev; 2123 struct net_device *dev;
2124 int err = -EINVAL; 2124 int err = -EINVAL;
2125 __u8 *addr; 2125 __u8 *addr;
2126 2126
2127 if (nlmsg_len(nlh) < sizeof(*ndm)) 2127 if (!capable(CAP_NET_ADMIN))
2128 return -EINVAL; 2128 return -EPERM;
2129
2130 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
2131 if (err < 0)
2132 return err;
2129 2133
2130 ndm = nlmsg_data(nlh); 2134 ndm = nlmsg_data(nlh);
2131 if (ndm->ndm_ifindex == 0) { 2135 if (ndm->ndm_ifindex == 0) {
@@ -2139,13 +2143,17 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2139 return -ENODEV; 2143 return -ENODEV;
2140 } 2144 }
2141 2145
2142 llattr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_LLADDR); 2146 if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) {
2143 if (llattr == NULL || nla_len(llattr) != ETH_ALEN) { 2147 pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid address\n");
2144 pr_info("PF_BRIGDE: RTM_DELNEIGH with invalid address\n"); 2148 return -EINVAL;
2149 }
2150
2151 addr = nla_data(tb[NDA_LLADDR]);
2152 if (!is_valid_ether_addr(addr)) {
2153 pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid ether address\n");
2145 return -EINVAL; 2154 return -EINVAL;
2146 } 2155 }
2147 2156
2148 addr = nla_data(llattr);
2149 err = -EOPNOTSUPP; 2157 err = -EOPNOTSUPP;
2150 2158
2151 /* Support fdb on master device the net/bridge default case */ 2159 /* Support fdb on master device the net/bridge default case */
@@ -2155,7 +2163,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2155 const struct net_device_ops *ops = br_dev->netdev_ops; 2163 const struct net_device_ops *ops = br_dev->netdev_ops;
2156 2164
2157 if (ops->ndo_fdb_del) 2165 if (ops->ndo_fdb_del)
2158 err = ops->ndo_fdb_del(ndm, dev, addr); 2166 err = ops->ndo_fdb_del(ndm, tb, dev, addr);
2159 2167
2160 if (err) 2168 if (err)
2161 goto out; 2169 goto out;
@@ -2165,7 +2173,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2165 2173
2166 /* Embedded bridge, macvlan, and any other device support */ 2174 /* Embedded bridge, macvlan, and any other device support */
2167 if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) { 2175 if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) {
2168 err = dev->netdev_ops->ndo_fdb_del(ndm, dev, addr); 2176 err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr);
2169 2177
2170 if (!err) { 2178 if (!err) {
2171 rtnl_fdb_notify(dev, addr, RTM_DELNEIGH); 2179 rtnl_fdb_notify(dev, addr, RTM_DELNEIGH);