]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/zclient.c
Merge pull request #5009 from donaldsharp/interface_deletion
[mirror_frr.git] / lib / zclient.c
index 0972590ca695e9dfd70a1102e22dca1301c8b7c7..9129466685c9662ae8bd540a74728d9d5a20195c 100644 (file)
@@ -49,6 +49,9 @@ enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
 /* Prototype for event manager. */
 static void zclient_event(enum event, struct zclient *);
 
+static void zebra_interface_if_set_value(struct stream *s,
+                                        struct interface *ifp);
+
 struct zclient_options zclient_options_default = {.receive_notify = false};
 
 struct sockaddr_storage zclient_addr;
@@ -62,10 +65,13 @@ struct zclient *zclient_new(struct thread_master *master,
                            struct zclient_options *opt)
 {
        struct zclient *zclient;
+       size_t stream_size =
+               MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route));
+
        zclient = XCALLOC(MTYPE_ZCLIENT, sizeof(struct zclient));
 
-       zclient->ibuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
-       zclient->obuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
+       zclient->ibuf = stream_new(stream_size);
+       zclient->obuf = stream_new(stream_size);
        zclient->wb = buffer_new(0);
        zclient->master = master;
 
@@ -322,8 +328,9 @@ int zclient_read_header(struct stream *s, int sock, uint16_t *size,
        if (*size && stream_read(s, sock, *size) != *size)
                return -1;
 
-stream_failure:
        return 0;
+stream_failure:
+       return -1;
 }
 
 bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr)
@@ -762,6 +769,92 @@ int zclient_route_send(uint8_t cmd, struct zclient *zclient,
        return zclient_send_message(zclient);
 }
 
+static int zapi_nexthop_labels_cmp(const struct zapi_nexthop *next1,
+                                  const struct zapi_nexthop *next2)
+{
+       if (next1->label_num > next2->label_num)
+               return 1;
+
+       if (next1->label_num < next2->label_num)
+               return -1;
+
+       return memcmp(next1->labels, next2->labels, next1->label_num);
+}
+
+static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1,
+                                     const struct zapi_nexthop *next2)
+{
+       int ret = 0;
+
+       if (next1->vrf_id < next2->vrf_id)
+               return -1;
+
+       if (next1->vrf_id > next2->vrf_id)
+               return 1;
+
+       if (next1->type < next2->type)
+               return -1;
+
+       if (next1->type > next2->type)
+               return 1;
+
+       switch (next1->type) {
+       case NEXTHOP_TYPE_IPV4:
+       case NEXTHOP_TYPE_IPV6:
+               ret = nexthop_g_addr_cmp(next1->type, &next1->gate,
+                                        &next2->gate);
+               if (ret != 0)
+                       return ret;
+               break;
+       case NEXTHOP_TYPE_IPV4_IFINDEX:
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+               ret = nexthop_g_addr_cmp(next1->type, &next1->gate,
+                                        &next2->gate);
+               if (ret != 0)
+                       return ret;
+               /* Intentional Fall-Through */
+       case NEXTHOP_TYPE_IFINDEX:
+               if (next1->ifindex < next2->ifindex)
+                       return -1;
+
+               if (next1->ifindex > next2->ifindex)
+                       return 1;
+               break;
+       case NEXTHOP_TYPE_BLACKHOLE:
+               if (next1->bh_type < next2->bh_type)
+                       return -1;
+
+               if (next1->bh_type > next2->bh_type)
+                       return 1;
+               break;
+       }
+
+       return 0;
+}
+
+static int zapi_nexthop_cmp(const void *item1, const void *item2)
+{
+       int ret = 0;
+
+       const struct zapi_nexthop *next1 = item1;
+       const struct zapi_nexthop *next2 = item2;
+
+       ret = zapi_nexthop_cmp_no_labels(next1, next2);
+       if (ret != 0)
+               return ret;
+
+       ret = zapi_nexthop_labels_cmp(next1, next2);
+
+       return ret;
+}
+
+static void zapi_nexthop_group_sort(struct zapi_nexthop *nh_grp,
+                                   uint16_t nexthop_num)
+{
+       qsort(nh_grp, nexthop_num, sizeof(struct zapi_nexthop),
+             &zapi_nexthop_cmp);
+}
+
 int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
 {
        struct zapi_nexthop *api_nh;
@@ -817,6 +910,8 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
                        return -1;
                }
 
+               zapi_nexthop_group_sort(api->nexthops, api->nexthop_num);
+
                stream_putw(s, api->nexthop_num);
 
                for (i = 0; i < api->nexthop_num; i++) {
@@ -1053,8 +1148,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
        if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID))
                STREAM_GETL(s, api->tableid);
 
-stream_failure:
        return 0;
+stream_failure:
+       return -1;
 }
 
 static void zapi_encode_prefix(struct stream *s, struct prefix *p,
@@ -1454,10 +1550,11 @@ static void zclient_vrf_delete(struct zclient *zclient, vrf_id_t vrf_id)
        vrf_delete(vrf);
 }
 
-struct interface *zebra_interface_add_read(struct stream *s, vrf_id_t vrf_id)
+static void zclient_interface_add(struct zclient *zclient, vrf_id_t vrf_id)
 {
        struct interface *ifp;
        char ifname_tmp[INTERFACE_NAMSIZ];
+       struct stream *s = zclient->ibuf;
 
        /* Read interface name. */
        stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
@@ -1467,15 +1564,14 @@ struct interface *zebra_interface_add_read(struct stream *s, vrf_id_t vrf_id)
 
        zebra_interface_if_set_value(s, ifp);
 
-       return ifp;
+       if_new_via_zapi(ifp);
 }
 
 /*
  * Read interface up/down msg (ZEBRA_INTERFACE_UP/ZEBRA_INTERFACE_DOWN)
  * from zebra server.  The format of this message is the same as
- * that sent for ZEBRA_INTERFACE_ADD/ZEBRA_INTERFACE_DELETE (see
- * comments for zebra_interface_add_read), except that no sockaddr_dl
- * is sent at the tail of the message.
+ * that sent for ZEBRA_INTERFACE_ADD/ZEBRA_INTERFACE_DELETE,
+ * except that no sockaddr_dl is sent at the tail of the message.
  */
 struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id)
 {
@@ -1499,6 +1595,46 @@ struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id)
        return ifp;
 }
 
+static void zclient_interface_delete(struct zclient *zclient, vrf_id_t vrf_id)
+{
+       struct interface *ifp;
+       struct stream *s = zclient->ibuf;
+
+       ifp = zebra_interface_state_read(s, vrf_id);
+
+       if (ifp == NULL)
+               return;
+
+       if_destroy_via_zapi(ifp);
+       return;
+}
+
+static void zclient_interface_up(struct zclient *zclient, vrf_id_t vrf_id)
+{
+       struct interface *ifp;
+       struct stream *s = zclient->ibuf;
+
+       ifp = zebra_interface_state_read(s, vrf_id);
+
+       if (!ifp)
+               return;
+
+       if_up_via_zapi(ifp);
+}
+
+static void zclient_interface_down(struct zclient *zclient, vrf_id_t vrf_id)
+{
+       struct interface *ifp;
+       struct stream *s = zclient->ibuf;
+
+       ifp = zebra_interface_state_read(s, vrf_id);
+
+       if (!ifp)
+               return;
+
+       if_down_via_zapi(ifp);
+}
+
 static void link_params_set_value(struct stream *s, struct if_link_params *iflp)
 {
 
@@ -1563,7 +1699,8 @@ struct interface *zebra_interface_link_params_read(struct stream *s,
        return ifp;
 }
 
-void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
+static void zebra_interface_if_set_value(struct stream *s,
+                                        struct interface *ifp)
 {
        uint8_t link_params_status = 0;
        ifindex_t old_ifindex;
@@ -1992,10 +2129,11 @@ int lm_label_manager_connect(struct zclient *zclient, int async)
  * @param zclient Zclient used to connect to label manager (zebra)
  * @param keep Avoid garbage collection
  * @param chunk_size Amount of labels requested
+ * @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care
  * @result 0 on success, -1 otherwise
  */
 int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
-                                uint32_t chunk_size)
+                                uint32_t chunk_size, uint32_t base)
 {
        struct stream *s;
 
@@ -2015,6 +2153,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
        stream_putw(s, zclient->instance);
        stream_putc(s, keep);
        stream_putl(s, chunk_size);
+       stream_putl(s, base);
 
        /* Put length at the first point of the stream. */
        stream_putw_at(s, 0, stream_get_endp(s));
@@ -2035,7 +2174,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
  * @param end To write last assigned chunk label to
  * @result 0 on success, -1 otherwise
  */
-int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
+int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t base,
                       uint32_t chunk_size, uint32_t *start, uint32_t *end)
 {
        int ret;
@@ -2060,6 +2199,8 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
        stream_putc(s, keep);
        /* chunk size */
        stream_putl(s, chunk_size);
+       /* requested chunk base */
+       stream_putl(s, base);
        /* Put length at the first point of the stream. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
@@ -2100,6 +2241,15 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
                         "Wrong instId (%u) in get chunk response Should be %u",
                         instance, zclient->instance);
 
+       /* if we requested a specific chunk and it could not be allocated, the
+        * response message will end here
+        */
+       if (!STREAM_READABLE(s)) {
+               zlog_info("Unable to assign Label Chunk to %s instance %u",
+                         zebra_route_string(proto), instance);
+               return -1;
+       }
+
        /* keep */
        response_keep = stream_getc(s);
        /* start and end labels */
@@ -2238,7 +2388,7 @@ int tm_table_manager_connect(struct zclient *zclient)
 
        return (int)result;
 stream_failure:
-       return 0;
+       return -1;
 }
 
 /**
@@ -2305,8 +2455,9 @@ int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
        if (zclient_debug)
                zlog_debug("Table Chunk assign: %u - %u ", *start, *end);
 
-stream_failure:
        return 0;
+stream_failure:
+       return -1;
 }
 
 /**
@@ -2344,6 +2495,143 @@ int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
        return zclient_send_message(zclient);
 }
 
+int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
+                          struct zapi_labels *zl)
+{
+       if (zapi_labels_encode(zclient->obuf, cmd, zl) < 0)
+               return -1;
+       return zclient_send_message(zclient);
+}
+
+int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl)
+{
+       struct zapi_nexthop_label *znh;
+
+       stream_reset(s);
+
+       zclient_create_header(s, cmd, VRF_DEFAULT);
+       stream_putc(s, zl->message);
+       stream_putc(s, zl->type);
+       stream_putl(s, zl->local_label);
+
+       if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
+               stream_putw(s, zl->route.prefix.family);
+               stream_put_prefix(s, &zl->route.prefix);
+               stream_putc(s, zl->route.type);
+               stream_putw(s, zl->route.instance);
+       }
+
+       if (zl->nexthop_num > MULTIPATH_NUM) {
+               flog_err(
+                       EC_LIB_ZAPI_ENCODE,
+                       "%s: label %u: can't encode %u nexthops (maximum is %u)",
+                       __func__, zl->local_label, zl->nexthop_num,
+                       MULTIPATH_NUM);
+               return -1;
+       }
+       stream_putw(s, zl->nexthop_num);
+
+       for (int i = 0; i < zl->nexthop_num; i++) {
+               znh = &zl->nexthops[i];
+
+               stream_putc(s, znh->type);
+               stream_putw(s, znh->family);
+               switch (znh->family) {
+               case AF_INET:
+                       stream_put_in_addr(s, &znh->address.ipv4);
+                       break;
+               case AF_INET6:
+                       stream_write(s, (uint8_t *)&znh->address.ipv6, 16);
+                       break;
+               default:
+                       break;
+               }
+               stream_putl(s, znh->ifindex);
+               stream_putl(s, znh->label);
+       }
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return 0;
+}
+
+int zapi_labels_decode(struct stream *s, struct zapi_labels *zl)
+{
+       struct zapi_nexthop_label *znh;
+
+       memset(zl, 0, sizeof(*zl));
+
+       /* Get data. */
+       STREAM_GETC(s, zl->message);
+       STREAM_GETC(s, zl->type);
+       STREAM_GETL(s, zl->local_label);
+
+       if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
+               size_t psize;
+
+               STREAM_GETW(s, zl->route.prefix.family);
+               STREAM_GETC(s, zl->route.prefix.prefixlen);
+
+               psize = PSIZE(zl->route.prefix.prefixlen);
+               switch (zl->route.prefix.family) {
+               case AF_INET:
+                       if (zl->route.prefix.prefixlen > IPV4_MAX_BITLEN) {
+                               zlog_debug(
+                                       "%s: Specified prefix length %d is greater than a v4 address can support",
+                                       __PRETTY_FUNCTION__,
+                                       zl->route.prefix.prefixlen);
+                               return -1;
+                       }
+                       STREAM_GET(&zl->route.prefix.u.prefix4.s_addr, s,
+                                  psize);
+                       break;
+               case AF_INET6:
+                       if (zl->route.prefix.prefixlen > IPV6_MAX_BITLEN) {
+                               zlog_debug(
+                                       "%s: Specified prefix length %d is greater than a v6 address can support",
+                                       __PRETTY_FUNCTION__,
+                                       zl->route.prefix.prefixlen);
+                               return -1;
+                       }
+                       STREAM_GET(&zl->route.prefix.u.prefix6, s, psize);
+                       break;
+               default:
+                       flog_err(EC_LIB_ZAPI_ENCODE,
+                                "%s: Specified family %u is not v4 or v6",
+                                __PRETTY_FUNCTION__, zl->route.prefix.family);
+                       return -1;
+               }
+
+               STREAM_GETC(s, zl->route.type);
+               STREAM_GETW(s, zl->route.instance);
+       }
+
+       STREAM_GETW(s, zl->nexthop_num);
+       for (int i = 0; i < zl->nexthop_num; i++) {
+               znh = &zl->nexthops[i];
+
+               STREAM_GETC(s, znh->type);
+               STREAM_GETW(s, znh->family);
+               switch (znh->family) {
+               case AF_INET:
+                       STREAM_GET(&znh->address.ipv4.s_addr, s,
+                                  IPV4_MAX_BYTELEN);
+                       break;
+               case AF_INET6:
+                       STREAM_GET(&znh->address.ipv6, s, 16);
+                       break;
+               default:
+                       break;
+               }
+               STREAM_GETL(s, znh->ifindex);
+               STREAM_GETL(s, znh->label);
+       }
+
+       return 0;
+stream_failure:
+       return -1;
+}
 
 int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
 {
@@ -2545,14 +2833,10 @@ static int zclient_read(struct thread *thread)
                zclient_vrf_delete(zclient, vrf_id);
                break;
        case ZEBRA_INTERFACE_ADD:
-               if (zclient->interface_add)
-                       (*zclient->interface_add)(command, zclient, length,
-                                                 vrf_id);
+               zclient_interface_add(zclient, vrf_id);
                break;
        case ZEBRA_INTERFACE_DELETE:
-               if (zclient->interface_delete)
-                       (*zclient->interface_delete)(command, zclient, length,
-                                                    vrf_id);
+               zclient_interface_delete(zclient, vrf_id);
                break;
        case ZEBRA_INTERFACE_ADDRESS_ADD:
                if (zclient->interface_address_add)
@@ -2580,14 +2864,10 @@ static int zclient_read(struct thread *thread)
                                command, zclient, length, vrf_id);
                break;
        case ZEBRA_INTERFACE_UP:
-               if (zclient->interface_up)
-                       (*zclient->interface_up)(command, zclient, length,
-                                                vrf_id);
+               zclient_interface_up(zclient, vrf_id);
                break;
        case ZEBRA_INTERFACE_DOWN:
-               if (zclient->interface_down)
-                       (*zclient->interface_down)(command, zclient, length,
-                                                  vrf_id);
+               zclient_interface_down(zclient, vrf_id);
                break;
        case ZEBRA_INTERFACE_VRF_UPDATE:
                if (zclient->interface_vrf_update)