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

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
Loading
Loading
Loading
Loading
+65 −34
Original line number Diff line number Diff line
@@ -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)
		return;

	fri.fi = fc->fi;
	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->kern_dscp;
	fri.type = fc->kern_type;
		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;
	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;