forked from Mirror/frr
lib,zebra: VRF table-direct support
Implement the necessary data structures and code changes to support sending table-direct routes to protocols running in different VRFs. Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
This commit is contained in:
parent
dfdc12e164
commit
28a9ca3405
138
lib/zclient.c
138
lib/zclient.c
|
@ -31,6 +31,7 @@
|
|||
|
||||
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient");
|
||||
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs");
|
||||
DEFINE_MTYPE_STATIC(LIB, REDIST_TABLE_DIRECT, "Redistribution table direct");
|
||||
|
||||
/* Zebra client events. */
|
||||
enum zclient_event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
|
||||
|
@ -157,6 +158,87 @@ void redist_del_instance(struct redist_proto *red, unsigned short instance)
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!red->instances)
|
||||
|
@ -483,6 +565,17 @@ enum zclient_send_status zclient_send_localsid(struct zclient *zclient,
|
|||
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. */
|
||||
void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
|
||||
{
|
||||
|
@ -516,6 +609,12 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
|
|||
if (!zclient->mi_redist[afi][i].enabled)
|
||||
continue;
|
||||
|
||||
if (i == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||
zclient_send_table_direct(zclient, afi,
|
||||
ZEBRA_REDISTRIBUTE_ADD);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct listnode *node;
|
||||
unsigned short *id;
|
||||
|
||||
|
@ -583,6 +682,12 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id)
|
|||
if (!zclient->mi_redist[afi][i].enabled)
|
||||
continue;
|
||||
|
||||
if (i == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||
zclient_send_table_direct(zclient, afi,
|
||||
ZEBRA_REDISTRIBUTE_DELETE);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct listnode *node;
|
||||
unsigned short *id;
|
||||
|
||||
|
@ -4637,9 +4742,42 @@ static void zclient_read(struct event *thread)
|
|||
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,
|
||||
int type, unsigned short instance, vrf_id_t vrf_id)
|
||||
{
|
||||
if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||
zclient_redistribute_table_direct(zclient, vrf_id, afi, instance, command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (instance) {
|
||||
if (command == ZEBRA_REDISTRIBUTE_ADD) {
|
||||
|
|
|
@ -268,6 +268,15 @@ struct redist_proto {
|
|||
struct list *instances;
|
||||
};
|
||||
|
||||
/**
|
||||
* Redistribute table direct instance data structure: keeps the VRF
|
||||
* that subscribed to the table ID.
|
||||
*/
|
||||
struct redist_table_direct {
|
||||
vrf_id_t vrf_id;
|
||||
int table_id;
|
||||
};
|
||||
|
||||
struct zclient_capabilities {
|
||||
uint32_t ecmp;
|
||||
bool mpls_enabled;
|
||||
|
@ -924,6 +933,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_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
|
||||
* itself for L3VPN's. Repeated calls of this function with
|
||||
|
|
|
@ -82,8 +82,8 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id)
|
|||
|
||||
RNODE_FOREACH_RE (rn, newre) {
|
||||
if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED))
|
||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
|
||||
client, rn, newre, false);
|
||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, rn,
|
||||
newre, NULL);
|
||||
}
|
||||
|
||||
route_unlock_node(rn);
|
||||
|
@ -91,6 +91,24 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id)
|
|||
}
|
||||
|
||||
/* 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,
|
||||
unsigned short instance, struct zebra_vrf *zvrf,
|
||||
int afi)
|
||||
|
@ -102,13 +120,9 @@ static void zebra_redistribute(struct zserv *client, int type,
|
|||
vrf_id_t vrf_id = zvrf_id(zvrf);
|
||||
|
||||
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, SAFI_UNICAST);
|
||||
type = ZEBRA_ROUTE_ALL;
|
||||
is_table_direct = true;
|
||||
} else
|
||||
return;
|
||||
} else
|
||||
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))
|
||||
continue;
|
||||
|
||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
|
||||
client, rn, newre, is_table_direct);
|
||||
if (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
|
||||
* return 0 otherwise
|
||||
* This function can be called only if zebra_redistribute_check returns TRUE
|
||||
* Checks if the route entry can be used as table-direct or not.
|
||||
* `table-direct` routes always belong to `VRF_DEFAULT` and has an table
|
||||
* 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)
|
||||
{
|
||||
|
@ -177,15 +196,14 @@ static bool zebra_redistribute_check(const struct route_node *rn,
|
|||
|
||||
afi = family2afi(rn->p.family);
|
||||
zvrf = zebra_vrf_lookup_by_id(re->vrf_id);
|
||||
if (re->vrf_id == VRF_DEFAULT && zvrf->table_id != re->table) {
|
||||
if (re->table &&
|
||||
redist_check_instance(&client->mi_redist
|
||||
[afi][ZEBRA_ROUTE_TABLE_DIRECT],
|
||||
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.
|
||||
if (zvrf->table_id != re->table) {
|
||||
/*
|
||||
* Routes with table ID different from VRFs can be used as
|
||||
* `table-direct` if enabled.
|
||||
*/
|
||||
if (re->table &&
|
||||
redist_table_direct_has_id(&client->mi_redist[afi][ZEBRA_ROUTE_TABLE_DIRECT],
|
||||
re->table)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -227,7 +245,6 @@ void redistribute_update(const struct route_node *rn,
|
|||
{
|
||||
struct listnode *node, *nnode;
|
||||
struct zserv *client;
|
||||
bool is_table_direct;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_RIB)
|
||||
zlog_debug(
|
||||
|
@ -242,7 +259,6 @@ void redistribute_update(const struct route_node *rn,
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
|
||||
if (zebra_redistribute_check(rn, re, client)) {
|
||||
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->distance, re->metric);
|
||||
}
|
||||
is_table_direct = zebra_redistribute_is_table_direct(re);
|
||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
|
||||
client, rn, re,
|
||||
is_table_direct);
|
||||
if (zebra_redistribute_is_table_direct(re))
|
||||
redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_ADD, rn,
|
||||
re);
|
||||
else
|
||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, rn,
|
||||
re, NULL);
|
||||
} else if (zebra_redistribute_check(rn, prev_re, client)) {
|
||||
is_table_direct = zebra_redistribute_is_table_direct(prev_re);
|
||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
|
||||
client, rn, prev_re,
|
||||
is_table_direct);
|
||||
if (zebra_redistribute_is_table_direct(prev_re))
|
||||
redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_DEL, rn,
|
||||
prev_re);
|
||||
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 zserv *client;
|
||||
vrf_id_t vrfid;
|
||||
bool is_table_direct;
|
||||
|
||||
if (old_re)
|
||||
vrfid = old_re->vrf_id;
|
||||
|
@ -344,10 +363,12 @@ void redistribute_delete(const struct route_node *rn,
|
|||
* happy.
|
||||
*/
|
||||
assert(old_re);
|
||||
is_table_direct = zebra_redistribute_is_table_direct(old_re);
|
||||
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
|
||||
client, rn, old_re,
|
||||
is_table_direct);
|
||||
if (zebra_redistribute_is_table_direct(old_re))
|
||||
redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_DEL, rn,
|
||||
old_re);
|
||||
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 (!redist_check_instance(&client->mi_redist[afi][type],
|
||||
instance)) {
|
||||
if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
|
||||
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],
|
||||
instance);
|
||||
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
|
||||
* 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);
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
int zsend_redistribute_route(int cmd, struct zserv *client,
|
||||
const struct route_node *rn,
|
||||
const struct route_entry *re, bool is_table_direct)
|
||||
int zsend_redistribute_route(int cmd, struct zserv *client, const struct route_node *rn,
|
||||
const struct route_entry *re, vrf_id_t *to_vrf)
|
||||
{
|
||||
struct zapi_route api;
|
||||
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.type = re->type;
|
||||
api.safi = SAFI_UNICAST;
|
||||
if (is_table_direct) {
|
||||
if (to_vrf != NULL) {
|
||||
api.instance = re->table;
|
||||
api.type = ZEBRA_ROUTE_TABLE_DIRECT;
|
||||
api.vrf_id = *to_vrf;
|
||||
} else
|
||||
api.instance = re->instance;
|
||||
api.flags = re->flags;
|
||||
|
@ -598,7 +598,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client,
|
|||
|
||||
/* Attributes. */
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
|
||||
if (is_table_direct)
|
||||
if (to_vrf != NULL)
|
||||
api.distance = ZEBRA_TABLEDIRECT_DISTANCE_DEFAULT;
|
||||
else
|
||||
api.distance = re->distance;
|
||||
|
|
|
@ -51,10 +51,8 @@ extern void nbr_connected_delete_ipv6(struct interface *ifp,
|
|||
struct in6_addr *address);
|
||||
extern int zsend_interface_update(int cmd, struct zserv *client,
|
||||
struct interface *ifp);
|
||||
extern int zsend_redistribute_route(int cmd, struct zserv *zclient,
|
||||
const struct route_node *rn,
|
||||
const struct route_entry *re,
|
||||
bool is_table_direct);
|
||||
extern int zsend_redistribute_route(int cmd, struct zserv *zclient, const struct route_node *rn,
|
||||
const struct route_entry *re, vrf_id_t *to_vrf);
|
||||
|
||||
extern int zsend_router_id_update(struct zserv *zclient, afi_t afi,
|
||||
struct prefix *p, vrf_id_t vrf_id);
|
||||
|
|
Loading…
Reference in a new issue