aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_fdb.c91
-rw-r--r--net/bridge/br_private.h3
2 files changed, 92 insertions, 2 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index b1be971eb06c..cc36e59db7d7 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -481,6 +481,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
481 fdb->is_local = 0; 481 fdb->is_local = 0;
482 fdb->is_static = 0; 482 fdb->is_static = 0;
483 fdb->added_by_user = 0; 483 fdb->added_by_user = 0;
484 fdb->added_by_external_learn = 0;
484 fdb->updated = fdb->used = jiffies; 485 fdb->updated = fdb->used = jiffies;
485 hlist_add_head_rcu(&fdb->hlist, head); 486 hlist_add_head_rcu(&fdb->hlist, head);
486 } 487 }
@@ -613,7 +614,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
613 ndm->ndm_family = AF_BRIDGE; 614 ndm->ndm_family = AF_BRIDGE;
614 ndm->ndm_pad1 = 0; 615 ndm->ndm_pad1 = 0;
615 ndm->ndm_pad2 = 0; 616 ndm->ndm_pad2 = 0;
616 ndm->ndm_flags = 0; 617 ndm->ndm_flags = fdb->added_by_external_learn ? NTF_EXT_LEARNED : 0;
617 ndm->ndm_type = 0; 618 ndm->ndm_type = 0;
618 ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex; 619 ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex;
619 ndm->ndm_state = fdb_to_nud(fdb); 620 ndm->ndm_state = fdb_to_nud(fdb);
@@ -983,3 +984,91 @@ void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p)
983 } 984 }
984 } 985 }
985} 986}
987
988int br_fdb_external_learn_add(struct net_device *dev,
989 const unsigned char *addr, u16 vid)
990{
991 struct net_bridge_port *p;
992 struct net_bridge *br;
993 struct hlist_head *head;
994 struct net_bridge_fdb_entry *fdb;
995 int err = 0;
996
997 rtnl_lock();
998
999 p = br_port_get_rtnl(dev);
1000 if (!p) {
1001 pr_info("bridge: %s not a bridge port\n", dev->name);
1002 err = -EINVAL;
1003 goto err_rtnl_unlock;
1004 }
1005
1006 br = p->br;
1007
1008 spin_lock_bh(&br->hash_lock);
1009
1010 head = &br->hash[br_mac_hash(addr, vid)];
1011 fdb = fdb_find(head, addr, vid);
1012 if (!fdb) {
1013 fdb = fdb_create(head, p, addr, vid);
1014 if (!fdb) {
1015 err = -ENOMEM;
1016 goto err_unlock;
1017 }
1018 fdb->added_by_external_learn = 1;
1019 fdb_notify(br, fdb, RTM_NEWNEIGH);
1020 } else if (fdb->added_by_external_learn) {
1021 /* Refresh entry */
1022 fdb->updated = fdb->used = jiffies;
1023 } else if (!fdb->added_by_user) {
1024 /* Take over SW learned entry */
1025 fdb->added_by_external_learn = 1;
1026 fdb->updated = jiffies;
1027 fdb_notify(br, fdb, RTM_NEWNEIGH);
1028 }
1029
1030err_unlock:
1031 spin_unlock_bh(&br->hash_lock);
1032err_rtnl_unlock:
1033 rtnl_unlock();
1034
1035 return err;
1036}
1037EXPORT_SYMBOL(br_fdb_external_learn_add);
1038
1039int br_fdb_external_learn_del(struct net_device *dev,
1040 const unsigned char *addr, u16 vid)
1041{
1042 struct net_bridge_port *p;
1043 struct net_bridge *br;
1044 struct hlist_head *head;
1045 struct net_bridge_fdb_entry *fdb;
1046 int err = 0;
1047
1048 rtnl_lock();
1049
1050 p = br_port_get_rtnl(dev);
1051 if (!p) {
1052 pr_info("bridge: %s not a bridge port\n", dev->name);
1053 err = -EINVAL;
1054 goto err_rtnl_unlock;
1055 }
1056
1057 br = p->br;
1058
1059 spin_lock_bh(&br->hash_lock);
1060
1061 head = &br->hash[br_mac_hash(addr, vid)];
1062 fdb = fdb_find(head, addr, vid);
1063 if (fdb && fdb->added_by_external_learn)
1064 fdb_delete(br, fdb);
1065 else
1066 err = -ENOENT;
1067
1068 spin_unlock_bh(&br->hash_lock);
1069err_rtnl_unlock:
1070 rtnl_unlock();
1071
1072 return err;
1073}
1074EXPORT_SYMBOL(br_fdb_external_learn_del);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 1b529da8234d..cc36fb3efbdd 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -100,7 +100,8 @@ struct net_bridge_fdb_entry
100 mac_addr addr; 100 mac_addr addr;
101 unsigned char is_local:1, 101 unsigned char is_local:1,
102 is_static:1, 102 is_static:1,
103 added_by_user:1; 103 added_by_user:1,
104 added_by_external_learn:1;
104 __u16 vlan_id; 105 __u16 vlan_id;
105}; 106};
106 107