diff options
Diffstat (limited to 'lib/zclient.c')
| -rw-r--r-- | lib/zclient.c | 655 |
1 files changed, 530 insertions, 125 deletions
diff --git a/lib/zclient.c b/lib/zclient.c index 8ec82ab7bb..c36bcc6e2e 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1,22 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Zebra's client library. * Copyright (C) 1999 Kunihiro Ishiguro * Copyright (C) 2005 Andrew J. Schorr - * - * This file is part of GNU Zebra. - * - * GNU Zebra is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * GNU Zebra is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; see the file COPYING; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <zebra.h> @@ -29,7 +14,7 @@ #include "vrf_int.h" #include "if.h" #include "log.h" -#include "thread.h" +#include "frrevent.h" #include "zclient.h" #include "memory.h" #include "table.h" @@ -37,6 +22,7 @@ #include "mpls.h" #include "sockopt.h" #include "pbr.h" +#include "tc.h" #include "nexthop_group.h" #include "lib_errors.h" #include "srte.h" @@ -65,7 +51,7 @@ socklen_t zclient_addr_len; static int zclient_debug; /* Allocate zclient structure. */ -struct zclient *zclient_new(struct thread_master *master, +struct zclient *zclient_new(struct event_loop *master, struct zclient_options *opt, zclient_handler *const *handlers, size_t n_handlers) { @@ -174,9 +160,9 @@ void zclient_stop(struct zclient *zclient) zlog_debug("zclient %p stopped", zclient); /* Stop threads. */ - THREAD_OFF(zclient->t_read); - THREAD_OFF(zclient->t_connect); - THREAD_OFF(zclient->t_write); + EVENT_OFF(zclient->t_read); + EVENT_OFF(zclient->t_connect); + EVENT_OFF(zclient->t_write); /* Reset streams. */ stream_reset(zclient->ibuf); @@ -194,14 +180,14 @@ void zclient_stop(struct zclient *zclient) for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - vrf_bitmap_free(zclient->redist[afi][i]); + vrf_bitmap_free(&zclient->redist[afi][i]); zclient->redist[afi][i] = VRF_BITMAP_NULL; } redist_del_instance( &zclient->mi_redist[afi][zclient->redist_default], zclient->instance); - vrf_bitmap_free(zclient->default_information[afi]); + vrf_bitmap_free(&zclient->default_information[afi]); zclient->default_information[afi] = VRF_BITMAP_NULL; } } @@ -263,9 +249,9 @@ static enum zclient_send_status zclient_failed(struct zclient *zclient) return ZCLIENT_SEND_FAILURE; } -static void zclient_flush_data(struct thread *thread) +static void zclient_flush_data(struct event *thread) { - struct zclient *zclient = THREAD_ARG(thread); + struct zclient *zclient = EVENT_ARG(thread); zclient->t_write = NULL; if (zclient->sock < 0) @@ -280,8 +266,8 @@ static void zclient_flush_data(struct thread *thread) return; case BUFFER_PENDING: zclient->t_write = NULL; - thread_add_write(zclient->master, zclient_flush_data, zclient, - zclient->sock, &zclient->t_write); + event_add_write(zclient->master, zclient_flush_data, zclient, + zclient->sock, &zclient->t_write); break; case BUFFER_EMPTY: if (zclient->zebra_buffer_write_ready) @@ -309,11 +295,11 @@ enum zclient_send_status zclient_send_message(struct zclient *zclient) __func__, zclient->sock); return zclient_failed(zclient); case BUFFER_EMPTY: - THREAD_OFF(zclient->t_write); + EVENT_OFF(zclient->t_write); return ZCLIENT_SEND_SUCCESS; case BUFFER_PENDING: - thread_add_write(zclient->master, zclient_flush_data, zclient, - zclient->sock, &zclient->t_write); + event_add_write(zclient->master, zclient_flush_data, zclient, + zclient->sock, &zclient->t_write); return ZCLIENT_SEND_BUFFERED; } @@ -441,13 +427,18 @@ enum zclient_send_status zclient_send_vrf_label(struct zclient *zclient, } enum zclient_send_status zclient_send_localsid(struct zclient *zclient, - const struct in6_addr *sid, ifindex_t oif, + const struct in6_addr *sid, vrf_id_t vrf_id, enum seg6local_action_t action, const struct seg6local_context *context) { struct prefix_ipv6 p = {}; struct zapi_route api = {}; struct zapi_nexthop *znh; + struct interface *ifp; + + ifp = if_get_vrf_loopback(vrf_id); + if (ifp == NULL) + return ZCLIENT_SEND_FAILURE; p.family = AF_INET6; p.prefixlen = IPV6_MAX_BITLEN; @@ -470,7 +461,7 @@ enum zclient_send_status zclient_send_localsid(struct zclient *zclient, memset(znh, 0, sizeof(*znh)); znh->type = NEXTHOP_TYPE_IFINDEX; - znh->ifindex = oif; + znh->ifindex = ifp->ifindex; SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL); znh->seg6local_action = action; memcpy(&znh->seg6local_ctx, context, sizeof(struct seg6local_context)); @@ -503,7 +494,7 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id) /* Set unwanted redistribute route. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) - vrf_bitmap_set(zclient->redist[afi][zclient->redist_default], + vrf_bitmap_set(&zclient->redist[afi][zclient->redist_default], vrf_id); /* Flush all redistribute request. */ @@ -533,15 +524,15 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id) /* Resend all redistribute request. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (i != zclient->redist_default - && vrf_bitmap_check(zclient->redist[afi][i], - vrf_id)) + if (i != zclient->redist_default && + vrf_bitmap_check(&zclient->redist[afi][i], vrf_id)) zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, i, 0, vrf_id); /* If default information is needed. */ - if (vrf_bitmap_check(zclient->default_information[afi], vrf_id)) + if (vrf_bitmap_check(&zclient->default_information[afi], + vrf_id)) zebra_redistribute_default_send( ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, afi, vrf_id); @@ -570,7 +561,7 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) /* Set unwanted redistribute route. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) - vrf_bitmap_unset(zclient->redist[afi][zclient->redist_default], + vrf_bitmap_unset(&zclient->redist[afi][zclient->redist_default], vrf_id); /* Flush all redistribute request. */ @@ -600,15 +591,15 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) /* Flush all redistribute request. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (i != zclient->redist_default - && vrf_bitmap_check(zclient->redist[afi][i], - vrf_id)) + if (i != zclient->redist_default && + vrf_bitmap_check(&zclient->redist[afi][i], vrf_id)) zebra_redistribute_send( ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, i, 0, vrf_id); /* If default information is needed. */ - if (vrf_bitmap_check(zclient->default_information[afi], vrf_id)) + if (vrf_bitmap_check(&zclient->default_information[afi], + vrf_id)) zebra_redistribute_default_send( ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, afi, vrf_id); @@ -735,7 +726,7 @@ void zclient_init(struct zclient *zclient, int redist_default, /* Clear redistribution flags. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - zclient->redist[afi][i] = vrf_bitmap_init(); + vrf_bitmap_init(&zclient->redist[afi][i]); /* Set unwanted redistribute route. bgpd does not need BGP route redistribution. */ @@ -747,7 +738,7 @@ void zclient_init(struct zclient *zclient, int redist_default, instance); /* Set default-information redistribute to zero. */ - zclient->default_information[afi] = vrf_bitmap_init(); + vrf_bitmap_init(&zclient->default_information[afi]); } if (zclient_debug) @@ -758,11 +749,11 @@ void zclient_init(struct zclient *zclient, int redist_default, /* This function is a wrapper function for calling zclient_start from timer or event thread. */ -static void zclient_connect(struct thread *t) +static void zclient_connect(struct event *t) { struct zclient *zclient; - zclient = THREAD_ARG(t); + zclient = EVENT_ARG(t); zclient->t_connect = NULL; if (zclient_debug) @@ -1034,6 +1025,7 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, */ if (api_nh->label_num > 0) { stream_putc(s, api_nh->label_num); + stream_putc(s, api_nh->label_type); stream_put(s, &api_nh->labels[0], api_nh->label_num * sizeof(mpls_label_t)); } @@ -1088,6 +1080,7 @@ int zapi_srv6_locator_chunk_encode(struct stream *s, stream_putc(s, c->node_bits_length); stream_putc(s, c->function_bits_length); stream_putc(s, c->argument_bits_length); + stream_putc(s, c->flags); return 0; } @@ -1109,6 +1102,7 @@ int zapi_srv6_locator_chunk_decode(struct stream *s, STREAM_GETC(s, c->node_bits_length); STREAM_GETC(s, c->function_bits_length); STREAM_GETC(s, c->argument_bits_length); + STREAM_GETC(s, c->flags); return 0; stream_failure: @@ -1166,6 +1160,10 @@ static int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg) stream_putw(s, api_nhg->proto); stream_putl(s, api_nhg->id); + stream_putw(s, api_nhg->resilience.buckets); + stream_putl(s, api_nhg->resilience.idle_timer); + stream_putl(s, api_nhg->resilience.unbalanced_timer); + if (cmd == ZEBRA_NHG_ADD) { /* Nexthops */ zapi_nexthop_group_sort(api_nhg->nexthops, @@ -1390,6 +1388,7 @@ int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, /* MPLS labels for BGP-LU or Segment Routing */ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)) { STREAM_GETC(s, api_nh->label_num); + STREAM_GETC(s, api_nh->label_type); if (api_nh->label_num > MPLS_MAX_LABELS) { flog_err( EC_LIB_ZAPI_ENCODE, @@ -1612,30 +1611,105 @@ static void zapi_encode_prefix(struct stream *s, struct prefix *p, stream_put(s, &p->u.prefix, prefix_blen(p)); } -int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule) +static bool zapi_decode_prefix(struct stream *s, struct prefix *p) { - stream_reset(s); - zclient_create_header(s, cmd, zrule->vrf_id); + STREAM_GETC(s, p->family); + STREAM_GETC(s, p->prefixlen); + STREAM_GET(&(p->u.prefix), s, prefix_blen(p)); + return true; + +stream_failure: + return false; +} +/* + * Encode filter subsection of pbr_rule + */ +static void zapi_pbr_rule_filter_encode(struct stream *s, struct pbr_filter *f) +{ + assert(f->src_ip.family == f->dst_ip.family); + assert((f->src_ip.family == AF_INET) || (f->src_ip.family == AF_INET6)); + + stream_putl(s, f->filter_bm); + stream_putc(s, f->ip_proto); + + /* addresses */ + zapi_encode_prefix(s, &f->src_ip, f->src_ip.family); + zapi_encode_prefix(s, &f->dst_ip, f->dst_ip.family); + + /* port numbers */ + stream_putw(s, f->src_port); + stream_putw(s, f->dst_port); + + /* vlan */ + stream_putc(s, f->pcp); + stream_putw(s, f->vlan_id); + stream_putw(s, f->vlan_flags); + + stream_putc(s, f->dsfield); + stream_putl(s, f->fwmark); +} + +static bool zapi_pbr_rule_filter_decode(struct stream *s, struct pbr_filter *f) +{ + STREAM_GETL(s, f->filter_bm); + STREAM_GETC(s, f->ip_proto); + if (!zapi_decode_prefix(s, &(f->src_ip))) + goto stream_failure; + if (!zapi_decode_prefix(s, &(f->dst_ip))) + goto stream_failure; + STREAM_GETW(s, f->src_port); + STREAM_GETW(s, f->dst_port); + STREAM_GETC(s, f->pcp); + STREAM_GETW(s, f->vlan_id); + STREAM_GETW(s, f->vlan_flags); + STREAM_GETC(s, f->dsfield); + STREAM_GETL(s, f->fwmark); + return true; + +stream_failure: + return false; +} + +static void zapi_pbr_rule_action_encode(struct stream *s, struct pbr_action *a) +{ + stream_putl(s, a->flags); + stream_putl(s, a->table); + stream_putl(s, a->queue_id); + stream_putc(s, a->pcp); + stream_putw(s, a->vlan_id); + stream_putw(s, a->vlan_flags); +} + +static bool zapi_pbr_rule_action_decode(struct stream *s, struct pbr_action *a) +{ + STREAM_GETL(s, a->flags); + STREAM_GETL(s, a->table); + STREAM_GETL(s, a->queue_id); + STREAM_GETC(s, a->pcp); + STREAM_GETW(s, a->vlan_id); + STREAM_GETW(s, a->vlan_flags); + return true; + +stream_failure: + return false; +} + +int zapi_pbr_rule_encode(struct stream *s, struct pbr_rule *r) +{ /* - * We are sending one item at a time at the moment + * PBR record count is always 1 */ stream_putl(s, 1); - stream_putl(s, zrule->seq); - stream_putl(s, zrule->priority); - stream_putl(s, zrule->unique); + stream_putl(s, r->seq); + stream_putl(s, r->priority); + stream_putl(s, r->unique); - zapi_encode_prefix(s, &(zrule->filter.src_ip), - zrule->filter.src_ip.family); - stream_putw(s, zrule->filter.src_port); /* src port */ - zapi_encode_prefix(s, &(zrule->filter.dst_ip), - zrule->filter.src_ip.family); - stream_putw(s, zrule->filter.dst_port); /* dst port */ - stream_putw(s, zrule->filter.fwmark); /* fwmark */ + zapi_pbr_rule_filter_encode(s, &(r->filter)); + zapi_pbr_rule_action_encode(s, &(r->action)); - stream_putl(s, zrule->action.table); - stream_put(s, zrule->ifname, INTERFACE_NAMSIZ); + stream_put(s, r->ifname, INTERFACE_NAMSIZ); /* Put length at the first point of the stream. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -1643,6 +1717,122 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule) return 0; } +bool zapi_pbr_rule_decode(struct stream *s, struct pbr_rule *r) +{ + /* NB caller has already read 4-byte rule count */ + + memset(r, 0, sizeof(*r)); + + STREAM_GETL(s, r->seq); + STREAM_GETL(s, r->priority); + STREAM_GETL(s, r->unique); + + if (!zapi_pbr_rule_filter_decode(s, &(r->filter))) + goto stream_failure; + if (!zapi_pbr_rule_action_decode(s, &(r->action))) + goto stream_failure; + + STREAM_GET(r->ifname, s, INTERFACE_NAMSIZ); + return true; + +stream_failure: + return false; +} + +int zapi_tc_qdisc_encode(uint8_t cmd, struct stream *s, struct tc_qdisc *qdisc) +{ + stream_reset(s); + zclient_create_header(s, cmd, VRF_DEFAULT); + + + stream_putl(s, 1); + + stream_putl(s, qdisc->ifindex); + stream_putl(s, qdisc->kind); + + stream_putw_at(s, 0, stream_get_endp(s)); + + return 0; +} + +int zapi_tc_class_encode(uint8_t cmd, struct stream *s, struct tc_class *class) +{ + stream_reset(s); + zclient_create_header(s, cmd, VRF_DEFAULT); + + stream_putl(s, 1); + + stream_putl(s, class->ifindex); + stream_putl(s, class->handle); + stream_putl(s, class->kind); + + switch (class->kind) { + case TC_QDISC_HTB: + stream_putq(s, class->u.htb.rate); + stream_putq(s, class->u.htb.ceil); + break; + case TC_QDISC_UNSPEC: + case TC_QDISC_NOQUEUE: + /* not implemented */ + break; + } + stream_putw_at(s, 0, stream_get_endp(s)); + + return 0; +} + +int zapi_tc_filter_encode(uint8_t cmd, struct stream *s, + struct tc_filter *filter) +{ + stream_reset(s); + zclient_create_header(s, cmd, VRF_DEFAULT); + + stream_putl(s, 1); + + stream_putl(s, filter->ifindex); + stream_putl(s, filter->handle); + stream_putl(s, filter->priority); + stream_putl(s, filter->protocol); + stream_putl(s, filter->kind); + + switch (filter->kind) { + case TC_FILTER_FLOWER: + stream_putl(s, filter->u.flower.filter_bm); + if (filter->u.flower.filter_bm & TC_FLOWER_IP_PROTOCOL) + stream_putc(s, filter->u.flower.ip_proto); + if (filter->u.flower.filter_bm & TC_FLOWER_SRC_IP) + zapi_encode_prefix(s, &filter->u.flower.src_ip, + filter->u.flower.src_ip.family); + if (filter->u.flower.filter_bm & TC_FLOWER_SRC_PORT) { + stream_putw(s, filter->u.flower.src_port_min); + stream_putw(s, filter->u.flower.src_port_max); + } + if (filter->u.flower.filter_bm & TC_FLOWER_DST_IP) + zapi_encode_prefix(s, &filter->u.flower.dst_ip, + filter->u.flower.dst_ip.family); + if (filter->u.flower.filter_bm & TC_FLOWER_DST_PORT) { + stream_putw(s, filter->u.flower.dst_port_min); + stream_putw(s, filter->u.flower.dst_port_max); + } + if (filter->u.flower.filter_bm & TC_FLOWER_DSFIELD) { + stream_putc(s, filter->u.flower.dsfield); + stream_putc(s, filter->u.flower.dsfield_mask); + } + stream_putl(s, filter->u.flower.classid); + break; + case TC_FILTER_UNSPEC: + case TC_FILTER_BPF: + case TC_FILTER_FLOW: + case TC_FILTER_U32: + /* not implemented */ + break; + } + + stream_putw_at(s, 0, stream_get_endp(s)); + + return 0; +} + bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id, enum zapi_nhg_notify_owner *note) { @@ -1847,6 +2037,7 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, znh->labels[i] = nh->nh_label->label[i]; znh->label_num = i; + znh->label_type = nh->nh_label_type; SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL); } @@ -2299,13 +2490,22 @@ static int zclient_handle_error(ZAPI_CALLBACK_ARGS) return 0; } -static int link_params_set_value(struct stream *s, struct if_link_params *iflp) +static int link_params_set_value(struct stream *s, struct interface *ifp) { + uint8_t link_params_enabled, nb_ext_adm_grp; + struct if_link_params *iflp; + uint32_t bwclassnum, bitmap_data; + + iflp = if_link_params_get(ifp); if (iflp == NULL) - return -1; + iflp = if_link_params_init(ifp); - uint32_t bwclassnum; + STREAM_GETC(s, link_params_enabled); + if (!link_params_enabled) { + if_link_params_free(ifp); + return 0; + } STREAM_GETL(s, iflp->lp_status); STREAM_GETL(s, iflp->te_metric); @@ -2323,6 +2523,15 @@ static int link_params_set_value(struct stream *s, struct if_link_params *iflp) __func__, bwclassnum, MAX_CLASS_TYPE); } STREAM_GETL(s, iflp->admin_grp); + + /* Extended Administrative Group */ + admin_group_clear(&iflp->ext_admin_grp); + STREAM_GETC(s, nb_ext_adm_grp); + for (size_t i = 0; i < nb_ext_adm_grp; i++) { + STREAM_GETL(s, bitmap_data); + admin_group_bulk_set(&iflp->ext_admin_grp, bitmap_data, i); + } + STREAM_GETL(s, iflp->rmt_as); iflp->rmt_ip.s_addr = stream_get_ipv4(s); @@ -2346,9 +2555,9 @@ struct interface *zebra_interface_link_params_read(struct stream *s, bool *changed) { struct if_link_params *iflp; - struct if_link_params iflp_copy; + struct if_link_params iflp_prev = {0}; ifindex_t ifindex; - bool params_changed = false; + bool iflp_prev_set = false; STREAM_GETL(s, ifindex); @@ -2361,26 +2570,43 @@ struct interface *zebra_interface_link_params_read(struct stream *s, return NULL; } - if (ifp->link_params == NULL) - params_changed = true; + iflp = if_link_params_get(ifp); - if ((iflp = if_link_params_get(ifp)) == NULL) - return NULL; - - memcpy(&iflp_copy, iflp, sizeof(iflp_copy)); + if (iflp) { + iflp_prev_set = true; + admin_group_init(&iflp_prev.ext_admin_grp); + if_link_params_copy(&iflp_prev, iflp); + } - if (link_params_set_value(s, iflp) != 0) + /* read the link_params from stream + * Free ifp->link_params if the stream has no params + * to means that link-params are not enabled on links. + */ + if (link_params_set_value(s, ifp) != 0) goto stream_failure; - if (memcmp(&iflp_copy, iflp, sizeof(iflp_copy))) - params_changed = true; + if (changed != NULL) { + iflp = if_link_params_get(ifp); - if (changed) - *changed = params_changed; + if (iflp_prev_set && iflp) { + if (if_link_params_cmp(&iflp_prev, iflp)) + *changed = false; + else + *changed = true; + } else if (!iflp_prev_set && !iflp) + *changed = false; + else + *changed = true; + } + + if (iflp_prev_set) + admin_group_term(&iflp_prev.ext_admin_grp); return ifp; stream_failure: + if (iflp_prev_set) + admin_group_term(&iflp_prev.ext_admin_grp); return NULL; } @@ -2415,10 +2641,8 @@ static void zebra_interface_if_set_value(struct stream *s, /* Read Traffic Engineering status */ link_params_status = stream_getc(s); /* Then, Traffic Engineering parameters if any */ - if (link_params_status) { - struct if_link_params *iflp = if_link_params_get(ifp); - link_params_set_value(s, iflp); - } + if (link_params_status) + link_params_set_value(s, ifp); nexthop_group_interface_state_change(ifp, old_ifindex); @@ -2431,16 +2655,25 @@ stream_failure: size_t zebra_interface_link_params_write(struct stream *s, struct interface *ifp) { - size_t w; + size_t w, nb_ext_adm_grp; struct if_link_params *iflp; int i; - if (s == NULL || ifp == NULL || ifp->link_params == NULL) + + if (s == NULL || ifp == NULL) return 0; iflp = ifp->link_params; w = 0; + /* encode if link_params is enabled */ + if (iflp) { + w += stream_putc(s, true); + } else { + w += stream_putc(s, false); + return w; + } + w += stream_putl(s, iflp->lp_status); w += stream_putl(s, iflp->te_metric); @@ -2452,6 +2685,13 @@ size_t zebra_interface_link_params_write(struct stream *s, w += stream_putf(s, iflp->unrsv_bw[i]); w += stream_putl(s, iflp->admin_grp); + + /* Extended Administrative Group */ + nb_ext_adm_grp = admin_group_nb_words(&iflp->ext_admin_grp); + w += stream_putc(s, nb_ext_adm_grp); + for (size_t i = 0; i < nb_ext_adm_grp; i++) + stream_putl(s, admin_group_get_offset(&iflp->ext_admin_grp, i)); + w += stream_putl(s, iflp->rmt_as); w += stream_put_in_addr(s, &iflp->rmt_ip); @@ -3681,6 +3921,53 @@ enum zclient_send_status zclient_send_mlag_data(struct zclient *client, } /* + * Init/header setup for opaque zapi messages + */ +enum zclient_send_status zapi_opaque_init(struct zclient *zclient, + uint32_t type, uint16_t flags) +{ + struct stream *s; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT); + + /* Send sub-type and flags */ + stream_putl(s, type); + stream_putw(s, flags); + + /* Source daemon identifiers */ + stream_putc(s, zclient->redist_default); + stream_putw(s, zclient->instance); + stream_putl(s, zclient->session_id); + + return ZCLIENT_SEND_SUCCESS; +} + +/* + * Init, header setup for opaque unicast messages. + */ +enum zclient_send_status +zapi_opaque_unicast_init(struct zclient *zclient, uint32_t type, uint16_t flags, + uint8_t proto, uint16_t instance, uint32_t session_id) +{ + struct stream *s; + + s = zclient->obuf; + + /* Common init */ + zapi_opaque_init(zclient, type, flags | ZAPI_OPAQUE_FLAG_UNICAST); + + /* Send destination client info */ + stream_putc(s, proto); + stream_putw(s, instance); + stream_putl(s, session_id); + + return ZCLIENT_SEND_SUCCESS; +} + +/* * Send an OPAQUE message, contents opaque to zebra. The message header * is a message subtype. */ @@ -3697,16 +3984,12 @@ enum zclient_send_status zclient_send_opaque(struct zclient *zclient, return ZCLIENT_SEND_FAILURE; s = zclient->obuf; - stream_reset(s); - zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT); - - /* Send sub-type and flags */ - stream_putl(s, type); - stream_putw(s, flags); + zapi_opaque_init(zclient, type, flags); /* Send opaque data */ - stream_write(s, data, datasize); + if (datasize > 0) + stream_write(s, data, datasize); /* Put length into the header at the start of the stream. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -3733,22 +4016,14 @@ zclient_send_opaque_unicast(struct zclient *zclient, uint32_t type, return ZCLIENT_SEND_FAILURE; s = zclient->obuf; - stream_reset(s); - - zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT); - - /* Send sub-type and flags */ - SET_FLAG(flags, ZAPI_OPAQUE_FLAG_UNICAST); - stream_putl(s, type); - stream_putw(s, flags); - /* Send destination client info */ - stream_putc(s, proto); - stream_putw(s, instance); - stream_putl(s, session_id); + /* Common init */ + zapi_opaque_unicast_init(zclient, type, flags, proto, instance, + session_id); /* Send opaque data */ - stream_write(s, data, datasize); + if (datasize > 0) + stream_write(s, data, datasize); /* Put length into the header at the start of the stream. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -3767,11 +4042,16 @@ int zclient_opaque_decode(struct stream *s, struct zapi_opaque_msg *info) STREAM_GETL(s, info->type); STREAM_GETW(s, info->flags); - /* Decode unicast client info if present */ + /* Decode sending daemon info */ + STREAM_GETC(s, info->src_proto); + STREAM_GETW(s, info->src_instance); + STREAM_GETL(s, info->src_session_id); + + /* Decode unicast destination info, if present */ if (CHECK_FLAG(info->flags, ZAPI_OPAQUE_FLAG_UNICAST)) { - STREAM_GETC(s, info->proto); - STREAM_GETW(s, info->instance); - STREAM_GETL(s, info->session_id); + STREAM_GETC(s, info->dest_proto); + STREAM_GETW(s, info->dest_instance); + STREAM_GETL(s, info->dest_session_id); } info->len = STREAM_READABLE(s); @@ -3888,7 +4168,7 @@ static zclient_handler *const lib_handlers[] = { }; /* Zebra client message read function. */ -static void zclient_read(struct thread *thread) +static void zclient_read(struct event *thread) { size_t already; uint16_t length, command; @@ -3897,7 +4177,7 @@ static void zclient_read(struct thread *thread) struct zclient *zclient; /* Get socket to zebra. */ - zclient = THREAD_ARG(thread); + zclient = EVENT_ARG(thread); zclient->t_read = NULL; /* Read zebra header (if we don't have it already). */ @@ -4025,15 +4305,15 @@ void zclient_redistribute(int command, struct zclient *zclient, afi_t afi, } else { if (command == ZEBRA_REDISTRIBUTE_ADD) { - if (vrf_bitmap_check(zclient->redist[afi][type], + if (vrf_bitmap_check(&zclient->redist[afi][type], vrf_id)) return; - vrf_bitmap_set(zclient->redist[afi][type], vrf_id); + vrf_bitmap_set(&zclient->redist[afi][type], vrf_id); } else { - if (!vrf_bitmap_check(zclient->redist[afi][type], + if (!vrf_bitmap_check(&zclient->redist[afi][type], vrf_id)) return; - vrf_bitmap_unset(zclient->redist[afi][type], vrf_id); + vrf_bitmap_unset(&zclient->redist[afi][type], vrf_id); } } @@ -4048,14 +4328,15 @@ void zclient_redistribute_default(int command, struct zclient *zclient, { if (command == ZEBRA_REDISTRIBUTE_DEFAULT_ADD) { - if (vrf_bitmap_check(zclient->default_information[afi], vrf_id)) + if (vrf_bitmap_check(&zclient->default_information[afi], + vrf_id)) return; - vrf_bitmap_set(zclient->default_information[afi], vrf_id); + vrf_bitmap_set(&zclient->default_information[afi], vrf_id); } else { - if (!vrf_bitmap_check(zclient->default_information[afi], + if (!vrf_bitmap_check(&zclient->default_information[afi], vrf_id)) return; - vrf_bitmap_unset(zclient->default_information[afi], vrf_id); + vrf_bitmap_unset(&zclient->default_information[afi], vrf_id); } if (zclient->sock > 0) @@ -4066,22 +4347,22 @@ static void zclient_event(enum zclient_event event, struct zclient *zclient) { switch (event) { case ZCLIENT_SCHEDULE: - thread_add_event(zclient->master, zclient_connect, zclient, 0, - &zclient->t_connect); + event_add_event(zclient->master, zclient_connect, zclient, 0, + &zclient->t_connect); break; case ZCLIENT_CONNECT: if (zclient_debug) zlog_debug( "zclient connect failures: %d schedule interval is now %d", zclient->fail, zclient->fail < 3 ? 10 : 60); - thread_add_timer(zclient->master, zclient_connect, zclient, - zclient->fail < 3 ? 10 : 60, - &zclient->t_connect); + event_add_timer(zclient->master, zclient_connect, zclient, + zclient->fail < 3 ? 10 : 60, + &zclient->t_connect); break; case ZCLIENT_READ: zclient->t_read = NULL; - thread_add_read(zclient->master, zclient_read, zclient, - zclient->sock, &zclient->t_read); + event_add_read(zclient->master, zclient_read, zclient, + zclient->sock, &zclient->t_read); break; } } @@ -4156,6 +4437,8 @@ int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api) memset(api, 0, sizeof(*api)); + api->safi = SAFI_UNICAST; + STREAM_GETL(s, api->cap); switch (api->cap) { case ZEBRA_CLIENT_GR_CAPABILITIES: @@ -4327,3 +4610,125 @@ int zclient_send_zebra_gre_request(struct zclient *client, zclient_send_message(client); return 0; } + + +/* + * Opaque notification features + */ + +/* + * Common encode helper for opaque notifications, both registration + * and async notification messages. + */ +static int opaque_notif_encode_common(struct stream *s, uint32_t msg_type, + bool request, bool reg, uint8_t proto, + uint16_t instance, uint32_t session_id) +{ + int ret = 0; + uint8_t val = 0; + + stream_reset(s); + + zclient_create_header(s, ZEBRA_OPAQUE_NOTIFY, VRF_DEFAULT); + + /* Notification or request */ + if (request) + val = 1; + stream_putc(s, val); + + if (reg) + val = 1; + else + val = 0; + stream_putc(s, val); + + stream_putl(s, msg_type); + + stream_putc(s, proto); + stream_putw(s, instance); + stream_putl(s, session_id); + + /* And capture message length */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return ret; +} + +/* + * Encode a zapi opaque message type notification into buffer 's' + */ +int zclient_opaque_notif_encode(struct stream *s, uint32_t msg_type, bool reg, + uint8_t proto, uint16_t instance, + uint32_t session_id) +{ + return opaque_notif_encode_common(s, msg_type, false /* !request */, + reg, proto, instance, session_id); +} + +/* + * Decode an incoming zapi opaque message type notification + */ +int zclient_opaque_notif_decode(struct stream *s, + struct zapi_opaque_notif_info *info) +{ + uint8_t val; + + memset(info, 0, sizeof(*info)); + + STREAM_GETC(s, val); /* Registration or notification */ + info->request = (val != 0); + + STREAM_GETC(s, val); + info->reg = (val != 0); + + STREAM_GETL(s, info->msg_type); + + STREAM_GETC(s, info->proto); + STREAM_GETW(s, info->instance); + STREAM_GETL(s, info->session_id); + + return 0; + +stream_failure: + return -1; +} + +/* + * Encode and send a zapi opaque message type notification request to zebra + */ +enum zclient_send_status zclient_opaque_request_notify(struct zclient *zclient, + uint32_t msgtype) +{ + struct stream *s; + + if (!zclient || zclient->sock < 0) + return ZCLIENT_SEND_FAILURE; + + s = zclient->obuf; + + opaque_notif_encode_common(s, msgtype, true /* request */, + true /* register */, zclient->redist_default, + zclient->instance, zclient->session_id); + + return zclient_send_message(zclient); +} + +/* + * Encode and send a request to drop notifications for an opaque message type. + */ +enum zclient_send_status zclient_opaque_drop_notify(struct zclient *zclient, + uint32_t msgtype) +{ + struct stream *s; + + if (!zclient || zclient->sock < 0) + return ZCLIENT_SEND_FAILURE; + + s = zclient->obuf; + + opaque_notif_encode_common(s, msgtype, true /* req */, + false /* unreg */, zclient->redist_default, + zclient->instance, zclient->session_id); + + return zclient_send_message(zclient); +} |
