summaryrefslogtreecommitdiff
path: root/lib/zclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/zclient.c')
-rw-r--r--lib/zclient.c702
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);
+}