Skip to content

Commit

Permalink
Merge pull request FRRouting#4897 from sworleys/zebra_nhg_add
Browse files Browse the repository at this point in the history
Zebra Nexthop Group Rework and Kernel Nexthop Object API Init
  • Loading branch information
Mark Stapp authored Oct 28, 2019
2 parents 2d50e11 + f3354e1 commit 882364f
Show file tree
Hide file tree
Showing 50 changed files with 4,064 additions and 617 deletions.
24 changes: 20 additions & 4 deletions doc/user/zebra.rst
Original file line number Diff line number Diff line change
Expand Up @@ -839,11 +839,22 @@ zebra Terminal Mode Commands
.. index:: show ipv6 route
.. clicmd:: show ipv6 route

.. index:: show interface [{vrf VRF|brief}]
.. clicmd:: show interface [{vrf VRF|brief}]
.. index:: show [ip|ipv6] route [PREFIX] [nexthop-group]
.. clicmd:: show [ip|ipv6] route [PREFIX] [nexthop-group]

.. index:: show interface [{vrf all|brief}]
.. clicmd:: show interface [{vrf all|brief}]
Display detailed information about a route. If [nexthop-group] is
included, it will display the nexthop group ID the route is using as well.

.. index:: show interface [NAME] [{vrf VRF|brief}] [nexthop-group]
.. clicmd:: show interface [NAME] [{vrf VRF|brief}] [nexthop-group]

.. index:: show interface [NAME] [{vrf all|brief}] [nexthop-group]
.. clicmd:: show interface [NAME] [{vrf all|brief}] [nexthop-group]

Display interface information. If no extra information is added, it will
dump information on all interfaces. If [NAME] is specified, it will display
detailed information about that single interface. If [nexthop-group] is
specified, it will display nexthop groups pointing out that interface.

.. index:: show ip prefix-list [NAME]
.. clicmd:: show ip prefix-list [NAME]
Expand Down Expand Up @@ -900,3 +911,8 @@ zebra Terminal Mode Commands
Reset statistics related to the zebra code that interacts with the
optional Forwarding Plane Manager (FPM) component.

.. index:: show nexthop-group [ID] [vrf NAME] [ip|ipv6]
.. clicmd:: show nexthop-group [ID] [vrf NAME] [ip|ipv6]

Display nexthop groups created by zebra.

58 changes: 58 additions & 0 deletions include/linux/nexthop.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _LINUX_NEXTHOP_H
#define _LINUX_NEXTHOP_H

#include <linux/types.h>

#define RTM_NHA(h) ((struct rtattr *)(((char *)(h)) + \
NLMSG_ALIGN(sizeof(struct nhmsg))))

struct nhmsg {
unsigned char nh_family;
unsigned char nh_scope; /* return only */
unsigned char nh_protocol; /* Routing protocol that installed nh */
unsigned char resvd;
unsigned int nh_flags; /* RTNH_F flags */
};

struct nexthop_grp {
__u32 id; /* nexthop id - must exist */
__u8 weight; /* weight of this nexthop */
__u8 resvd1;
__u16 resvd2;
};

enum {
NEXTHOP_GRP_TYPE_MPATH, /* default type if not specified */
__NEXTHOP_GRP_TYPE_MAX,
};

#define NEXTHOP_GRP_TYPE_MAX (__NEXTHOP_GRP_TYPE_MAX - 1)

enum {
NHA_UNSPEC,
NHA_ID, /* u32; id for nexthop. id == 0 means auto-assign */

NHA_GROUP, /* array of nexthop_grp */
NHA_GROUP_TYPE, /* u16 one of NEXTHOP_GRP_TYPE */
/* if NHA_GROUP attribute is added, no other attributes can be set */

NHA_BLACKHOLE, /* flag; nexthop used to blackhole packets */
/* if NHA_BLACKHOLE is added, OIF, GATEWAY, ENCAP can not be set */

NHA_OIF, /* u32; nexthop device */
NHA_GATEWAY, /* be32 (IPv4) or in6_addr (IPv6) gw address */
NHA_ENCAP_TYPE, /* u16; lwt encap type */
NHA_ENCAP, /* lwt encap data */

/* NHA_OIF can be appended to dump request to return only
* nexthops using given device
*/
NHA_GROUPS, /* flag; only return nexthop groups in dump */
NHA_MASTER, /* u32; only return nexthops with given master dev */

__NHA_MAX,
};

#define NHA_MAX (__NHA_MAX - 1)
#endif
1 change: 1 addition & 0 deletions include/subdir.am
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ noinst_HEADERS += \
include/linux/mpls_iptunnel.h \
include/linux/neighbour.h \
include/linux/netlink.h \
include/linux/nexthop.h \
include/linux/rtnetlink.h \
include/linux/socket.h \
include/linux/net_namespace.h \
Expand Down
62 changes: 45 additions & 17 deletions lib/nexthop.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ const char *nexthop2str(const struct nexthop *nexthop, char *str, int size)
* left branch is 'resolved' and right branch is 'next':
* https://en.wikipedia.org/wiki/Tree_traversal#/media/File:Sorted_binary_tree_preorder.svg
*/
struct nexthop *nexthop_next(struct nexthop *nexthop)
struct nexthop *nexthop_next(const struct nexthop *nexthop)
{
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
return nexthop->resolved;
Expand All @@ -364,6 +364,19 @@ struct nexthop *nexthop_next(struct nexthop *nexthop)
return NULL;
}

/* Return the next nexthop in the tree that is resolved and active */
struct nexthop *nexthop_next_active_resolved(const struct nexthop *nexthop)
{
struct nexthop *next = nexthop_next(nexthop);

while (next
&& (CHECK_FLAG(next->flags, NEXTHOP_FLAG_RECURSIVE)
|| !CHECK_FLAG(next->flags, NEXTHOP_FLAG_ACTIVE)))
next = nexthop_next(next);

return next;
}

unsigned int nexthop_level(struct nexthop *nexthop)
{
unsigned int rv = 0;
Expand All @@ -374,16 +387,13 @@ unsigned int nexthop_level(struct nexthop *nexthop)
return rv;
}

uint32_t nexthop_hash(const struct nexthop *nexthop)
/* Only hash word-sized things, let cmp do the rest. */
uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
{
uint32_t key = 0x45afe398;

key = jhash_3words(nexthop->type, nexthop->vrf_id,
nexthop->nh_label_type, key);
/* gate and blackhole are together in a union */
key = jhash(&nexthop->gate, sizeof(nexthop->gate), key);
key = jhash(&nexthop->src, sizeof(nexthop->src), key);
key = jhash(&nexthop->rmap_src, sizeof(nexthop->rmap_src), key);

if (nexthop->nh_label) {
int labels = nexthop->nh_label->num_labels;
Expand All @@ -410,17 +420,35 @@ uint32_t nexthop_hash(const struct nexthop *nexthop)
key = jhash_1word(nexthop->nh_label->label[i], key);
}

switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV6_IFINDEX:
case NEXTHOP_TYPE_IFINDEX:
key = jhash_1word(nexthop->ifindex, key);
break;
case NEXTHOP_TYPE_BLACKHOLE:
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV6:
break;
}
key = jhash_2words(nexthop->ifindex,
CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK),
key);

return key;
}


#define GATE_SIZE 4 /* Number of uint32_t words in struct g_addr */

/* For a more granular hash */
uint32_t nexthop_hash(const struct nexthop *nexthop)
{
uint32_t gate_src_rmap_raw[GATE_SIZE * 3] = {};
/* Get all the quick stuff */
uint32_t key = nexthop_hash_quick(nexthop);

assert(((sizeof(nexthop->gate) + sizeof(nexthop->src)
+ sizeof(nexthop->rmap_src))
/ 3)
== (GATE_SIZE * sizeof(uint32_t)));

memcpy(gate_src_rmap_raw, &nexthop->gate, GATE_SIZE);
memcpy(gate_src_rmap_raw + GATE_SIZE, &nexthop->src, GATE_SIZE);
memcpy(gate_src_rmap_raw + (2 * GATE_SIZE), &nexthop->rmap_src,
GATE_SIZE);

key = jhash2(gate_src_rmap_raw, (GATE_SIZE * 3), key);

return key;
}

Expand Down
12 changes: 11 additions & 1 deletion lib/nexthop.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ void nexthop_del_labels(struct nexthop *);
* 32-bit hash of nexthop
*/
uint32_t nexthop_hash(const struct nexthop *nexthop);
/*
* Hash a nexthop only on word-sized attributes:
* - vrf_id
* - ifindex
* - type
* - (some) flags
*/
uint32_t nexthop_hash_quick(const struct nexthop *nexthop);

extern bool nexthop_same(const struct nexthop *nh1, const struct nexthop *nh2);
extern bool nexthop_same_no_labels(const struct nexthop *nh1,
Expand All @@ -153,7 +161,9 @@ extern int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2);

extern const char *nexthop2str(const struct nexthop *nexthop,
char *str, int size);
extern struct nexthop *nexthop_next(struct nexthop *nexthop);
extern struct nexthop *nexthop_next(const struct nexthop *nexthop);
extern struct nexthop *
nexthop_next_active_resolved(const struct nexthop *nexthop);
extern unsigned int nexthop_level(struct nexthop *nexthop);
/* Copies to an already allocated nexthop struct */
extern void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
Expand Down
130 changes: 128 additions & 2 deletions lib/nexthop_group.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg)
return num;
}

uint8_t nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg)
{
struct nexthop *nhop;
uint8_t num = 0;

for (nhop = nhg->nexthop; nhop; nhop = nhop->next)
num++;

return num;
}

uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg)
{
struct nexthop *nhop;
Expand All @@ -94,7 +105,22 @@ uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg)
return num;
}

struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh)
uint8_t
nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group *nhg)
{
struct nexthop *nhop;
uint8_t num = 0;

for (nhop = nhg->nexthop; nhop; nhop = nhop->next) {
if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE))
num++;
}

return num;
}

struct nexthop *nexthop_exists(const struct nexthop_group *nhg,
const struct nexthop *nh)
{
struct nexthop *nexthop;

Expand All @@ -106,6 +132,74 @@ struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh)
return NULL;
}

static bool
nexthop_group_equal_common(const struct nexthop_group *nhg1,
const struct nexthop_group *nhg2,
uint8_t (*nexthop_group_nexthop_num_func)(
const struct nexthop_group *nhg))
{
if (nhg1 && !nhg2)
return false;

if (!nhg1 && nhg2)
return false;

if (nhg1 == nhg2)
return true;

if (nexthop_group_nexthop_num_func(nhg1)
!= nexthop_group_nexthop_num_func(nhg2))
return false;

return true;
}

/* This assumes ordered */
bool nexthop_group_equal_no_recurse(const struct nexthop_group *nhg1,
const struct nexthop_group *nhg2)
{
struct nexthop *nh1 = NULL;
struct nexthop *nh2 = NULL;

if (!nexthop_group_equal_common(nhg1, nhg2,
&nexthop_group_nexthop_num_no_recurse))
return false;

for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 || nh2;
nh1 = nh1->next, nh2 = nh2->next) {
if (nh1 && !nh2)
return false;
if (!nh1 && nh2)
return false;
if (!nexthop_same(nh1, nh2))
return false;
}

return true;
}

/* This assumes ordered */
bool nexthop_group_equal(const struct nexthop_group *nhg1,
const struct nexthop_group *nhg2)
{
struct nexthop *nh1 = NULL;
struct nexthop *nh2 = NULL;

if (!nexthop_group_equal_common(nhg1, nhg2, &nexthop_group_nexthop_num))
return false;

for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 || nh2;
nh1 = nexthop_next(nh1), nh2 = nexthop_next(nh2)) {
if (nh1 && !nh2)
return false;
if (!nh1 && nh2)
return false;
if (!nexthop_same(nh1, nh2))
return false;
}

return true;
}
struct nexthop_group *nexthop_group_new(void)
{
return XCALLOC(MTYPE_NEXTHOP_GROUP, sizeof(struct nexthop_group));
Expand All @@ -119,6 +213,9 @@ void nexthop_group_copy(struct nexthop_group *to, struct nexthop_group *from)

void nexthop_group_delete(struct nexthop_group **nhg)
{
if ((*nhg)->nexthop)
nexthops_free((*nhg)->nexthop);

XFREE(MTYPE_NEXTHOP_GROUP, *nhg);
}

Expand Down Expand Up @@ -217,7 +314,7 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
}
}

uint32_t nexthop_group_hash(const struct nexthop_group *nhg)
uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg)
{
struct nexthop *nh;
uint32_t key = 0;
Expand All @@ -232,6 +329,35 @@ uint32_t nexthop_group_hash(const struct nexthop_group *nhg)
return key;
}

uint32_t nexthop_group_hash(const struct nexthop_group *nhg)
{
struct nexthop *nh;
uint32_t key = 0;

for (ALL_NEXTHOPS_PTR(nhg, nh))
key = jhash_1word(nexthop_hash(nh), key);

return key;
}

void nexthop_group_mark_duplicates(struct nexthop_group *nhg)
{
struct nexthop *nexthop, *prev;

for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
for (ALL_NEXTHOPS_PTR(nhg, prev)) {
if (prev == nexthop)
break;
if (nexthop_same_firsthop(nexthop, prev)) {
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_DUPLICATE);
break;
}
}
}
}

static void nhgc_delete_nexthops(struct nexthop_group_cmd *nhgc)
{
struct nexthop *nexthop;
Expand Down
Loading

0 comments on commit 882364f

Please sign in to comment.