diff options
Diffstat (limited to 'lib/zclient.c')
| -rw-r--r-- | lib/zclient.c | 702 |
1 files changed, 578 insertions, 124 deletions
diff --git a/lib/zclient.c b/lib/zclient.c index 8526cbfaa1..4cbd04c116 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -41,8 +41,20 @@ static void zclient_event(enum zclient_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, - .synchronous = false}; +const struct zclient_options zclient_options_default = { + .synchronous = false, + .auxiliary = false, +}; + +const struct zclient_options zclient_options_sync = { + .synchronous = true, + .auxiliary = true, +}; + +const struct zclient_options zclient_options_auxiliary = { + .synchronous = false, + .auxiliary = true, +}; struct sockaddr_storage zclient_addr; socklen_t zclient_addr_len; @@ -52,7 +64,7 @@ static int zclient_debug; /* Allocate zclient structure. */ struct zclient *zclient_new(struct event_loop *master, - struct zclient_options *opt, + const struct zclient_options *opt, zclient_handler *const *handlers, size_t n_handlers) { struct zclient *zclient; @@ -69,8 +81,8 @@ struct zclient *zclient_new(struct event_loop *master, zclient->handlers = handlers; zclient->n_handlers = n_handlers; - zclient->receive_notify = opt->receive_notify; zclient->synchronous = opt->synchronous; + zclient->auxiliary = opt->auxiliary; return zclient; } @@ -180,14 +192,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; } } @@ -270,6 +282,7 @@ static void zclient_flush_data(struct event *thread) zclient->sock, &zclient->t_write); break; case BUFFER_EMPTY: + /* Currently only Sharpd and Bgpd has callbacks defined */ if (zclient->zebra_buffer_write_ready) (*zclient->zebra_buffer_write_ready)(); break; @@ -392,10 +405,6 @@ enum zclient_send_status zclient_send_hello(struct zclient *zclient) stream_putc(s, zclient->redist_default); stream_putw(s, zclient->instance); stream_putl(s, zclient->session_id); - if (zclient->receive_notify) - stream_putc(s, 1); - else - stream_putc(s, 0); if (zclient->synchronous) stream_putc(s, 1); else @@ -494,7 +503,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. */ @@ -524,15 +533,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); @@ -561,7 +570,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. */ @@ -591,15 +600,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); @@ -726,7 +735,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. */ @@ -738,7 +747,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) @@ -891,7 +900,7 @@ static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1, &next2->gate); if (ret != 0) return ret; - /* Intentional Fall-Through */ + fallthrough; case NEXTHOP_TYPE_IFINDEX: if (next1->ifindex < next2->ifindex) return -1; @@ -1061,10 +1070,11 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, sizeof(struct seg6local_context)); } - if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_SEG6)) - stream_write(s, &api_nh->seg6_segs, - sizeof(struct in6_addr)); - + if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_SEG6)) { + stream_putc(s, api_nh->seg_num); + stream_put(s, &api_nh->seg6_segs[0], + api_nh->seg_num * sizeof(struct in6_addr)); + } done: return ret; } @@ -1430,9 +1440,18 @@ int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, sizeof(struct seg6local_context)); } - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6)) - STREAM_GET(&api_nh->seg6_segs, s, - sizeof(struct in6_addr)); + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6)) { + STREAM_GETC(s, api_nh->seg_num); + if (api_nh->seg_num > SRV6_MAX_SIDS) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: invalid number of SRv6 Segs (%u)", + __func__, api_nh->seg_num); + return -1; + } + + STREAM_GET(&api_nh->seg6_segs[0], s, + api_nh->seg_num * sizeof(struct in6_addr)); + } /* Success */ ret = 0; @@ -1611,30 +1630,237 @@ 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; +} + +static void zapi_encode_sockunion(struct stream *s, const union sockunion *su) +{ + int family = sockunion_family(su); + size_t addrlen = family2addrsize(family); + + /* + * Must know length to encode + */ + assert(addrlen); + + stream_putc(s, (uint8_t)family); + + stream_write(s, sockunion_get_addr(su), addrlen); +} + +static bool zapi_decode_sockunion(struct stream *s, union sockunion *su) +{ + uint8_t family; + size_t addrlen; + uint8_t buf[sizeof(union sockunion)]; + + memset(su, 0, sizeof(*su)); + + STREAM_GETC(s, family); + sockunion_family(su) = family; + + addrlen = family2addrsize(family); + if (!addrlen) + return false; + + if (addrlen > sizeof(buf)) + return false; + + STREAM_GET(buf, s, addrlen); + sockunion_set(su, family, buf, addrlen); + 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); + + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_IP_PROTOCOL)) + stream_putc(s, f->ip_proto); + + /* addresses */ + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_SRC_IP)) + zapi_encode_prefix(s, &f->src_ip, f->src_ip.family); + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DST_IP)) + zapi_encode_prefix(s, &f->dst_ip, f->dst_ip.family); + + /* port numbers */ + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_SRC_PORT)) + stream_putw(s, f->src_port); + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DST_PORT)) + stream_putw(s, f->dst_port); + + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DSCP)) + stream_putc(s, f->dsfield & PBR_DSFIELD_DSCP); + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_ECN)) + stream_putc(s, f->dsfield & PBR_DSFIELD_ECN); + + /* vlan */ + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_PCP)) + stream_putc(s, f->pcp); + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_VLAN_ID)) + stream_putw(s, f->vlan_id); + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_VLAN_FLAGS)) + stream_putw(s, f->vlan_flags); + + + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_FWMARK)) + stream_putl(s, f->fwmark); +} + +static bool zapi_pbr_rule_filter_decode(struct stream *s, struct pbr_filter *f) +{ + uint8_t dscp = 0; + uint8_t ecn = 0; + + STREAM_GETL(s, f->filter_bm); + + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_IP_PROTOCOL)) + STREAM_GETC(s, f->ip_proto); + + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_SRC_IP)) + if (!zapi_decode_prefix(s, &(f->src_ip))) + goto stream_failure; + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DST_IP)) + if (!zapi_decode_prefix(s, &(f->dst_ip))) + goto stream_failure; + + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_SRC_PORT)) + STREAM_GETW(s, f->src_port); + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DST_PORT)) + STREAM_GETW(s, f->dst_port); + + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DSCP)) + STREAM_GETC(s, dscp); + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_ECN)) + STREAM_GETC(s, ecn); + f->dsfield = (dscp & PBR_DSFIELD_DSCP) | (ecn & PBR_DSFIELD_ECN); + + /* vlan */ + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_PCP)) + STREAM_GETC(s, f->pcp); + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_VLAN_ID)) + STREAM_GETW(s, f->vlan_id); + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_VLAN_FLAGS)) + STREAM_GETW(s, f->vlan_flags); + + if (CHECK_FLAG(f->filter_bm, PBR_FILTER_FWMARK)) + 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); + + if (CHECK_FLAG(a->flags, PBR_ACTION_TABLE)) + stream_putl(s, a->table); + if (CHECK_FLAG(a->flags, PBR_ACTION_QUEUE_ID)) + stream_putl(s, a->queue_id); + + /* L3 */ + if (CHECK_FLAG(a->flags, PBR_ACTION_SRC_IP)) + zapi_encode_sockunion(s, &a->src_ip); + if (CHECK_FLAG(a->flags, PBR_ACTION_DST_IP)) + zapi_encode_sockunion(s, &a->dst_ip); + if (CHECK_FLAG(a->flags, PBR_ACTION_SRC_PORT)) + stream_putw(s, a->src_port); + if (CHECK_FLAG(a->flags, PBR_ACTION_DST_PORT)) + stream_putw(s, a->dst_port); + + if (CHECK_FLAG(a->flags, PBR_ACTION_DSCP)) + stream_putc(s, a->dscp & PBR_DSFIELD_DSCP); + if (CHECK_FLAG(a->flags, PBR_ACTION_ECN)) + stream_putc(s, a->ecn & PBR_DSFIELD_ECN); + + /* L2 */ + if (CHECK_FLAG(a->flags, PBR_ACTION_PCP)) + stream_putc(s, a->pcp); + if (CHECK_FLAG(a->flags, PBR_ACTION_VLAN_ID)) + stream_putw(s, a->vlan_id); +} + +static bool zapi_pbr_rule_action_decode(struct stream *s, struct pbr_action *a) +{ + STREAM_GETL(s, a->flags); + + if (CHECK_FLAG(a->flags, PBR_ACTION_TABLE)) + STREAM_GETL(s, a->table); + if (CHECK_FLAG(a->flags, PBR_ACTION_QUEUE_ID)) + STREAM_GETL(s, a->queue_id); + + /* L3 */ + if (CHECK_FLAG(a->flags, PBR_ACTION_SRC_IP)) { + if (!zapi_decode_sockunion(s, &(a->src_ip))) + goto stream_failure; + } + if (CHECK_FLAG(a->flags, PBR_ACTION_DST_IP)) + if (!zapi_decode_sockunion(s, &(a->dst_ip))) + goto stream_failure; + + if (CHECK_FLAG(a->flags, PBR_ACTION_SRC_PORT)) + STREAM_GETW(s, a->src_port); + if (CHECK_FLAG(a->flags, PBR_ACTION_DST_PORT)) + STREAM_GETW(s, a->dst_port); + + if (CHECK_FLAG(a->flags, PBR_ACTION_DSCP)) { + STREAM_GETC(s, a->dscp); + a->dscp &= PBR_DSFIELD_DSCP; + } + if (CHECK_FLAG(a->flags, PBR_ACTION_ECN)) { + STREAM_GETC(s, a->ecn); + a->ecn &= PBR_DSFIELD_ECN; + } + + /* L2 */ + if (CHECK_FLAG(a->flags, PBR_ACTION_PCP)) + STREAM_GETC(s, a->pcp); + if (CHECK_FLAG(a->flags, PBR_ACTION_VLAN_ID)) + STREAM_GETW(s, a->vlan_id); + 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_putc(s, r->family); + 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, IFNAMSIZ); /* Put length at the first point of the stream. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -1642,6 +1868,29 @@ 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_GETC(s, r->family); + 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, IFNAMSIZ); + return true; + +stream_failure: + return false; +} + int zapi_tc_qdisc_encode(uint8_t cmd, struct stream *s, struct tc_qdisc *qdisc) { stream_reset(s); @@ -1794,7 +2043,7 @@ bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno, STREAM_GETL(s, seq); STREAM_GETL(s, prio); STREAM_GETL(s, uni); - STREAM_GET(ifname, s, INTERFACE_NAMSIZ); + STREAM_GET(ifname, s, IFNAMSIZ); if (zclient_debug) zlog_debug("%s: %u %u %u %s", __func__, seq, prio, uni, ifname); @@ -1902,8 +2151,8 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) nexthop_add_srv6_seg6local(n, znh->seg6local_action, &znh->seg6local_ctx); - if (!sid_zero(&znh->seg6_segs)) - nexthop_add_srv6_seg6(n, &znh->seg6_segs); + if (znh->seg_num && !sid_zero_ipv6(znh->seg6_segs)) + nexthop_add_srv6_seg6(n, &znh->seg6_segs[0], znh->seg_num); return n; } @@ -1963,10 +2212,14 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, sizeof(struct seg6local_context)); } - if (!sid_zero(&nh->nh_srv6->seg6_segs)) { + if (nh->nh_srv6->seg6_segs && nh->nh_srv6->seg6_segs->num_segs && + !sid_zero(nh->nh_srv6->seg6_segs)) { SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6); - memcpy(&znh->seg6_segs, &nh->nh_srv6->seg6_segs, - sizeof(struct in6_addr)); + znh->seg_num = nh->nh_srv6->seg6_segs->num_segs; + for (i = 0; i < nh->nh_srv6->seg6_segs->num_segs; i++) + memcpy(&znh->seg6_segs[i], + &nh->nh_srv6->seg6_segs->seg[i], + sizeof(struct in6_addr)); } } @@ -2025,8 +2278,8 @@ const char *zapi_nexthop2str(const struct zapi_nexthop *znh, char *buf, /* * Decode the nexthop-tracking update message */ -bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match, - struct zapi_route *nhr) +static bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match, + struct zapi_route *nhr) { uint32_t i; @@ -2282,12 +2535,12 @@ static int zclient_vrf_delete(ZAPI_CALLBACK_ARGS) static int zclient_interface_add(ZAPI_CALLBACK_ARGS) { struct interface *ifp; - char ifname_tmp[INTERFACE_NAMSIZ + 1] = {}; + char ifname_tmp[IFNAMSIZ + 1] = {}; struct stream *s = zclient->ibuf; struct vrf *vrf; /* Read interface name. */ - STREAM_GET(ifname_tmp, s, INTERFACE_NAMSIZ); + STREAM_GET(ifname_tmp, s, IFNAMSIZ); /* Lookup/create interface by name. */ vrf = vrf_lookup_by_id(vrf_id); @@ -2318,10 +2571,10 @@ stream_failure: struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id) { struct interface *ifp; - char ifname_tmp[INTERFACE_NAMSIZ + 1] = {}; + char ifname_tmp[IFNAMSIZ + 1] = {}; /* Read interface name. */ - STREAM_GET(ifname_tmp, s, INTERFACE_NAMSIZ); + STREAM_GET(ifname_tmp, s, IFNAMSIZ); /* Lookup this by interface index. */ ifp = if_lookup_by_name(ifname_tmp, vrf_id); @@ -2531,6 +2784,7 @@ static void zebra_interface_if_set_value(struct stream *s, STREAM_GETC(s, ifp->ptm_status); STREAM_GETL(s, ifp->metric); STREAM_GETL(s, ifp->speed); + STREAM_GETL(s, ifp->txqlen); STREAM_GETL(s, ifp->mtu); STREAM_GETL(s, ifp->mtu6); STREAM_GETL(s, ifp->bandwidth); @@ -2806,36 +3060,6 @@ stream_failure: return NULL; } -struct interface *zebra_interface_vrf_update_read(struct stream *s, - vrf_id_t vrf_id, - vrf_id_t *new_vrf_id) -{ - char ifname[INTERFACE_NAMSIZ + 1] = {}; - struct interface *ifp; - vrf_id_t new_id; - - /* Read interface name. */ - STREAM_GET(ifname, s, INTERFACE_NAMSIZ); - - /* Lookup interface. */ - ifp = if_lookup_by_name(ifname, vrf_id); - if (ifp == NULL) { - flog_err(EC_LIB_ZAPI_ENCODE, - "INTERFACE_VRF_UPDATE: Cannot find IF %s in VRF %d", - ifname, vrf_id); - return NULL; - } - - /* Fetch new VRF Id. */ - STREAM_GETL(s, new_id); - - *new_vrf_id = new_id; - return ifp; - -stream_failure: - return NULL; -} - /* filter unwanted messages until the expected one arrives */ static int zclient_read_sync_response(struct zclient *zclient, uint16_t expected_cmd) @@ -3701,7 +3925,7 @@ enum zclient_send_status zebra_send_pw(struct zclient *zclient, int command, stream_reset(s); zclient_create_header(s, command, VRF_DEFAULT); - stream_write(s, pw->ifname, INTERFACE_NAMSIZ); + stream_write(s, pw->ifname, IFNAMSIZ); stream_putl(s, pw->ifindex); /* Put type */ @@ -3748,7 +3972,7 @@ int zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_status *pw) s = zclient->ibuf; /* Get data. */ - stream_get(pw->ifname, s, INTERFACE_NAMSIZ); + stream_get(pw->ifname, s, IFNAMSIZ); STREAM_GETL(s, pw->ifindex); STREAM_GETL(s, pw->status); @@ -3779,6 +4003,7 @@ static int zclient_capability_decode(ZAPI_CALLBACK_ARGS) cap.mpls_enabled = !!mpls_enabled; STREAM_GETL(s, cap.ecmp); STREAM_GETC(s, cap.role); + STREAM_GETC(s, cap.v6_with_v4_nexthop); if (zclient->zebra_capabilities) (*zclient->zebra_capabilities)(&cap); @@ -3824,6 +4049,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. */ @@ -3840,16 +4112,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)); @@ -3876,22 +4144,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)); @@ -3910,11 +4170,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); @@ -4012,6 +4277,28 @@ stream_failure: return -1; } +static int zclient_nexthop_update(ZAPI_CALLBACK_ARGS) +{ + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + struct prefix match; + struct zapi_route route; + + if (!vrf) { + zlog_warn("nexthop update for unknown VRF ID %u", vrf_id); + return 0; + } + + if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &route)) { + zlog_err("failed to decode nexthop update"); + return -1; + } + + if (zclient->nexthop_update) + zclient->nexthop_update(vrf, &match, &route); + + return 0; +} + static zclient_handler *const lib_handlers[] = { /* fundamentals */ [ZEBRA_CAPABILITIES] = zclient_capability_decode, @@ -4025,6 +4312,9 @@ static zclient_handler *const lib_handlers[] = { [ZEBRA_INTERFACE_UP] = zclient_interface_up, [ZEBRA_INTERFACE_DOWN] = zclient_interface_down, + /* NHT pre-decode */ + [ZEBRA_NEXTHOP_UPDATE] = zclient_nexthop_update, + /* BFD */ [ZEBRA_BFD_DEST_REPLAY] = zclient_bfd_session_replay, [ZEBRA_INTERFACE_BFD_DEST_UPDATE] = zclient_bfd_session_update, @@ -4133,7 +4423,8 @@ static void zclient_read(struct event *thread) zlog_debug("zclient %p command %s VRF %u", zclient, zserv_command_string(command), vrf_id); - if (command < array_size(lib_handlers) && lib_handlers[command]) + if (!zclient->auxiliary && command < array_size(lib_handlers) && + lib_handlers[command]) lib_handlers[command](command, zclient, length, vrf_id); if (command < zclient->n_handlers && zclient->handlers[command]) zclient->handlers[command](command, zclient, length, vrf_id); @@ -4168,15 +4459,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); } } @@ -4191,14 +4482,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) @@ -4229,6 +4521,24 @@ static void zclient_event(enum zclient_event event, struct zclient *zclient) } } +enum zclient_send_status zclient_interface_set_arp(struct zclient *client, + struct interface *ifp, + bool arp_enable) +{ + struct stream *s; + + s = client->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_INTERFACE_SET_ARP, ifp->vrf->vrf_id); + + stream_putl(s, ifp->ifindex); + stream_putc(s, arp_enable); + + stream_putw_at(s, 0, stream_get_endp(s)); + return zclient_send_message(client); +} + enum zclient_send_status zclient_interface_set_master(struct zclient *client, struct interface *master, struct interface *slave) @@ -4418,7 +4728,7 @@ static int zclient_neigh_ip_read_entry(struct stream *s, struct ipaddr *add) int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in, union sockunion *out, struct interface *ifp, - int ndm_state) + int ndm_state, int ip_len) { int ret = 0; @@ -4431,6 +4741,7 @@ int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in, sockunion_get_addrlen(out)); } else stream_putc(s, AF_UNSPEC); + stream_putl(s, ip_len); stream_putl(s, ifp->ifindex); if (out) stream_putl(s, ndm_state); @@ -4448,6 +4759,7 @@ int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api) return -1; zclient_neigh_ip_read_entry(s, &api->ip_out); + STREAM_GETL(s, api->ip_len); STREAM_GETL(s, api->index); STREAM_GETL(s, api->ndm_state); return 0; @@ -4472,3 +4784,145 @@ 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); +} + +void zclient_register_neigh(struct zclient *zclient, vrf_id_t vrf_id, afi_t afi, + bool reg) +{ + struct stream *s; + + if (!zclient || zclient->sock < 0) + return; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, + reg ? ZEBRA_NEIGH_REGISTER + : ZEBRA_NEIGH_UNREGISTER, + vrf_id); + stream_putw(s, afi); + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(zclient); +} |
