net: bridge: Receive notification about successful FDB offload
authorArkadi Sharshevsky <arkadis@mellanox.com>
Thu, 8 Jun 2017 06:44:15 +0000 (08:44 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 8 Jun 2017 18:16:25 +0000 (14:16 -0400)
When a new static FDB is added to the bridge a notification is sent to
the driver for offload. In case of successful offload the driver should
notify the bridge back, which in turn should mark the FDB as offloaded.

Currently, externally learned is equivalent for being offloaded which is
not correct due to the fact that FDBs which are added from user-space are
also marked as externally learned. In order to specify if an FDB was
successfully offloaded a new flag is introduced.

Signed-off-by: Arkadi Sharshevsky <arkadis@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Reviewed-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/switchdev.h
include/uapi/linux/neighbour.h
net/bridge/br.c
net/bridge/br_fdb.c
net/bridge/br_private.h

index 8165ed93c58b280a8277ac6a68ed03631fd83f26..c784a6ac6ef1b95fa6252e694427b895d42dd76c 100644 (file)
@@ -159,6 +159,7 @@ enum switchdev_notifier_type {
        SWITCHDEV_FDB_DEL_TO_BRIDGE,
        SWITCHDEV_FDB_ADD_TO_DEVICE,
        SWITCHDEV_FDB_DEL_TO_DEVICE,
+       SWITCHDEV_FDB_OFFLOADED,
 };
 
 struct switchdev_notifier_info {
index f3d16dbe09d64424d2d92c581f30771f6add6e0b..3199d28980b35442021ed1141151ab957b41c9f9 100644 (file)
@@ -41,6 +41,7 @@ enum {
 #define NTF_MASTER     0x04
 #define NTF_PROXY      0x08    /* == ATF_PUBL */
 #define NTF_EXT_LEARNED        0x10
+#define NTF_OFFLOADED   0x20
 #define NTF_ROUTER     0x80
 
 /*
index 96d209caf6db6775e85e68b349141d92a353fa96..1407d1ba7577ffe553969d2cbefad2bd23f66aab 100644 (file)
@@ -142,8 +142,12 @@ static int br_switchdev_event(struct notifier_block *unused,
                fdb_info = ptr;
                err = br_fdb_external_learn_add(br, p, fdb_info->addr,
                                                fdb_info->vid);
-               if (err)
+               if (err) {
                        err = notifier_from_errno(err);
+                       break;
+               }
+               br_fdb_offloaded_set(br, p, fdb_info->addr,
+                                    fdb_info->vid);
                break;
        case SWITCHDEV_FDB_DEL_TO_BRIDGE:
                fdb_info = ptr;
@@ -152,6 +156,11 @@ static int br_switchdev_event(struct notifier_block *unused,
                if (err)
                        err = notifier_from_errno(err);
                break;
+       case SWITCHDEV_FDB_OFFLOADED:
+               fdb_info = ptr;
+               br_fdb_offloaded_set(br, p, fdb_info->addr,
+                                    fdb_info->vid);
+               break;
        }
 
 out:
index 26a1dae2d434274daca29d41a68e95a662dd027a..fef7872a320b4a0097009d25f2bd91e3f69d41dd 100644 (file)
@@ -511,6 +511,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
                fdb->is_static = is_static;
                fdb->added_by_user = 0;
                fdb->added_by_external_learn = 0;
+               fdb->offloaded = 0;
                fdb->updated = fdb->used = jiffies;
                hlist_add_head_rcu(&fdb->hlist, head);
        }
@@ -647,11 +648,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
        ndm->ndm_family  = AF_BRIDGE;
        ndm->ndm_pad1    = 0;
        ndm->ndm_pad2    = 0;
-       ndm->ndm_flags   = fdb->added_by_external_learn ? NTF_EXT_LEARNED : 0;
+       ndm->ndm_flags   = 0;
        ndm->ndm_type    = 0;
        ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex;
        ndm->ndm_state   = fdb_to_nud(br, fdb);
 
+       if (fdb->offloaded)
+               ndm->ndm_flags |= NTF_OFFLOADED;
+       if (fdb->added_by_external_learn)
+               ndm->ndm_flags |= NTF_EXT_LEARNED;
+
        if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->addr))
                goto nla_put_failure;
        if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
@@ -1123,3 +1129,17 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
 
        return err;
 }
+
+void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p,
+                         const unsigned char *addr, u16 vid)
+{
+       struct net_bridge_fdb_entry *fdb;
+
+       spin_lock_bh(&br->hash_lock);
+
+       fdb = br_fdb_find(br, addr, vid);
+       if (fdb)
+               fdb->offloaded = 1;
+
+       spin_unlock_bh(&br->hash_lock);
+}
index 98410ea032cbf31c1abbd543975dbcb4e89567ce..c18682f804a0b4b40b76ceeae1998f21098c12c9 100644 (file)
@@ -169,7 +169,8 @@ struct net_bridge_fdb_entry {
        unsigned char                   is_local:1,
                                        is_static:1,
                                        added_by_user:1,
-                                       added_by_external_learn:1;
+                                       added_by_external_learn:1,
+                                       offloaded:1;
 
        /* write-heavy members should not affect lookups */
        unsigned long                   updated ____cacheline_aligned_in_smp;
@@ -536,6 +537,8 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
                              const unsigned char *addr, u16 vid);
 int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
                              const unsigned char *addr, u16 vid);
+void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p,
+                         const unsigned char *addr, u16 vid);
 
 /* br_forward.c */
 enum br_pkt_type {