forked from Mirror/frr
lib: Handle if up/down and vrf enable/disable events
Properly notice when we get if up/down and vrf enable/disable events and attempt to properly install nexthops as they come in. Ticket: CM20489 Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
parent
d7b3ad4016
commit
98cbbaea91
|
@ -331,6 +331,47 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
|
||||||
XFREE(MTYPE_TMP, nh);
|
XFREE(MTYPE_TMP, nh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
|
||||||
|
const union sockunion *addr,
|
||||||
|
const char *intf, const char *name)
|
||||||
|
{
|
||||||
|
struct vrf *vrf;
|
||||||
|
|
||||||
|
memset(nhop, 0, sizeof(*nhop));
|
||||||
|
|
||||||
|
if (name)
|
||||||
|
vrf = vrf_lookup_by_name(name);
|
||||||
|
else
|
||||||
|
vrf = vrf_lookup_by_id(VRF_DEFAULT);
|
||||||
|
|
||||||
|
if (!vrf)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
nhop->vrf_id = vrf->vrf_id;
|
||||||
|
|
||||||
|
if (addr->sa.sa_family == AF_INET) {
|
||||||
|
nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
||||||
|
if (intf) {
|
||||||
|
nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
||||||
|
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
||||||
|
if (nhop->ifindex == IFINDEX_INTERNAL)
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
nhop->type = NEXTHOP_TYPE_IPV4;
|
||||||
|
} else {
|
||||||
|
memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16);
|
||||||
|
if (intf) {
|
||||||
|
nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||||
|
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
||||||
|
if (nhop->ifindex == IFINDEX_INTERNAL)
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
nhop->type = NEXTHOP_TYPE_IPV6;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
||||||
"[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
|
"[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
|
||||||
NO_STR
|
NO_STR
|
||||||
|
@ -342,64 +383,26 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
||||||
"The nexthop-vrf Name\n")
|
"The nexthop-vrf Name\n")
|
||||||
{
|
{
|
||||||
VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
|
VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
|
||||||
struct vrf *vrf;
|
|
||||||
struct nexthop nhop;
|
struct nexthop nhop;
|
||||||
struct nexthop *nh;
|
struct nexthop *nh;
|
||||||
|
bool legal;
|
||||||
|
|
||||||
if (name)
|
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
|
||||||
vrf = vrf_lookup_by_name(name);
|
|
||||||
else
|
|
||||||
vrf = vrf_lookup_by_id(VRF_DEFAULT);
|
|
||||||
|
|
||||||
if (!vrf) {
|
if (nhop.type == NEXTHOP_TYPE_IPV6
|
||||||
vty_out(vty, "Specified: %s is non-existent\n", name);
|
&& IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
|
||||||
return CMD_WARNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&nhop, 0, sizeof(nhop));
|
|
||||||
nhop.vrf_id = vrf->vrf_id;
|
|
||||||
|
|
||||||
if (addr->sa.sa_family == AF_INET) {
|
|
||||||
nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
|
||||||
if (intf) {
|
|
||||||
nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
|
||||||
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
|
||||||
if (nhop.ifindex == IFINDEX_INTERNAL) {
|
|
||||||
vty_out(vty,
|
|
||||||
"Specified Intf %s does not exist in vrf: %s\n",
|
|
||||||
intf, vrf->name);
|
|
||||||
return CMD_WARNING;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
nhop.type = NEXTHOP_TYPE_IPV4;
|
|
||||||
} else {
|
|
||||||
memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
|
|
||||||
if (intf) {
|
|
||||||
nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
|
||||||
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
|
||||||
if (nhop.ifindex == IFINDEX_INTERNAL) {
|
|
||||||
vty_out(vty,
|
|
||||||
"Specified Intf %s does not exist in vrf: %s\n",
|
|
||||||
intf, vrf->name);
|
|
||||||
return CMD_WARNING;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
|
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"Specified a v6 LL with no interface, rejecting\n");
|
"Specified a v6 LL with no interface, rejecting\n");
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
}
|
}
|
||||||
nhop.type = NEXTHOP_TYPE_IPV6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nh = nexthop_exists(&nhgc->nhg, &nhop);
|
nh = nexthop_exists(&nhgc->nhg, &nhop);
|
||||||
|
|
||||||
if (no) {
|
if (no) {
|
||||||
|
nexthop_group_unsave_nhop(nhgc, name, addr, intf);
|
||||||
if (nh) {
|
if (nh) {
|
||||||
nexthop_del(&nhgc->nhg, nh);
|
nexthop_del(&nhgc->nhg, nh);
|
||||||
|
|
||||||
nexthop_group_unsave_nhop(nhgc, name, addr, intf);
|
|
||||||
if (nhg_hooks.del_nexthop)
|
if (nhg_hooks.del_nexthop)
|
||||||
nhg_hooks.del_nexthop(nhgc, nh);
|
nhg_hooks.del_nexthop(nhgc, nh);
|
||||||
|
|
||||||
|
@ -407,14 +410,16 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
||||||
}
|
}
|
||||||
} else if (!nh) {
|
} else if (!nh) {
|
||||||
/* must be adding new nexthop since !no and !nexthop_exists */
|
/* must be adding new nexthop since !no and !nexthop_exists */
|
||||||
|
if (legal) {
|
||||||
nh = nexthop_new();
|
nh = nexthop_new();
|
||||||
|
|
||||||
memcpy(nh, &nhop, sizeof(nhop));
|
memcpy(nh, &nhop, sizeof(nhop));
|
||||||
nexthop_add(&nhgc->nhg.nexthop, nh);
|
nexthop_add(&nhgc->nhg.nexthop, nh);
|
||||||
|
}
|
||||||
|
|
||||||
nexthop_group_save_nhop(nhgc, name, addr, intf);
|
nexthop_group_save_nhop(nhgc, name, addr, intf);
|
||||||
|
|
||||||
if (nhg_hooks.add_nexthop)
|
if (legal && nhg_hooks.add_nexthop)
|
||||||
nhg_hooks.add_nexthop(nhgc, nh);
|
nhg_hooks.add_nexthop(nhgc, nh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,6 +509,152 @@ static int nexthop_group_write(struct vty *vty)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nexthop_group_enable_vrf(struct vrf *vrf)
|
||||||
|
{
|
||||||
|
struct nexthop_group_cmd *nhgc;
|
||||||
|
struct nexthop_hold *nhh;
|
||||||
|
|
||||||
|
RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
|
||||||
|
struct listnode *node;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
|
||||||
|
struct nexthop nhop;
|
||||||
|
struct nexthop *nh;
|
||||||
|
|
||||||
|
if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
|
||||||
|
nhh->intf,
|
||||||
|
nhh->nhvrf_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nh = nexthop_exists(&nhgc->nhg, &nhop);
|
||||||
|
|
||||||
|
if (nh)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nhop.vrf_id != vrf->vrf_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nh = nexthop_new();
|
||||||
|
|
||||||
|
memcpy(nh, &nhop, sizeof(nhop));
|
||||||
|
nexthop_add(&nhgc->nhg.nexthop, nh);
|
||||||
|
|
||||||
|
if (nhg_hooks.add_nexthop)
|
||||||
|
nhg_hooks.add_nexthop(nhgc, nh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nexthop_group_disable_vrf(struct vrf *vrf)
|
||||||
|
{
|
||||||
|
struct nexthop_group_cmd *nhgc;
|
||||||
|
struct nexthop_hold *nhh;
|
||||||
|
|
||||||
|
RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
|
||||||
|
struct listnode *node;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
|
||||||
|
struct nexthop nhop;
|
||||||
|
struct nexthop *nh;
|
||||||
|
|
||||||
|
if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
|
||||||
|
nhh->intf,
|
||||||
|
nhh->nhvrf_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nh = nexthop_exists(&nhgc->nhg, &nhop);
|
||||||
|
|
||||||
|
if (!nh)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nh->vrf_id != vrf->vrf_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nexthop_del(&nhgc->nhg, nh);
|
||||||
|
|
||||||
|
if (nhg_hooks.del_nexthop)
|
||||||
|
nhg_hooks.del_nexthop(nhgc, nh);
|
||||||
|
|
||||||
|
nexthop_free(nh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nexthop_group_interface_state_change(struct interface *ifp,
|
||||||
|
ifindex_t oldifindex)
|
||||||
|
{
|
||||||
|
struct nexthop_group_cmd *nhgc;
|
||||||
|
struct nexthop_hold *nhh;
|
||||||
|
|
||||||
|
RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
|
||||||
|
struct listnode *node;
|
||||||
|
struct nexthop *nh;
|
||||||
|
|
||||||
|
if (if_is_up(ifp)) {
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
|
||||||
|
struct nexthop nhop;
|
||||||
|
|
||||||
|
if (!nexthop_group_parse_nexthop(
|
||||||
|
&nhop, &nhh->addr, nhh->intf,
|
||||||
|
nhh->nhvrf_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (nhop.type) {
|
||||||
|
case NEXTHOP_TYPE_IPV4:
|
||||||
|
case NEXTHOP_TYPE_IPV6:
|
||||||
|
case NEXTHOP_TYPE_BLACKHOLE:
|
||||||
|
continue;
|
||||||
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||||
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nh = nexthop_exists(&nhgc->nhg, &nhop);
|
||||||
|
|
||||||
|
if (nh)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ifp->ifindex != nhop.ifindex)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nh = nexthop_new();
|
||||||
|
|
||||||
|
memcpy(nh, &nhop, sizeof(nhop));
|
||||||
|
nexthop_add(&nhgc->nhg.nexthop, nh);
|
||||||
|
|
||||||
|
if (nhg_hooks.add_nexthop)
|
||||||
|
nhg_hooks.add_nexthop(nhgc, nh);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct nexthop *next_nh;
|
||||||
|
|
||||||
|
for (nh = nhgc->nhg.nexthop; nh; nh = next_nh) {
|
||||||
|
next_nh = nh->next;
|
||||||
|
switch (nh->type) {
|
||||||
|
case NEXTHOP_TYPE_IPV4:
|
||||||
|
case NEXTHOP_TYPE_IPV6:
|
||||||
|
case NEXTHOP_TYPE_BLACKHOLE:
|
||||||
|
continue;
|
||||||
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||||
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldifindex != nh->ifindex)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nexthop_del(&nhgc->nhg, nh);
|
||||||
|
|
||||||
|
if (nhg_hooks.del_nexthop)
|
||||||
|
nhg_hooks.del_nexthop(nhgc, nh);
|
||||||
|
|
||||||
|
nexthop_free(nh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void nexthop_group_init(void (*new)(const char *name),
|
void nexthop_group_init(void (*new)(const char *name),
|
||||||
void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
|
void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
|
||||||
const struct nexthop *nhop),
|
const struct nexthop *nhop),
|
||||||
|
|
|
@ -94,6 +94,11 @@ void nexthop_group_init(
|
||||||
const struct nexthop *nhop),
|
const struct nexthop *nhop),
|
||||||
void (*delete)(const char *name));
|
void (*delete)(const char *name));
|
||||||
|
|
||||||
|
void nexthop_group_enable_vrf(struct vrf *vrf);
|
||||||
|
void nexthop_group_disable_vrf(struct vrf *vrf);
|
||||||
|
void nexthop_group_interface_state_change(struct interface *ifp,
|
||||||
|
ifindex_t oldifindex);
|
||||||
|
|
||||||
extern struct nexthop *nexthop_exists(struct nexthop_group *nhg,
|
extern struct nexthop *nexthop_exists(struct nexthop_group *nhg,
|
||||||
struct nexthop *nh);
|
struct nexthop *nh);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "ns.h"
|
#include "ns.h"
|
||||||
#include "privs.h"
|
#include "privs.h"
|
||||||
|
#include "nexthop_group.h"
|
||||||
|
|
||||||
/* default VRF ID value used when VRF backend is not NETNS */
|
/* default VRF ID value used when VRF backend is not NETNS */
|
||||||
#define VRF_DEFAULT_INTERNAL 0
|
#define VRF_DEFAULT_INTERNAL 0
|
||||||
|
@ -269,6 +270,13 @@ int vrf_enable(struct vrf *vrf)
|
||||||
if (vrf_master.vrf_enable_hook)
|
if (vrf_master.vrf_enable_hook)
|
||||||
(*vrf_master.vrf_enable_hook)(vrf);
|
(*vrf_master.vrf_enable_hook)(vrf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have any nexthop group entries that
|
||||||
|
* are awaiting vrf initialization then
|
||||||
|
* let's let people know about it
|
||||||
|
*/
|
||||||
|
nexthop_group_enable_vrf(vrf);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "mpls.h"
|
#include "mpls.h"
|
||||||
#include "sockopt.h"
|
#include "sockopt.h"
|
||||||
#include "pbr.h"
|
#include "pbr.h"
|
||||||
|
#include "nexthop_group.h"
|
||||||
|
|
||||||
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
|
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
|
||||||
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
|
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
|
||||||
|
@ -1697,7 +1698,9 @@ struct interface *zebra_interface_link_params_read(struct stream *s)
|
||||||
void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
|
void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
|
||||||
{
|
{
|
||||||
uint8_t link_params_status = 0;
|
uint8_t link_params_status = 0;
|
||||||
|
ifindex_t old_ifindex;
|
||||||
|
|
||||||
|
old_ifindex = ifp->ifindex;
|
||||||
/* Read interface's index. */
|
/* Read interface's index. */
|
||||||
if_set_index(ifp, stream_getl(s));
|
if_set_index(ifp, stream_getl(s));
|
||||||
ifp->status = stream_getc(s);
|
ifp->status = stream_getc(s);
|
||||||
|
@ -1724,6 +1727,8 @@ void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
|
||||||
struct if_link_params *iflp = if_link_params_get(ifp);
|
struct if_link_params *iflp = if_link_params_get(ifp);
|
||||||
link_params_set_value(s, iflp);
|
link_params_set_value(s, iflp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nexthop_group_interface_state_change(ifp, old_ifindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t zebra_interface_link_params_write(struct stream *s,
|
size_t zebra_interface_link_params_write(struct stream *s,
|
||||||
|
|
Loading…
Reference in a new issue