Messages in this thread Patch in this message | | | Date | Mon, 19 Dec 2022 00:16:18 +0200 | From | Yevhen Orlov <> | 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@plvision.eu> Signed-off-by: Taras Chornyi <taras.chornyi@plvision.eu> Co-developed-by: Elad Nachman <enachman@marvell.com> Signed-off-by: Elad Nachman <enachman@marvell.com> Signed-off-by: Yevhen Orlov <yevhen.orlov@plvision.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
| |