lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:   Thu, 22 Sep 2022 12:16:52 +0200
From:   Paolo Abeni <pabeni@...hat.com>
To:     Yevhen Orlov <yevhen.orlov@...ision.eu>, netdev@...r.kernel.org
Cc:     Volodymyr Mytnyk <volodymyr.mytnyk@...ision.eu>,
        Taras Chornyi <taras.chornyi@...ision.eu>,
        Mickey Rachamim <mickeyr@...vell.com>,
        Serhiy Pshyk <serhiy.pshyk@...ision.eu>,
        "David S . Miller" <davem@...emloft.net>,
        Eric Dumazet <edumazet@...gle.com>,
        Jakub Kicinski <kuba@...nel.org>, Andrew Lunn <andrew@...n.ch>,
        Stephen Hemminger <stephen@...workplumber.org>,
        linux-kernel@...r.kernel.org, Taras Chornyi <tchornyi@...vell.com>,
        Oleksandr Mazur <oleksandr.mazur@...ision.eu>
Subject: Re: [PATCH net-next v6 8/9] net: marvell: prestera: Add neighbour
 cache accounting

On Sun, 2022-09-18 at 22:46 +0300, Yevhen Orlov wrote:
> Move forward and use new PRESTERA_FIB_TYPE_UC_NH to provide basic
> nexthop routes support.
> Provide deinitialization sequence for all created router objects.
> 
> Limitations:
> - Only "local" and "main" tables supported
> - Only generic interfaces supported for router (no bridges or vlans)
> 
> Co-developed-by: Taras Chornyi <tchornyi@...vell.com>
> Signed-off-by: Taras Chornyi <tchornyi@...vell.com>
> Co-developed-by: Oleksandr Mazur <oleksandr.mazur@...ision.eu>
> Signed-off-by: Oleksandr Mazur <oleksandr.mazur@...ision.eu>
> Signed-off-by: Yevhen Orlov <yevhen.orlov@...ision.eu>
> ---
>  .../net/ethernet/marvell/prestera/prestera.h  |   1 +
>  .../marvell/prestera/prestera_router.c        | 815 +++++++++++++++++-
>  2 files changed, 813 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/ethernet/marvell/prestera/prestera.h b/drivers/net/ethernet/marvell/prestera/prestera.h
> index 2f2f80e7e358..540a36069b79 100644
> --- a/drivers/net/ethernet/marvell/prestera/prestera.h
> +++ b/drivers/net/ethernet/marvell/prestera/prestera.h
> @@ -316,6 +316,7 @@ struct prestera_router {
>  	struct rhashtable nh_neigh_ht;
>  	struct rhashtable nexthop_group_ht;
>  	struct rhashtable fib_ht;
> +	struct rhashtable kern_neigh_cache_ht;
>  	struct rhashtable kern_fib_cache_ht;
>  	struct notifier_block inetaddr_nb;
>  	struct notifier_block inetaddr_valid_nb;
> diff --git a/drivers/net/ethernet/marvell/prestera/prestera_router.c b/drivers/net/ethernet/marvell/prestera/prestera_router.c
> index a6af3b53838e..771d123345ac 100644
> --- a/drivers/net/ethernet/marvell/prestera/prestera_router.c
> +++ b/drivers/net/ethernet/marvell/prestera/prestera_router.c
> @@ -8,11 +8,30 @@
>  #include <net/switchdev.h>
>  #include <linux/rhashtable.h>
>  #include <net/nexthop.h>
> +#include <net/arp.h>
> +#include <linux/if_vlan.h>
> +#include <linux/if_macvlan.h>
>  #include <net/netevent.h>
>  
>  #include "prestera.h"
>  #include "prestera_router_hw.h"
>  
> +struct prestera_kern_neigh_cache_key {
> +	struct prestera_ip_addr addr;
> +	struct net_device *dev;
> +};
> +
> +struct prestera_kern_neigh_cache {
> +	struct prestera_kern_neigh_cache_key key;
> +	struct rhash_head ht_node;
> +	struct list_head kern_fib_cache_list;
> +	/* Hold prepared nh_neigh info if is in_kernel */
> +	struct prestera_neigh_info nh_neigh_info;
> +	/* Indicate if neighbour is reachable by direct route */
> +	bool reachable;
> +	/* Lock cache if neigh is present in kernel */
> +	bool in_kernel;
> +};
>  struct prestera_kern_fib_cache_key {
>  	struct prestera_ip_addr addr;
>  	u32 prefix_len;
> @@ -25,9 +44,15 @@ struct prestera_kern_fib_cache {
>  	struct {
>  		struct prestera_fib_key fib_key;
>  		enum prestera_fib_type fib_type;
> +		struct prestera_nexthop_group_key nh_grp_key;
>  	} 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 prestera_kern_neigh_cache_head {
> +		struct prestera_kern_fib_cache *this;
> +		struct list_head head;
> +		struct prestera_kern_neigh_cache *n_cache;
> +	} kern_neigh_cache_head[PRESTERA_NHGR_SIZE_MAX];
>  	union {
>  		struct fib_notifier_info info; /* point to any of 4/6 */
>  		struct fib_entry_notifier_info fen4_info;
> @@ -35,6 +60,13 @@ struct prestera_kern_fib_cache {
>  	bool reachable;
>  };
>  
> +static const struct rhashtable_params __prestera_kern_neigh_cache_ht_params = {
> +	.key_offset  = offsetof(struct prestera_kern_neigh_cache, key),
> +	.head_offset = offsetof(struct prestera_kern_neigh_cache, ht_node),
> +	.key_len     = sizeof(struct prestera_kern_neigh_cache_key),
> +	.automatic_shrinking = true,
> +};
> +
>  static const struct rhashtable_params __prestera_kern_fib_cache_ht_params = {
>  	.key_offset  = offsetof(struct prestera_kern_fib_cache, key),
>  	.head_offset = offsetof(struct prestera_kern_fib_cache, ht_node),
> @@ -67,6 +99,278 @@ prestera_util_fen_info2fib_cache_key(struct fib_notifier_info *info,
>  	key->kern_tb_id = fen_info->tb_id;
>  }
>  
> +static int prestera_util_nhc2nc_key(struct prestera_switch *sw,
> +				    struct fib_nh_common *nhc,
> +				    struct prestera_kern_neigh_cache_key *nk)
> +{
> +	memset(nk, 0, sizeof(*nk));
> +	if (nhc->nhc_gw_family == AF_INET) {
> +		nk->addr.v = PRESTERA_IPV4;
> +		nk->addr.u.ipv4 = nhc->nhc_gw.ipv4;
> +	} else {
> +		nk->addr.v = PRESTERA_IPV6;
> +		nk->addr.u.ipv6 = nhc->nhc_gw.ipv6;
> +	}
> +
> +	nk->dev = nhc->nhc_dev;
> +	return 0;
> +}
> +
> +static void
> +prestera_util_nc_key2nh_key(struct prestera_kern_neigh_cache_key *ck,
> +			    struct prestera_nh_neigh_key *nk)
> +{
> +	memset(nk, 0, sizeof(*nk));
> +	nk->addr = ck->addr;
> +	nk->rif = (void *)ck->dev;
> +}
> +
> +static bool
> +prestera_util_nhc_eq_n_cache_key(struct prestera_switch *sw,
> +				 struct fib_nh_common *nhc,
> +				 struct prestera_kern_neigh_cache_key *nk)
> +{
> +	struct prestera_kern_neigh_cache_key tk;
> +	int err;
> +
> +	err = prestera_util_nhc2nc_key(sw, nhc, &tk);
> +	if (err)
> +		return false;
> +
> +	if (memcmp(&tk, nk, sizeof(tk)))
> +		return false;
> +
> +	return true;
> +}
> +
> +static int
> +prestera_util_neigh2nc_key(struct prestera_switch *sw, struct neighbour *n,
> +			   struct prestera_kern_neigh_cache_key *key)
> +{
> +	memset(key, 0, sizeof(*key));
> +	if (n->tbl->family == AF_INET) {
> +		key->addr.v = PRESTERA_IPV4;
> +		key->addr.u.ipv4 = *(__be32 *)n->primary_key;
> +	} else {
> +		return -ENOENT;
> +	}
> +
> +	key->dev = n->dev;
> +
> +	return 0;
> +}
> +
> +static bool __prestera_fi_is_direct(struct fib_info *fi)
> +{
> +	struct fib_nh *fib_nh;
> +
> +	if (fib_info_num_path(fi) == 1) {
> +		fib_nh = fib_info_nh(fi, 0);
> +		if (fib_nh->fib_nh_gw_family == AF_UNSPEC)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static bool prestera_fi_is_direct(struct fib_info *fi)
> +{
> +	if (fi->fib_type != RTN_UNICAST)
> +		return false;
> +
> +	return __prestera_fi_is_direct(fi);
> +}
> +
> +static bool prestera_fi_is_nh(struct fib_info *fi)
> +{
> +	if (fi->fib_type != RTN_UNICAST)
> +		return false;
> +
> +	return !__prestera_fi_is_direct(fi);
> +}
> +
> +static bool __prestera_fi6_is_direct(struct fib6_info *fi)
> +{
> +	if (!fi->fib6_nh->nh_common.nhc_gw_family)
> +		return true;
> +
> +	return false;
> +}
> +
> +static bool prestera_fi6_is_direct(struct fib6_info *fi)
> +{
> +	if (fi->fib6_type != RTN_UNICAST)
> +		return false;
> +
> +	return __prestera_fi6_is_direct(fi);
> +}
> +
> +static bool prestera_fi6_is_nh(struct fib6_info *fi)
> +{
> +	if (fi->fib6_type != RTN_UNICAST)
> +		return false;
> +
> +	return !__prestera_fi6_is_direct(fi);
> +}
> +
> +static bool prestera_fib_info_is_direct(struct fib_notifier_info *info)
> +{
> +	struct fib6_entry_notifier_info *fen6_info =
> +		container_of(info, struct fib6_entry_notifier_info, info);
> +	struct fib_entry_notifier_info *fen_info =
> +		container_of(info, struct fib_entry_notifier_info, info);
> +
> +	if (info->family == AF_INET)
> +		return prestera_fi_is_direct(fen_info->fi);
> +	else
> +		return prestera_fi6_is_direct(fen6_info->rt);
> +}
> +
> +static bool prestera_fib_info_is_nh(struct fib_notifier_info *info)
> +{
> +	struct fib6_entry_notifier_info *fen6_info =
> +		container_of(info, struct fib6_entry_notifier_info, info);
> +	struct fib_entry_notifier_info *fen_info =
> +		container_of(info, struct fib_entry_notifier_info, info);
> +
> +	if (info->family == AF_INET)
> +		return prestera_fi_is_nh(fen_info->fi);
> +	else
> +		return prestera_fi6_is_nh(fen6_info->rt);
> +}
> +
> +/* must be called with rcu_read_lock() */
> +static int prestera_util_kern_get_route(struct fib_result *res, u32 tb_id,
> +					__be32 *addr)
> +{
> +	struct fib_table *tb;
> +	struct flowi4 fl4;
> +	int ret;
> +
> +	/* TODO: walkthrough appropriate tables in kernel
> +	 * to know if the same prefix exists in several tables
> +	 */
> +	tb = fib_new_table(&init_net, tb_id);
> +	if (!tb)
> +		return -ENOENT;
> +
> +	memset(&fl4, 0, sizeof(fl4));
> +	fl4.daddr = *addr;
> +	ret = fib_table_lookup(tb, &fl4, res, FIB_LOOKUP_NOREF);
> +	if (ret)
> +		return ret;

Likely you can use fib_lookup() instead of all the above.

Thanks,

Paolo

Powered by blists - more mailing lists