mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 16:04:49 +00:00
Merge pull request #17736 from opensourcerouting/table-direct
bgpd,lib,zebra: permit table-direct on VRFs
This commit is contained in:
commit
7b6f686a9f
@ -17575,12 +17575,6 @@ DEFUN (bgp_redistribute_ipv4_ospf,
|
|||||||
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
||||||
protocol = ZEBRA_ROUTE_OSPF;
|
protocol = ZEBRA_ROUTE_OSPF;
|
||||||
else {
|
else {
|
||||||
if (bgp->vrf_id != VRF_DEFAULT) {
|
|
||||||
vty_out(vty,
|
|
||||||
"%% Only default BGP instance can use '%s'\n",
|
|
||||||
argv[idx_ospf_table]->arg);
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
|
||||||
}
|
|
||||||
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
||||||
strlen("table-direct")) == 0) {
|
strlen("table-direct")) == 0) {
|
||||||
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
||||||
@ -17634,12 +17628,6 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap,
|
|||||||
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
||||||
protocol = ZEBRA_ROUTE_OSPF;
|
protocol = ZEBRA_ROUTE_OSPF;
|
||||||
else {
|
else {
|
||||||
if (bgp->vrf_id != VRF_DEFAULT) {
|
|
||||||
vty_out(vty,
|
|
||||||
"%% Only default BGP instance can use '%s'\n",
|
|
||||||
argv[idx_ospf_table]->arg);
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
|
||||||
}
|
|
||||||
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
||||||
strlen("table-direct")) == 0) {
|
strlen("table-direct")) == 0) {
|
||||||
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
||||||
@ -17697,12 +17685,6 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric,
|
|||||||
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
||||||
protocol = ZEBRA_ROUTE_OSPF;
|
protocol = ZEBRA_ROUTE_OSPF;
|
||||||
else {
|
else {
|
||||||
if (bgp->vrf_id != VRF_DEFAULT) {
|
|
||||||
vty_out(vty,
|
|
||||||
"%% Only default BGP instance can use '%s'\n",
|
|
||||||
argv[idx_ospf_table]->arg);
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
|
||||||
}
|
|
||||||
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
||||||
strlen("table-direct")) == 0) {
|
strlen("table-direct")) == 0) {
|
||||||
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
||||||
@ -17767,12 +17749,6 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric,
|
|||||||
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
||||||
protocol = ZEBRA_ROUTE_OSPF;
|
protocol = ZEBRA_ROUTE_OSPF;
|
||||||
else {
|
else {
|
||||||
if (bgp->vrf_id != VRF_DEFAULT) {
|
|
||||||
vty_out(vty,
|
|
||||||
"%% Only default BGP instance can use '%s'\n",
|
|
||||||
argv[idx_ospf_table]->arg);
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
|
||||||
}
|
|
||||||
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
||||||
strlen("table-direct")) == 0) {
|
strlen("table-direct")) == 0) {
|
||||||
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
||||||
@ -17842,13 +17818,7 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap,
|
|||||||
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
||||||
protocol = ZEBRA_ROUTE_OSPF;
|
protocol = ZEBRA_ROUTE_OSPF;
|
||||||
else {
|
else {
|
||||||
if (bgp->vrf_id != VRF_DEFAULT) {
|
if (strncmp(argv[idx_ospf_table]->arg, "table-direct", strlen("table-direct")) == 0) {
|
||||||
vty_out(vty,
|
|
||||||
"%% Only default BGP instance can use '%s'\n",
|
|
||||||
argv[idx_ospf_table]->arg);
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
|
||||||
} else if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
|
||||||
strlen("table-direct")) == 0) {
|
|
||||||
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
||||||
if (instance == RT_TABLE_MAIN ||
|
if (instance == RT_TABLE_MAIN ||
|
||||||
instance == RT_TABLE_LOCAL) {
|
instance == RT_TABLE_LOCAL) {
|
||||||
@ -17911,12 +17881,6 @@ DEFUN (no_bgp_redistribute_ipv4_ospf,
|
|||||||
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
|
||||||
protocol = ZEBRA_ROUTE_OSPF;
|
protocol = ZEBRA_ROUTE_OSPF;
|
||||||
else {
|
else {
|
||||||
if (bgp->vrf_id != VRF_DEFAULT) {
|
|
||||||
vty_out(vty,
|
|
||||||
"%% Only default BGP instance can use '%s'\n",
|
|
||||||
argv[idx_ospf_table]->arg);
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
|
||||||
}
|
|
||||||
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
|
||||||
strlen("table-direct")) == 0) {
|
strlen("table-direct")) == 0) {
|
||||||
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
|
||||||
|
@ -2042,11 +2042,34 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type,
|
|||||||
|
|
||||||
/* Return if already redistribute flag is set. */
|
/* Return if already redistribute flag is set. */
|
||||||
if (instance) {
|
if (instance) {
|
||||||
if (redist_check_instance(&zclient->mi_redist[afi][type],
|
if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||||
instance))
|
/*
|
||||||
return CMD_WARNING;
|
* When redistribution type is `table-direct` the
|
||||||
|
* instance means `table identification`.
|
||||||
|
*
|
||||||
|
* `table_id` support 32bit integers, however since
|
||||||
|
* `instance` is being overloaded to `table_id` it
|
||||||
|
* will only be possible to use the first 65535
|
||||||
|
* entries.
|
||||||
|
*
|
||||||
|
* Also the ZAPI must also support `int`
|
||||||
|
* (see `zebra_redistribute_add`).
|
||||||
|
*/
|
||||||
|
struct redist_table_direct table = {
|
||||||
|
.table_id = instance,
|
||||||
|
.vrf_id = bgp->vrf_id,
|
||||||
|
};
|
||||||
|
if (redist_lookup_table_direct(&zclient->mi_redist[afi][type], &table) !=
|
||||||
|
NULL)
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
redist_add_instance(&zclient->mi_redist[afi][type], instance);
|
redist_add_table_direct(&zclient->mi_redist[afi][type], &table);
|
||||||
|
} else {
|
||||||
|
if (redist_check_instance(&zclient->mi_redist[afi][type], instance))
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
redist_add_instance(&zclient->mi_redist[afi][type], instance);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (vrf_bitmap_check(&zclient->redist[afi][type], bgp->vrf_id))
|
if (vrf_bitmap_check(&zclient->redist[afi][type], bgp->vrf_id))
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
@ -2174,10 +2197,22 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type,
|
|||||||
|
|
||||||
/* Return if zebra connection is disabled. */
|
/* Return if zebra connection is disabled. */
|
||||||
if (instance) {
|
if (instance) {
|
||||||
if (!redist_check_instance(&zclient->mi_redist[afi][type],
|
if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||||
instance))
|
struct redist_table_direct table = {
|
||||||
return CMD_WARNING;
|
.table_id = instance,
|
||||||
redist_del_instance(&zclient->mi_redist[afi][type], instance);
|
.vrf_id = bgp->vrf_id,
|
||||||
|
};
|
||||||
|
if (redist_lookup_table_direct(&zclient->mi_redist[afi][type], &table) ==
|
||||||
|
NULL)
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
redist_del_table_direct(&zclient->mi_redist[afi][type], &table);
|
||||||
|
} else {
|
||||||
|
if (!redist_check_instance(&zclient->mi_redist[afi][type], instance))
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
redist_del_instance(&zclient->mi_redist[afi][type], instance);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!vrf_bitmap_check(&zclient->redist[afi][type], bgp->vrf_id))
|
if (!vrf_bitmap_check(&zclient->redist[afi][type], bgp->vrf_id))
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
|
165
lib/zclient.c
165
lib/zclient.c
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
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");
|
||||||
|
DEFINE_MTYPE_STATIC(LIB, REDIST_TABLE_DIRECT, "Redistribution table direct");
|
||||||
|
|
||||||
/* Zebra client events. */
|
/* Zebra client events. */
|
||||||
enum zclient_event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
|
enum zclient_event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
|
||||||
@ -104,6 +105,11 @@ void zclient_free(struct zclient *zclient)
|
|||||||
XFREE(MTYPE_ZCLIENT, zclient);
|
XFREE(MTYPE_ZCLIENT, zclient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void redist_free_instance(void *data)
|
||||||
|
{
|
||||||
|
XFREE(MTYPE_REDIST_INST, data);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned short *redist_check_instance(struct redist_proto *red,
|
unsigned short *redist_check_instance(struct redist_proto *red,
|
||||||
unsigned short instance)
|
unsigned short instance)
|
||||||
{
|
{
|
||||||
@ -126,8 +132,10 @@ void redist_add_instance(struct redist_proto *red, unsigned short instance)
|
|||||||
|
|
||||||
red->enabled = 1;
|
red->enabled = 1;
|
||||||
|
|
||||||
if (!red->instances)
|
if (!red->instances) {
|
||||||
red->instances = list_new();
|
red->instances = list_new();
|
||||||
|
red->instances->del = redist_free_instance;
|
||||||
|
}
|
||||||
|
|
||||||
in = XMALLOC(MTYPE_REDIST_INST, sizeof(unsigned short));
|
in = XMALLOC(MTYPE_REDIST_INST, sizeof(unsigned short));
|
||||||
*in = instance;
|
*in = instance;
|
||||||
@ -143,23 +151,100 @@ void redist_del_instance(struct redist_proto *red, unsigned short instance)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
listnode_delete(red->instances, id);
|
listnode_delete(red->instances, id);
|
||||||
XFREE(MTYPE_REDIST_INST, id);
|
red->instances->del(id);
|
||||||
if (!red->instances->count) {
|
if (!red->instances->count) {
|
||||||
red->enabled = 0;
|
red->enabled = 0;
|
||||||
list_delete(&red->instances);
|
list_delete(&red->instances);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void redist_free_table_direct(void *data)
|
||||||
|
{
|
||||||
|
XFREE(MTYPE_REDIST_TABLE_DIRECT, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct redist_table_direct *redist_lookup_table_direct(const struct redist_proto *red,
|
||||||
|
const struct redist_table_direct *table)
|
||||||
|
{
|
||||||
|
struct redist_table_direct *ntable;
|
||||||
|
struct listnode *node;
|
||||||
|
|
||||||
|
if (red->instances == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(red->instances, node, ntable)) {
|
||||||
|
if (table->vrf_id != ntable->vrf_id)
|
||||||
|
continue;
|
||||||
|
if (table->table_id != ntable->table_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return ntable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool redist_table_direct_has_id(const struct redist_proto *red, int table_id)
|
||||||
|
{
|
||||||
|
struct redist_table_direct *table;
|
||||||
|
struct listnode *node;
|
||||||
|
|
||||||
|
if (red->instances == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(red->instances, node, table)) {
|
||||||
|
if (table->table_id != table_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void redist_add_table_direct(struct redist_proto *red, const struct redist_table_direct *table)
|
||||||
|
{
|
||||||
|
struct redist_table_direct *ntable;
|
||||||
|
|
||||||
|
ntable = redist_lookup_table_direct(red, table);
|
||||||
|
if (ntable != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (red->instances == NULL) {
|
||||||
|
red->instances = list_new();
|
||||||
|
red->instances->del = redist_free_table_direct;
|
||||||
|
}
|
||||||
|
|
||||||
|
red->enabled = 1;
|
||||||
|
|
||||||
|
ntable = XCALLOC(MTYPE_REDIST_TABLE_DIRECT, sizeof(*ntable));
|
||||||
|
ntable->vrf_id = table->vrf_id;
|
||||||
|
ntable->table_id = table->table_id;
|
||||||
|
listnode_add(red->instances, ntable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void redist_del_table_direct(struct redist_proto *red, const struct redist_table_direct *table)
|
||||||
|
{
|
||||||
|
struct redist_table_direct *ntable;
|
||||||
|
|
||||||
|
ntable = redist_lookup_table_direct(red, table);
|
||||||
|
if (ntable == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
listnode_delete(red->instances, ntable);
|
||||||
|
red->instances->del(ntable);
|
||||||
|
if (red->instances->count == 0) {
|
||||||
|
red->enabled = 0;
|
||||||
|
list_delete(&red->instances);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void redist_del_all_instances(struct redist_proto *red)
|
void redist_del_all_instances(struct redist_proto *red)
|
||||||
{
|
{
|
||||||
struct listnode *ln, *nn;
|
|
||||||
unsigned short *id;
|
|
||||||
|
|
||||||
if (!red->instances)
|
if (!red->instances)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS(red->instances, ln, nn, id))
|
list_delete(&red->instances);
|
||||||
redist_del_instance(red, *id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop zebra client services. */
|
/* Stop zebra client services. */
|
||||||
@ -480,6 +565,17 @@ enum zclient_send_status zclient_send_localsid(struct zclient *zclient,
|
|||||||
return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
|
return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void zclient_send_table_direct(struct zclient *zclient, afi_t afi, int type)
|
||||||
|
{
|
||||||
|
struct redist_table_direct *table;
|
||||||
|
struct redist_proto *red = &zclient->mi_redist[afi][ZEBRA_ROUTE_TABLE_DIRECT];
|
||||||
|
struct listnode *node;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(red->instances, node, table))
|
||||||
|
zebra_redistribute_send(type, zclient, afi, ZEBRA_ROUTE_TABLE_DIRECT,
|
||||||
|
table->table_id, table->vrf_id);
|
||||||
|
}
|
||||||
|
|
||||||
/* Send register requests to zebra daemon for the information in a VRF. */
|
/* Send register requests to zebra daemon for the information in a VRF. */
|
||||||
void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
|
void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
|
||||||
{
|
{
|
||||||
@ -513,6 +609,12 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
|
|||||||
if (!zclient->mi_redist[afi][i].enabled)
|
if (!zclient->mi_redist[afi][i].enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (i == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||||
|
zclient_send_table_direct(zclient, afi,
|
||||||
|
ZEBRA_REDISTRIBUTE_ADD);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
unsigned short *id;
|
unsigned short *id;
|
||||||
|
|
||||||
@ -580,6 +682,12 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id)
|
|||||||
if (!zclient->mi_redist[afi][i].enabled)
|
if (!zclient->mi_redist[afi][i].enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (i == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||||
|
zclient_send_table_direct(zclient, afi,
|
||||||
|
ZEBRA_REDISTRIBUTE_DELETE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
unsigned short *id;
|
unsigned short *id;
|
||||||
|
|
||||||
@ -4634,9 +4742,52 @@ static void zclient_read(struct event *thread)
|
|||||||
zclient_event(ZCLIENT_READ, zclient);
|
zclient_event(ZCLIENT_READ, zclient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void zclient_redistribute_table_direct(struct zclient *zclient, vrf_id_t vrf_id, afi_t afi,
|
||||||
|
int instance, int command)
|
||||||
|
{
|
||||||
|
struct redist_proto *red = &zclient->mi_redist[afi][ZEBRA_ROUTE_TABLE_DIRECT];
|
||||||
|
bool has_table;
|
||||||
|
struct redist_table_direct table = {
|
||||||
|
.vrf_id = vrf_id,
|
||||||
|
.table_id = instance,
|
||||||
|
};
|
||||||
|
|
||||||
|
has_table = redist_lookup_table_direct(red, &table);
|
||||||
|
|
||||||
|
if (command == ZEBRA_REDISTRIBUTE_ADD) {
|
||||||
|
if (has_table)
|
||||||
|
return;
|
||||||
|
|
||||||
|
redist_add_table_direct(red, &table);
|
||||||
|
} else {
|
||||||
|
if (!has_table)
|
||||||
|
return;
|
||||||
|
|
||||||
|
redist_del_table_direct(red, &table);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zclient->sock > 0)
|
||||||
|
zebra_redistribute_send(command, zclient, afi, ZEBRA_ROUTE_TABLE_DIRECT, instance,
|
||||||
|
vrf_id);
|
||||||
|
}
|
||||||
|
|
||||||
void zclient_redistribute(int command, struct zclient *zclient, afi_t afi,
|
void zclient_redistribute(int command, struct zclient *zclient, afi_t afi,
|
||||||
int type, unsigned short instance, vrf_id_t vrf_id)
|
int type, unsigned short instance, vrf_id_t vrf_id)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* When asking for table-direct redistribution the parameter
|
||||||
|
* `instance` has a different meaning: it means table
|
||||||
|
* identification.
|
||||||
|
*
|
||||||
|
* The table identification information is stored in
|
||||||
|
* `zclient->mi_redist` along with the VRF identification
|
||||||
|
* information in a pair (different from the usual single protocol
|
||||||
|
* instance value).
|
||||||
|
*/
|
||||||
|
if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||||
|
zclient_redistribute_table_direct(zclient, vrf_id, afi, instance, command);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (instance) {
|
if (instance) {
|
||||||
if (command == ZEBRA_REDISTRIBUTE_ADD) {
|
if (command == ZEBRA_REDISTRIBUTE_ADD) {
|
||||||
|
@ -268,6 +268,21 @@ struct redist_proto {
|
|||||||
struct list *instances;
|
struct list *instances;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redistribute table direct instance data structure: keeps the VRF
|
||||||
|
* that subscribed to the table ID.
|
||||||
|
*
|
||||||
|
* **NOTE**
|
||||||
|
* `table_id` is an integer because that is what the netlink interface
|
||||||
|
* uses for route attribute RTA_TABLE (32bit int), however the whole
|
||||||
|
* zclient API uses `unsigned short` (and CLI commands) so it will be
|
||||||
|
* limited to the range 1 to 65535.
|
||||||
|
*/
|
||||||
|
struct redist_table_direct {
|
||||||
|
vrf_id_t vrf_id;
|
||||||
|
int table_id;
|
||||||
|
};
|
||||||
|
|
||||||
struct zclient_capabilities {
|
struct zclient_capabilities {
|
||||||
uint32_t ecmp;
|
uint32_t ecmp;
|
||||||
bool mpls_enabled;
|
bool mpls_enabled;
|
||||||
@ -924,6 +939,15 @@ extern void redist_add_instance(struct redist_proto *, unsigned short);
|
|||||||
extern void redist_del_instance(struct redist_proto *, unsigned short);
|
extern void redist_del_instance(struct redist_proto *, unsigned short);
|
||||||
extern void redist_del_all_instances(struct redist_proto *red);
|
extern void redist_del_all_instances(struct redist_proto *red);
|
||||||
|
|
||||||
|
extern struct redist_table_direct *
|
||||||
|
redist_lookup_table_direct(const struct redist_proto *red, const struct redist_table_direct *table);
|
||||||
|
extern bool redist_table_direct_has_id(const struct redist_proto *red, int table_id);
|
||||||
|
extern void redist_add_table_direct(struct redist_proto *red,
|
||||||
|
const struct redist_table_direct *table);
|
||||||
|
extern void redist_del_table_direct(struct redist_proto *red,
|
||||||
|
const struct redist_table_direct *table);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send to zebra that the specified vrf is using label to resolve
|
* Send to zebra that the specified vrf is using label to resolve
|
||||||
* itself for L3VPN's. Repeated calls of this function with
|
* itself for L3VPN's. Repeated calls of this function with
|
||||||
|
0
tests/topotests/bgp_table_direct_topo1/__init__.py
Normal file
0
tests/topotests/bgp_table_direct_topo1/__init__.py
Normal file
31
tests/topotests/bgp_table_direct_topo1/r1/frr.conf
Normal file
31
tests/topotests/bgp_table_direct_topo1/r1/frr.conf
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
log commands
|
||||||
|
!
|
||||||
|
debug bgp zebra
|
||||||
|
debug zebra events
|
||||||
|
!
|
||||||
|
ip route 10.254.254.1/32 lo table 2000
|
||||||
|
ip route 10.254.254.2/32 lo table 2000
|
||||||
|
ip route 10.254.254.3/32 lo table 2000
|
||||||
|
!
|
||||||
|
interface r1-eth0
|
||||||
|
ip address 192.168.10.1/24
|
||||||
|
!
|
||||||
|
interface r1-eth1 vrf blue
|
||||||
|
ip address 192.168.20.1/24
|
||||||
|
!
|
||||||
|
router bgp 65001
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 192.168.10.2 remote-as external
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute table-direct 2000
|
||||||
|
exit-address-family
|
||||||
|
!
|
||||||
|
router bgp 65001 vrf blue
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 192.168.20.2 remote-as external
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute table-direct 2000
|
||||||
|
exit-address-family
|
||||||
|
!
|
10
tests/topotests/bgp_table_direct_topo1/r2/frr.conf
Normal file
10
tests/topotests/bgp_table_direct_topo1/r2/frr.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
log commands
|
||||||
|
!
|
||||||
|
interface r2-eth0
|
||||||
|
ip address 192.168.10.2/24
|
||||||
|
!
|
||||||
|
router bgp 65002
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 192.168.10.1 remote-as external
|
||||||
|
!
|
10
tests/topotests/bgp_table_direct_topo1/r3/frr.conf
Normal file
10
tests/topotests/bgp_table_direct_topo1/r3/frr.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
log commands
|
||||||
|
!
|
||||||
|
interface r3-eth0
|
||||||
|
ip address 192.168.20.2/24
|
||||||
|
!
|
||||||
|
router bgp 65003
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 192.168.20.1 remote-as external
|
||||||
|
!
|
@ -0,0 +1,201 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# SPDX-License-Identifier: ISC
|
||||||
|
|
||||||
|
#
|
||||||
|
# test_bgp_table_direct_topo1.py
|
||||||
|
# Part of NetDEF Topology Tests
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 by
|
||||||
|
# Network Device Education Foundation, Inc. ("NetDEF")
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
test_bgp_table_direct_topo1.py: Test the FRR PIM MSDP peer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
from functools import partial
|
||||||
|
import re
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
# Save the Current Working Directory to find configuration files.
|
||||||
|
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
sys.path.append(os.path.join(CWD, "../"))
|
||||||
|
|
||||||
|
# pylint: disable=C0413
|
||||||
|
# Import topogen and topotest helpers
|
||||||
|
from lib import topotest
|
||||||
|
|
||||||
|
# Required to instantiate the topology builder class.
|
||||||
|
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||||
|
from lib.topolog import logger
|
||||||
|
|
||||||
|
from lib.pim import McastTesterHelper
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.bgpd, pytest.mark.pimd]
|
||||||
|
|
||||||
|
app_helper = McastTesterHelper()
|
||||||
|
|
||||||
|
|
||||||
|
def build_topo(tgen):
|
||||||
|
"""
|
||||||
|
+----+ +----+
|
||||||
|
| r1 | <-> | r2 |
|
||||||
|
+----+ +----+
|
||||||
|
|
|
||||||
|
| +----+
|
||||||
|
--------| r3 |
|
||||||
|
+----+
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Create 3 routers
|
||||||
|
for routern in range(1, 4):
|
||||||
|
tgen.add_router(f"r{routern}")
|
||||||
|
|
||||||
|
switch = tgen.add_switch("s1")
|
||||||
|
switch.add_link(tgen.gears["r1"])
|
||||||
|
switch.add_link(tgen.gears["r2"])
|
||||||
|
|
||||||
|
switch = tgen.add_switch("s2")
|
||||||
|
switch.add_link(tgen.gears["r1"])
|
||||||
|
switch.add_link(tgen.gears["r3"])
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module(mod):
|
||||||
|
"Sets up the pytest environment"
|
||||||
|
tgen = Topogen(build_topo, mod.__name__)
|
||||||
|
tgen.start_topology()
|
||||||
|
|
||||||
|
router_list = tgen.routers()
|
||||||
|
for _, router in router_list.items():
|
||||||
|
router.load_frr_config(os.path.join(CWD, f"{router.name}/frr.conf"))
|
||||||
|
|
||||||
|
tgen.gears["r1"].run("ip link add blue type vrf table 10")
|
||||||
|
tgen.gears["r1"].run("ip link set blue up")
|
||||||
|
tgen.gears["r1"].run("ip link set r1-eth1 master blue")
|
||||||
|
|
||||||
|
# Initialize all routers.
|
||||||
|
tgen.start_router()
|
||||||
|
|
||||||
|
app_helper.init(tgen)
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_module():
|
||||||
|
"Teardown the pytest environment"
|
||||||
|
tgen = get_topogen()
|
||||||
|
app_helper.cleanup()
|
||||||
|
tgen.stop_topology()
|
||||||
|
|
||||||
|
|
||||||
|
def expect_bgp_route(router, iptype, route, missing=False):
|
||||||
|
"Wait until route is present on RIB for protocol."
|
||||||
|
if missing:
|
||||||
|
logger.info("waiting route {} go missing in {}".format(route, router))
|
||||||
|
else:
|
||||||
|
logger.info("waiting route {} in {}".format(route, router))
|
||||||
|
|
||||||
|
tgen = get_topogen()
|
||||||
|
expected_output = {route: [{"protocol": "bgp"}]}
|
||||||
|
wait_time = 130
|
||||||
|
if missing:
|
||||||
|
expected_output = {route: None}
|
||||||
|
wait_time = 5
|
||||||
|
|
||||||
|
test_func = partial(
|
||||||
|
topotest.router_json_cmp,
|
||||||
|
tgen.gears[router],
|
||||||
|
"show {} route json".format(iptype),
|
||||||
|
expected_output
|
||||||
|
)
|
||||||
|
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
|
||||||
|
assertmsg = f'"{router}" convergence failure'
|
||||||
|
assert result is None, assertmsg
|
||||||
|
|
||||||
|
|
||||||
|
def test_bgp_convergence():
|
||||||
|
"Wait for BGP protocol convergence"
|
||||||
|
tgen = get_topogen()
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
logger.info("waiting for protocols to converge")
|
||||||
|
|
||||||
|
# Wait for R2
|
||||||
|
expect_bgp_route("r2", "ip", "10.254.254.1/32")
|
||||||
|
expect_bgp_route("r2", "ip", "10.254.254.2/32")
|
||||||
|
expect_bgp_route("r2", "ip", "10.254.254.3/32")
|
||||||
|
|
||||||
|
# Wait for R3
|
||||||
|
expect_bgp_route("r3", "ip", "10.254.254.1/32")
|
||||||
|
expect_bgp_route("r3", "ip", "10.254.254.2/32")
|
||||||
|
expect_bgp_route("r3", "ip", "10.254.254.3/32")
|
||||||
|
|
||||||
|
|
||||||
|
def test_route_change_convergence():
|
||||||
|
"Change routes in table 2000 to test zebra redistribution."
|
||||||
|
tgen = get_topogen()
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
tgen.gears["r1"].vtysh_cmd("""
|
||||||
|
configure terminal
|
||||||
|
no ip route 10.254.254.2/32 lo table 2000
|
||||||
|
ip route 10.254.254.10/32 lo table 2000
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Check R2
|
||||||
|
expect_bgp_route("r2", "ip", "10.254.254.2/32", missing=True)
|
||||||
|
expect_bgp_route("r2", "ip", "10.254.254.10/32")
|
||||||
|
|
||||||
|
# Check R3
|
||||||
|
expect_bgp_route("r3", "ip", "10.254.254.2/32", missing=True)
|
||||||
|
expect_bgp_route("r3", "ip", "10.254.254.10/32")
|
||||||
|
|
||||||
|
|
||||||
|
def test_configuration_removal_convergence():
|
||||||
|
"Remove table direct configuration and check if routes went missing."
|
||||||
|
tgen = get_topogen()
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
tgen.gears["r1"].vtysh_cmd("""
|
||||||
|
configure terminal
|
||||||
|
router bgp 65001
|
||||||
|
address-family ipv4 unicast
|
||||||
|
no redistribute table-direct 2000
|
||||||
|
exit-address-family
|
||||||
|
exit
|
||||||
|
|
||||||
|
router bgp 65001 vrf blue
|
||||||
|
address-family ipv4 unicast
|
||||||
|
no redistribute table-direct 2000
|
||||||
|
exit-address-family
|
||||||
|
exit
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Check R2
|
||||||
|
expect_bgp_route("r2", "ip", "10.254.254.1/32", missing=True)
|
||||||
|
expect_bgp_route("r2", "ip", "10.254.254.3/32", missing=True)
|
||||||
|
expect_bgp_route("r2", "ip", "10.254.254.10/32", missing=True)
|
||||||
|
|
||||||
|
# Check R3
|
||||||
|
expect_bgp_route("r3", "ip", "10.254.254.1/32", missing=True)
|
||||||
|
expect_bgp_route("r3", "ip", "10.254.254.3/32", missing=True)
|
||||||
|
expect_bgp_route("r3", "ip", "10.254.254.10/32", missing=True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_memory_leak():
|
||||||
|
"Run the memory leak test and report results."
|
||||||
|
tgen = get_topogen()
|
||||||
|
if not tgen.is_memleak_enabled():
|
||||||
|
pytest.skip("Memory leak test/report is disabled")
|
||||||
|
|
||||||
|
tgen.report_memory_leaks()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = ["-s"] + sys.argv[1:]
|
||||||
|
sys.exit(pytest.main(args))
|
@ -82,8 +82,8 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id)
|
|||||||
|
|
||||||
RNODE_FOREACH_RE (rn, newre) {
|
RNODE_FOREACH_RE (rn, newre) {
|
||||||
if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED))
|
if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED))
|
||||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
|
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, rn,
|
||||||
client, rn, newre, false);
|
newre, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
route_unlock_node(rn);
|
route_unlock_node(rn);
|
||||||
@ -91,6 +91,24 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Redistribute routes. */
|
/* Redistribute routes. */
|
||||||
|
static void redistribute_table_direct(struct zserv *client, int type, const struct route_node *rn,
|
||||||
|
const struct route_entry *re)
|
||||||
|
{
|
||||||
|
struct redist_table_direct *table;
|
||||||
|
struct redist_proto *red;
|
||||||
|
struct listnode *node;
|
||||||
|
afi_t afi = family2afi(rn->p.family);
|
||||||
|
|
||||||
|
red = &client->mi_redist[afi][ZEBRA_ROUTE_TABLE_DIRECT];
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(red->instances, node, table)) {
|
||||||
|
if (table->table_id != (int)re->table)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
zsend_redistribute_route(type, client, rn, re, &table->vrf_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void zebra_redistribute(struct zserv *client, int type,
|
static void zebra_redistribute(struct zserv *client, int type,
|
||||||
unsigned short instance, struct zebra_vrf *zvrf,
|
unsigned short instance, struct zebra_vrf *zvrf,
|
||||||
int afi)
|
int afi)
|
||||||
@ -102,13 +120,9 @@ static void zebra_redistribute(struct zserv *client, int type,
|
|||||||
vrf_id_t vrf_id = zvrf_id(zvrf);
|
vrf_id_t vrf_id = zvrf_id(zvrf);
|
||||||
|
|
||||||
if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
|
if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||||
if (vrf_id == VRF_DEFAULT) {
|
table = zebra_router_find_table(zvrf, instance, afi, SAFI_UNICAST);
|
||||||
table = zebra_router_find_table(zvrf, instance, afi,
|
type = ZEBRA_ROUTE_ALL;
|
||||||
SAFI_UNICAST);
|
is_table_direct = true;
|
||||||
type = ZEBRA_ROUTE_ALL;
|
|
||||||
is_table_direct = true;
|
|
||||||
} else
|
|
||||||
return;
|
|
||||||
} else
|
} else
|
||||||
table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id);
|
table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id);
|
||||||
|
|
||||||
@ -140,15 +154,20 @@ static void zebra_redistribute(struct zserv *client, int type,
|
|||||||
if (!zebra_check_addr(&rn->p))
|
if (!zebra_check_addr(&rn->p))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
|
if (is_table_direct)
|
||||||
client, rn, newre, is_table_direct);
|
redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_ADD, rn,
|
||||||
|
newre);
|
||||||
|
else
|
||||||
|
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, rn,
|
||||||
|
newre, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function to return a valid table id value if table-direct is used
|
* Checks if the route entry can be used as table-direct or not.
|
||||||
* return 0 otherwise
|
* `table-direct` routes always belong to `VRF_DEFAULT` and has an table
|
||||||
* This function can be called only if zebra_redistribute_check returns TRUE
|
* ID different than the VRF it belongs (example main VRF table is 254,
|
||||||
|
* so in order to be `table-direct` the route's table ID must be != 254).
|
||||||
*/
|
*/
|
||||||
static bool zebra_redistribute_is_table_direct(const struct route_entry *re)
|
static bool zebra_redistribute_is_table_direct(const struct route_entry *re)
|
||||||
{
|
{
|
||||||
@ -177,15 +196,14 @@ static bool zebra_redistribute_check(const struct route_node *rn,
|
|||||||
|
|
||||||
afi = family2afi(rn->p.family);
|
afi = family2afi(rn->p.family);
|
||||||
zvrf = zebra_vrf_lookup_by_id(re->vrf_id);
|
zvrf = zebra_vrf_lookup_by_id(re->vrf_id);
|
||||||
if (re->vrf_id == VRF_DEFAULT && zvrf->table_id != re->table) {
|
if (zvrf->table_id != re->table) {
|
||||||
|
/*
|
||||||
|
* Routes with table ID different from VRFs can be used as
|
||||||
|
* `table-direct` if enabled.
|
||||||
|
*/
|
||||||
if (re->table &&
|
if (re->table &&
|
||||||
redist_check_instance(&client->mi_redist
|
redist_table_direct_has_id(&client->mi_redist[afi][ZEBRA_ROUTE_TABLE_DIRECT],
|
||||||
[afi][ZEBRA_ROUTE_TABLE_DIRECT],
|
re->table)) {
|
||||||
re->table)) {
|
|
||||||
/* table-direct redistribution only for route entries which
|
|
||||||
* are on the default vrf, and that have table id different
|
|
||||||
* from the default table.
|
|
||||||
*/
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -227,7 +245,6 @@ void redistribute_update(const struct route_node *rn,
|
|||||||
{
|
{
|
||||||
struct listnode *node, *nnode;
|
struct listnode *node, *nnode;
|
||||||
struct zserv *client;
|
struct zserv *client;
|
||||||
bool is_table_direct;
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_RIB)
|
if (IS_ZEBRA_DEBUG_RIB)
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
@ -242,7 +259,6 @@ void redistribute_update(const struct route_node *rn,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
|
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
|
||||||
if (zebra_redistribute_check(rn, re, client)) {
|
if (zebra_redistribute_check(rn, re, client)) {
|
||||||
if (IS_ZEBRA_DEBUG_RIB) {
|
if (IS_ZEBRA_DEBUG_RIB) {
|
||||||
@ -253,15 +269,19 @@ void redistribute_update(const struct route_node *rn,
|
|||||||
re->vrf_id, re->table, re->type,
|
re->vrf_id, re->table, re->type,
|
||||||
re->distance, re->metric);
|
re->distance, re->metric);
|
||||||
}
|
}
|
||||||
is_table_direct = zebra_redistribute_is_table_direct(re);
|
if (zebra_redistribute_is_table_direct(re))
|
||||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
|
redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_ADD, rn,
|
||||||
client, rn, re,
|
re);
|
||||||
is_table_direct);
|
else
|
||||||
|
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, rn,
|
||||||
|
re, NULL);
|
||||||
} else if (zebra_redistribute_check(rn, prev_re, client)) {
|
} else if (zebra_redistribute_check(rn, prev_re, client)) {
|
||||||
is_table_direct = zebra_redistribute_is_table_direct(prev_re);
|
if (zebra_redistribute_is_table_direct(prev_re))
|
||||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
|
redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_DEL, rn,
|
||||||
client, rn, prev_re,
|
prev_re);
|
||||||
is_table_direct);
|
else
|
||||||
|
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, client, rn,
|
||||||
|
prev_re, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,7 +301,6 @@ void redistribute_delete(const struct route_node *rn,
|
|||||||
struct listnode *node, *nnode;
|
struct listnode *node, *nnode;
|
||||||
struct zserv *client;
|
struct zserv *client;
|
||||||
vrf_id_t vrfid;
|
vrf_id_t vrfid;
|
||||||
bool is_table_direct;
|
|
||||||
|
|
||||||
if (old_re)
|
if (old_re)
|
||||||
vrfid = old_re->vrf_id;
|
vrfid = old_re->vrf_id;
|
||||||
@ -344,10 +363,12 @@ void redistribute_delete(const struct route_node *rn,
|
|||||||
* happy.
|
* happy.
|
||||||
*/
|
*/
|
||||||
assert(old_re);
|
assert(old_re);
|
||||||
is_table_direct = zebra_redistribute_is_table_direct(old_re);
|
if (zebra_redistribute_is_table_direct(old_re))
|
||||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
|
redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_DEL, rn,
|
||||||
client, rn, old_re,
|
old_re);
|
||||||
is_table_direct);
|
else
|
||||||
|
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, client, rn,
|
||||||
|
old_re, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,8 +404,16 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (instance) {
|
if (instance) {
|
||||||
if (!redist_check_instance(&client->mi_redist[afi][type],
|
if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||||
instance)) {
|
struct redist_table_direct table = {
|
||||||
|
.vrf_id = zvrf->vrf->vrf_id,
|
||||||
|
.table_id = instance,
|
||||||
|
};
|
||||||
|
if (!redist_lookup_table_direct(&client->mi_redist[afi][type], &table)) {
|
||||||
|
redist_add_table_direct(&client->mi_redist[afi][type], &table);
|
||||||
|
zebra_redistribute(client, type, instance, zvrf, afi);
|
||||||
|
}
|
||||||
|
} else if (!redist_check_instance(&client->mi_redist[afi][type], instance)) {
|
||||||
redist_add_instance(&client->mi_redist[afi][type],
|
redist_add_instance(&client->mi_redist[afi][type],
|
||||||
instance);
|
instance);
|
||||||
zebra_redistribute(client, type, instance, zvrf, afi);
|
zebra_redistribute(client, type, instance, zvrf, afi);
|
||||||
@ -443,7 +472,13 @@ void zebra_redistribute_delete(ZAPI_HANDLER_ARGS)
|
|||||||
* themselves should keep track of the received routes from zebra and
|
* themselves should keep track of the received routes from zebra and
|
||||||
* withdraw them when necessary.
|
* withdraw them when necessary.
|
||||||
*/
|
*/
|
||||||
if (instance)
|
if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||||
|
struct redist_table_direct table = {
|
||||||
|
.vrf_id = zvrf->vrf->vrf_id,
|
||||||
|
.table_id = instance,
|
||||||
|
};
|
||||||
|
redist_del_table_direct(&client->mi_redist[afi][type], &table);
|
||||||
|
} else if (instance)
|
||||||
redist_del_instance(&client->mi_redist[afi][type], instance);
|
redist_del_instance(&client->mi_redist[afi][type], instance);
|
||||||
else
|
else
|
||||||
vrf_bitmap_unset(&client->redist[afi][type], zvrf_id(zvrf));
|
vrf_bitmap_unset(&client->redist[afi][type], zvrf_id(zvrf));
|
||||||
|
@ -509,9 +509,8 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp)
|
|||||||
return zserv_send_message(client, s);
|
return zserv_send_message(client, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
int zsend_redistribute_route(int cmd, struct zserv *client,
|
int zsend_redistribute_route(int cmd, struct zserv *client, const struct route_node *rn,
|
||||||
const struct route_node *rn,
|
const struct route_entry *re, vrf_id_t *to_vrf)
|
||||||
const struct route_entry *re, bool is_table_direct)
|
|
||||||
{
|
{
|
||||||
struct zapi_route api;
|
struct zapi_route api;
|
||||||
struct zapi_nexthop *api_nh;
|
struct zapi_nexthop *api_nh;
|
||||||
@ -527,9 +526,10 @@ int zsend_redistribute_route(int cmd, struct zserv *client,
|
|||||||
api.vrf_id = re->vrf_id;
|
api.vrf_id = re->vrf_id;
|
||||||
api.type = re->type;
|
api.type = re->type;
|
||||||
api.safi = SAFI_UNICAST;
|
api.safi = SAFI_UNICAST;
|
||||||
if (is_table_direct) {
|
if (to_vrf != NULL) {
|
||||||
api.instance = re->table;
|
api.instance = re->table;
|
||||||
api.type = ZEBRA_ROUTE_TABLE_DIRECT;
|
api.type = ZEBRA_ROUTE_TABLE_DIRECT;
|
||||||
|
api.vrf_id = *to_vrf;
|
||||||
} else
|
} else
|
||||||
api.instance = re->instance;
|
api.instance = re->instance;
|
||||||
api.flags = re->flags;
|
api.flags = re->flags;
|
||||||
@ -598,7 +598,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client,
|
|||||||
|
|
||||||
/* Attributes. */
|
/* Attributes. */
|
||||||
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
|
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
|
||||||
if (is_table_direct)
|
if (to_vrf != NULL)
|
||||||
api.distance = ZEBRA_TABLEDIRECT_DISTANCE_DEFAULT;
|
api.distance = ZEBRA_TABLEDIRECT_DISTANCE_DEFAULT;
|
||||||
else
|
else
|
||||||
api.distance = re->distance;
|
api.distance = re->distance;
|
||||||
|
@ -51,10 +51,8 @@ extern void nbr_connected_delete_ipv6(struct interface *ifp,
|
|||||||
struct in6_addr *address);
|
struct in6_addr *address);
|
||||||
extern int zsend_interface_update(int cmd, struct zserv *client,
|
extern int zsend_interface_update(int cmd, struct zserv *client,
|
||||||
struct interface *ifp);
|
struct interface *ifp);
|
||||||
extern int zsend_redistribute_route(int cmd, struct zserv *zclient,
|
extern int zsend_redistribute_route(int cmd, struct zserv *zclient, const struct route_node *rn,
|
||||||
const struct route_node *rn,
|
const struct route_entry *re, vrf_id_t *to_vrf);
|
||||||
const struct route_entry *re,
|
|
||||||
bool is_table_direct);
|
|
||||||
|
|
||||||
extern int zsend_router_id_update(struct zserv *zclient, afi_t afi,
|
extern int zsend_router_id_update(struct zserv *zclient, afi_t afi,
|
||||||
struct prefix *p, vrf_id_t vrf_id);
|
struct prefix *p, vrf_id_t vrf_id);
|
||||||
|
Loading…
Reference in New Issue
Block a user