]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib/zserv: introduce address-family independent ZAPI message types
authorRenato Westphal <renato@opensourcerouting.org>
Sun, 20 Aug 2017 00:59:41 +0000 (21:59 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Wed, 23 Aug 2017 20:45:17 +0000 (17:45 -0300)
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>
babeld/kernel.c
lib/log.c
lib/zclient.c
lib/zclient.h
zebra/zserv.c

index 105a7d0518867e4cabd2084b458bc8f6fb15cc34..6cdd66e48db1321bd95db2c19ae4de2c9c66ee36 100644 (file)
@@ -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
index b9ce9e69bc5f2eeb5f951cb6f216f05f7cf8f1f0..92b2d3b66b25abfcfe0bff97c31a3a474d943c37 100644 (file)
--- 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),
index 53e8569b77ecca615e31cacaf981c056c4e42c56..3f5c7a0f6f5afeb923addf9695e248e0cc6a0abd 100644 (file)
@@ -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;
 }
 
 /*
index 92aeabb07f732d669c08d133c8924980a40fbe77..2e450ed398f212caac8e56556d9b280d5161c63f 100644 (file)
@@ -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 */
index e00e1d7c20a17b903c9c47c888675d3452cb8585..94e34865b5c23fda03b31a4cc1cfc889d3bce6e9 100644 (file)
@@ -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;