OSDN Git Service

net: marvell: prestera: Add heplers to interact with fib_notifier_info
authorYevhen Orlov <yevhen.orlov@plvision.eu>
Sat, 1 Oct 2022 09:34:14 +0000 (12:34 +0300)
committerJakub Kicinski <kuba@kernel.org>
Tue, 4 Oct 2022 00:14:53 +0000 (17:14 -0700)
This will be used to implement nexthops related logic in next patches.
Also try to keep ipv4/6 abstraction to be able to reuse helpers for ipv6
in the future.

Co-developed-by: Taras Chornyi <tchornyi@marvell.com>
Signed-off-by: Taras Chornyi <tchornyi@marvell.com>
Co-developed-by: Oleksandr Mazur <oleksandr.mazur@plvision.eu>
Signed-off-by: Oleksandr Mazur <oleksandr.mazur@plvision.eu>
Signed-off-by: Yevhen Orlov <yevhen.orlov@plvision.eu>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/marvell/prestera/prestera_router.c

index 9625c58..607efd4 100644 (file)
@@ -7,6 +7,7 @@
 #include <net/inet_dscp.h>
 #include <net/switchdev.h>
 #include <linux/rhashtable.h>
+#include <net/nexthop.h>
 
 #include "prestera.h"
 #include "prestera_router_hw.h"
@@ -26,9 +27,10 @@ struct prestera_kern_fib_cache {
        } lpm_info; /* hold prepared lpm info */
        /* Indicate if route is not overlapped by another table */
        struct rhash_head ht_node; /* node of prestera_router */
-       struct fib_info *fi;
-       dscp_t kern_dscp;
-       u8 kern_type;
+       union {
+               struct fib_notifier_info info; /* point to any of 4/6 */
+               struct fib_entry_notifier_info fen4_info;
+       };
        bool reachable;
 };
 
@@ -51,15 +53,41 @@ static u32 prestera_fix_tb_id(u32 tb_id)
 }
 
 static void
-prestera_util_fen_info2fib_cache_key(struct fib_entry_notifier_info *fen_info,
+prestera_util_fen_info2fib_cache_key(struct fib_notifier_info *info,
                                     struct prestera_kern_fib_cache_key *key)
 {
+       struct fib_entry_notifier_info *fen_info =
+               container_of(info, struct fib_entry_notifier_info, info);
+
        memset(key, 0, sizeof(*key));
+       key->addr.v = PRESTERA_IPV4;
        key->addr.u.ipv4 = cpu_to_be32(fen_info->dst);
        key->prefix_len = fen_info->dst_len;
        key->kern_tb_id = fen_info->tb_id;
 }
 
+static unsigned char
+prestera_kern_fib_info_type(struct fib_notifier_info *info)
+{
+       struct fib6_entry_notifier_info *fen6_info;
+       struct fib_entry_notifier_info *fen4_info;
+
+       if (info->family == AF_INET) {
+               fen4_info = container_of(info, struct fib_entry_notifier_info,
+                                        info);
+               return fen4_info->fi->fib_type;
+       } else if (info->family == AF_INET6) {
+               fen6_info = container_of(info, struct fib6_entry_notifier_info,
+                                        info);
+               /* TODO: ECMP in ipv6 is several routes.
+                * Every route has single nh.
+                */
+               return fen6_info->rt->fib6_type;
+       }
+
+       return RTN_UNSPEC;
+}
+
 static struct prestera_kern_fib_cache *
 prestera_kern_fib_cache_find(struct prestera_switch *sw,
                             struct prestera_kern_fib_cache_key *key)
@@ -76,7 +104,7 @@ static void
 __prestera_kern_fib_cache_destruct(struct prestera_switch *sw,
                                   struct prestera_kern_fib_cache *fib_cache)
 {
-       fib_info_put(fib_cache->fi);
+       fib_info_put(fib_cache->fen4_info.fi);
 }
 
 static void
@@ -96,8 +124,10 @@ prestera_kern_fib_cache_destroy(struct prestera_switch *sw,
 static struct prestera_kern_fib_cache *
 prestera_kern_fib_cache_create(struct prestera_switch *sw,
                               struct prestera_kern_fib_cache_key *key,
-                              struct fib_info *fi, dscp_t dscp, u8 type)
+                              struct fib_notifier_info *info)
 {
+       struct fib_entry_notifier_info *fen_info =
+               container_of(info, struct fib_entry_notifier_info, info);
        struct prestera_kern_fib_cache *fib_cache;
        int err;
 
@@ -106,10 +136,8 @@ prestera_kern_fib_cache_create(struct prestera_switch *sw,
                goto err_kzalloc;
 
        memcpy(&fib_cache->key, key, sizeof(*key));
-       fib_info_hold(fi);
-       fib_cache->fi = fi;
-       fib_cache->kern_dscp = dscp;
-       fib_cache->kern_type = type;
+       fib_info_hold(fen_info->fi);
+       memcpy(&fib_cache->fen4_info, fen_info, sizeof(*fen_info));
 
        err = rhashtable_insert_fast(&sw->router->kern_fib_cache_ht,
                                     &fib_cache->ht_node,
@@ -120,7 +148,7 @@ prestera_kern_fib_cache_create(struct prestera_switch *sw,
        return fib_cache;
 
 err_ht_insert:
-       fib_info_put(fi);
+       fib_info_put(fen_info->fi);
        kfree(fib_cache);
 err_kzalloc:
        return NULL;
@@ -133,21 +161,25 @@ __prestera_k_arb_fib_lpm_offload_set(struct prestera_switch *sw,
 {
        struct fib_rt_info fri;
 
-       if (fc->key.addr.v != PRESTERA_IPV4)
+       switch (fc->key.addr.v) {
+       case PRESTERA_IPV4:
+               fri.fi = fc->fen4_info.fi;
+               fri.tb_id = fc->key.kern_tb_id;
+               fri.dst = fc->key.addr.u.ipv4;
+               fri.dst_len = fc->key.prefix_len;
+               fri.dscp = fc->fen4_info.dscp;
+               fri.type = fc->fen4_info.type;
+               /* flags begin */
+               fri.offload = offload;
+               fri.trap = trap;
+               fri.offload_failed = fail;
+               /* flags end */
+               fib_alias_hw_flags_set(&init_net, &fri);
                return;
-
-       fri.fi = fc->fi;
-       fri.tb_id = fc->key.kern_tb_id;
-       fri.dst = fc->key.addr.u.ipv4;
-       fri.dst_len = fc->key.prefix_len;
-       fri.dscp = fc->kern_dscp;
-       fri.type = fc->kern_type;
-       /* flags begin */
-       fri.offload = offload;
-       fri.trap = trap;
-       fri.offload_failed = fail;
-       /* flags end */
-       fib_alias_hw_flags_set(&init_net, &fri);
+       case PRESTERA_IPV6:
+               /* TODO */
+               return;
+       }
 }
 
 static int
@@ -156,7 +188,7 @@ __prestera_pr_k_arb_fc_lpm_info_calc(struct prestera_switch *sw,
 {
        memset(&fc->lpm_info, 0, sizeof(fc->lpm_info));
 
-       switch (fc->fi->fib_type) {
+       switch (prestera_kern_fib_info_type(&fc->info)) {
        case RTN_UNICAST:
                fc->lpm_info.fib_type = PRESTERA_FIB_TYPE_TRAP;
                break;
@@ -283,14 +315,14 @@ __prestera_k_arb_util_fib_overlapped(struct prestera_switch *sw,
 static int
 prestera_k_arb_fib_evt(struct prestera_switch *sw,
                       bool replace, /* replace or del */
-                      struct fib_entry_notifier_info *fen_info)
+                      struct fib_notifier_info *info)
 {
        struct prestera_kern_fib_cache *tfib_cache, *bfib_cache; /* top/btm */
        struct prestera_kern_fib_cache_key fc_key;
        struct prestera_kern_fib_cache *fib_cache;
        int err;
 
-       prestera_util_fen_info2fib_cache_key(fen_info, &fc_key);
+       prestera_util_fen_info2fib_cache_key(info, &fc_key);
        fib_cache = prestera_kern_fib_cache_find(sw, &fc_key);
        if (fib_cache) {
                fib_cache->reachable = false;
@@ -313,10 +345,7 @@ prestera_k_arb_fib_evt(struct prestera_switch *sw,
        }
 
        if (replace) {
-               fib_cache = prestera_kern_fib_cache_create(sw, &fc_key,
-                                                          fen_info->fi,
-                                                          fen_info->dscp,
-                                                          fen_info->type);
+               fib_cache = prestera_kern_fib_cache_create(sw, &fc_key, info);
                if (!fib_cache) {
                        dev_err(sw->dev->dev, "fib_cache == NULL");
                        return -ENOENT;
@@ -508,13 +537,15 @@ static void __prestera_router_fib_event_work(struct work_struct *work)
 
        switch (fib_work->event) {
        case FIB_EVENT_ENTRY_REPLACE:
-               err = prestera_k_arb_fib_evt(sw, true, &fib_work->fen_info);
+               err = prestera_k_arb_fib_evt(sw, true,
+                                            &fib_work->fen_info.info);
                if (err)
                        goto err_out;
 
                break;
        case FIB_EVENT_ENTRY_DEL:
-               err = prestera_k_arb_fib_evt(sw, false, &fib_work->fen_info);
+               err = prestera_k_arb_fib_evt(sw, false,
+                                            &fib_work->fen_info.info);
                if (err)
                        goto err_out;