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-next>] [day] [month] [year] [list]
Message-ID: <Y5+RMvhZCyG0bFgh@yorlov.ow.s>
Date:   Mon, 19 Dec 2022 00:16:18 +0200
From:   Yevhen Orlov <yevhen.orlov@...ision.eu>
To:     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>,
        Paolo Abeni <pabeni@...hat.com>, Andrew Lunn <andrew@...n.ch>,
        Stephen Hemminger <stephen@...workplumber.org>,
        linux-kernel@...r.kernel.org
Subject: [PATCH net-next v1 2/2] net: marvell: prestera: Handle ipv6
 lpm/neigh events

Handle AF_INET6 for events:
 - NETEVENT_NEIGH_UPDATE
 - FIB_EVENT_ENTRY_REPLACE
 - FIB_EVENT_ENTRY_DEL

Also try to make wrappers for ipv4/6 specific functions.
This allow us to pass fib_notifier_info for most cases.
E.g  prestera_util_fen_info_copy, prestera_util_fen_info_release.
Main idea is to increase number of agnostic about ip version functions.

Limitations:
- Only "local" and "main" tables supported
- Only generic interfaces supported for router (no bridges or vlans)

Co-developed-by: Taras Chornyi <taras.chornyi@...ision.eu>
Signed-off-by: Taras Chornyi <taras.chornyi@...ision.eu>
Co-developed-by: Elad Nachman <enachman@...vell.com>
Signed-off-by: Elad Nachman <enachman@...vell.com>
Signed-off-by: Yevhen Orlov <yevhen.orlov@...ision.eu>
---
 .../marvell/prestera/prestera_router.c        | 138 +++++++++++++-----
 1 file changed, 101 insertions(+), 37 deletions(-)

diff --git a/drivers/net/ethernet/marvell/prestera/prestera_router.c b/drivers/net/ethernet/marvell/prestera/prestera_router.c
index a9a1028cb17b..5ee0a9511878 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_router.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_router.c
@@ -12,6 +12,7 @@
 #include <linux/if_vlan.h>
 #include <linux/if_macvlan.h>
 #include <net/netevent.h>
+#include <net/ip6_route.h>
 
 #include "prestera.h"
 #include "prestera_router_hw.h"
@@ -60,6 +61,7 @@ struct prestera_kern_fib_cache {
 	union {
 		struct fib_notifier_info info; /* point to any of 4/6 */
 		struct fib_entry_notifier_info fen4_info;
+		struct fib6_entry_notifier_info fen6_info;
 	};
 	bool reachable;
 };
@@ -89,18 +91,67 @@ static u32 prestera_fix_tb_id(u32 tb_id)
 	return tb_id;
 }
 
+static void
+prestera_util_fen_info_copy(struct fib_notifier_info *sinfo,
+			    struct fib_notifier_info *tinfo)
+{
+	struct fib6_entry_notifier_info *sinfo6 =
+		container_of(sinfo, struct fib6_entry_notifier_info, info);
+	struct fib_entry_notifier_info *sinfo4 =
+		container_of(sinfo, struct fib_entry_notifier_info, info);
+	struct fib6_entry_notifier_info *tinfo6 =
+		container_of(tinfo, struct fib6_entry_notifier_info, info);
+	struct fib_entry_notifier_info *tinfo4 =
+		container_of(tinfo, struct fib_entry_notifier_info, info);
+
+	if (sinfo->family == AF_INET) {
+		fib_info_hold(sinfo4->fi);
+		*tinfo4 = *sinfo4;
+	} else if (sinfo->family == AF_INET6) {
+		fib6_info_hold(sinfo6->rt);
+		*tinfo6 = *sinfo6;
+	} else {
+		WARN(1, "Invalid address family %s %d", __func__, sinfo->family);
+	}
+}
+
+static void prestera_util_fen_info_release(struct fib_notifier_info *info)
+{
+	struct fib6_entry_notifier_info *info6 =
+		container_of(info, struct fib6_entry_notifier_info, info);
+	struct fib_entry_notifier_info *info4 =
+		container_of(info, struct fib_entry_notifier_info, info);
+
+	if (info->family == AF_INET)
+		fib_info_put(info4->fi);
+	else if (info->family == AF_INET6)
+		fib6_info_release(info6->rt);
+	else
+		WARN(1, "Invalid address family %s %d",
+		     __func__, info->family);
+}
+
 static void
 prestera_util_fen_info2fib_cache_key(struct fib_notifier_info *info,
 				     struct prestera_kern_fib_cache_key *key)
 {
+	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);
 
 	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;
+	if (info->family == AF_INET) {
+		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;
+	} else if (info->family == AF_INET6) {
+		key->addr.v = PRESTERA_IPV6;
+		key->addr.u.ipv6 = fen6_info->rt->fib6_dst.addr;
+		key->prefix_len = fen6_info->rt->fib6_dst.plen;
+		key->kern_tb_id = fen6_info->rt->fib6_table->tb6_id;
+	}
 }
 
 static int prestera_util_nhc2nc_key(struct prestera_switch *sw,
@@ -155,6 +206,9 @@ prestera_util_neigh2nc_key(struct prestera_switch *sw, struct neighbour *n,
 	if (n->tbl->family == AF_INET) {
 		key->addr.v = PRESTERA_IPV4;
 		key->addr.u.ipv4 = *(__be32 *)n->primary_key;
+	} else if (n->tbl->family == AF_INET6) {
+		key->addr.v = PRESTERA_IPV6;
+		key->addr.u.ipv6 = *(struct in6_addr *)n->primary_key;
 	} else {
 		return -ENOENT;
 	}
@@ -683,8 +737,15 @@ __prestera_k_arb_n_offload_set(struct prestera_switch *sw,
 {
 	struct neighbour *n;
 
-	n = neigh_lookup(&arp_tbl, &nc->key.addr.u.ipv4,
-			 nc->key.dev);
+	if (nc->key.addr.v == PRESTERA_IPV4)
+		n = neigh_lookup(&arp_tbl, &nc->key.addr.u.ipv4,
+				 nc->key.dev);
+	else if (nc->key.addr.v == PRESTERA_IPV6)
+		n = neigh_lookup(&nd_tbl, &nc->key.addr.u.ipv6,
+				 nc->key.dev);
+	else
+		n = NULL;
+
 	if (!n)
 		return;
 
@@ -715,7 +776,8 @@ __prestera_k_arb_fib_lpm_offload_set(struct prestera_switch *sw,
 		fib_alias_hw_flags_set(&init_net, &fri);
 		return;
 	case PRESTERA_IPV6:
-		/* TODO */
+		fib6_info_hw_flags_set(&init_net, fc->fen6_info.rt,
+				       offload, trap, fail);
 		return;
 	}
 }
@@ -1384,44 +1446,43 @@ static int __prestera_inetaddr_valid_cb(struct notifier_block *nb,
 struct prestera_fib_event_work {
 	struct work_struct work;
 	struct prestera_switch *sw;
-	struct fib_entry_notifier_info fen_info;
+	union {
+		struct fib_notifier_info info; /* point to any of 4/6 */
+		struct fib6_entry_notifier_info fen6_info;
+		struct fib_entry_notifier_info fen4_info;
+	};
 	unsigned long event;
 };
 
 static void __prestera_router_fib_event_work(struct work_struct *work)
 {
 	struct prestera_fib_event_work *fib_work =
-			container_of(work, struct prestera_fib_event_work, work);
-	struct prestera_switch *sw = fib_work->sw;
+		container_of(work, struct prestera_fib_event_work,
+			     work);
 	int err;
 
 	rtnl_lock();
 
 	switch (fib_work->event) {
 	case FIB_EVENT_ENTRY_REPLACE:
-		err = prestera_k_arb_fib_evt(sw, true,
-					     &fib_work->fen_info.info);
+		err = prestera_k_arb_fib_evt(fib_work->sw, true,
+					     &fib_work->info);
 		if (err)
-			goto err_out;
+			dev_err(fib_work->sw->dev->dev,
+				"Error when processing lpm entry");
 
 		break;
 	case FIB_EVENT_ENTRY_DEL:
-		err = prestera_k_arb_fib_evt(sw, false,
-					     &fib_work->fen_info.info);
+		err = prestera_k_arb_fib_evt(fib_work->sw, false,
+					     &fib_work->info);
 		if (err)
-			goto err_out;
+			dev_err(fib_work->sw->dev->dev,
+				"Cant delete lpm entry");
 
 		break;
 	}
 
-	goto out;
-
-err_out:
-	dev_err(sw->dev->dev, "Error when processing %pI4h/%d",
-		&fib_work->fen_info.dst,
-		fib_work->fen_info.dst_len);
-out:
-	fib_info_put(fib_work->fen_info.fi);
+	prestera_util_fen_info_release(&fib_work->info);
 	rtnl_unlock();
 	kfree(fib_work);
 }
@@ -1430,30 +1491,33 @@ static void __prestera_router_fib_event_work(struct work_struct *work)
 static int __prestera_router_fib_event(struct notifier_block *nb,
 				       unsigned long event, void *ptr)
 {
+	struct fib6_entry_notifier_info *info6 =
+		container_of(ptr, struct fib6_entry_notifier_info, info);
+	struct fib_entry_notifier_info *info4 =
+		container_of(ptr, struct fib_entry_notifier_info, info);
+	struct prestera_router *router =
+		container_of(nb, struct prestera_router, fib_nb);
 	struct prestera_fib_event_work *fib_work;
-	struct fib_entry_notifier_info *fen_info;
 	struct fib_notifier_info *info = ptr;
-	struct prestera_router *router;
-
-	if (info->family != AF_INET)
-		return NOTIFY_DONE;
-
-	router = container_of(nb, struct prestera_router, fib_nb);
 
 	switch (event) {
 	case FIB_EVENT_ENTRY_REPLACE:
 	case FIB_EVENT_ENTRY_DEL:
-		fen_info = container_of(info, struct fib_entry_notifier_info,
-					info);
-		if (!fen_info->fi)
+		if (info->family == AF_INET6) {
+			if (!info6->rt)
+				return NOTIFY_DONE;
+		} else if (info->family == AF_INET) {
+			if (!info4->fi)
+				return NOTIFY_DONE;
+		} else {
 			return NOTIFY_DONE;
+		}
 
 		fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC);
 		if (WARN_ON(!fib_work))
 			return NOTIFY_BAD;
 
-		fib_info_hold(fen_info->fi);
-		fib_work->fen_info = *fen_info;
+		prestera_util_fen_info_copy(info, &fib_work->info);
 		fib_work->event = event;
 		fib_work->sw = router->sw;
 		INIT_WORK(&fib_work->work, __prestera_router_fib_event_work);
@@ -1500,7 +1564,7 @@ static int prestera_router_netevent_event(struct notifier_block *nb,
 
 	switch (event) {
 	case NETEVENT_NEIGH_UPDATE:
-		if (n->tbl->family != AF_INET)
+		if (n->tbl->family != AF_INET && n->tbl->family != AF_INET6)
 			return NOTIFY_DONE;
 
 		net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ