mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-01 01:14:19 -04:00
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: 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>
This commit is contained in:
committed by
Jakub Kicinski
parent
59b44ea8aa
commit
04f24a1e6d
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user