mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-26 06:39:35 +00:00
Merge pull request #7016 from donaldsharp/pbr_vrf_is_burf
Pbr vrf is burf
This commit is contained in:
commit
edec686a2a
2
lib/if.c
2
lib/if.c
@ -188,7 +188,9 @@ void if_destroy_via_zapi(struct interface *ifp)
|
|||||||
if (ifp_master.destroy_hook)
|
if (ifp_master.destroy_hook)
|
||||||
(*ifp_master.destroy_hook)(ifp);
|
(*ifp_master.destroy_hook)(ifp);
|
||||||
|
|
||||||
|
ifp->oldifindex = ifp->ifindex;
|
||||||
if_set_index(ifp, IFINDEX_INTERNAL);
|
if_set_index(ifp, IFINDEX_INTERNAL);
|
||||||
|
|
||||||
if (!ifp->configured)
|
if (!ifp->configured)
|
||||||
if_delete(&ifp);
|
if_delete(&ifp);
|
||||||
}
|
}
|
||||||
|
2
lib/if.h
2
lib/if.h
@ -224,6 +224,8 @@ struct interface {
|
|||||||
not work as expected.
|
not work as expected.
|
||||||
*/
|
*/
|
||||||
ifindex_t ifindex;
|
ifindex_t ifindex;
|
||||||
|
ifindex_t oldifindex;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ifindex of parent interface, if any
|
* ifindex of parent interface, if any
|
||||||
*/
|
*/
|
||||||
|
@ -940,6 +940,12 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
|||||||
nhg_hooks.add_nexthop(nhgc, nh);
|
nhg_hooks.add_nexthop(nhgc, nh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (intf) {
|
||||||
|
struct interface *ifp = if_lookup_by_name_all_vrf(intf);
|
||||||
|
|
||||||
|
if (ifp)
|
||||||
|
ifp->configured = true;
|
||||||
|
}
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -952,24 +958,29 @@ static struct cmd_node nexthop_group_node = {
|
|||||||
.config_write = nexthop_group_write,
|
.config_write = nexthop_group_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh)
|
void nexthop_group_write_nexthop_simple(struct vty *vty,
|
||||||
|
const struct nexthop *nh,
|
||||||
|
char *altifname)
|
||||||
{
|
{
|
||||||
char buf[100];
|
char buf[100];
|
||||||
struct vrf *vrf;
|
char *ifname;
|
||||||
int i;
|
|
||||||
|
|
||||||
vty_out(vty, "nexthop ");
|
vty_out(vty, "nexthop ");
|
||||||
|
|
||||||
|
if (altifname)
|
||||||
|
ifname = altifname;
|
||||||
|
else
|
||||||
|
ifname = (char *)ifindex2ifname(nh->ifindex, nh->vrf_id);
|
||||||
|
|
||||||
switch (nh->type) {
|
switch (nh->type) {
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
vty_out(vty, "%s", ifindex2ifname(nh->ifindex, nh->vrf_id));
|
vty_out(vty, "%s", ifname);
|
||||||
break;
|
break;
|
||||||
case NEXTHOP_TYPE_IPV4:
|
case NEXTHOP_TYPE_IPV4:
|
||||||
vty_out(vty, "%s", inet_ntoa(nh->gate.ipv4));
|
vty_out(vty, "%s", inet_ntoa(nh->gate.ipv4));
|
||||||
break;
|
break;
|
||||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||||
vty_out(vty, "%s %s", inet_ntoa(nh->gate.ipv4),
|
vty_out(vty, "%s %s", inet_ntoa(nh->gate.ipv4), ifname);
|
||||||
ifindex2ifname(nh->ifindex, nh->vrf_id));
|
|
||||||
break;
|
break;
|
||||||
case NEXTHOP_TYPE_IPV6:
|
case NEXTHOP_TYPE_IPV6:
|
||||||
vty_out(vty, "%s",
|
vty_out(vty, "%s",
|
||||||
@ -978,11 +989,19 @@ void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh)
|
|||||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||||
vty_out(vty, "%s %s",
|
vty_out(vty, "%s %s",
|
||||||
inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)),
|
inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)),
|
||||||
ifindex2ifname(nh->ifindex, nh->vrf_id));
|
ifname);
|
||||||
break;
|
break;
|
||||||
case NEXTHOP_TYPE_BLACKHOLE:
|
case NEXTHOP_TYPE_BLACKHOLE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh)
|
||||||
|
{
|
||||||
|
struct vrf *vrf;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
nexthop_group_write_nexthop_simple(vty, nh, NULL);
|
||||||
|
|
||||||
if (nh->vrf_id != VRF_DEFAULT) {
|
if (nh->vrf_id != VRF_DEFAULT) {
|
||||||
vrf = vrf_lookup_by_id(nh->vrf_id);
|
vrf = vrf_lookup_by_id(nh->vrf_id);
|
||||||
@ -1229,6 +1248,7 @@ void nexthop_group_interface_state_change(struct interface *ifp,
|
|||||||
if (ifp->ifindex != nhop.ifindex)
|
if (ifp->ifindex != nhop.ifindex)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
ifp->configured = true;
|
||||||
nh = nexthop_new();
|
nh = nexthop_new();
|
||||||
|
|
||||||
memcpy(nh, &nhop, sizeof(nhop));
|
memcpy(nh, &nhop, sizeof(nhop));
|
||||||
|
@ -135,6 +135,9 @@ extern bool nexthop_group_equal(const struct nexthop_group *nhg1,
|
|||||||
|
|
||||||
extern struct nexthop_group_cmd *nhgc_find(const char *name);
|
extern struct nexthop_group_cmd *nhgc_find(const char *name);
|
||||||
|
|
||||||
|
extern void nexthop_group_write_nexthop_simple(struct vty *vty,
|
||||||
|
const struct nexthop *nh,
|
||||||
|
char *altifname);
|
||||||
extern void nexthop_group_write_nexthop(struct vty *vty,
|
extern void nexthop_group_write_nexthop(struct vty *vty,
|
||||||
const struct nexthop *nh);
|
const struct nexthop *nh);
|
||||||
|
|
||||||
|
@ -2068,7 +2068,7 @@ static void zebra_interface_if_set_value(struct stream *s,
|
|||||||
uint8_t link_params_status = 0;
|
uint8_t link_params_status = 0;
|
||||||
ifindex_t old_ifindex, new_ifindex;
|
ifindex_t old_ifindex, new_ifindex;
|
||||||
|
|
||||||
old_ifindex = ifp->ifindex;
|
old_ifindex = ifp->oldifindex;
|
||||||
/* Read interface's index. */
|
/* Read interface's index. */
|
||||||
STREAM_GETL(s, new_ifindex);
|
STREAM_GETL(s, new_ifindex);
|
||||||
if_set_index(ifp, new_ifindex);
|
if_set_index(ifp, new_ifindex);
|
||||||
|
@ -771,6 +771,57 @@ void pbr_map_check_nh_group_change(const char *nh_group)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pbr_map_check_vrf_nh_group_change(const char *nh_group,
|
||||||
|
struct pbr_vrf *pbr_vrf,
|
||||||
|
uint32_t old_vrf_id)
|
||||||
|
{
|
||||||
|
struct pbr_map *pbrm;
|
||||||
|
struct pbr_map_sequence *pbrms;
|
||||||
|
struct listnode *node;
|
||||||
|
|
||||||
|
|
||||||
|
RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
|
||||||
|
if (pbrms->nhgrp_name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pbrms->nhg
|
||||||
|
&& strcmp(nh_group, pbrms->internal_nhg_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pbrms->nhg->nexthop->vrf_id != old_vrf_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pbrms->nhg->nexthop->vrf_id = pbr_vrf_id(pbr_vrf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pbr_map_check_interface_nh_group_change(const char *nh_group,
|
||||||
|
struct interface *ifp,
|
||||||
|
ifindex_t oldifindex)
|
||||||
|
{
|
||||||
|
struct pbr_map *pbrm;
|
||||||
|
struct pbr_map_sequence *pbrms;
|
||||||
|
struct listnode *node;
|
||||||
|
|
||||||
|
RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
|
||||||
|
if (pbrms->nhgrp_name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pbrms->nhg
|
||||||
|
&& strcmp(nh_group, pbrms->internal_nhg_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pbrms->nhg->nexthop->ifindex != oldifindex)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pbrms->nhg->nexthop->ifindex = ifp->ifindex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void pbr_map_check(struct pbr_map_sequence *pbrms, bool changed)
|
void pbr_map_check(struct pbr_map_sequence *pbrms, bool changed)
|
||||||
{
|
{
|
||||||
struct pbr_map *pbrm;
|
struct pbr_map *pbrm;
|
||||||
|
@ -205,4 +205,11 @@ extern void pbr_map_install(struct pbr_map *pbrm);
|
|||||||
extern void pbr_map_policy_install(const char *name);
|
extern void pbr_map_policy_install(const char *name);
|
||||||
extern void pbr_map_policy_delete(struct pbr_map *pbrm,
|
extern void pbr_map_policy_delete(struct pbr_map *pbrm,
|
||||||
struct pbr_map_interface *pmi);
|
struct pbr_map_interface *pmi);
|
||||||
|
|
||||||
|
extern void pbr_map_check_vrf_nh_group_change(const char *nh_group,
|
||||||
|
struct pbr_vrf *pbr_vrf,
|
||||||
|
uint32_t old_vrf_id);
|
||||||
|
extern void pbr_map_check_interface_nh_group_change(const char *nh_group,
|
||||||
|
struct interface *ifp,
|
||||||
|
ifindex_t oldifindex);
|
||||||
#endif
|
#endif
|
||||||
|
262
pbrd/pbr_nht.c
262
pbrd/pbr_nht.c
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups")
|
DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups")
|
||||||
|
|
||||||
static struct hash *pbr_nhg_hash;
|
struct hash *pbr_nhg_hash;
|
||||||
static struct hash *pbr_nhrc_hash;
|
static struct hash *pbr_nhrc_hash;
|
||||||
|
|
||||||
static uint32_t pbr_nhg_low_table;
|
static uint32_t pbr_nhg_low_table;
|
||||||
@ -91,15 +91,15 @@ static void *pbr_nh_alloc(void *p)
|
|||||||
struct nhrc *nhrc;
|
struct nhrc *nhrc;
|
||||||
|
|
||||||
new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
|
new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
|
||||||
nhrc = hash_get(pbr_nhrc_hash, pnhc->nexthop, pbr_nhrc_hash_alloc);
|
nhrc = hash_get(pbr_nhrc_hash, &pnhc->nexthop, pbr_nhrc_hash_alloc);
|
||||||
new->nexthop = &nhrc->nexthop;
|
new->nexthop = nhrc->nexthop;
|
||||||
|
|
||||||
/* Decremented again in pbr_nh_delete */
|
/* Decremented again in pbr_nh_delete */
|
||||||
++nhrc->refcount;
|
++nhrc->refcount;
|
||||||
|
|
||||||
DEBUGD(&pbr_dbg_nht, "%s: Sending nexthop to Zebra", __func__);
|
DEBUGD(&pbr_dbg_nht, "%s: Sending nexthop to Zebra", __func__);
|
||||||
|
|
||||||
pbr_send_rnh(new->nexthop, true);
|
pbr_send_rnh(&new->nexthop, true);
|
||||||
|
|
||||||
new->valid = false;
|
new->valid = false;
|
||||||
return new;
|
return new;
|
||||||
@ -109,14 +109,14 @@ static void pbr_nh_delete(struct pbr_nexthop_cache **pnhc)
|
|||||||
{
|
{
|
||||||
struct nhrc *nhrc;
|
struct nhrc *nhrc;
|
||||||
|
|
||||||
nhrc = hash_lookup(pbr_nhrc_hash, (*pnhc)->nexthop);
|
nhrc = hash_lookup(pbr_nhrc_hash, &((*pnhc)->nexthop));
|
||||||
|
|
||||||
if (nhrc)
|
if (nhrc)
|
||||||
--nhrc->refcount;
|
--nhrc->refcount;
|
||||||
if (!nhrc || nhrc->refcount == 0) {
|
if (!nhrc || nhrc->refcount == 0) {
|
||||||
DEBUGD(&pbr_dbg_nht, "%s: Removing nexthop from Zebra",
|
DEBUGD(&pbr_dbg_nht, "%s: Removing nexthop from Zebra",
|
||||||
__func__);
|
__func__);
|
||||||
pbr_send_rnh((*pnhc)->nexthop, false);
|
pbr_send_rnh(&((*pnhc)->nexthop), false);
|
||||||
}
|
}
|
||||||
if (nhrc && nhrc->refcount == 0) {
|
if (nhrc && nhrc->refcount == 0) {
|
||||||
hash_release(pbr_nhrc_hash, nhrc);
|
hash_release(pbr_nhrc_hash, nhrc);
|
||||||
@ -136,7 +136,7 @@ static uint32_t pbr_nh_hash_key(const void *arg)
|
|||||||
uint32_t key;
|
uint32_t key;
|
||||||
const struct pbr_nexthop_cache *pbrnc = arg;
|
const struct pbr_nexthop_cache *pbrnc = arg;
|
||||||
|
|
||||||
key = nexthop_hash(pbrnc->nexthop);
|
key = nexthop_hash(&pbrnc->nexthop);
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
@ -148,28 +148,28 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2)
|
|||||||
const struct pbr_nexthop_cache *pbrnc2 =
|
const struct pbr_nexthop_cache *pbrnc2 =
|
||||||
(const struct pbr_nexthop_cache *)arg2;
|
(const struct pbr_nexthop_cache *)arg2;
|
||||||
|
|
||||||
if (pbrnc1->nexthop->vrf_id != pbrnc2->nexthop->vrf_id)
|
if (pbrnc1->nexthop.vrf_id != pbrnc2->nexthop.vrf_id)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (pbrnc1->nexthop->ifindex != pbrnc2->nexthop->ifindex)
|
if (pbrnc1->nexthop.ifindex != pbrnc2->nexthop.ifindex)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (pbrnc1->nexthop->type != pbrnc2->nexthop->type)
|
if (pbrnc1->nexthop.type != pbrnc2->nexthop.type)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (pbrnc1->nexthop->type) {
|
switch (pbrnc1->nexthop.type) {
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex;
|
return pbrnc1->nexthop.ifindex == pbrnc2->nexthop.ifindex;
|
||||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||||
case NEXTHOP_TYPE_IPV4:
|
case NEXTHOP_TYPE_IPV4:
|
||||||
return pbrnc1->nexthop->gate.ipv4.s_addr
|
return pbrnc1->nexthop.gate.ipv4.s_addr
|
||||||
== pbrnc2->nexthop->gate.ipv4.s_addr;
|
== pbrnc2->nexthop.gate.ipv4.s_addr;
|
||||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||||
case NEXTHOP_TYPE_IPV6:
|
case NEXTHOP_TYPE_IPV6:
|
||||||
return !memcmp(&pbrnc1->nexthop->gate.ipv6,
|
return !memcmp(&pbrnc1->nexthop.gate.ipv6,
|
||||||
&pbrnc2->nexthop->gate.ipv6, 16);
|
&pbrnc2->nexthop.gate.ipv6, 16);
|
||||||
case NEXTHOP_TYPE_BLACKHOLE:
|
case NEXTHOP_TYPE_BLACKHOLE:
|
||||||
return pbrnc1->nexthop->bh_type == pbrnc2->nexthop->bh_type;
|
return pbrnc1->nexthop.bh_type == pbrnc2->nexthop.bh_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -249,9 +249,8 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
|
|||||||
pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc);
|
pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc);
|
||||||
|
|
||||||
/* create & insert new pnhc into pnhgc->nhh */
|
/* create & insert new pnhc into pnhgc->nhh */
|
||||||
pnhc_find.nexthop = (struct nexthop *)nhop;
|
pnhc_find.nexthop = *nhop;
|
||||||
pnhc = hash_get(pnhgc->nhh, &pnhc_find, pbr_nh_alloc);
|
pnhc = hash_get(pnhgc->nhh, &pnhc_find, pbr_nh_alloc);
|
||||||
pnhc_find.nexthop = NULL;
|
|
||||||
|
|
||||||
/* set parent pnhgc */
|
/* set parent pnhgc */
|
||||||
pnhc->parent = pnhgc;
|
pnhc->parent = pnhgc;
|
||||||
@ -291,7 +290,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
|
|||||||
pnhgc = hash_lookup(pbr_nhg_hash, &pnhgc_find);
|
pnhgc = hash_lookup(pbr_nhg_hash, &pnhgc_find);
|
||||||
|
|
||||||
/* delete pnhc from pnhgc->nhh */
|
/* delete pnhc from pnhgc->nhh */
|
||||||
pnhc_find.nexthop = (struct nexthop *)nhop;
|
pnhc_find.nexthop = *nhop;
|
||||||
pnhc = hash_release(pnhgc->nhh, &pnhc_find);
|
pnhc = hash_release(pnhgc->nhh, &pnhc_find);
|
||||||
|
|
||||||
/* delete pnhc */
|
/* delete pnhc */
|
||||||
@ -499,7 +498,7 @@ void pbr_nht_change_group(const char *name)
|
|||||||
struct pbr_nexthop_cache lookup;
|
struct pbr_nexthop_cache lookup;
|
||||||
struct pbr_nexthop_cache *pnhc;
|
struct pbr_nexthop_cache *pnhc;
|
||||||
|
|
||||||
lookup.nexthop = nhop;
|
lookup.nexthop = *nhop;
|
||||||
pnhc = hash_lookup(pnhgc->nhh, &lookup);
|
pnhc = hash_lookup(pnhgc->nhh, &lookup);
|
||||||
if (!pnhc) {
|
if (!pnhc) {
|
||||||
pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
|
pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
|
||||||
@ -553,9 +552,25 @@ void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms,
|
|||||||
|
|
||||||
pnhgc = hash_get(pbr_nhg_hash, &find, pbr_nhgc_alloc);
|
pnhgc = hash_get(pbr_nhg_hash, &find, pbr_nhgc_alloc);
|
||||||
|
|
||||||
lookup.nexthop = pbrms->nhg->nexthop;
|
lookup.nexthop = *pbrms->nhg->nexthop;
|
||||||
pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
|
pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
|
||||||
pnhc->parent = pnhgc;
|
pnhc->parent = pnhgc;
|
||||||
|
if (nhop->vrf_id != VRF_DEFAULT) {
|
||||||
|
struct vrf *vrf = vrf_lookup_by_id(nhop->vrf_id);
|
||||||
|
|
||||||
|
if (vrf)
|
||||||
|
strlcpy(pnhc->vrf_name, vrf->name,
|
||||||
|
sizeof(pnhc->vrf_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nhop->ifindex != 0) {
|
||||||
|
struct interface *ifp =
|
||||||
|
if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
|
||||||
|
|
||||||
|
if (ifp)
|
||||||
|
strlcpy(pnhc->intf_name, ifp->name,
|
||||||
|
sizeof(pnhc->intf_name));
|
||||||
|
}
|
||||||
pbr_nht_install_nexthop_group(pnhgc, *pbrms->nhg);
|
pbr_nht_install_nexthop_group(pnhgc, *pbrms->nhg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,7 +589,7 @@ static void pbr_nht_release_individual_nexthop(struct pbr_map_sequence *pbrms)
|
|||||||
|
|
||||||
nh = pbrms->nhg->nexthop;
|
nh = pbrms->nhg->nexthop;
|
||||||
nh_type = nh->type;
|
nh_type = nh->type;
|
||||||
lup.nexthop = nh;
|
lup.nexthop = *nh;
|
||||||
pnhc = hash_lookup(pnhgc->nhh, &lup);
|
pnhc = hash_lookup(pnhgc->nhh, &lup);
|
||||||
pnhc->parent = NULL;
|
pnhc->parent = NULL;
|
||||||
hash_release(pnhgc->nhh, pnhc);
|
hash_release(pnhgc->nhh, pnhc);
|
||||||
@ -625,7 +640,7 @@ struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name)
|
|||||||
struct pbr_nexthop_cache lookupc;
|
struct pbr_nexthop_cache lookupc;
|
||||||
struct pbr_nexthop_cache *pnhc;
|
struct pbr_nexthop_cache *pnhc;
|
||||||
|
|
||||||
lookupc.nexthop = nhop;
|
lookupc.nexthop = *nhop;
|
||||||
pnhc = hash_lookup(pnhgc->nhh, &lookupc);
|
pnhc = hash_lookup(pnhgc->nhh, &lookupc);
|
||||||
if (!pnhc) {
|
if (!pnhc) {
|
||||||
pnhc = hash_get(pnhgc->nhh, &lookupc, pbr_nh_alloc);
|
pnhc = hash_get(pnhgc->nhh, &lookupc, pbr_nh_alloc);
|
||||||
@ -689,8 +704,13 @@ bool pbr_nht_nexthop_group_valid(const char *name)
|
|||||||
struct pbr_nht_individual {
|
struct pbr_nht_individual {
|
||||||
struct zapi_route *nhr;
|
struct zapi_route *nhr;
|
||||||
struct interface *ifp;
|
struct interface *ifp;
|
||||||
|
struct pbr_vrf *pbr_vrf;
|
||||||
|
struct pbr_nexthop_cache *pnhc;
|
||||||
|
vrf_id_t old_vrf_id;
|
||||||
|
|
||||||
uint32_t valid;
|
uint32_t valid;
|
||||||
|
|
||||||
|
bool nhr_matched;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -704,12 +724,12 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
|
|||||||
|
|
||||||
switch (pnhi->nhr->prefix.family) {
|
switch (pnhi->nhr->prefix.family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
if (pnhc->nexthop->gate.ipv4.s_addr
|
if (pnhc->nexthop.gate.ipv4.s_addr
|
||||||
!= pnhi->nhr->prefix.u.prefix4.s_addr)
|
!= pnhi->nhr->prefix.u.prefix4.s_addr)
|
||||||
goto done; /* Unrelated change */
|
goto done; /* Unrelated change */
|
||||||
break;
|
break;
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
if (memcmp(&pnhc->nexthop->gate.ipv6,
|
if (memcmp(&pnhc->nexthop.gate.ipv6,
|
||||||
&pnhi->nhr->prefix.u.prefix6, 16)
|
&pnhi->nhr->prefix.u.prefix6, 16)
|
||||||
!= 0)
|
!= 0)
|
||||||
goto done; /* Unrelated change */
|
goto done; /* Unrelated change */
|
||||||
@ -721,8 +741,8 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
|
if (pnhc->nexthop.type == NEXTHOP_TYPE_IPV4_IFINDEX
|
||||||
|| pnhc->nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
|
|| pnhc->nexthop.type == NEXTHOP_TYPE_IPV6_IFINDEX) {
|
||||||
|
|
||||||
/* GATEWAY_IFINDEX type shouldn't resolve to group */
|
/* GATEWAY_IFINDEX type shouldn't resolve to group */
|
||||||
if (pnhi->nhr->nexthop_num > 1) {
|
if (pnhi->nhr->nexthop_num > 1) {
|
||||||
@ -733,7 +753,7 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
|
|||||||
/* If whatever we resolved to wasn't on the interface we
|
/* If whatever we resolved to wasn't on the interface we
|
||||||
* specified. (i.e. not a connected route), its invalid.
|
* specified. (i.e. not a connected route), its invalid.
|
||||||
*/
|
*/
|
||||||
if (pnhi->nhr->nexthops[0].ifindex != pnhc->nexthop->ifindex) {
|
if (pnhi->nhr->nexthops[0].ifindex != pnhc->nexthop.ifindex) {
|
||||||
is_valid = false;
|
is_valid = false;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -755,7 +775,7 @@ static bool pbr_nht_individual_nexthop_interface_update(
|
|||||||
if (!pnhi->ifp) /* It doesn't care about non-interface updates */
|
if (!pnhi->ifp) /* It doesn't care about non-interface updates */
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (pnhc->nexthop->ifindex
|
if (pnhc->nexthop.ifindex
|
||||||
!= pnhi->ifp->ifindex) /* Un-related interface */
|
!= pnhi->ifp->ifindex) /* Un-related interface */
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
@ -779,12 +799,12 @@ pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc,
|
|||||||
{
|
{
|
||||||
assert(pnhi->nhr || pnhi->ifp); /* Either nexthop or interface update */
|
assert(pnhi->nhr || pnhi->ifp); /* Either nexthop or interface update */
|
||||||
|
|
||||||
switch (pnhc->nexthop->type) {
|
switch (pnhc->nexthop.type) {
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
|
pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
|
||||||
break;
|
break;
|
||||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||||
if (IN6_IS_ADDR_LINKLOCAL(&pnhc->nexthop->gate.ipv6)) {
|
if (IN6_IS_ADDR_LINKLOCAL(&pnhc->nexthop.gate.ipv6)) {
|
||||||
pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
|
pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -827,7 +847,7 @@ static void pbr_nexthop_group_cache_iterate_to_group(struct hash_bucket *b,
|
|||||||
struct nexthop_group *nhg = data;
|
struct nexthop_group *nhg = data;
|
||||||
struct nexthop *nh = NULL;
|
struct nexthop *nh = NULL;
|
||||||
|
|
||||||
copy_nexthops(&nh, pnhc->nexthop, NULL);
|
copy_nexthops(&nh, &pnhc->nexthop, NULL);
|
||||||
|
|
||||||
_nexthop_add(&nhg->nexthop, nh);
|
_nexthop_add(&nhg->nexthop, nh);
|
||||||
}
|
}
|
||||||
@ -877,6 +897,178 @@ void pbr_nht_nexthop_update(struct zapi_route *nhr)
|
|||||||
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
|
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nhrc_vrf_info {
|
||||||
|
struct pbr_vrf *pbr_vrf;
|
||||||
|
uint32_t old_vrf_id;
|
||||||
|
struct nhrc *nhrc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pbr_nht_nhrc_vrf_change(struct hash_bucket *b, void *data)
|
||||||
|
{
|
||||||
|
struct nhrc *nhrc = b->data;
|
||||||
|
struct nhrc_vrf_info *nhrcvi = data;
|
||||||
|
|
||||||
|
if (nhrc->nexthop.vrf_id == nhrcvi->old_vrf_id) {
|
||||||
|
nhrcvi->nhrc = nhrc;
|
||||||
|
return HASHWALK_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HASHWALK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pbr_nht_individual_nexthop_vrf_handle(struct hash_bucket *b,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct pbr_nexthop_cache *pnhc = b->data;
|
||||||
|
struct pbr_nht_individual *pnhi = data;
|
||||||
|
|
||||||
|
if (pnhc->looked_at == true)
|
||||||
|
return HASHWALK_CONTINUE;
|
||||||
|
|
||||||
|
if (pnhc->nexthop.vrf_id == VRF_DEFAULT)
|
||||||
|
return HASHWALK_CONTINUE;
|
||||||
|
|
||||||
|
if (strncmp(pnhc->vrf_name, pbr_vrf_name(pnhi->pbr_vrf),
|
||||||
|
sizeof(pnhc->vrf_name))
|
||||||
|
== 0) {
|
||||||
|
pnhi->pnhc = pnhc;
|
||||||
|
|
||||||
|
if (pnhc->nexthop.vrf_id != pbr_vrf_id(pnhi->pbr_vrf)) {
|
||||||
|
struct nhrc_vrf_info nhrcvi;
|
||||||
|
|
||||||
|
memset(&nhrcvi, 0, sizeof(nhrcvi));
|
||||||
|
nhrcvi.pbr_vrf = pnhi->pbr_vrf;
|
||||||
|
nhrcvi.old_vrf_id = pnhc->nexthop.vrf_id;
|
||||||
|
|
||||||
|
pnhi->nhr_matched = true;
|
||||||
|
pnhi->old_vrf_id = pnhc->nexthop.vrf_id;
|
||||||
|
|
||||||
|
do {
|
||||||
|
nhrcvi.nhrc = NULL;
|
||||||
|
hash_walk(pbr_nhrc_hash,
|
||||||
|
pbr_nht_nhrc_vrf_change, &nhrcvi);
|
||||||
|
if (nhrcvi.nhrc) {
|
||||||
|
hash_release(pbr_nhrc_hash,
|
||||||
|
nhrcvi.nhrc);
|
||||||
|
nhrcvi.nhrc->nexthop.vrf_id =
|
||||||
|
pbr_vrf_id(pnhi->pbr_vrf);
|
||||||
|
hash_get(pbr_nhrc_hash, nhrcvi.nhrc,
|
||||||
|
hash_alloc_intern);
|
||||||
|
pbr_send_rnh(&nhrcvi.nhrc->nexthop, true);
|
||||||
|
}
|
||||||
|
} while (nhrcvi.nhrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
pnhc->looked_at = true;
|
||||||
|
return HASHWALK_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HASHWALK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pbr_nht_clear_looked_at(struct hash_bucket *b, void *data)
|
||||||
|
{
|
||||||
|
struct pbr_nexthop_cache *pnhc = b->data;
|
||||||
|
|
||||||
|
pnhc->looked_at = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pbr_nht_nexthop_vrf_handle(struct hash_bucket *b, void *data)
|
||||||
|
{
|
||||||
|
struct pbr_nexthop_group_cache *pnhgc = b->data;
|
||||||
|
struct pbr_vrf *pbr_vrf = data;
|
||||||
|
struct pbr_nht_individual pnhi = {};
|
||||||
|
|
||||||
|
zlog_debug("pnhgc iterating");
|
||||||
|
hash_iterate(pnhgc->nhh, pbr_nht_clear_looked_at, NULL);
|
||||||
|
memset(&pnhi, 0, sizeof(pnhi));
|
||||||
|
pnhi.pbr_vrf = pbr_vrf;
|
||||||
|
do {
|
||||||
|
struct pbr_nexthop_cache *pnhc;
|
||||||
|
|
||||||
|
pnhi.pnhc = NULL;
|
||||||
|
hash_walk(pnhgc->nhh, pbr_nht_individual_nexthop_vrf_handle,
|
||||||
|
&pnhi);
|
||||||
|
|
||||||
|
if (!pnhi.pnhc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pnhc = pnhi.pnhc;
|
||||||
|
pnhc->nexthop.vrf_id = pnhi.old_vrf_id;
|
||||||
|
pnhi.pnhc = hash_release(pnhgc->nhh, pnhi.pnhc);
|
||||||
|
if (pnhi.pnhc) {
|
||||||
|
pnhi.pnhc->nexthop.vrf_id = pbr_vrf_id(pbr_vrf);
|
||||||
|
|
||||||
|
hash_get(pnhgc->nhh, pnhi.pnhc, hash_alloc_intern);
|
||||||
|
} else
|
||||||
|
pnhc->nexthop.vrf_id = pbr_vrf_id(pbr_vrf);
|
||||||
|
|
||||||
|
pbr_map_check_vrf_nh_group_change(pnhgc->name, pbr_vrf,
|
||||||
|
pnhi.old_vrf_id);
|
||||||
|
} while (pnhi.pnhc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pbr_nht_vrf_update(struct pbr_vrf *pbr_vrf)
|
||||||
|
{
|
||||||
|
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_vrf_handle, pbr_vrf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pbr_nht_individual_nexthop_interface_handle(struct hash_bucket *b,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct pbr_nexthop_cache *pnhc = b->data;
|
||||||
|
struct pbr_nht_individual *pnhi = data;
|
||||||
|
|
||||||
|
if (pnhc->nexthop.ifindex == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((strncmp(pnhc->intf_name, pnhi->ifp->name, sizeof(pnhc->intf_name))
|
||||||
|
== 0)
|
||||||
|
&& pnhc->nexthop.ifindex != pnhi->ifp->ifindex)
|
||||||
|
pnhi->pnhc = pnhc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pbr_nht_nexthop_interface_handle(struct hash_bucket *b, void *data)
|
||||||
|
{
|
||||||
|
struct pbr_nexthop_group_cache *pnhgc = b->data;
|
||||||
|
struct interface *ifp = data;
|
||||||
|
struct pbr_nht_individual pnhi = {};
|
||||||
|
struct nhrc *nhrc;
|
||||||
|
uint32_t old_ifindex;
|
||||||
|
|
||||||
|
do {
|
||||||
|
memset(&pnhi, 0, sizeof(pnhi));
|
||||||
|
pnhi.ifp = ifp;
|
||||||
|
hash_iterate(pnhgc->nhh,
|
||||||
|
pbr_nht_individual_nexthop_interface_handle,
|
||||||
|
&pnhi);
|
||||||
|
|
||||||
|
if (!pnhi.pnhc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pnhi.pnhc = hash_release(pnhgc->nhh, pnhi.pnhc);
|
||||||
|
old_ifindex = pnhi.pnhc->nexthop.ifindex;
|
||||||
|
|
||||||
|
nhrc = hash_lookup(pbr_nhrc_hash, &pnhi.pnhc->nexthop);
|
||||||
|
if (nhrc) {
|
||||||
|
hash_release(pbr_nhrc_hash, nhrc);
|
||||||
|
nhrc->nexthop.ifindex = ifp->ifindex;
|
||||||
|
hash_get(pbr_nhrc_hash, nhrc, hash_alloc_intern);
|
||||||
|
}
|
||||||
|
pnhi.pnhc->nexthop.ifindex = ifp->ifindex;
|
||||||
|
|
||||||
|
hash_get(pnhgc->nhh, pnhi.pnhc, hash_alloc_intern);
|
||||||
|
|
||||||
|
pbr_map_check_interface_nh_group_change(pnhgc->name, ifp,
|
||||||
|
old_ifindex);
|
||||||
|
} while (pnhi.pnhc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pbr_nht_interface_update(struct interface *ifp)
|
||||||
|
{
|
||||||
|
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_handle, ifp);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pbr_nht_individual_nexthop_interface_update_lookup(struct hash_bucket *b,
|
pbr_nht_individual_nexthop_interface_update_lookup(struct hash_bucket *b,
|
||||||
void *data)
|
void *data)
|
||||||
@ -1036,7 +1228,7 @@ static void pbr_nht_show_nhg_nexthops(struct hash_bucket *b, void *data)
|
|||||||
struct vty *vty = data;
|
struct vty *vty = data;
|
||||||
|
|
||||||
vty_out(vty, "\tValid: %d ", pnhc->valid);
|
vty_out(vty, "\tValid: %d ", pnhc->valid);
|
||||||
nexthop_group_write_nexthop(vty, pnhc->nexthop);
|
nexthop_group_write_nexthop(vty, &pnhc->nexthop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pbr_nht_json_nhg_nexthops(struct hash_bucket *b, void *data)
|
static void pbr_nht_json_nhg_nexthops(struct hash_bucket *b, void *data)
|
||||||
@ -1046,7 +1238,7 @@ static void pbr_nht_json_nhg_nexthops(struct hash_bucket *b, void *data)
|
|||||||
json_object *this_hop;
|
json_object *this_hop;
|
||||||
|
|
||||||
this_hop = json_object_new_object();
|
this_hop = json_object_new_object();
|
||||||
nexthop_group_json_nexthop(this_hop, pnhc->nexthop);
|
nexthop_group_json_nexthop(this_hop, &pnhc->nexthop);
|
||||||
json_object_boolean_add(this_hop, "valid", pnhc->valid);
|
json_object_boolean_add(this_hop, "valid", pnhc->valid);
|
||||||
|
|
||||||
json_object_array_add(all_hops, this_hop);
|
json_object_array_add(all_hops, this_hop);
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
#define PBR_NHC_NAMELEN PBR_MAP_NAMELEN + 10
|
#define PBR_NHC_NAMELEN PBR_MAP_NAMELEN + 10
|
||||||
|
|
||||||
|
extern struct hash *pbr_nhg_hash;
|
||||||
|
|
||||||
struct pbr_nexthop_group_cache {
|
struct pbr_nexthop_group_cache {
|
||||||
char name[PBR_NHC_NAMELEN];
|
char name[PBR_NHC_NAMELEN];
|
||||||
|
|
||||||
@ -46,8 +48,12 @@ struct pbr_nexthop_group_cache {
|
|||||||
struct pbr_nexthop_cache {
|
struct pbr_nexthop_cache {
|
||||||
struct pbr_nexthop_group_cache *parent;
|
struct pbr_nexthop_group_cache *parent;
|
||||||
|
|
||||||
struct nexthop *nexthop;
|
char vrf_name[VRF_NAMSIZ + 1];
|
||||||
|
char intf_name[INTERFACE_NAMSIZ + 1];
|
||||||
|
|
||||||
|
struct nexthop nexthop;
|
||||||
|
|
||||||
|
bool looked_at;
|
||||||
bool valid;
|
bool valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -126,4 +132,7 @@ extern void pbr_nht_nexthop_update(struct zapi_route *nhr);
|
|||||||
extern void pbr_nht_nexthop_interface_update(struct interface *ifp);
|
extern void pbr_nht_nexthop_interface_update(struct interface *ifp);
|
||||||
|
|
||||||
extern void pbr_nht_init(void);
|
extern void pbr_nht_init(void);
|
||||||
|
|
||||||
|
extern void pbr_nht_vrf_update(struct pbr_vrf *pbr_vrf);
|
||||||
|
extern void pbr_nht_interface_update(struct interface *ifp);
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "pbr_memory.h"
|
#include "pbr_memory.h"
|
||||||
#include "pbr_map.h"
|
#include "pbr_map.h"
|
||||||
#include "pbr_debug.h"
|
#include "pbr_debug.h"
|
||||||
|
#include "pbr_nht.h"
|
||||||
|
|
||||||
DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF")
|
DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF")
|
||||||
|
|
||||||
@ -59,6 +60,7 @@ static int pbr_vrf_enable(struct vrf *vrf)
|
|||||||
{
|
{
|
||||||
DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name);
|
DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name);
|
||||||
|
|
||||||
|
pbr_nht_vrf_update(vrf->info);
|
||||||
pbr_map_vrf_update(vrf->info);
|
pbr_map_vrf_update(vrf->info);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -618,6 +618,33 @@ DEFPY (show_pbr,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pbrms_nexthop_group_write_individual_nexthop(
|
||||||
|
struct vty *vty, const struct pbr_map_sequence *pbrms)
|
||||||
|
{
|
||||||
|
struct pbr_nexthop_group_cache find;
|
||||||
|
struct pbr_nexthop_group_cache *pnhgc;
|
||||||
|
struct pbr_nexthop_cache lookup;
|
||||||
|
struct pbr_nexthop_cache *pnhc;
|
||||||
|
|
||||||
|
memset(&find, 0, sizeof(find));
|
||||||
|
strlcpy(find.name, pbrms->internal_nhg_name, sizeof(find.name));
|
||||||
|
|
||||||
|
pnhgc = hash_lookup(pbr_nhg_hash, &find);
|
||||||
|
assert(pnhgc);
|
||||||
|
|
||||||
|
lookup.nexthop = *pbrms->nhg->nexthop;
|
||||||
|
pnhc = hash_lookup(pnhgc->nhh, &lookup);
|
||||||
|
|
||||||
|
nexthop_group_write_nexthop_simple(
|
||||||
|
vty, pbrms->nhg->nexthop,
|
||||||
|
pnhc->nexthop.ifindex != 0 ? pnhc->intf_name : NULL);
|
||||||
|
if (pnhc->nexthop.vrf_id != VRF_DEFAULT)
|
||||||
|
vty_out(vty, " nexthop-vrf %s", pnhc->vrf_name);
|
||||||
|
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
static void vty_show_pbrms(struct vty *vty,
|
static void vty_show_pbrms(struct vty *vty,
|
||||||
const struct pbr_map_sequence *pbrms, bool detail)
|
const struct pbr_map_sequence *pbrms, bool detail)
|
||||||
{
|
{
|
||||||
@ -670,7 +697,7 @@ static void vty_show_pbrms(struct vty *vty,
|
|||||||
|
|
||||||
} else if (pbrms->nhg) {
|
} else if (pbrms->nhg) {
|
||||||
vty_out(vty, " ");
|
vty_out(vty, " ");
|
||||||
nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
|
pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
|
||||||
if (detail)
|
if (detail)
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
" Installed: %u(%d) Tableid: %d\n",
|
" Installed: %u(%d) Tableid: %d\n",
|
||||||
@ -1065,7 +1092,7 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
|
|||||||
|
|
||||||
if (pbrms->nhg) {
|
if (pbrms->nhg) {
|
||||||
vty_out(vty, " set ");
|
vty_out(vty, " set ");
|
||||||
nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
|
pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
|
||||||
}
|
}
|
||||||
|
|
||||||
vty_out(vty, "!\n");
|
vty_out(vty, "!\n");
|
||||||
|
@ -67,6 +67,7 @@ int pbr_ifp_create(struct interface *ifp)
|
|||||||
if (!ifp->info)
|
if (!ifp->info)
|
||||||
pbr_if_new(ifp);
|
pbr_if_new(ifp);
|
||||||
|
|
||||||
|
pbr_nht_interface_update(ifp);
|
||||||
/* Update nexthops tracked from a `set nexthop` command */
|
/* Update nexthops tracked from a `set nexthop` command */
|
||||||
pbr_nht_nexthop_interface_update(ifp);
|
pbr_nht_nexthop_interface_update(ifp);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user