mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 19:39:28 +00:00
lib/zserv: introduce address-family independent ZAPI message types
As noticed in 657cde1
, the zapi_ipv[4|6]_route functions are broken in
many ways and that's the reason that many client daemons (e.g. ospfd,
isisd) need to send handcrafted messages to zebra.
The zapi_route() function introduced by Donald solves the problem
by providing a consistent way to send ipv4/ipv6 routes to zebra with
nexthops of any type, in all possible combinations including IPv4 routes
with IPv6 nexthops (for BGP unnumbered routes).
This patch goes a bit further and creates two new address-family
independent ZAPI message types that the client daemons can
use to advertise route information to zebra: ZEBRA_ROUTE_ADD and
ZEBRA_ROUTE_DELETE. The big advantage of having address-family independent
messages is that it allows us to remove a lot of duplicate code in zebra
and in the client daemons.
This patch also introduces the zapi_route_decode() function. It will be
used by zebra to decode route messages sent by the client daemons using
zclient_route_send(), which calls zapi_route_encode().
Later on we'll use this same pair of encode/decode functions to
send/receive redistributed routes from zebra to the client daemons,
taking the idea of removing code duplication to the next level.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
parent
bb1b9c47ca
commit
0e51b4a368
@ -190,9 +190,8 @@ kernel_route_v4(int add,
|
||||
|
||||
debugf(BABEL_DEBUG_ROUTE, "%s route (ipv4) to zebra",
|
||||
add ? "adding" : "removing" );
|
||||
return zapi_route (add ? ZEBRA_IPV4_ROUTE_ADD :
|
||||
ZEBRA_IPV4_ROUTE_DELETE,
|
||||
zclient, &api);
|
||||
return zclient_route_send (add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
|
||||
zclient, &api);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -242,9 +241,8 @@ kernel_route_v6(int add, const unsigned char *pref, unsigned short plen,
|
||||
|
||||
debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra",
|
||||
add ? "adding" : "removing" );
|
||||
return zapi_route (add ? ZEBRA_IPV6_ROUTE_ADD :
|
||||
ZEBRA_IPV6_ROUTE_DELETE,
|
||||
zclient, &api);
|
||||
return zclient_route_send (add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
|
||||
zclient, &api);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -867,6 +867,8 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY(ZEBRA_INTERFACE_UP),
|
||||
DESC_ENTRY(ZEBRA_INTERFACE_DOWN),
|
||||
DESC_ENTRY(ZEBRA_INTERFACE_SET_MASTER),
|
||||
DESC_ENTRY(ZEBRA_ROUTE_ADD),
|
||||
DESC_ENTRY(ZEBRA_ROUTE_DELETE),
|
||||
DESC_ENTRY(ZEBRA_IPV4_ROUTE_ADD),
|
||||
DESC_ENTRY(ZEBRA_IPV4_ROUTE_DELETE),
|
||||
DESC_ENTRY(ZEBRA_IPV6_ROUTE_ADD),
|
||||
|
116
lib/zclient.c
116
lib/zclient.c
@ -892,20 +892,23 @@ int zapi_ipv6_route(u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
|
||||
return zclient_send_message(zclient);
|
||||
}
|
||||
|
||||
int zapi_route(u_char cmd, struct zclient *zclient, struct zapi_route *api)
|
||||
int zclient_route_send(u_char cmd, struct zclient *zclient,
|
||||
struct zapi_route *api)
|
||||
{
|
||||
if (zapi_route_encode(cmd, zclient->obuf, api) < 0)
|
||||
return -1;
|
||||
return zclient_send_message(zclient);
|
||||
}
|
||||
|
||||
int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api)
|
||||
{
|
||||
struct zapi_nexthop *api_nh;
|
||||
int i;
|
||||
int psize;
|
||||
struct stream *s;
|
||||
struct zapi_nexthop *api_nh;
|
||||
|
||||
/* Reset stream. */
|
||||
s = zclient->obuf;
|
||||
stream_reset(s);
|
||||
|
||||
zclient_create_header(s, cmd, api->vrf_id);
|
||||
|
||||
/* Put type and nexthop. */
|
||||
stream_putc(s, api->type);
|
||||
stream_putw(s, api->instance);
|
||||
stream_putl(s, api->flags);
|
||||
@ -913,6 +916,7 @@ int zapi_route(u_char cmd, struct zclient *zclient, struct zapi_route *api)
|
||||
stream_putw(s, api->safi);
|
||||
|
||||
/* Put prefix information. */
|
||||
stream_putc(s, api->prefix.family);
|
||||
psize = PSIZE(api->prefix.prefixlen);
|
||||
stream_putc(s, api->prefix.prefixlen);
|
||||
stream_write(s, (u_char *)&api->prefix.u.prefix, psize);
|
||||
@ -923,7 +927,7 @@ int zapi_route(u_char cmd, struct zclient *zclient, struct zapi_route *api)
|
||||
stream_write(s, (u_char *)&api->src_prefix.prefix, psize);
|
||||
}
|
||||
|
||||
/* Nexthop, ifindex, distance and metric information. */
|
||||
/* Nexthops. */
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
|
||||
/* limit the number of nexthops if necessary */
|
||||
if (api->nexthop_num > MULTIPATH_NUM) {
|
||||
@ -973,6 +977,7 @@ int zapi_route(u_char cmd, struct zclient *zclient, struct zapi_route *api)
|
||||
}
|
||||
}
|
||||
|
||||
/* Attributes. */
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
|
||||
stream_putc(s, api->distance);
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_METRIC))
|
||||
@ -985,7 +990,100 @@ int zapi_route(u_char cmd, struct zclient *zclient, struct zapi_route *api)
|
||||
/* Put length at the first point of the stream. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
return zclient_send_message(zclient);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zapi_route_decode(struct stream *s, struct zapi_route *api)
|
||||
{
|
||||
struct zapi_nexthop *api_nh;
|
||||
int i;
|
||||
|
||||
memset(api, 0, sizeof(*api));
|
||||
|
||||
/* Type, flags, message. */
|
||||
api->type = stream_getc(s);
|
||||
api->instance = stream_getw(s);
|
||||
api->flags = stream_getl(s);
|
||||
api->message = stream_getc(s);
|
||||
api->safi = stream_getw(s);
|
||||
|
||||
/* Prefix. */
|
||||
api->prefix.family = stream_getc(s);
|
||||
switch (api->prefix.family) {
|
||||
case AF_INET:
|
||||
api->prefix.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc(s));
|
||||
break;
|
||||
case AF_INET6:
|
||||
api->prefix.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc(s));
|
||||
break;
|
||||
}
|
||||
stream_get(&api->prefix.u.prefix, s, PSIZE(api->prefix.prefixlen));
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_SRCPFX)) {
|
||||
api->src_prefix.family = AF_INET6;
|
||||
api->src_prefix.prefixlen = stream_getc(s);
|
||||
stream_get(&api->src_prefix.prefix, s,
|
||||
PSIZE(api->src_prefix.prefixlen));
|
||||
|
||||
if (api->prefix.family != AF_INET6
|
||||
|| api->src_prefix.prefixlen == 0)
|
||||
UNSET_FLAG(api->message, ZAPI_MESSAGE_SRCPFX);
|
||||
}
|
||||
|
||||
/* Nexthops. */
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
|
||||
api->nexthop_num = stream_getc(s);
|
||||
if (api->nexthop_num > MULTIPATH_NUM) {
|
||||
zlog_warn("%s: invalid number of nexthops (%u)",
|
||||
__func__, api->nexthop_num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < api->nexthop_num; i++) {
|
||||
api_nh = &api->nexthops[i];
|
||||
|
||||
api_nh->type = stream_getc(s);
|
||||
switch (api_nh->type) {
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
api_nh->gate.ipv4.s_addr = stream_get_ipv4(s);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
api_nh->gate.ipv4.s_addr = stream_get_ipv4(s);
|
||||
api_nh->ifindex = stream_getl(s);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
api_nh->ifindex = stream_getl(s);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
stream_get(&api_nh->gate.ipv6, s, 16);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
stream_get(&api_nh->gate.ipv6, s, 16);
|
||||
api_nh->ifindex = stream_getl(s);
|
||||
break;
|
||||
}
|
||||
|
||||
/* For labeled-unicast, each nexthop is followed
|
||||
* by label. */
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL)) {
|
||||
stream_get(&api_nh->label, s,
|
||||
sizeof(api_nh->label));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Attributes. */
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
|
||||
api->distance = stream_getc(s);
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_METRIC))
|
||||
api->metric = stream_getl(s);
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TAG))
|
||||
api->tag = stream_getl(s);
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU))
|
||||
api->mtu = stream_getl(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -59,6 +59,8 @@ typedef enum {
|
||||
ZEBRA_INTERFACE_UP,
|
||||
ZEBRA_INTERFACE_DOWN,
|
||||
ZEBRA_INTERFACE_SET_MASTER,
|
||||
ZEBRA_ROUTE_ADD,
|
||||
ZEBRA_ROUTE_DELETE,
|
||||
ZEBRA_IPV4_ROUTE_ADD,
|
||||
ZEBRA_IPV4_ROUTE_DELETE,
|
||||
ZEBRA_IPV6_ROUTE_ADD,
|
||||
@ -426,7 +428,8 @@ extern int zapi_ipv6_route(u_char cmd, struct zclient *zclient,
|
||||
extern int zapi_ipv4_route_ipv6_nexthop(u_char, struct zclient *,
|
||||
struct prefix_ipv4 *,
|
||||
struct zapi_ipv6 *);
|
||||
extern int zapi_route(u_char cmd, struct zclient *zclient,
|
||||
struct zapi_route *api);
|
||||
extern int zclient_route_send(u_char, struct zclient *, struct zapi_route *);
|
||||
extern int zapi_route_encode(u_char, struct stream *, struct zapi_route *);
|
||||
extern int zapi_route_decode(struct stream *, struct zapi_route *);
|
||||
|
||||
#endif /* _ZEBRA_ZCLIENT_H */
|
||||
|
144
zebra/zserv.c
144
zebra/zserv.c
@ -1157,6 +1157,144 @@ void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
|
||||
}
|
||||
}
|
||||
|
||||
static int zread_route_add(struct zserv *client, u_short length,
|
||||
struct zebra_vrf *zvrf)
|
||||
{
|
||||
struct stream *s;
|
||||
struct zapi_route api;
|
||||
struct zapi_nexthop *api_nh;
|
||||
afi_t afi;
|
||||
struct prefix_ipv6 *src_p = NULL;
|
||||
struct route_entry *re;
|
||||
struct nexthop *nexthop;
|
||||
int i, ret;
|
||||
|
||||
s = client->ibuf;
|
||||
if (zapi_route_decode(s, &api) < 0)
|
||||
return -1;
|
||||
|
||||
/* Allocate new route. */
|
||||
re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
|
||||
re->type = api.type;
|
||||
re->instance = api.instance;
|
||||
re->flags = api.flags;
|
||||
re->uptime = time(NULL);
|
||||
re->vrf_id = zvrf_id(zvrf);
|
||||
re->table = zvrf->table_id;
|
||||
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
|
||||
for (i = 0; i < api.nexthop_num; i++) {
|
||||
api_nh = &api.nexthops[i];
|
||||
|
||||
switch (api_nh->type) {
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
route_entry_nexthop_ifindex_add(
|
||||
re, api_nh->ifindex);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
nexthop = route_entry_nexthop_ipv4_add(
|
||||
re, &api_nh->gate.ipv4, NULL);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
nexthop = route_entry_nexthop_ipv4_ifindex_add(
|
||||
re, &api_nh->gate.ipv4, NULL,
|
||||
api_nh->ifindex);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
nexthop = route_entry_nexthop_ipv6_add(
|
||||
re, &api_nh->gate.ipv6);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
nexthop = route_entry_nexthop_ipv6_ifindex_add(
|
||||
re, &api_nh->gate.ipv6,
|
||||
api_nh->ifindex);
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
route_entry_nexthop_blackhole_add(re);
|
||||
break;
|
||||
}
|
||||
|
||||
/* MPLS labels for BGP-LU or Segment Routing */
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL)
|
||||
&& api_nh->type != NEXTHOP_TYPE_IFINDEX
|
||||
&& api_nh->type != NEXTHOP_TYPE_BLACKHOLE) {
|
||||
enum lsp_types_t label_type;
|
||||
|
||||
label_type =
|
||||
lsp_type_from_re_type(client->proto);
|
||||
nexthop_add_labels(nexthop, label_type, 1,
|
||||
&api_nh->label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
|
||||
re->distance = api.distance;
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
|
||||
re->metric = api.metric;
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
|
||||
re->tag = api.tag;
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_MTU))
|
||||
re->mtu = api.mtu;
|
||||
|
||||
afi = family2afi(api.prefix.family);
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
|
||||
src_p = &api.src_prefix;
|
||||
|
||||
ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re);
|
||||
|
||||
/* Stats */
|
||||
switch (api.prefix.family) {
|
||||
case AF_INET:
|
||||
if (ret > 0)
|
||||
client->v4_route_add_cnt++;
|
||||
else if (ret < 0)
|
||||
client->v4_route_upd8_cnt++;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (ret > 0)
|
||||
client->v6_route_add_cnt++;
|
||||
else if (ret < 0)
|
||||
client->v6_route_upd8_cnt++;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zread_route_del(struct zserv *client, u_short length,
|
||||
struct zebra_vrf *zvrf)
|
||||
{
|
||||
struct stream *s;
|
||||
struct zapi_route api;
|
||||
afi_t afi;
|
||||
struct prefix_ipv6 *src_p = NULL;
|
||||
|
||||
s = client->ibuf;
|
||||
if (zapi_route_decode(s, &api) < 0)
|
||||
return -1;
|
||||
|
||||
afi = family2afi(api.prefix.family);
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
|
||||
src_p = &api.src_prefix;
|
||||
|
||||
rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance,
|
||||
api.flags, &api.prefix, src_p, NULL, 0, zvrf->table_id,
|
||||
api.metric);
|
||||
|
||||
/* Stats */
|
||||
switch (api.prefix.family) {
|
||||
case AF_INET:
|
||||
client->v4_route_del_cnt++;
|
||||
break;
|
||||
case AF_INET6:
|
||||
client->v6_route_del_cnt++;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function support multiple nexthop. */
|
||||
/*
|
||||
* Parse the ZEBRA_IPV4_ROUTE_ADD sent from client. Update re and
|
||||
@ -2334,6 +2472,12 @@ static int zebra_client_read(struct thread *thread)
|
||||
case ZEBRA_INTERFACE_DELETE:
|
||||
zread_interface_delete(client, length, zvrf);
|
||||
break;
|
||||
case ZEBRA_ROUTE_ADD:
|
||||
zread_route_add(client, length, zvrf);
|
||||
break;
|
||||
case ZEBRA_ROUTE_DELETE:
|
||||
zread_route_del(client, length, zvrf);
|
||||
break;
|
||||
case ZEBRA_IPV4_ROUTE_ADD:
|
||||
zread_ipv4_add(client, length, zvrf);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user