Commit 04f24a1e authored by Yevhen Orlov's avatar Yevhen Orlov Committed by Jakub Kicinski

net: marvell: prestera: Add heplers to interact with fib_notifier_info

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: default avatarTaras Chornyi <tchornyi@marvell.com>
Signed-off-by: default avatarTaras Chornyi <tchornyi@marvell.com>
Co-developed-by: default avatarOleksandr Mazur <oleksandr.mazur@plvision.eu>
Signed-off-by: default avatarOleksandr Mazur <oleksandr.mazur@plvision.eu>
Signed-off-by: default avatarYevhen Orlov <yevhen.orlov@plvision.eu>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 59b44ea8
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment