summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRenato Westphal <renato@opensourcerouting.org>2017-08-19 21:59:41 -0300
committerRenato Westphal <renato@opensourcerouting.org>2017-08-23 17:45:17 -0300
commit0e51b4a368257d54b1e07ff74492ea4705de97f7 (patch)
treec213ed50bdf21a94fd031cc6abd838bff3c343e4
parentbb1b9c47ca090ce4484e1f8061f17b5c33f578ee (diff)
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>
-rw-r--r--babeld/kernel.c10
-rw-r--r--lib/log.c2
-rw-r--r--lib/zclient.c116
-rw-r--r--lib/zclient.h7
-rw-r--r--zebra/zserv.c144
5 files changed, 262 insertions, 17 deletions
diff --git a/babeld/kernel.c b/babeld/kernel.c
index 105a7d0518..6cdd66e48d 100644
--- a/babeld/kernel.c
+++ b/babeld/kernel.c
@@ -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
diff --git a/lib/log.c b/lib/log.c
index b9ce9e69bc..92b2d3b66b 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -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),
diff --git a/lib/zclient.c b/lib/zclient.c
index 53e8569b77..3f5c7a0f6f 100644
--- a/lib/zclient.c
+++ b/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;
}
/*
diff --git a/lib/zclient.h b/lib/zclient.h
index 92aeabb07f..2e450ed398 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -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 */
diff --git a/zebra/zserv.c b/zebra/zserv.c
index e00e1d7c20..94e34865b5 100644
--- a/zebra/zserv.c
+++ b/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;