mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 22:26:14 +00:00
zebra: Use a nhe context dataplane and rib metaq
We will use a nhe context for dataplane interaction with nextho group hash entries. New nhe's from the kernel will be put into a group array if they are a group and queued on the rib metaq to be processed later. New nhe's sent to the kernel will be set on the dataplane context with approprate ID's in the group array if needed. Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com>
This commit is contained in:
parent
71593b3f0f
commit
e22e80010e
@ -84,6 +84,7 @@ ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR"
|
|||||||
ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
|
ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
|
||||||
ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric"
|
ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric"
|
||||||
ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP"
|
ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP"
|
||||||
|
ZEBRA_ROUTE_NHG, nhg, none, '-', 0, 0, 0, "Nexthop Group"
|
||||||
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
|
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
|
||||||
|
|
||||||
|
|
||||||
@ -113,3 +114,4 @@ ZEBRA_ROUTE_PBR, "Policy Based Routing (PBR)"
|
|||||||
ZEBRA_ROUTE_BFD, "Bidirectional Fowarding Detection (BFD)"
|
ZEBRA_ROUTE_BFD, "Bidirectional Fowarding Detection (BFD)"
|
||||||
ZEBRA_ROUTE_VRRP, "Virtual Router Redundancy Protocol (VRRP)"
|
ZEBRA_ROUTE_VRRP, "Virtual Router Redundancy Protocol (VRRP)"
|
||||||
ZEBRA_ROUTE_OPENFABRIC, "OpenFabric Routing Protocol"
|
ZEBRA_ROUTE_OPENFABRIC, "OpenFabric Routing Protocol"
|
||||||
|
ZEBRA_ROUTE_NHG, "Zebra Nexthop Groups (NHG)"
|
||||||
|
@ -189,6 +189,20 @@ static int if_zebra_new_hook(struct interface *ifp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void if_nhg_dependents_release(struct interface *ifp)
|
||||||
|
{
|
||||||
|
if (!if_nhg_dependents_is_empty(ifp)) {
|
||||||
|
struct nhg_connected *rb_node_dep = NULL;
|
||||||
|
struct zebra_if *zif = (struct zebra_if *)ifp->info;
|
||||||
|
|
||||||
|
RB_FOREACH (rb_node_dep, nhg_connected_head,
|
||||||
|
&zif->nhg_dependents) {
|
||||||
|
rb_node_dep->nhe->ifp = NULL;
|
||||||
|
zebra_nhg_set_invalid(rb_node_dep->nhe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Called when interface is deleted. */
|
/* Called when interface is deleted. */
|
||||||
static int if_zebra_delete_hook(struct interface *ifp)
|
static int if_zebra_delete_hook(struct interface *ifp)
|
||||||
{
|
{
|
||||||
@ -210,6 +224,7 @@ static int if_zebra_delete_hook(struct interface *ifp)
|
|||||||
list_delete(&rtadv->AdvDNSSLList);
|
list_delete(&rtadv->AdvDNSSLList);
|
||||||
#endif /* HAVE_RTADV */
|
#endif /* HAVE_RTADV */
|
||||||
|
|
||||||
|
if_nhg_dependents_release(ifp);
|
||||||
zebra_if_nhg_dependents_free(zebra_if);
|
zebra_if_nhg_dependents_free(zebra_if);
|
||||||
|
|
||||||
XFREE(MTYPE_TMP, zebra_if->desc);
|
XFREE(MTYPE_TMP, zebra_if->desc);
|
||||||
@ -983,7 +998,7 @@ bool if_nhg_dependents_is_empty(const struct interface *ifp)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_down_nhg_dependents(const struct interface *ifp)
|
static void if_down_nhg_dependents(const struct interface *ifp)
|
||||||
{
|
{
|
||||||
if (!if_nhg_dependents_is_empty(ifp)) {
|
if (!if_nhg_dependents_is_empty(ifp)) {
|
||||||
struct nhg_connected *rb_node_dep = NULL;
|
struct nhg_connected *rb_node_dep = NULL;
|
||||||
|
@ -441,7 +441,6 @@ extern void if_nhg_dependents_del(struct interface *ifp,
|
|||||||
struct nhg_hash_entry *nhe);
|
struct nhg_hash_entry *nhe);
|
||||||
extern unsigned int if_nhg_dependents_count(const struct interface *ifp);
|
extern unsigned int if_nhg_dependents_count(const struct interface *ifp);
|
||||||
extern bool if_nhg_dependents_is_empty(const struct interface *ifp);
|
extern bool if_nhg_dependents_is_empty(const struct interface *ifp);
|
||||||
extern void if_down_nhg_dependents(const struct interface *ifp);
|
|
||||||
|
|
||||||
extern void vrf_add_update(struct vrf *vrfp);
|
extern void vrf_add_update(struct vrf *vrfp);
|
||||||
|
|
||||||
|
23
zebra/rib.h
23
zebra/rib.h
@ -153,13 +153,14 @@ struct route_entry {
|
|||||||
#define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type)
|
#define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type)
|
||||||
|
|
||||||
/* meta-queue structure:
|
/* meta-queue structure:
|
||||||
* sub-queue 0: connected, kernel
|
* sub-queue 0: nexthop group objects
|
||||||
* sub-queue 1: static
|
* sub-queue 1: connected, kernel
|
||||||
* sub-queue 2: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP
|
* sub-queue 2: static
|
||||||
* sub-queue 3: iBGP, eBGP
|
* sub-queue 3: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP
|
||||||
* sub-queue 4: any other origin (if any)
|
* sub-queue 4: iBGP, eBGP
|
||||||
|
* sub-queue 5: any other origin (if any)
|
||||||
*/
|
*/
|
||||||
#define MQ_SIZE 5
|
#define MQ_SIZE 6
|
||||||
struct meta_queue {
|
struct meta_queue {
|
||||||
struct list *subq[MQ_SIZE];
|
struct list *subq[MQ_SIZE];
|
||||||
uint32_t size; /* sum of lengths of all subqueues */
|
uint32_t size; /* sum of lengths of all subqueues */
|
||||||
@ -209,7 +210,7 @@ DECLARE_LIST(re_list, struct route_entry, next);
|
|||||||
|
|
||||||
#define RIB_ROUTE_QUEUED(x) (1 << (x))
|
#define RIB_ROUTE_QUEUED(x) (1 << (x))
|
||||||
// If MQ_SIZE is modified this value needs to be updated.
|
// If MQ_SIZE is modified this value needs to be updated.
|
||||||
#define RIB_ROUTE_ANY_QUEUED 0x1F
|
#define RIB_ROUTE_ANY_QUEUED 0x3F
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The maximum qindex that can be used.
|
* The maximum qindex that can be used.
|
||||||
@ -397,7 +398,13 @@ extern unsigned long rib_score_proto(uint8_t proto, unsigned short instance);
|
|||||||
extern unsigned long rib_score_proto_table(uint8_t proto,
|
extern unsigned long rib_score_proto_table(uint8_t proto,
|
||||||
unsigned short instance,
|
unsigned short instance,
|
||||||
struct route_table *table);
|
struct route_table *table);
|
||||||
extern void rib_queue_add(struct route_node *rn);
|
|
||||||
|
extern int rib_queue_add(struct route_node *rn);
|
||||||
|
|
||||||
|
struct nhg_ctx; /* Forward declaration */
|
||||||
|
|
||||||
|
extern int rib_queue_nhg_add(struct nhg_ctx *ctx);
|
||||||
|
|
||||||
extern void meta_queue_free(struct meta_queue *mq);
|
extern void meta_queue_free(struct meta_queue *mq);
|
||||||
extern int zebra_rib_labeled_unicast(struct route_entry *re);
|
extern int zebra_rib_labeled_unicast(struct route_entry *re);
|
||||||
extern struct route_table *rib_table_ipv6;
|
extern struct route_table *rib_table_ipv6;
|
||||||
|
@ -1889,11 +1889,11 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
|
|||||||
*
|
*
|
||||||
* @n: Netlink message header struct
|
* @n: Netlink message header struct
|
||||||
* @req_size: Size allocated for this message
|
* @req_size: Size allocated for this message
|
||||||
* @depends_info: Array of depend_info structs
|
* @z_grp: Array of nh_grp structs
|
||||||
* @count: How many depencies there are
|
* @count: How many depencies there are
|
||||||
*/
|
*/
|
||||||
static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
|
static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
|
||||||
const struct depend_info *depends_info,
|
const struct nh_grp *z_grp,
|
||||||
const uint8_t count)
|
const uint8_t count)
|
||||||
{
|
{
|
||||||
struct nexthop_grp grp[count];
|
struct nexthop_grp grp[count];
|
||||||
@ -1902,8 +1902,8 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
|
|||||||
|
|
||||||
if (count) {
|
if (count) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
grp[i].id = depends_info[i].id;
|
grp[i].id = z_grp[i].id;
|
||||||
grp[i].weight = depends_info[i].weight;
|
grp[i].weight = z_grp[i].weight;
|
||||||
}
|
}
|
||||||
addattr_l(n, req_size, NHA_GROUP, grp, count * sizeof(*grp));
|
addattr_l(n, req_size, NHA_GROUP, grp, count * sizeof(*grp));
|
||||||
}
|
}
|
||||||
@ -1946,11 +1946,11 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
|
|||||||
addattr32(&req.n, sizeof(req), NHA_ID, id);
|
addattr32(&req.n, sizeof(req), NHA_ID, id);
|
||||||
|
|
||||||
if (cmd == RTM_NEWNEXTHOP) {
|
if (cmd == RTM_NEWNEXTHOP) {
|
||||||
if (dplane_ctx_get_nhe_depends_count(ctx))
|
if (dplane_ctx_get_nhe_nh_grp_count(ctx))
|
||||||
_netlink_nexthop_build_group(
|
_netlink_nexthop_build_group(
|
||||||
&req.n, sizeof(req),
|
&req.n, sizeof(req),
|
||||||
dplane_ctx_get_nhe_depends_info(ctx),
|
dplane_ctx_get_nhe_nh_grp(ctx),
|
||||||
dplane_ctx_get_nhe_depends_count(ctx));
|
dplane_ctx_get_nhe_nh_grp_count(ctx));
|
||||||
else {
|
else {
|
||||||
const struct nexthop *nh =
|
const struct nexthop *nh =
|
||||||
dplane_ctx_get_nhe_ng(ctx)->nexthop;
|
dplane_ctx_get_nhe_ng(ctx)->nexthop;
|
||||||
@ -2144,16 +2144,16 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
|
|||||||
*
|
*
|
||||||
* Return: New nexthop
|
* Return: New nexthop
|
||||||
*/
|
*/
|
||||||
static struct nexthop *netlink_nexthop_process_nh(struct rtattr **tb,
|
static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb,
|
||||||
unsigned char family,
|
unsigned char family,
|
||||||
struct interface **ifp,
|
struct interface **ifp,
|
||||||
ns_id_t ns_id)
|
ns_id_t ns_id)
|
||||||
{
|
{
|
||||||
struct nexthop *nh = NULL;
|
struct nexthop nh = {};
|
||||||
void *gate = NULL;
|
void *gate = NULL;
|
||||||
enum nexthop_types_t type = 0;
|
enum nexthop_types_t type = 0;
|
||||||
int if_index;
|
int if_index = 0;
|
||||||
size_t sz;
|
size_t sz = 0;
|
||||||
|
|
||||||
if_index = *(int *)RTA_DATA(tb[NHA_OIF]);
|
if_index = *(int *)RTA_DATA(tb[NHA_OIF]);
|
||||||
|
|
||||||
@ -2173,35 +2173,31 @@ static struct nexthop *netlink_nexthop_process_nh(struct rtattr **tb,
|
|||||||
EC_ZEBRA_BAD_NHG_MESSAGE,
|
EC_ZEBRA_BAD_NHG_MESSAGE,
|
||||||
"Nexthop gateway with bad address family (%d) received from kernel",
|
"Nexthop gateway with bad address family (%d) received from kernel",
|
||||||
family);
|
family);
|
||||||
return NULL;
|
return nh;
|
||||||
}
|
}
|
||||||
gate = RTA_DATA(tb[NHA_GATEWAY]);
|
gate = RTA_DATA(tb[NHA_GATEWAY]);
|
||||||
} else {
|
} else
|
||||||
type = NEXTHOP_TYPE_IFINDEX;
|
type = NEXTHOP_TYPE_IFINDEX;
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate the new nexthop */
|
|
||||||
nh = nexthop_new();
|
|
||||||
|
|
||||||
if (type)
|
if (type)
|
||||||
nh->type = type;
|
nh.type = type;
|
||||||
|
|
||||||
if (gate)
|
if (gate)
|
||||||
memcpy(&(nh->gate), gate, sz);
|
memcpy(&(nh.gate), gate, sz);
|
||||||
|
|
||||||
if (if_index)
|
if (if_index)
|
||||||
nh->ifindex = if_index;
|
nh.ifindex = if_index;
|
||||||
|
|
||||||
*ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh->ifindex);
|
*ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex);
|
||||||
if (ifp) {
|
if (ifp)
|
||||||
nh->vrf_id = (*ifp)->vrf_id;
|
nh.vrf_id = (*ifp)->vrf_id;
|
||||||
} else {
|
else {
|
||||||
flog_warn(
|
flog_warn(
|
||||||
EC_ZEBRA_UNKNOWN_INTERFACE,
|
EC_ZEBRA_UNKNOWN_INTERFACE,
|
||||||
"%s: Unknown nexthop interface %u received, defaulting to VRF_DEFAULT",
|
"%s: Unknown nexthop interface %u received, defaulting to VRF_DEFAULT",
|
||||||
__PRETTY_FUNCTION__, nh->ifindex);
|
__PRETTY_FUNCTION__, nh.ifindex);
|
||||||
|
|
||||||
nh->vrf_id = VRF_DEFAULT;
|
nh.vrf_id = VRF_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tb[NHA_ENCAP] && tb[NHA_ENCAP_TYPE]) {
|
if (tb[NHA_ENCAP] && tb[NHA_ENCAP_TYPE]) {
|
||||||
@ -2209,35 +2205,23 @@ static struct nexthop *netlink_nexthop_process_nh(struct rtattr **tb,
|
|||||||
int num_labels = 0;
|
int num_labels = 0;
|
||||||
mpls_label_t labels[MPLS_MAX_LABELS] = {0};
|
mpls_label_t labels[MPLS_MAX_LABELS] = {0};
|
||||||
|
|
||||||
if (encap_type == LWTUNNEL_ENCAP_MPLS) {
|
if (encap_type == LWTUNNEL_ENCAP_MPLS)
|
||||||
num_labels = parse_encap_mpls(tb[NHA_ENCAP], labels);
|
num_labels = parse_encap_mpls(tb[NHA_ENCAP], labels);
|
||||||
}
|
|
||||||
|
|
||||||
if (num_labels) {
|
if (num_labels)
|
||||||
nexthop_add_labels(nh, ZEBRA_LSP_STATIC, num_labels,
|
nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels,
|
||||||
labels);
|
labels);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nh;
|
return nh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* netlink_nexthop_process_group() - Iterate over nhmsg nexthop group
|
|
||||||
*
|
|
||||||
* @tb: Netlink RTA data
|
|
||||||
* @nhg_depends: Tree head of nexthops in the group
|
|
||||||
* @nhg: Nexthop group struct
|
|
||||||
*
|
|
||||||
* Return: Count of nexthops in the group
|
|
||||||
*/
|
|
||||||
static int netlink_nexthop_process_group(struct rtattr **tb,
|
static int netlink_nexthop_process_group(struct rtattr **tb,
|
||||||
struct nexthop_group *nhg,
|
struct nh_grp *z_grp)
|
||||||
struct nhg_connected_head *nhg_depends)
|
|
||||||
{
|
{
|
||||||
int count = 0;
|
uint8_t count = 0;
|
||||||
|
/* linux/nexthop.h group struct */
|
||||||
struct nexthop_grp *n_grp = NULL;
|
struct nexthop_grp *n_grp = NULL;
|
||||||
struct nhg_hash_entry *depend = NULL;
|
|
||||||
|
|
||||||
n_grp = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]);
|
n_grp = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]);
|
||||||
count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*n_grp));
|
count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*n_grp));
|
||||||
@ -2252,32 +2236,10 @@ static int netlink_nexthop_process_group(struct rtattr **tb,
|
|||||||
zlog_debug("Nexthop group type: %d",
|
zlog_debug("Nexthop group type: %d",
|
||||||
*((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE])));
|
*((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE])));
|
||||||
|
|
||||||
nhg_connected_head_init(nhg_depends);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
/* We do not care about nexthop_grp.weight at
|
z_grp[i].id = n_grp[i].id;
|
||||||
* this time. But we should figure out
|
z_grp[i].weight = n_grp[i].weight;
|
||||||
* how to adapt this to our code in
|
|
||||||
* the future.
|
|
||||||
*/
|
|
||||||
depend = zebra_nhg_lookup_id(n_grp[i].id);
|
|
||||||
if (depend) {
|
|
||||||
nhg_connected_head_add(nhg_depends, depend);
|
|
||||||
/*
|
|
||||||
* If this is a nexthop with its own group
|
|
||||||
* dependencies, add them as well. Not sure its
|
|
||||||
* even possible to have a group within a group
|
|
||||||
* in the kernel.
|
|
||||||
*/
|
|
||||||
|
|
||||||
copy_nexthops(&nhg->nexthop, depend->nhg->nexthop,
|
|
||||||
NULL);
|
|
||||||
} else {
|
|
||||||
flog_err(
|
|
||||||
EC_ZEBRA_NHG_SYNC,
|
|
||||||
"Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
|
|
||||||
n_grp[i].id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@ -2301,16 +2263,13 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
|||||||
vrf_id_t vrf_id = 0;
|
vrf_id_t vrf_id = 0;
|
||||||
struct interface *ifp = NULL;
|
struct interface *ifp = NULL;
|
||||||
struct nhmsg *nhm = NULL;
|
struct nhmsg *nhm = NULL;
|
||||||
/* struct for nexthop group abstraction */
|
struct nexthop nh = {};
|
||||||
struct nexthop_group *nhg = NULL;
|
struct nh_grp grp[MULTIPATH_NUM] = {};
|
||||||
struct nexthop *nh = NULL;
|
|
||||||
/* If its a group, tree head of nexthops */
|
|
||||||
struct nhg_connected_head nhg_depends = {0};
|
|
||||||
/* Count of nexthops in group array */
|
/* Count of nexthops in group array */
|
||||||
int dep_count = 0;
|
uint8_t grp_count = 0;
|
||||||
/* struct that goes into our tables */
|
/* struct that goes into our tables */
|
||||||
struct nhg_hash_entry *nhe = NULL;
|
struct nhg_hash_entry *nhe = NULL;
|
||||||
struct rtattr *tb[NHA_MAX + 1];
|
struct rtattr *tb[NHA_MAX + 1] = {};
|
||||||
|
|
||||||
|
|
||||||
nhm = NLMSG_DATA(h);
|
nhm = NLMSG_DATA(h);
|
||||||
@ -2327,7 +2286,6 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(tb, 0, sizeof(tb));
|
|
||||||
netlink_parse_rtattr(tb, NHA_MAX, RTM_NHA(nhm), len);
|
netlink_parse_rtattr(tb, NHA_MAX, RTM_NHA(nhm), len);
|
||||||
|
|
||||||
|
|
||||||
@ -2351,18 +2309,13 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
|||||||
nl_family_to_str(family), ns_id);
|
nl_family_to_str(family), ns_id);
|
||||||
|
|
||||||
|
|
||||||
nhe = zebra_nhg_lookup_id(id);
|
|
||||||
|
|
||||||
if (h->nlmsg_type == RTM_NEWNEXTHOP) {
|
if (h->nlmsg_type == RTM_NEWNEXTHOP) {
|
||||||
nhg = nexthop_group_new();
|
|
||||||
|
|
||||||
if (tb[NHA_GROUP]) {
|
if (tb[NHA_GROUP]) {
|
||||||
/**
|
/**
|
||||||
* If this is a group message its only going to have
|
* If this is a group message its only going to have
|
||||||
* an array of nexthop IDs associated with it
|
* an array of nexthop IDs associated with it
|
||||||
*/
|
*/
|
||||||
dep_count = netlink_nexthop_process_group(tb, nhg,
|
grp_count = netlink_nexthop_process_group(tb, grp);
|
||||||
&nhg_depends);
|
|
||||||
} else {
|
} else {
|
||||||
if (tb[NHA_BLACKHOLE]) {
|
if (tb[NHA_BLACKHOLE]) {
|
||||||
/**
|
/**
|
||||||
@ -2370,92 +2323,42 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
|||||||
* traffic, it should not have an OIF, GATEWAY,
|
* traffic, it should not have an OIF, GATEWAY,
|
||||||
* or ENCAP
|
* or ENCAP
|
||||||
*/
|
*/
|
||||||
nh = nexthop_new();
|
nh.type = NEXTHOP_TYPE_BLACKHOLE;
|
||||||
nh->type = NEXTHOP_TYPE_BLACKHOLE;
|
nh.bh_type = BLACKHOLE_UNSPEC;
|
||||||
nh->bh_type = BLACKHOLE_UNSPEC;
|
} else if (tb[NHA_OIF])
|
||||||
} else if (tb[NHA_OIF]) {
|
|
||||||
/**
|
/**
|
||||||
* This is a true new nexthop, so we need
|
* This is a true new nexthop, so we need
|
||||||
* to parse the gateway and device info
|
* to parse the gateway and device info
|
||||||
*/
|
*/
|
||||||
nh = netlink_nexthop_process_nh(tb, family,
|
nh = netlink_nexthop_process_nh(tb, family,
|
||||||
&ifp, ns_id);
|
&ifp, ns_id);
|
||||||
}
|
else {
|
||||||
if (nh) {
|
|
||||||
SET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE);
|
|
||||||
if (nhm->nh_flags & RTNH_F_ONLINK)
|
|
||||||
SET_FLAG(nh->flags,
|
|
||||||
NEXTHOP_FLAG_ONLINK);
|
|
||||||
vrf_id = nh->vrf_id;
|
|
||||||
nexthop_group_add_sorted(nhg, nh);
|
|
||||||
} else {
|
|
||||||
flog_warn(
|
flog_warn(
|
||||||
EC_ZEBRA_BAD_NHG_MESSAGE,
|
EC_ZEBRA_BAD_NHG_MESSAGE,
|
||||||
"Invalid Nexthop message received from the kernel with ID (%u)",
|
"Invalid Nexthop message received from the kernel with ID (%u)",
|
||||||
id);
|
id);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
SET_FLAG(nh.flags, NEXTHOP_FLAG_ACTIVE);
|
||||||
|
if (nhm->nh_flags & RTNH_F_ONLINK)
|
||||||
|
SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK);
|
||||||
|
vrf_id = nh.vrf_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nhg->nexthop) {
|
// TODO: Apparently we don't want changes
|
||||||
/* Nothing to lookup */
|
// to already created one in our table.
|
||||||
nexthop_group_free_delete(&nhg);
|
// They should be immutable...
|
||||||
nhg_connected_head_free(&nhg_depends);
|
// Gotta figure that one out.
|
||||||
|
|
||||||
|
|
||||||
|
if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
if (nhe) {
|
|
||||||
// TODO: Apparently we don't want changes
|
|
||||||
// to already created one in our table.
|
|
||||||
// They should be immutable...
|
|
||||||
// Gotta figure that one out.
|
|
||||||
|
|
||||||
/* This is a change to a group we already have
|
|
||||||
*/
|
|
||||||
|
|
||||||
zebra_nhg_set_invalid(nhe);
|
|
||||||
nexthop_group_free_delete(&nhg);
|
|
||||||
nhg_connected_head_free(&nhg_depends);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* This is a new nexthop group */
|
|
||||||
nhe = zebra_nhg_find(nhg, vrf_id, afi, id, &nhg_depends,
|
|
||||||
true);
|
|
||||||
/* The group was copied over, so free it */
|
|
||||||
nexthop_group_free_delete(&nhg);
|
|
||||||
|
|
||||||
if (!nhe) {
|
|
||||||
flog_err(
|
|
||||||
EC_ZEBRA_TABLE_LOOKUP_FAILED,
|
|
||||||
"Zebra failed to find or create a nexthop hash entry for ID (%u) from the kernel",
|
|
||||||
id);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
nhe->is_kernel_nh = true;
|
|
||||||
|
|
||||||
if (id != nhe->id) {
|
|
||||||
/* Duplicate but with different ID from
|
|
||||||
* the kernel */
|
|
||||||
|
|
||||||
/* The kernel allows duplicate nexthops
|
|
||||||
* as long as they have different IDs.
|
|
||||||
* We are ignoring those to prevent
|
|
||||||
* syncing problems with the kernel
|
|
||||||
* changes.
|
|
||||||
*/
|
|
||||||
flog_warn(
|
|
||||||
EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
|
|
||||||
"Nexthop Group from kernel with ID (%d) is a duplicate, ignoring",
|
|
||||||
id);
|
|
||||||
nhg_connected_head_free(&nhg_depends);
|
|
||||||
} else {
|
|
||||||
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
|
||||||
SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (h->nlmsg_type == RTM_DELNEXTHOP) {
|
} else if (h->nlmsg_type == RTM_DELNEXTHOP) {
|
||||||
|
// TODO: Add new function in nhgc to handle del
|
||||||
|
nhe = zebra_nhg_lookup_id(id);
|
||||||
if (!nhe) {
|
if (!nhe) {
|
||||||
flog_warn(
|
flog_warn(
|
||||||
EC_ZEBRA_BAD_NHG_MESSAGE,
|
EC_ZEBRA_BAD_NHG_MESSAGE,
|
||||||
@ -2474,9 +2377,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
|||||||
"Kernel deleted a nexthop group with ID (%u) that we are still using for a route, sending it back down",
|
"Kernel deleted a nexthop group with ID (%u) that we are still using for a route, sending it back down",
|
||||||
nhe->id);
|
nhe->id);
|
||||||
zebra_nhg_install_kernel(nhe);
|
zebra_nhg_install_kernel(nhe);
|
||||||
} else {
|
} else
|
||||||
zebra_nhg_release(nhe);
|
zebra_nhg_set_invalid(nhe);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -76,8 +76,8 @@ struct dplane_nexthop_info {
|
|||||||
bool is_kernel_nh;
|
bool is_kernel_nh;
|
||||||
|
|
||||||
struct nexthop_group ng;
|
struct nexthop_group ng;
|
||||||
struct depend_info depends_info[MULTIPATH_NUM];
|
struct nh_grp nh_grp[MULTIPATH_NUM];
|
||||||
uint8_t depends_count;
|
uint8_t nh_grp_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1090,17 +1090,17 @@ dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx)
|
|||||||
return &(ctx->u.rinfo.nhe.ng);
|
return &(ctx->u.rinfo.nhe.ng);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct depend_info *
|
const struct nh_grp *
|
||||||
dplane_ctx_get_nhe_depends_info(const struct zebra_dplane_ctx *ctx)
|
dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx)
|
||||||
{
|
{
|
||||||
DPLANE_CTX_VALID(ctx);
|
DPLANE_CTX_VALID(ctx);
|
||||||
return ctx->u.rinfo.nhe.depends_info;
|
return ctx->u.rinfo.nhe.nh_grp;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t dplane_ctx_get_nhe_depends_count(const struct zebra_dplane_ctx *ctx)
|
uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx)
|
||||||
{
|
{
|
||||||
DPLANE_CTX_VALID(ctx);
|
DPLANE_CTX_VALID(ctx);
|
||||||
return ctx->u.rinfo.nhe.depends_count;
|
return ctx->u.rinfo.nhe.nh_grp_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Accessors for LSP information */
|
/* Accessors for LSP information */
|
||||||
@ -1572,15 +1572,18 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx,
|
|||||||
struct nhg_connected *rb_node_dep = NULL;
|
struct nhg_connected *rb_node_dep = NULL;
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
|
|
||||||
|
// TODO: This doesn't work with depends being recursive
|
||||||
|
// resolved nh's as well. Yea, good luck future stephen
|
||||||
|
// this one...
|
||||||
|
|
||||||
RB_FOREACH (rb_node_dep, nhg_connected_head,
|
RB_FOREACH (rb_node_dep, nhg_connected_head,
|
||||||
&nhe->nhg_depends) {
|
&nhe->nhg_depends) {
|
||||||
ctx->u.rinfo.nhe.depends_info[i].id =
|
ctx->u.rinfo.nhe.nh_grp[i].id = rb_node_dep->nhe->id;
|
||||||
rb_node_dep->nhe->id;
|
|
||||||
/* We aren't using weights for anything right now */
|
/* We aren't using weights for anything right now */
|
||||||
ctx->u.rinfo.nhe.depends_info[i].weight = 0;
|
ctx->u.rinfo.nhe.nh_grp[i].weight = 0;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
ctx->u.rinfo.nhe.depends_count = i;
|
ctx->u.rinfo.nhe.nh_grp_count = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract ns info - can't use pointers to 'core'
|
/* Extract ns info - can't use pointers to 'core'
|
||||||
|
@ -282,9 +282,9 @@ vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx);
|
|||||||
bool dplane_ctx_get_nhe_is_kernel_nh(const struct zebra_dplane_ctx *ctx);
|
bool dplane_ctx_get_nhe_is_kernel_nh(const struct zebra_dplane_ctx *ctx);
|
||||||
const struct nexthop_group *
|
const struct nexthop_group *
|
||||||
dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx);
|
dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx);
|
||||||
const struct depend_info *
|
const struct nh_grp *
|
||||||
dplane_ctx_get_nhe_depends_info(const struct zebra_dplane_ctx *ctx);
|
dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx);
|
||||||
uint8_t dplane_ctx_get_nhe_depends_count(const struct zebra_dplane_ctx *ctx);
|
uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx);
|
||||||
|
|
||||||
/* Accessors for LSP information */
|
/* Accessors for LSP information */
|
||||||
mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx);
|
mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx);
|
||||||
|
@ -44,12 +44,14 @@
|
|||||||
|
|
||||||
DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
|
DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
|
||||||
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
|
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
|
||||||
|
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
|
||||||
|
|
||||||
static int nhg_connected_cmp(const struct nhg_connected *dep1,
|
static int nhg_connected_cmp(const struct nhg_connected *dep1,
|
||||||
const struct nhg_connected *dep2);
|
const struct nhg_connected *dep2);
|
||||||
|
|
||||||
RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp);
|
RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp);
|
||||||
|
|
||||||
|
|
||||||
void nhg_connected_free(struct nhg_connected *dep)
|
void nhg_connected_free(struct nhg_connected *dep)
|
||||||
{
|
{
|
||||||
XFREE(MTYPE_NHG_CONNECTED, dep);
|
XFREE(MTYPE_NHG_CONNECTED, dep);
|
||||||
@ -286,12 +288,9 @@ static void *zebra_nhg_alloc(void *arg)
|
|||||||
struct nhg_hash_entry *copy = arg;
|
struct nhg_hash_entry *copy = arg;
|
||||||
struct nhg_connected *rb_node_dep = NULL;
|
struct nhg_connected *rb_node_dep = NULL;
|
||||||
|
|
||||||
|
|
||||||
nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
|
nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
|
||||||
|
|
||||||
|
|
||||||
nhe->id = copy->id;
|
nhe->id = copy->id;
|
||||||
|
|
||||||
nhe->nhg_depends = copy->nhg_depends;
|
nhe->nhg_depends = copy->nhg_depends;
|
||||||
|
|
||||||
nhe->nhg = nexthop_group_new();
|
nhe->nhg = nexthop_group_new();
|
||||||
@ -334,15 +333,6 @@ static void *zebra_nhg_alloc(void *arg)
|
|||||||
/* Add to id table as well */
|
/* Add to id table as well */
|
||||||
zebra_nhg_insert_id(nhe);
|
zebra_nhg_insert_id(nhe);
|
||||||
|
|
||||||
|
|
||||||
// TODO: This needs to be moved
|
|
||||||
// It should only install AFTER it gets
|
|
||||||
// the ifp right?
|
|
||||||
//
|
|
||||||
/* Send it to the kernel */
|
|
||||||
if (!nhe->is_kernel_nh)
|
|
||||||
zebra_nhg_install_kernel(nhe);
|
|
||||||
|
|
||||||
return nhe;
|
return nhe;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,72 +400,70 @@ static int nhg_connected_cmp(const struct nhg_connected *con1,
|
|||||||
return (con1->nhe->id - con2->nhe->id);
|
return (con1->nhe->id - con2->nhe->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void zebra_nhg_process_grp(struct nexthop_group *nhg,
|
||||||
* zebra_nhg_find() - Find the zebra nhg in our table, or create it
|
struct nhg_connected_head *depends,
|
||||||
*
|
struct nh_grp *grp, uint8_t count)
|
||||||
* @nhg: Nexthop group we lookup with
|
{
|
||||||
* @vrf_id: VRF id
|
nhg_connected_head_init(depends);
|
||||||
* @afi: Address Family type
|
|
||||||
* @id: ID we lookup with, 0 means its from us and we
|
for (int i = 0; i < count; i++) {
|
||||||
* need to give it an ID, otherwise its from the
|
struct nhg_hash_entry *depend = NULL;
|
||||||
* kernel as we use the ID it gave us.
|
/* We do not care about nexthop_grp.weight at
|
||||||
* @nhg_depends: Nexthop dependency tree head
|
* this time. But we should figure out
|
||||||
* @is_kernel_nh: Was the nexthop created by the kernel
|
* how to adapt this to our code in
|
||||||
*
|
* the future.
|
||||||
* Return: Hash entry found or created
|
*/
|
||||||
*
|
depend = zebra_nhg_lookup_id(grp[i].id);
|
||||||
* The nhg and n_grp are fundementally the same thing (a group of nexthops).
|
if (depend) {
|
||||||
* We are just using the nhg representation with routes and the n_grp
|
nhg_connected_head_add(depends, depend);
|
||||||
* is what the kernel gives us (a list of IDs). Our nhg_hash_entry
|
/*
|
||||||
* will contain both.
|
* If this is a nexthop with its own group
|
||||||
*
|
* dependencies, add them as well. Not sure its
|
||||||
* nhg_hash_entry example:
|
* even possible to have a group within a group
|
||||||
*
|
* in the kernel.
|
||||||
* nhe:
|
*/
|
||||||
* ->nhg:
|
|
||||||
* .nexthop->nexthop->nexthop
|
copy_nexthops(&nhg->nexthop, depend->nhg->nexthop,
|
||||||
* ->nhg_depends:
|
NULL);
|
||||||
* .nhe->nhe->nhe
|
} else {
|
||||||
*
|
flog_err(
|
||||||
* Routes will use the nhg directly, and any updating of nexthops
|
EC_ZEBRA_NHG_SYNC,
|
||||||
* we have to do or flag setting, we use the nhg_depends.
|
"Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
|
||||||
*
|
grp[i].id);
|
||||||
*/
|
}
|
||||||
struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg,
|
}
|
||||||
vrf_id_t vrf_id, afi_t afi, uint32_t id,
|
}
|
||||||
struct nhg_connected_head *nhg_depends,
|
|
||||||
bool is_kernel_nh)
|
|
||||||
|
static struct nhg_hash_entry *
|
||||||
|
zebra_nhg_find(uint32_t id, struct nexthop_group *nhg,
|
||||||
|
struct nhg_connected_head *nhg_depends, vrf_id_t vrf_id,
|
||||||
|
afi_t afi, bool is_kernel_nh)
|
||||||
{
|
{
|
||||||
/* lock for getiing and setting the id */
|
|
||||||
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
/* id counter to keep in sync with kernel */
|
/* id counter to keep in sync with kernel */
|
||||||
static uint32_t id_counter = 0;
|
static uint32_t id_counter = 0;
|
||||||
|
|
||||||
struct nhg_hash_entry lookup = {};
|
struct nhg_hash_entry lookup = {};
|
||||||
struct nhg_hash_entry *nhe = NULL;
|
struct nhg_hash_entry *nhe = NULL;
|
||||||
uint32_t old_id_counter = 0;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&lock); /* Lock, set the id counter */
|
uint32_t old_id_counter = id_counter;
|
||||||
|
|
||||||
old_id_counter = id_counter;
|
if (id > id_counter) {
|
||||||
|
/* Increase our counter so we don't try to create
|
||||||
if (id) {
|
* an ID that already exists
|
||||||
if (id > id_counter) {
|
*/
|
||||||
/* Increase our counter so we don't try to create
|
id_counter = id;
|
||||||
* an ID that already exists
|
|
||||||
*/
|
|
||||||
id_counter = id;
|
|
||||||
}
|
|
||||||
lookup.id = id;
|
lookup.id = id;
|
||||||
} else {
|
} else
|
||||||
lookup.id = ++id_counter;
|
lookup.id = ++id_counter;
|
||||||
}
|
|
||||||
|
|
||||||
lookup.vrf_id = vrf_id;
|
|
||||||
lookup.afi = afi;
|
lookup.afi = afi;
|
||||||
lookup.nhg = nhg;
|
lookup.vrf_id = vrf_id;
|
||||||
lookup.nhg_depends = *nhg_depends;
|
|
||||||
lookup.is_kernel_nh = is_kernel_nh;
|
lookup.is_kernel_nh = is_kernel_nh;
|
||||||
|
lookup.nhg = nhg;
|
||||||
|
|
||||||
|
if (nhg_depends)
|
||||||
|
lookup.nhg_depends = *nhg_depends;
|
||||||
|
|
||||||
if (id)
|
if (id)
|
||||||
nhe = zebra_nhg_lookup_id(id);
|
nhe = zebra_nhg_lookup_id(id);
|
||||||
@ -486,33 +474,227 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg,
|
|||||||
if (nhe)
|
if (nhe)
|
||||||
id_counter = old_id_counter;
|
id_counter = old_id_counter;
|
||||||
|
|
||||||
pthread_mutex_unlock(&lock);
|
|
||||||
|
|
||||||
if (!nhe)
|
if (!nhe)
|
||||||
nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc);
|
nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc);
|
||||||
|
|
||||||
return nhe;
|
return nhe;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Find/create a single nexthop */
|
||||||
* zebra_nhg_find_nexthop() - Create a group with a single nexthop, find it in
|
static struct nhg_hash_entry *zebra_nhg_find_nexthop(uint32_t id,
|
||||||
* our table, or create it
|
struct nexthop *nh,
|
||||||
*
|
afi_t afi,
|
||||||
* @nh: Nexthop to lookup
|
bool is_kernel_nh)
|
||||||
* @afi: Address Family type
|
|
||||||
*
|
|
||||||
* Return: Hash entry found or created
|
|
||||||
*/
|
|
||||||
struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi)
|
|
||||||
{
|
{
|
||||||
|
struct nexthop_group nhg = {};
|
||||||
|
|
||||||
|
_nexthop_group_add_sorted(&nhg, nh);
|
||||||
|
|
||||||
|
return zebra_nhg_find(id, &nhg, NULL, nh->vrf_id, afi, is_kernel_nh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nhg_ctx *nhg_ctx_new()
|
||||||
|
{
|
||||||
|
struct nhg_ctx *new = NULL;
|
||||||
|
|
||||||
|
new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nhg_ctx_free(struct nhg_ctx *ctx)
|
||||||
|
{
|
||||||
|
XFREE(MTYPE_NHG_CTX, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_result status)
|
||||||
|
{
|
||||||
|
ctx->status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum nhg_ctx_result nhg_ctx_get_status(const struct nhg_ctx *ctx)
|
||||||
|
{
|
||||||
|
return ctx->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nhg_ctx_set_op(struct nhg_ctx *ctx, enum nhg_ctx_op_e op)
|
||||||
|
{
|
||||||
|
ctx->op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx)
|
||||||
|
{
|
||||||
|
return ctx->op;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nhg_ctx_process_new(struct nhg_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct nexthop_group *nhg = NULL;
|
||||||
|
struct nhg_connected_head nhg_depends = {};
|
||||||
struct nhg_hash_entry *nhe = NULL;
|
struct nhg_hash_entry *nhe = NULL;
|
||||||
|
|
||||||
struct nexthop_group *nhg = nexthop_group_new();
|
if (ctx->count) {
|
||||||
|
nhg = nexthop_group_new();
|
||||||
|
zebra_nhg_process_grp(nhg, &nhg_depends, ctx->u.grp,
|
||||||
|
ctx->count);
|
||||||
|
nhe = zebra_nhg_find(ctx->id, nhg, &nhg_depends, ctx->vrf_id,
|
||||||
|
ctx->afi, true);
|
||||||
|
/* These got copied over in zebra_nhg_alloc() */
|
||||||
|
nexthop_group_free_delete(&nhg);
|
||||||
|
} else
|
||||||
|
nhe = zebra_nhg_find_nexthop(ctx->id, &ctx->u.nh, ctx->afi,
|
||||||
|
ctx->is_kernel_nh);
|
||||||
|
|
||||||
nexthop_group_add_sorted(nhg, nh);
|
if (nhe) {
|
||||||
nhe = zebra_nhg_find(nhg, nh->vrf_id, afi, 0, NULL, false);
|
if (ctx->id != nhe->id)
|
||||||
|
/* Duplicate but with different ID from
|
||||||
|
* the kernel */
|
||||||
|
|
||||||
nexthop_group_delete(&nhg);
|
/* The kernel allows duplicate nexthops
|
||||||
|
* as long as they have different IDs.
|
||||||
|
* We are ignoring those to prevent
|
||||||
|
* syncing problems with the kernel
|
||||||
|
* changes.
|
||||||
|
*/
|
||||||
|
flog_warn(
|
||||||
|
EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
|
||||||
|
"Nexthop Group with ID (%d) is a duplicate, ignoring",
|
||||||
|
ctx->id);
|
||||||
|
else {
|
||||||
|
/* It actually created a new nhe */
|
||||||
|
if (nhe->is_kernel_nh) {
|
||||||
|
SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
|
||||||
|
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
flog_err(
|
||||||
|
EC_ZEBRA_TABLE_LOOKUP_FAILED,
|
||||||
|
"Zebra failed to find or create a nexthop hash entry for ID (%u)",
|
||||||
|
ctx->id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nhg_ctx_process_finish(struct nhg_ctx *ctx)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Just freeing for now, maybe do something more in the future
|
||||||
|
* based on flag.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ctx)
|
||||||
|
nhg_ctx_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nhg_ctx_process(struct nhg_ctx *ctx)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
switch (nhg_ctx_get_op(ctx)) {
|
||||||
|
case NHG_CTX_OP_NEW:
|
||||||
|
ret = nhg_ctx_process_new(ctx);
|
||||||
|
break;
|
||||||
|
case NHG_CTX_OP_DEL:
|
||||||
|
case NHG_CTX_OP_NONE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
|
||||||
|
|
||||||
|
nhg_ctx_process_finish(ctx);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int queue_add(struct nhg_ctx *ctx)
|
||||||
|
{
|
||||||
|
/* If its queued or already processed do nothing */
|
||||||
|
if (nhg_ctx_get_status(ctx))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (rib_queue_nhg_add(ctx)) {
|
||||||
|
nhg_ctx_set_status(ctx, NHG_CTX_FAILURE);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nhg_ctx_set_status(ctx, NHG_CTX_QUEUED);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kernel-side, you either get a single new nexthop or a array of ID's */
|
||||||
|
int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
|
||||||
|
uint8_t count, vrf_id_t vrf_id, afi_t afi)
|
||||||
|
{
|
||||||
|
// TODO: Can probably put table lookup
|
||||||
|
// here before queueing? And if deleted, re-send to kernel?
|
||||||
|
// ... Well, if changing the flags it probably needs to be queued
|
||||||
|
// still...
|
||||||
|
|
||||||
|
struct nhg_ctx *ctx = NULL;
|
||||||
|
|
||||||
|
ctx = nhg_ctx_new();
|
||||||
|
|
||||||
|
ctx->id = id;
|
||||||
|
ctx->vrf_id = vrf_id;
|
||||||
|
ctx->afi = afi;
|
||||||
|
ctx->is_kernel_nh = true;
|
||||||
|
ctx->count = count;
|
||||||
|
|
||||||
|
if (count)
|
||||||
|
/* Copy over the array */
|
||||||
|
memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp));
|
||||||
|
else
|
||||||
|
ctx->u.nh = *nh;
|
||||||
|
|
||||||
|
nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
|
||||||
|
|
||||||
|
if (queue_add(ctx)) {
|
||||||
|
nhg_ctx_process_finish(ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rib-side, you get a nexthop group struct */
|
||||||
|
struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id,
|
||||||
|
struct nexthop_group *nhg,
|
||||||
|
vrf_id_t rt_vrf_id, afi_t rt_afi)
|
||||||
|
{
|
||||||
|
struct nhg_hash_entry *nhe = NULL;
|
||||||
|
struct nhg_connected_head nhg_depends = {};
|
||||||
|
// Defualt the nhe to the afi and vrf of the route
|
||||||
|
afi_t nhg_afi = rt_afi;
|
||||||
|
vrf_id_t nhg_vrf_id = rt_vrf_id;
|
||||||
|
|
||||||
|
/* If its a group, create a dependency list */
|
||||||
|
if (nhg && nhg->nexthop->next) {
|
||||||
|
struct nexthop *nh = NULL;
|
||||||
|
struct nexthop lookup = {0};
|
||||||
|
struct nhg_hash_entry *depend = NULL;
|
||||||
|
|
||||||
|
nhg_connected_head_init(&nhg_depends);
|
||||||
|
|
||||||
|
for (ALL_NEXTHOPS_PTR(nhg, nh)) {
|
||||||
|
lookup = *nh;
|
||||||
|
/* Clear it, since its a group */
|
||||||
|
lookup.next = NULL;
|
||||||
|
/* Use the route afi here, since a single nh */
|
||||||
|
depend = zebra_nhg_find_nexthop(0, &lookup, rt_afi,
|
||||||
|
false);
|
||||||
|
nhg_connected_head_add(&nhg_depends, depend);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* change the afi/vrf_id since its a group */
|
||||||
|
nhg_afi = AFI_UNSPEC;
|
||||||
|
nhg_vrf_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nhe = zebra_nhg_find(id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi, false);
|
||||||
|
|
||||||
return nhe;
|
return nhe;
|
||||||
}
|
}
|
||||||
@ -552,7 +734,7 @@ void zebra_nhg_free(void *arg)
|
|||||||
*
|
*
|
||||||
* @nhe: Nexthop group hash entry
|
* @nhe: Nexthop group hash entry
|
||||||
*/
|
*/
|
||||||
void zebra_nhg_release(struct nhg_hash_entry *nhe)
|
static void zebra_nhg_release(struct nhg_hash_entry *nhe)
|
||||||
{
|
{
|
||||||
zlog_debug("Releasing nexthop group with ID (%u)", nhe->id);
|
zlog_debug("Releasing nexthop group with ID (%u)", nhe->id);
|
||||||
|
|
||||||
@ -564,6 +746,7 @@ void zebra_nhg_release(struct nhg_hash_entry *nhe)
|
|||||||
|
|
||||||
hash_release(zrouter.nhgs, nhe);
|
hash_release(zrouter.nhgs, nhe);
|
||||||
hash_release(zrouter.nhgs_id, nhe);
|
hash_release(zrouter.nhgs_id, nhe);
|
||||||
|
|
||||||
zebra_nhg_free(nhe);
|
zebra_nhg_free(nhe);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,6 +760,8 @@ void zebra_nhg_release(struct nhg_hash_entry *nhe)
|
|||||||
*/
|
*/
|
||||||
void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
|
void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
|
||||||
{
|
{
|
||||||
|
nhe->refcnt--;
|
||||||
|
|
||||||
if (!zebra_nhg_depends_is_empty(nhe)) {
|
if (!zebra_nhg_depends_is_empty(nhe)) {
|
||||||
struct nhg_connected *rb_node_dep = NULL;
|
struct nhg_connected *rb_node_dep = NULL;
|
||||||
|
|
||||||
@ -586,12 +771,8 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nhe->refcnt--;
|
if (!nhe->is_kernel_nh && nhe->refcnt <= 0)
|
||||||
|
|
||||||
if (!nhe->is_kernel_nh && nhe->refcnt <= 0) {
|
|
||||||
zebra_nhg_uninstall_kernel(nhe);
|
zebra_nhg_uninstall_kernel(nhe);
|
||||||
zebra_nhg_release(nhe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -601,6 +782,8 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
|
|||||||
*/
|
*/
|
||||||
void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
|
void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
|
||||||
{
|
{
|
||||||
|
nhe->refcnt++;
|
||||||
|
|
||||||
if (!zebra_nhg_depends_is_empty(nhe)) {
|
if (!zebra_nhg_depends_is_empty(nhe)) {
|
||||||
struct nhg_connected *rb_node_dep = NULL;
|
struct nhg_connected *rb_node_dep = NULL;
|
||||||
|
|
||||||
@ -609,12 +792,34 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
|
|||||||
zebra_nhg_increment_ref(rb_node_dep->nhe);
|
zebra_nhg_increment_ref(rb_node_dep->nhe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nhe->refcnt++;
|
static bool zebra_nhg_is_valid(struct nhg_hash_entry *nhe)
|
||||||
|
{
|
||||||
|
if (nhe->flags & NEXTHOP_GROUP_VALID)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool zebra_nhg_id_is_valid(uint32_t id)
|
||||||
|
{
|
||||||
|
struct nhg_hash_entry *nhe = NULL;
|
||||||
|
bool is_valid = false;
|
||||||
|
|
||||||
|
nhe = zebra_nhg_lookup_id(id);
|
||||||
|
|
||||||
|
if (nhe)
|
||||||
|
is_valid = zebra_nhg_is_valid(nhe);
|
||||||
|
|
||||||
|
return is_valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
|
void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
|
||||||
{
|
{
|
||||||
|
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
|
||||||
|
/* Assuming uninstalled as well here */
|
||||||
|
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
||||||
|
|
||||||
if (!zebra_nhg_dependents_is_empty(nhe)) {
|
if (!zebra_nhg_dependents_is_empty(nhe)) {
|
||||||
struct nhg_connected *rb_node_dep = NULL;
|
struct nhg_connected *rb_node_dep = NULL;
|
||||||
@ -624,10 +829,6 @@ void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
|
|||||||
zebra_nhg_set_invalid(rb_node_dep->nhe);
|
zebra_nhg_set_invalid(rb_node_dep->nhe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
|
|
||||||
/* Assuming uninstalled as well here */
|
|
||||||
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
|
void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
|
||||||
@ -1118,6 +1319,32 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
|
|||||||
unsigned int prev_active, new_active;
|
unsigned int prev_active, new_active;
|
||||||
ifindex_t prev_index;
|
ifindex_t prev_index;
|
||||||
uint8_t curr_active = 0;
|
uint8_t curr_active = 0;
|
||||||
|
afi_t rt_afi = AFI_UNSPEC;
|
||||||
|
|
||||||
|
// TODO: Temporary until we get this function sorted out
|
||||||
|
// a little better.
|
||||||
|
//
|
||||||
|
if (re->nhe_id) {
|
||||||
|
struct nhg_hash_entry *nhe = NULL;
|
||||||
|
|
||||||
|
nhe = zebra_nhg_lookup_id(re->nhe_id);
|
||||||
|
|
||||||
|
if (nhe) {
|
||||||
|
if (!re->ng) {
|
||||||
|
/* This is its first time getting attached */
|
||||||
|
zebra_nhg_increment_ref(nhe);
|
||||||
|
re->ng = nhe->nhg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
flog_err(
|
||||||
|
EC_ZEBRA_TABLE_LOOKUP_FAILED,
|
||||||
|
"Zebra failed to find the nexthop hash entry for id=%u in a route entry",
|
||||||
|
re->nhe_id);
|
||||||
|
}
|
||||||
|
|
||||||
UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
||||||
|
|
||||||
@ -1158,6 +1385,40 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
|
|||||||
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Update this when we have this function
|
||||||
|
// figured out a little better.
|
||||||
|
//
|
||||||
|
struct nhg_hash_entry *new_nhe = NULL;
|
||||||
|
|
||||||
|
rt_afi = family2afi(rn->p.family);
|
||||||
|
// TODO: Add proto type here
|
||||||
|
|
||||||
|
// TODO: Maybe make this a UPDATE message?
|
||||||
|
// Right now we are just creating a new one
|
||||||
|
// and deleting the old.
|
||||||
|
new_nhe = zebra_nhg_rib_find(0, re->ng, re->vrf_id, rt_afi);
|
||||||
|
|
||||||
|
if (new_nhe && (re->nhe_id != new_nhe->id)) {
|
||||||
|
struct nhg_hash_entry *old_nhe =
|
||||||
|
zebra_nhg_lookup_id(re->nhe_id);
|
||||||
|
|
||||||
|
/* It should point to the nhe nexthop group now */
|
||||||
|
if (re->ng)
|
||||||
|
nexthop_group_free_delete(&re->ng);
|
||||||
|
re->ng = new_nhe->nhg;
|
||||||
|
re->nhe_id = new_nhe->id;
|
||||||
|
|
||||||
|
zebra_nhg_increment_ref(new_nhe);
|
||||||
|
if (old_nhe)
|
||||||
|
zebra_nhg_decrement_ref(old_nhe);
|
||||||
|
|
||||||
|
if (curr_active) {
|
||||||
|
SET_FLAG(new_nhe->flags, NEXTHOP_GROUP_VALID);
|
||||||
|
if (!new_nhe->is_kernel_nh)
|
||||||
|
zebra_nhg_install_kernel(new_nhe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return curr_active;
|
return curr_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1168,7 +1429,8 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
|
|||||||
*/
|
*/
|
||||||
void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
|
void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
|
||||||
{
|
{
|
||||||
if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
|
if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
|
||||||
|
&& !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
|
||||||
nhe->is_kernel_nh = false;
|
nhe->is_kernel_nh = false;
|
||||||
int ret = dplane_nexthop_add(nhe);
|
int ret = dplane_nexthop_add(nhe);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
@ -1209,9 +1471,11 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
|
|||||||
break;
|
break;
|
||||||
case ZEBRA_DPLANE_REQUEST_SUCCESS:
|
case ZEBRA_DPLANE_REQUEST_SUCCESS:
|
||||||
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
||||||
|
zebra_nhg_release(nhe);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
|
zebra_nhg_release(nhe);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1254,6 +1518,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
|
|||||||
status = dplane_ctx_get_status(ctx);
|
status = dplane_ctx_get_status(ctx);
|
||||||
|
|
||||||
id = dplane_ctx_get_nhe_id(ctx);
|
id = dplane_ctx_get_nhe_id(ctx);
|
||||||
|
|
||||||
nhe = zebra_nhg_lookup_id(id);
|
nhe = zebra_nhg_lookup_id(id);
|
||||||
|
|
||||||
if (nhe) {
|
if (nhe) {
|
||||||
@ -1268,6 +1533,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
|
|||||||
case DPLANE_OP_NH_DELETE:
|
case DPLANE_OP_NH_DELETE:
|
||||||
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
|
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
|
||||||
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
||||||
|
zebra_nhg_release(nhe);
|
||||||
} else {
|
} else {
|
||||||
flog_err(
|
flog_err(
|
||||||
EC_ZEBRA_DP_DELETE_FAIL,
|
EC_ZEBRA_DP_DELETE_FAIL,
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
* It is designed to mimic the netlink nexthop_grp
|
* It is designed to mimic the netlink nexthop_grp
|
||||||
* struct in include/linux/nexthop.h
|
* struct in include/linux/nexthop.h
|
||||||
*/
|
*/
|
||||||
struct depend_info {
|
struct nh_grp {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint8_t weight;
|
uint8_t weight;
|
||||||
};
|
};
|
||||||
@ -98,6 +98,47 @@ struct nhg_connected {
|
|||||||
|
|
||||||
RB_PROTOTYPE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp);
|
RB_PROTOTYPE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp);
|
||||||
|
|
||||||
|
|
||||||
|
enum nhg_ctx_op_e {
|
||||||
|
NHG_CTX_OP_NONE = 0,
|
||||||
|
NHG_CTX_OP_NEW,
|
||||||
|
NHG_CTX_OP_DEL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum nhg_ctx_result {
|
||||||
|
NHG_CTX_NONE = 0,
|
||||||
|
NHG_CTX_QUEUED,
|
||||||
|
NHG_CTX_SUCCESS,
|
||||||
|
NHG_CTX_FAILURE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Context needed to queue nhg updates on the
|
||||||
|
* work queue.
|
||||||
|
*/
|
||||||
|
struct nhg_ctx {
|
||||||
|
|
||||||
|
/* Unique ID */
|
||||||
|
uint32_t id;
|
||||||
|
|
||||||
|
vrf_id_t vrf_id;
|
||||||
|
afi_t afi;
|
||||||
|
bool is_kernel_nh;
|
||||||
|
|
||||||
|
/* If its a group array, how many? */
|
||||||
|
uint8_t count;
|
||||||
|
|
||||||
|
/* Its either a single nexthop or an array of ID's */
|
||||||
|
union {
|
||||||
|
struct nexthop nh;
|
||||||
|
struct nh_grp grp[MULTIPATH_NUM];
|
||||||
|
} u;
|
||||||
|
|
||||||
|
enum nhg_ctx_op_e op;
|
||||||
|
enum nhg_ctx_result status;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
void zebra_nhg_init(void);
|
void zebra_nhg_init(void);
|
||||||
void zebra_nhg_terminate(void);
|
void zebra_nhg_terminate(void);
|
||||||
|
|
||||||
@ -147,20 +188,31 @@ extern uint32_t zebra_nhg_id_key(const void *arg);
|
|||||||
extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2);
|
extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2);
|
||||||
extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2);
|
extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2);
|
||||||
|
|
||||||
extern struct nhg_hash_entry *
|
/*
|
||||||
zebra_nhg_find(struct nexthop_group *nhg, vrf_id_t vrf_id, afi_t afi,
|
* Process a context off of a queue.
|
||||||
uint32_t id, struct nhg_connected_head *nhg_depends,
|
* Specifically this should be from
|
||||||
bool is_kernel_nh);
|
* the rib meta queue.
|
||||||
|
*/
|
||||||
|
extern int nhg_ctx_process(struct nhg_ctx *ctx);
|
||||||
|
|
||||||
extern struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh,
|
/* Find via kernel nh creation */
|
||||||
afi_t afi);
|
extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
|
||||||
|
struct nh_grp *grp, uint8_t count,
|
||||||
|
vrf_id_t vrf_id, afi_t afi);
|
||||||
|
|
||||||
|
/* Find via route creation */
|
||||||
|
extern struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id,
|
||||||
|
struct nexthop_group *nhg,
|
||||||
|
vrf_id_t rt_vrf_id,
|
||||||
|
afi_t rt_afi);
|
||||||
|
|
||||||
|
|
||||||
void zebra_nhg_free_members(struct nhg_hash_entry *nhe);
|
void zebra_nhg_free_members(struct nhg_hash_entry *nhe);
|
||||||
void zebra_nhg_free(void *arg);
|
void zebra_nhg_free(void *arg);
|
||||||
void zebra_nhg_release(struct nhg_hash_entry *nhe);
|
|
||||||
void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe);
|
void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe);
|
||||||
void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe);
|
void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe);
|
||||||
|
|
||||||
|
extern bool zebra_nhg_id_is_valid(uint32_t id);
|
||||||
void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe);
|
void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe);
|
||||||
void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp);
|
void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp);
|
||||||
|
|
||||||
|
@ -56,7 +56,6 @@
|
|||||||
#include "zebra/zebra_vxlan.h"
|
#include "zebra/zebra_vxlan.h"
|
||||||
#include "zebra/zapi_msg.h"
|
#include "zebra/zapi_msg.h"
|
||||||
#include "zebra/zebra_dplane.h"
|
#include "zebra/zebra_dplane.h"
|
||||||
#include "zebra/zebra_nhg.h"
|
|
||||||
|
|
||||||
DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object");
|
DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object");
|
||||||
|
|
||||||
@ -79,34 +78,35 @@ static const struct {
|
|||||||
uint8_t distance;
|
uint8_t distance;
|
||||||
uint8_t meta_q_map;
|
uint8_t meta_q_map;
|
||||||
} route_info[ZEBRA_ROUTE_MAX] = {
|
} route_info[ZEBRA_ROUTE_MAX] = {
|
||||||
[ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 4},
|
[ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Uneeded for nhg's */, 0},
|
||||||
[ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 0},
|
[ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 5},
|
||||||
[ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 0},
|
[ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 1},
|
||||||
[ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 1},
|
[ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 1},
|
||||||
[ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 2},
|
[ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 2},
|
||||||
[ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 2},
|
[ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 3},
|
||||||
[ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 2},
|
[ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 3},
|
||||||
[ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 2},
|
[ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 3},
|
||||||
[ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 2},
|
[ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 3},
|
||||||
[ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 3},
|
[ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 3},
|
||||||
[ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 4},
|
[ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 4},
|
||||||
[ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 2},
|
[ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 5},
|
||||||
[ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 2},
|
[ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 3},
|
||||||
[ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 4},
|
[ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 3},
|
||||||
[ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 4},
|
[ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 5},
|
||||||
[ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 1},
|
[ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 5},
|
||||||
[ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 4},
|
[ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 2},
|
||||||
[ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 3},
|
[ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 5},
|
||||||
[ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 3},
|
[ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 4},
|
||||||
[ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 3},
|
[ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 4},
|
||||||
[ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 3},
|
[ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 4},
|
||||||
[ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 3},
|
[ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 4},
|
||||||
[ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 2},
|
[ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 4},
|
||||||
[ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 4},
|
[ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 3},
|
||||||
[ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 4},
|
[ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 5},
|
||||||
[ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 4},
|
[ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 5},
|
||||||
[ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 2},
|
[ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 5},
|
||||||
[ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 4}
|
[ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 3},
|
||||||
|
[ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 5}
|
||||||
/* Any new route type added to zebra, should be mirrored here */
|
/* Any new route type added to zebra, should be mirrored here */
|
||||||
|
|
||||||
/* no entry/default: 150 */
|
/* no entry/default: 150 */
|
||||||
@ -618,6 +618,16 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re)
|
|||||||
rib_table_info_t *info = srcdest_rnode_table_info(rn);
|
rib_table_info_t *info = srcdest_rnode_table_info(rn);
|
||||||
struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id);
|
struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id);
|
||||||
|
|
||||||
|
// TODO: Might need to move this?
|
||||||
|
// It checks if the nhe is even valid
|
||||||
|
// before trying to uninstall it. If the
|
||||||
|
// nexthop is invalid/uninstalled, then
|
||||||
|
// this route is not in the kernel anymore
|
||||||
|
// most likely.
|
||||||
|
if (!zebra_nhg_id_is_valid(re->nhe_id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
if (info->safi != SAFI_UNICAST) {
|
if (info->safi != SAFI_UNICAST) {
|
||||||
UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
|
UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
|
||||||
for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
|
for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
|
||||||
@ -1082,6 +1092,12 @@ static struct route_entry *rib_choose_best(struct route_entry *current,
|
|||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Core function for processing nexthop group contexts's off metaq */
|
||||||
|
static void rib_nhg_process(struct nhg_ctx *ctx)
|
||||||
|
{
|
||||||
|
nhg_ctx_process(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
/* Core function for processing routing information base. */
|
/* Core function for processing routing information base. */
|
||||||
static void rib_process(struct route_node *rn)
|
static void rib_process(struct route_node *rn)
|
||||||
{
|
{
|
||||||
@ -2058,19 +2074,28 @@ done:
|
|||||||
dplane_ctx_fini(&ctx);
|
dplane_ctx_fini(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Take a list of route_node structs and return 1, if there was a record
|
static void process_subq_nhg(struct listnode *lnode)
|
||||||
* picked from it and processed by rib_process(). Don't process more,
|
|
||||||
* than one RN record; operate only in the specified sub-queue.
|
|
||||||
*/
|
|
||||||
static unsigned int process_subq(struct list *subq, uint8_t qindex)
|
|
||||||
{
|
{
|
||||||
struct listnode *lnode = listhead(subq);
|
struct nhg_ctx *ctx = NULL;
|
||||||
struct route_node *rnode;
|
uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map;
|
||||||
rib_dest_t *dest;
|
|
||||||
struct zebra_vrf *zvrf = NULL;
|
|
||||||
|
|
||||||
if (!lnode)
|
ctx = listgetdata(lnode);
|
||||||
return 0;
|
|
||||||
|
if (!ctx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
||||||
|
zlog_debug("NHG Context id=%u dequeued from sub-queue %u",
|
||||||
|
ctx->id, qindex);
|
||||||
|
|
||||||
|
rib_nhg_process(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_subq_route(struct listnode *lnode, uint8_t qindex)
|
||||||
|
{
|
||||||
|
struct route_node *rnode = NULL;
|
||||||
|
rib_dest_t *dest = NULL;
|
||||||
|
struct zebra_vrf *zvrf = NULL;
|
||||||
|
|
||||||
rnode = listgetdata(lnode);
|
rnode = listgetdata(lnode);
|
||||||
dest = rib_dest_from_rnode(rnode);
|
dest = rib_dest_from_rnode(rnode);
|
||||||
@ -2100,7 +2125,26 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
route_unlock_node(rnode);
|
route_unlock_node(rnode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Take a list of route_node structs and return 1, if there was a record
|
||||||
|
* picked from it and processed by rib_process(). Don't process more,
|
||||||
|
* than one RN record; operate only in the specified sub-queue.
|
||||||
|
*/
|
||||||
|
static unsigned int process_subq(struct list *subq, uint8_t qindex)
|
||||||
|
{
|
||||||
|
struct listnode *lnode = listhead(subq);
|
||||||
|
|
||||||
|
if (!lnode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (qindex == route_info[ZEBRA_ROUTE_NHG].meta_q_map)
|
||||||
|
process_subq_nhg(lnode);
|
||||||
|
else
|
||||||
|
process_subq_route(lnode, qindex);
|
||||||
|
|
||||||
list_delete_node(subq, lnode);
|
list_delete_node(subq, lnode);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2158,11 +2202,14 @@ static wq_item_status meta_queue_process(struct work_queue *dummy, void *data)
|
|||||||
* original metaqueue index value will win and we'll end up with
|
* original metaqueue index value will win and we'll end up with
|
||||||
* the route node enqueued once.
|
* the route node enqueued once.
|
||||||
*/
|
*/
|
||||||
static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn)
|
static int rib_meta_queue_add(struct meta_queue *mq, void *data)
|
||||||
{
|
{
|
||||||
|
struct route_node *rn = NULL;
|
||||||
struct route_entry *re = NULL, *curr_re = NULL;
|
struct route_entry *re = NULL, *curr_re = NULL;
|
||||||
uint8_t qindex = MQ_SIZE, curr_qindex = MQ_SIZE;
|
uint8_t qindex = MQ_SIZE, curr_qindex = MQ_SIZE;
|
||||||
|
|
||||||
|
rn = (struct route_node *)data;
|
||||||
|
|
||||||
RNODE_FOREACH_RE (rn, curr_re) {
|
RNODE_FOREACH_RE (rn, curr_re) {
|
||||||
curr_qindex = route_info[curr_re->type].meta_q_map;
|
curr_qindex = route_info[curr_re->type].meta_q_map;
|
||||||
|
|
||||||
@ -2173,7 +2220,7 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!re)
|
if (!re)
|
||||||
return;
|
return -1;
|
||||||
|
|
||||||
/* Invariant: at this point we always have rn->info set. */
|
/* Invariant: at this point we always have rn->info set. */
|
||||||
if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
|
if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
|
||||||
@ -2182,7 +2229,7 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn)
|
|||||||
rnode_debug(rn, re->vrf_id,
|
rnode_debug(rn, re->vrf_id,
|
||||||
"rn %p is already queued in sub-queue %u",
|
"rn %p is already queued in sub-queue %u",
|
||||||
(void *)rn, qindex);
|
(void *)rn, qindex);
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_FLAG(rib_dest_from_rnode(rn)->flags, RIB_ROUTE_QUEUED(qindex));
|
SET_FLAG(rib_dest_from_rnode(rn)->flags, RIB_ROUTE_QUEUED(qindex));
|
||||||
@ -2193,26 +2240,37 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn)
|
|||||||
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
||||||
rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %u",
|
rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %u",
|
||||||
(void *)rn, qindex);
|
(void *)rn, qindex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add route_node to work queue and schedule processing */
|
static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data)
|
||||||
void rib_queue_add(struct route_node *rn)
|
|
||||||
{
|
{
|
||||||
assert(rn);
|
struct nhg_ctx *ctx = NULL;
|
||||||
|
uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map;
|
||||||
|
|
||||||
/* Pointless to queue a route_node with no RIB entries to add or remove
|
ctx = (struct nhg_ctx *)data;
|
||||||
*/
|
|
||||||
if (!rnode_to_ribs(rn)) {
|
|
||||||
zlog_debug("%s: called for route_node (%p, %d) with no ribs",
|
|
||||||
__func__, (void *)rn, rn->lock);
|
|
||||||
zlog_backtrace(LOG_DEBUG);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
listnode_add(mq->subq[qindex], ctx);
|
||||||
|
mq->size++;
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
||||||
|
zlog_debug("NHG Context id=%u queued into sub-queue %u",
|
||||||
|
ctx->id, qindex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mq_add_handler(void *data,
|
||||||
|
int (*mq_add_func)(struct meta_queue *mq, void *data))
|
||||||
|
{
|
||||||
if (zrouter.ribq == NULL) {
|
if (zrouter.ribq == NULL) {
|
||||||
flog_err(EC_ZEBRA_WQ_NONEXISTENT,
|
flog_err(EC_ZEBRA_WQ_NONEXISTENT,
|
||||||
"%s: work_queue does not exist!", __func__);
|
"%s: work_queue does not exist!", __func__);
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2226,9 +2284,31 @@ void rib_queue_add(struct route_node *rn)
|
|||||||
if (work_queue_empty(zrouter.ribq))
|
if (work_queue_empty(zrouter.ribq))
|
||||||
work_queue_add(zrouter.ribq, zrouter.mq);
|
work_queue_add(zrouter.ribq, zrouter.mq);
|
||||||
|
|
||||||
rib_meta_queue_add(zrouter.mq, rn);
|
return mq_add_func(zrouter.mq, data);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
/* Add route_node to work queue and schedule processing */
|
||||||
|
int rib_queue_add(struct route_node *rn)
|
||||||
|
{
|
||||||
|
assert(rn);
|
||||||
|
|
||||||
|
/* Pointless to queue a route_node with no RIB entries to add or remove
|
||||||
|
*/
|
||||||
|
if (!rnode_to_ribs(rn)) {
|
||||||
|
zlog_debug("%s: called for route_node (%p, %d) with no ribs",
|
||||||
|
__func__, (void *)rn, rn->lock);
|
||||||
|
zlog_backtrace(LOG_DEBUG);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mq_add_handler(rn, &rib_meta_queue_add);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rib_queue_nhg_add(struct nhg_ctx *ctx)
|
||||||
|
{
|
||||||
|
assert(ctx);
|
||||||
|
|
||||||
|
return mq_add_handler(ctx, &rib_meta_queue_nhg_add);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create new meta queue.
|
/* Create new meta queue.
|
||||||
@ -2411,9 +2491,12 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
|
|||||||
if (dest->selected_fib == re)
|
if (dest->selected_fib == re)
|
||||||
dest->selected_fib = NULL;
|
dest->selected_fib = NULL;
|
||||||
|
|
||||||
nhe = zebra_nhg_lookup_id(re->nhe_id);
|
if (re->nhe_id) {
|
||||||
if (nhe)
|
nhe = zebra_nhg_lookup_id(re->nhe_id);
|
||||||
zebra_nhg_decrement_ref(nhe);
|
if (nhe)
|
||||||
|
zebra_nhg_decrement_ref(nhe);
|
||||||
|
} else if (re->ng)
|
||||||
|
nexthop_group_free_delete(&re->ng);
|
||||||
|
|
||||||
nexthops_free(re->fib_ng.nexthop);
|
nexthops_free(re->fib_ng.nexthop);
|
||||||
|
|
||||||
@ -2637,12 +2720,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
|||||||
struct route_table *table;
|
struct route_table *table;
|
||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
struct route_entry *same = NULL;
|
struct route_entry *same = NULL;
|
||||||
struct nhg_hash_entry *nhe = NULL;
|
|
||||||
struct nhg_connected_head nhg_depends = {0};
|
|
||||||
/* Default to route afi */
|
|
||||||
afi_t nhg_afi = afi;
|
|
||||||
/* Default to route vrf id */
|
|
||||||
vrf_id_t nhg_vrf_id = re->vrf_id;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!re)
|
if (!re)
|
||||||
@ -2664,48 +2741,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
|||||||
if (src_p)
|
if (src_p)
|
||||||
apply_mask_ipv6(src_p);
|
apply_mask_ipv6(src_p);
|
||||||
|
|
||||||
/* If its a group, create a dependency list */
|
|
||||||
if (re->ng && re->ng->nexthop->next) {
|
|
||||||
struct nexthop *nh = NULL;
|
|
||||||
struct nexthop lookup = {0};
|
|
||||||
struct nhg_hash_entry *depend = NULL;
|
|
||||||
|
|
||||||
nhg_connected_head_init(&nhg_depends);
|
|
||||||
|
|
||||||
for (ALL_NEXTHOPS_PTR(re->ng, nh)) {
|
|
||||||
lookup = *nh;
|
|
||||||
/* Clear it, since its a group */
|
|
||||||
lookup.next = NULL;
|
|
||||||
/* Use the route afi here, since a single nh */
|
|
||||||
depend = zebra_nhg_find_nexthop(&lookup, afi);
|
|
||||||
nhg_connected_head_add(&nhg_depends, depend);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* change the afi for group */
|
|
||||||
nhg_afi = AFI_UNSPEC;
|
|
||||||
nhg_vrf_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add proto type here
|
|
||||||
nhe = zebra_nhg_find(re->ng, nhg_vrf_id, nhg_afi, re->nhe_id,
|
|
||||||
&nhg_depends, false);
|
|
||||||
|
|
||||||
if (nhe) {
|
|
||||||
/* It should point to the nhe nexthop group now */
|
|
||||||
if (re->ng)
|
|
||||||
nexthop_group_free_delete(&re->ng);
|
|
||||||
re->ng = nhe->nhg;
|
|
||||||
re->nhe_id = nhe->id;
|
|
||||||
zebra_nhg_increment_ref(nhe);
|
|
||||||
} else {
|
|
||||||
flog_err(
|
|
||||||
EC_ZEBRA_TABLE_LOOKUP_FAILED,
|
|
||||||
"Zebra failed to find or create a nexthop hash entry for id=%u in a route entry",
|
|
||||||
re->nhe_id);
|
|
||||||
nhg_connected_head_free(&nhg_depends);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Set default distance by route type. */
|
/* Set default distance by route type. */
|
||||||
if (re->distance == 0)
|
if (re->distance == 0)
|
||||||
re->distance = route_distance(re->type);
|
re->distance = route_distance(re->type);
|
||||||
@ -3006,12 +3041,14 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
|
|||||||
re->tag = tag;
|
re->tag = tag;
|
||||||
re->nhe_id = nhe_id;
|
re->nhe_id = nhe_id;
|
||||||
|
|
||||||
re->ng = nexthop_group_new();
|
if (!nhe_id) {
|
||||||
|
re->ng = nexthop_group_new();
|
||||||
|
|
||||||
/* Add nexthop. */
|
/* Add nexthop. */
|
||||||
nexthop = nexthop_new();
|
nexthop = nexthop_new();
|
||||||
*nexthop = *nh;
|
*nexthop = *nh;
|
||||||
route_entry_nexthop_add(re, nexthop);
|
route_entry_nexthop_add(re, nexthop);
|
||||||
|
}
|
||||||
|
|
||||||
return rib_add_multipath(afi, safi, p, src_p, re);
|
return rib_add_multipath(afi, safi, p, src_p, re);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user