+ vl_api_ip_add_del_route_t *mp;
+ u32 sw_if_index = ~0, vrf_id = 0;
+ u8 is_ipv6 = 0;
+ u8 is_local = 0, is_drop = 0;
+ u8 is_unreach = 0, is_prohibit = 0;
+ u8 is_add = 1;
+ u32 next_hop_weight = 1;
+ u8 is_multipath = 0;
+ u8 address_set = 0;
+ u8 address_length_set = 0;
+ u32 next_hop_table_id = 0;
+ u32 resolve_attempts = 0;
+ u32 dst_address_length = 0;
+ u8 next_hop_set = 0;
+ ip4_address_t v4_dst_address, v4_next_hop_address;
+ ip6_address_t v6_dst_address, v6_next_hop_address;
+ int count = 1;
+ int j;
+ f64 before = 0;
+ u32 random_add_del = 0;
+ u32 *random_vector = 0;
+ uword *random_hash;
+ u32 random_seed = 0xdeaddabe;
+ u32 classify_table_index = ~0;
+ u8 is_classify = 0;
+ u8 resolve_host = 0, resolve_attached = 0;
+ vl_api_fib_mpls_label_t *next_hop_out_label_stack = NULL;
+ mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID;
+ mpls_label_t next_hop_via_label = MPLS_LABEL_INVALID;
+
+ clib_memset (&v4_next_hop_address, 0, sizeof (ip4_address_t));
+ clib_memset (&v6_next_hop_address, 0, sizeof (ip6_address_t));
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+ ;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ ;
+ else if (unformat (i, "%U", unformat_ip4_address, &v4_dst_address))
+ {
+ address_set = 1;
+ is_ipv6 = 0;
+ }
+ else if (unformat (i, "%U", unformat_ip6_address, &v6_dst_address))
+ {
+ address_set = 1;
+ is_ipv6 = 1;
+ }
+ else if (unformat (i, "/%d", &dst_address_length))
+ {
+ address_length_set = 1;
+ }
+
+ else if (is_ipv6 == 0 && unformat (i, "via %U", unformat_ip4_address,
+ &v4_next_hop_address))
+ {
+ next_hop_set = 1;
+ }
+ else if (is_ipv6 == 1 && unformat (i, "via %U", unformat_ip6_address,
+ &v6_next_hop_address))
+ {
+ next_hop_set = 1;
+ }
+ else
+ if (unformat
+ (i, "via %U", api_unformat_sw_if_index, vam, &sw_if_index))
+ {
+ next_hop_set = 1;
+ }
+ else if (unformat (i, "via sw_if_index %d", &sw_if_index))
+ {
+ next_hop_set = 1;
+ }
+ else if (unformat (i, "resolve-attempts %d", &resolve_attempts))
+ ;
+ else if (unformat (i, "weight %d", &next_hop_weight))
+ ;
+ else if (unformat (i, "drop"))
+ {
+ is_drop = 1;
+ }
+ else if (unformat (i, "null-send-unreach"))
+ {
+ is_unreach = 1;
+ }
+ else if (unformat (i, "null-send-prohibit"))
+ {
+ is_prohibit = 1;
+ }
+ else if (unformat (i, "local"))
+ {
+ is_local = 1;
+ }
+ else if (unformat (i, "classify %d", &classify_table_index))
+ {
+ is_classify = 1;
+ }
+ else if (unformat (i, "del"))
+ is_add = 0;
+ else if (unformat (i, "add"))
+ is_add = 1;
+ else if (unformat (i, "resolve-via-host"))
+ resolve_host = 1;
+ else if (unformat (i, "resolve-via-attached"))
+ resolve_attached = 1;
+ else if (unformat (i, "multipath"))
+ is_multipath = 1;
+ else if (unformat (i, "vrf %d", &vrf_id))
+ ;
+ else if (unformat (i, "count %d", &count))
+ ;
+ else if (unformat (i, "lookup-in-vrf %d", &next_hop_table_id))
+ ;
+ else if (unformat (i, "next-hop-table %d", &next_hop_table_id))
+ ;
+ else if (unformat (i, "out-label %d", &next_hop_out_label))
+ {
+ vl_api_fib_mpls_label_t fib_label = {
+ .label = ntohl (next_hop_out_label),
+ .ttl = 64,
+ .exp = 0,
+ };
+ vec_add1 (next_hop_out_label_stack, fib_label);
+ }
+ else if (unformat (i, "via via-label %d", &next_hop_via_label))
+ ;
+ else if (unformat (i, "random"))
+ random_add_del = 1;
+ else if (unformat (i, "seed %d", &random_seed))
+ ;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (!next_hop_set && !is_drop && !is_local &&
+ !is_classify && !is_unreach && !is_prohibit &&
+ MPLS_LABEL_INVALID == next_hop_via_label)
+ {
+ errmsg
+ ("next hop / local / drop / unreach / prohibit / classify not set");
+ return -99;
+ }
+
+ if (next_hop_set && MPLS_LABEL_INVALID != next_hop_via_label)
+ {
+ errmsg ("next hop and next-hop via label set");
+ return -99;
+ }
+ if (address_set == 0)
+ {
+ errmsg ("missing addresses");
+ return -99;
+ }
+
+ if (address_length_set == 0)
+ {
+ errmsg ("missing address length");
+ return -99;
+ }
+
+ /* Generate a pile of unique, random routes */
+ if (random_add_del)
+ {
+ u32 this_random_address;
+ random_hash = hash_create (count, sizeof (uword));
+
+ hash_set (random_hash, v4_next_hop_address.as_u32, 1);
+ for (j = 0; j <= count; j++)
+ {
+ do
+ {
+ this_random_address = random_u32 (&random_seed);
+ this_random_address =
+ clib_host_to_net_u32 (this_random_address);
+ }
+ while (hash_get (random_hash, this_random_address));
+ vec_add1 (random_vector, this_random_address);
+ hash_set (random_hash, this_random_address, 1);
+ }
+ hash_free (random_hash);
+ v4_dst_address.as_u32 = random_vector[0];
+ }
+
+ if (count > 1)
+ {
+ /* Turn on async mode */
+ vam->async_mode = 1;
+ vam->async_errors = 0;
+ before = vat_time_now (vam);
+ }
+
+ for (j = 0; j < count; j++)
+ {
+ /* Construct the API message */
+ M2 (IP_ADD_DEL_ROUTE, mp, sizeof (vl_api_fib_mpls_label_t) *
+ vec_len (next_hop_out_label_stack));
+
+ mp->next_hop_sw_if_index = ntohl (sw_if_index);
+ mp->table_id = ntohl (vrf_id);
+
+ mp->is_add = is_add;
+ mp->is_drop = is_drop;
+ mp->is_unreach = is_unreach;
+ mp->is_prohibit = is_prohibit;
+ mp->is_ipv6 = is_ipv6;
+ mp->is_local = is_local;
+ mp->is_classify = is_classify;
+ mp->is_multipath = is_multipath;
+ mp->is_resolve_host = resolve_host;
+ mp->is_resolve_attached = resolve_attached;
+ mp->next_hop_weight = next_hop_weight;
+ mp->next_hop_preference = 0;
+ mp->dst_address_length = dst_address_length;
+ mp->next_hop_table_id = ntohl (next_hop_table_id);
+ mp->classify_table_index = ntohl (classify_table_index);
+ mp->next_hop_via_label = ntohl (next_hop_via_label);
+ mp->next_hop_n_out_labels = vec_len (next_hop_out_label_stack);
+ if (0 != mp->next_hop_n_out_labels)
+ {
+ memcpy (mp->next_hop_out_label_stack,
+ next_hop_out_label_stack,
+ (vec_len (next_hop_out_label_stack) *
+ sizeof (vl_api_fib_mpls_label_t)));
+ vec_free (next_hop_out_label_stack);
+ }
+
+ if (is_ipv6)
+ {
+ clib_memcpy (mp->dst_address, &v6_dst_address,
+ sizeof (v6_dst_address));
+ if (next_hop_set)
+ clib_memcpy (mp->next_hop_address, &v6_next_hop_address,
+ sizeof (v6_next_hop_address));
+ increment_v6_address (&v6_dst_address);
+ }
+ else
+ {
+ clib_memcpy (mp->dst_address, &v4_dst_address,
+ sizeof (v4_dst_address));
+ if (next_hop_set)
+ clib_memcpy (mp->next_hop_address, &v4_next_hop_address,
+ sizeof (v4_next_hop_address));
+ if (random_add_del)
+ v4_dst_address.as_u32 = random_vector[j + 1];
+ else
+ increment_v4_address (&v4_dst_address);
+ }
+ /* send it... */
+ S (mp);
+ /* If we receive SIGTERM, stop now... */
+ if (vam->do_exit)
+ break;
+ }
+
+ /* When testing multiple add/del ops, use a control-ping to sync */
+ if (count > 1)
+ {
+ vl_api_control_ping_t *mp_ping;
+ f64 after;
+ f64 timeout;
+
+ /* Shut off async mode */
+ vam->async_mode = 0;
+
+ MPING (CONTROL_PING, mp_ping);
+ S (mp_ping);
+
+ timeout = vat_time_now (vam) + 1.0;
+ while (vat_time_now (vam) < timeout)
+ if (vam->result_ready == 1)
+ goto out;
+ vam->retval = -99;
+
+ out:
+ if (vam->retval == -99)
+ errmsg ("timeout");
+
+ if (vam->async_errors > 0)
+ {
+ errmsg ("%d asynchronous errors", vam->async_errors);
+ vam->retval = -98;
+ }
+ vam->async_errors = 0;
+ after = vat_time_now (vam);
+
+ /* slim chance, but we might have eaten SIGTERM on the first iteration */
+ if (j > 0)
+ count = j;
+
+ print (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec",
+ count, after - before, count / (after - before));
+ }
+ else
+ {
+ int ret;
+
+ /* Wait for a reply... */
+ W (ret);
+ return ret;
+ }
+
+ /* Return the good/bad news */
+ return (vam->retval);
+}
+
+static int
+api_ip_mroute_add_del (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_ip_mroute_add_del_t *mp;
+ u32 sw_if_index = ~0, vrf_id = 0;
+ u8 is_ipv6 = 0;
+ u8 is_local = 0;
+ u8 is_add = 1;
+ u8 address_set = 0;
+ u32 grp_address_length = 0;
+ ip4_address_t v4_grp_address, v4_src_address;
+ ip6_address_t v6_grp_address, v6_src_address;
+ mfib_itf_flags_t iflags = 0;
+ mfib_entry_flags_t eflags = 0;
+ int ret;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "sw_if_index %d", &sw_if_index))
+ ;
+ else if (unformat (i, "%U %U",
+ unformat_ip4_address, &v4_src_address,
+ unformat_ip4_address, &v4_grp_address))
+ {
+ grp_address_length = 64;
+ address_set = 1;
+ is_ipv6 = 0;
+ }
+ else if (unformat (i, "%U %U",
+ unformat_ip6_address, &v6_src_address,
+ unformat_ip6_address, &v6_grp_address))
+ {
+ grp_address_length = 256;
+ address_set = 1;
+ is_ipv6 = 1;
+ }
+ else if (unformat (i, "%U", unformat_ip4_address, &v4_grp_address))
+ {
+ clib_memset (&v4_src_address, 0, sizeof (v4_src_address));
+ grp_address_length = 32;
+ address_set = 1;
+ is_ipv6 = 0;
+ }
+ else if (unformat (i, "%U", unformat_ip6_address, &v6_grp_address))
+ {
+ clib_memset (&v6_src_address, 0, sizeof (v6_src_address));
+ grp_address_length = 128;
+ address_set = 1;
+ is_ipv6 = 1;
+ }
+ else if (unformat (i, "/%d", &grp_address_length))
+ ;
+ else if (unformat (i, "local"))
+ {
+ is_local = 1;
+ }
+ else if (unformat (i, "del"))
+ is_add = 0;
+ else if (unformat (i, "add"))
+ is_add = 1;
+ else if (unformat (i, "vrf %d", &vrf_id))
+ ;
+ else if (unformat (i, "%U", unformat_mfib_itf_flags, &iflags))
+ ;
+ else if (unformat (i, "%U", unformat_mfib_entry_flags, &eflags))
+ ;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (address_set == 0)
+ {
+ errmsg ("missing addresses\n");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M (IP_MROUTE_ADD_DEL, mp);
+
+ mp->next_hop_sw_if_index = ntohl (sw_if_index);
+ mp->table_id = ntohl (vrf_id);
+
+ mp->is_add = is_add;
+ mp->is_ipv6 = is_ipv6;
+ mp->is_local = is_local;
+ mp->itf_flags = ntohl (iflags);
+ mp->entry_flags = ntohl (eflags);
+ mp->grp_address_length = grp_address_length;
+ mp->grp_address_length = ntohs (mp->grp_address_length);
+
+ if (is_ipv6)
+ {
+ clib_memcpy (mp->grp_address, &v6_grp_address, sizeof (v6_grp_address));
+ clib_memcpy (mp->src_address, &v6_src_address, sizeof (v6_src_address));
+ }
+ else
+ {
+ clib_memcpy (mp->grp_address, &v4_grp_address, sizeof (v4_grp_address));
+ clib_memcpy (mp->src_address, &v4_src_address, sizeof (v4_src_address));
+
+ }
+
+ /* send it... */
+ S (mp);
+ /* Wait for a reply... */
+ W (ret);
+ return ret;
+}
+
+static int
+api_mpls_table_add_del (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_mpls_table_add_del_t *mp;
+ u32 table_id = ~0;
+ u8 is_add = 1;
+ int ret = 0;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "table %d", &table_id))
+ ;
+ else if (unformat (i, "del"))
+ is_add = 0;
+ else if (unformat (i, "add"))
+ is_add = 1;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (~0 == table_id)
+ {
+ errmsg ("missing table-ID");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M (MPLS_TABLE_ADD_DEL, mp);
+
+ mp->mt_table_id = ntohl (table_id);
+ mp->mt_is_add = is_add;
+
+ /* send it... */
+ S (mp);
+
+ /* Wait for a reply... */
+ W (ret);
+
+ return ret;
+}
+
+static int
+api_mpls_route_add_del (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_mpls_route_add_del_t *mp;
+ u32 sw_if_index = ~0, table_id = 0;
+ u8 is_add = 1;
+ u32 next_hop_weight = 1;
+ u8 is_multipath = 0;
+ u32 next_hop_table_id = 0;
+ u8 next_hop_set = 0;
+ ip4_address_t v4_next_hop_address = {
+ .as_u32 = 0,
+ };
+ ip6_address_t v6_next_hop_address = { {0} };
+ int count = 1;
+ int j;
+ f64 before = 0;
+ u32 classify_table_index = ~0;
+ u8 is_classify = 0;
+ u8 resolve_host = 0, resolve_attached = 0;
+ u8 is_interface_rx = 0;
+ mpls_label_t next_hop_via_label = MPLS_LABEL_INVALID;
+ mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID;
+ vl_api_fib_mpls_label_t *next_hop_out_label_stack = NULL;
+ mpls_label_t local_label = MPLS_LABEL_INVALID;
+ u8 is_eos = 0;
+ dpo_proto_t next_hop_proto = DPO_PROTO_MPLS;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+ ;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ ;
+ else if (unformat (i, "%d", &local_label))
+ ;
+ else if (unformat (i, "eos"))
+ is_eos = 1;
+ else if (unformat (i, "non-eos"))
+ is_eos = 0;
+ else if (unformat (i, "via %U", unformat_ip4_address,
+ &v4_next_hop_address))
+ {
+ next_hop_set = 1;
+ next_hop_proto = DPO_PROTO_IP4;
+ }
+ else if (unformat (i, "via %U", unformat_ip6_address,
+ &v6_next_hop_address))
+ {
+ next_hop_set = 1;
+ next_hop_proto = DPO_PROTO_IP6;
+ }
+ else if (unformat (i, "weight %d", &next_hop_weight))
+ ;
+ else if (unformat (i, "classify %d", &classify_table_index))
+ {
+ is_classify = 1;
+ }
+ else if (unformat (i, "del"))
+ is_add = 0;
+ else if (unformat (i, "add"))
+ is_add = 1;
+ else if (unformat (i, "resolve-via-host"))
+ resolve_host = 1;
+ else if (unformat (i, "resolve-via-attached"))
+ resolve_attached = 1;
+ else if (unformat (i, "multipath"))
+ is_multipath = 1;
+ else if (unformat (i, "count %d", &count))
+ ;
+ else if (unformat (i, "via lookup-in-ip4-table %d", &next_hop_table_id))
+ {
+ next_hop_set = 1;
+ next_hop_proto = DPO_PROTO_IP4;
+ }
+ else if (unformat (i, "via lookup-in-ip6-table %d", &next_hop_table_id))
+ {
+ next_hop_set = 1;
+ next_hop_proto = DPO_PROTO_IP6;
+ }
+ else
+ if (unformat
+ (i, "via l2-input-on %U", api_unformat_sw_if_index, vam,
+ &sw_if_index))
+ {
+ next_hop_set = 1;
+ next_hop_proto = DPO_PROTO_ETHERNET;
+ is_interface_rx = 1;
+ }
+ else if (unformat (i, "via l2-input-on sw_if_index %d", &sw_if_index))
+ {
+ next_hop_set = 1;
+ next_hop_proto = DPO_PROTO_ETHERNET;
+ is_interface_rx = 1;
+ }
+ else if (unformat (i, "via next-hop-table %d", &next_hop_table_id))
+ next_hop_set = 1;
+ else if (unformat (i, "via via-label %d", &next_hop_via_label))
+ next_hop_set = 1;
+ else if (unformat (i, "out-label %d", &next_hop_out_label))
+ {
+ vl_api_fib_mpls_label_t fib_label = {
+ .label = ntohl (next_hop_out_label),
+ .ttl = 64,
+ .exp = 0,
+ };
+ vec_add1 (next_hop_out_label_stack, fib_label);
+ }
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (!next_hop_set && !is_classify)
+ {
+ errmsg ("next hop / classify not set");
+ return -99;
+ }
+
+ if (MPLS_LABEL_INVALID == local_label)
+ {
+ errmsg ("missing label");
+ return -99;
+ }
+
+ if (count > 1)
+ {
+ /* Turn on async mode */
+ vam->async_mode = 1;
+ vam->async_errors = 0;
+ before = vat_time_now (vam);
+ }
+
+ for (j = 0; j < count; j++)
+ {
+ /* Construct the API message */
+ M2 (MPLS_ROUTE_ADD_DEL, mp, sizeof (vl_api_fib_mpls_label_t) *
+ vec_len (next_hop_out_label_stack));
+
+ mp->mr_next_hop_sw_if_index = ntohl (sw_if_index);
+ mp->mr_table_id = ntohl (table_id);
+
+ mp->mr_is_add = is_add;
+ mp->mr_next_hop_proto = next_hop_proto;
+ mp->mr_is_classify = is_classify;
+ mp->mr_is_multipath = is_multipath;
+ mp->mr_is_resolve_host = resolve_host;
+ mp->mr_is_resolve_attached = resolve_attached;
+ mp->mr_is_interface_rx = is_interface_rx;
+ mp->mr_next_hop_weight = next_hop_weight;
+ mp->mr_next_hop_preference = 0;
+ mp->mr_next_hop_table_id = ntohl (next_hop_table_id);
+ mp->mr_classify_table_index = ntohl (classify_table_index);
+ mp->mr_next_hop_via_label = ntohl (next_hop_via_label);
+ mp->mr_label = ntohl (local_label);
+ mp->mr_eos = is_eos;
+
+ mp->mr_next_hop_n_out_labels = vec_len (next_hop_out_label_stack);
+ if (0 != mp->mr_next_hop_n_out_labels)
+ {
+ memcpy (mp->mr_next_hop_out_label_stack,
+ next_hop_out_label_stack,
+ vec_len (next_hop_out_label_stack) *
+ sizeof (vl_api_fib_mpls_label_t));
+ vec_free (next_hop_out_label_stack);
+ }
+
+ if (next_hop_set)
+ {
+ if (DPO_PROTO_IP4 == next_hop_proto)
+ {
+ clib_memcpy (mp->mr_next_hop,
+ &v4_next_hop_address,
+ sizeof (v4_next_hop_address));
+ }
+ else if (DPO_PROTO_IP6 == next_hop_proto)
+
+ {
+ clib_memcpy (mp->mr_next_hop,
+ &v6_next_hop_address,
+ sizeof (v6_next_hop_address));
+ }
+ }
+ local_label++;
+
+ /* send it... */
+ S (mp);
+ /* If we receive SIGTERM, stop now... */
+ if (vam->do_exit)
+ break;
+ }
+
+ /* When testing multiple add/del ops, use a control-ping to sync */
+ if (count > 1)
+ {
+ vl_api_control_ping_t *mp_ping;
+ f64 after;
+ f64 timeout;
+
+ /* Shut off async mode */
+ vam->async_mode = 0;
+
+ MPING (CONTROL_PING, mp_ping);
+ S (mp_ping);
+
+ timeout = vat_time_now (vam) + 1.0;
+ while (vat_time_now (vam) < timeout)
+ if (vam->result_ready == 1)
+ goto out;
+ vam->retval = -99;
+
+ out:
+ if (vam->retval == -99)
+ errmsg ("timeout");
+
+ if (vam->async_errors > 0)
+ {
+ errmsg ("%d asynchronous errors", vam->async_errors);
+ vam->retval = -98;
+ }
+ vam->async_errors = 0;
+ after = vat_time_now (vam);
+
+ /* slim chance, but we might have eaten SIGTERM on the first iteration */
+ if (j > 0)
+ count = j;
+
+ print (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec",
+ count, after - before, count / (after - before));
+ }
+ else
+ {
+ int ret;
+
+ /* Wait for a reply... */
+ W (ret);
+ return ret;
+ }
+
+ /* Return the good/bad news */
+ return (vam->retval);
+}
+
+static int
+api_mpls_ip_bind_unbind (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_mpls_ip_bind_unbind_t *mp;
+ u32 ip_table_id = 0;
+ u8 is_bind = 1;
+ u8 is_ip4 = 1;
+ ip4_address_t v4_address;
+ ip6_address_t v6_address;
+ u32 address_length;
+ u8 address_set = 0;
+ mpls_label_t local_label = MPLS_LABEL_INVALID;
+ int ret;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U/%d", unformat_ip4_address,
+ &v4_address, &address_length))
+ {
+ is_ip4 = 1;
+ address_set = 1;
+ }
+ else if (unformat (i, "%U/%d", unformat_ip6_address,
+ &v6_address, &address_length))
+ {
+ is_ip4 = 0;
+ address_set = 1;
+ }
+ else if (unformat (i, "%d", &local_label))
+ ;
+ else if (unformat (i, "table-id %d", &ip_table_id))
+ ;
+ else if (unformat (i, "unbind"))
+ is_bind = 0;
+ else if (unformat (i, "bind"))
+ is_bind = 1;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (!address_set)
+ {
+ errmsg ("IP address not set");
+ return -99;
+ }
+
+ if (MPLS_LABEL_INVALID == local_label)
+ {
+ errmsg ("missing label");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M (MPLS_IP_BIND_UNBIND, mp);
+
+ mp->mb_is_bind = is_bind;
+ mp->mb_is_ip4 = is_ip4;
+ mp->mb_ip_table_id = ntohl (ip_table_id);
+ mp->mb_mpls_table_id = 0;
+ mp->mb_label = ntohl (local_label);
+ mp->mb_address_length = address_length;
+
+ if (is_ip4)
+ clib_memcpy (mp->mb_address, &v4_address, sizeof (v4_address));
+ else
+ clib_memcpy (mp->mb_address, &v6_address, sizeof (v6_address));
+
+ /* send it... */
+ S (mp);
+
+ /* Wait for a reply... */
+ W (ret);
+ return ret;
+}
+
+static int
+api_sr_mpls_policy_add (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_sr_mpls_policy_add_t *mp;
+ u32 bsid = 0;
+ u32 weight = 1;
+ u8 type = 0;
+ u8 n_segments = 0;
+ u32 sid;
+ u32 *segments = NULL;
+ int ret;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "bsid %d", &bsid))
+ ;
+ else if (unformat (i, "weight %d", &weight))
+ ;
+ else if (unformat (i, "spray"))
+ type = 1;
+ else if (unformat (i, "next %d", &sid))
+ {
+ n_segments += 1;
+ vec_add1 (segments, htonl (sid));
+ }
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (bsid == 0)
+ {
+ errmsg ("bsid not set");
+ return -99;
+ }
+
+ if (n_segments == 0)
+ {
+ errmsg ("no sid in segment stack");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M2 (SR_MPLS_POLICY_ADD, mp, sizeof (u32) * n_segments);
+
+ mp->bsid = htonl (bsid);
+ mp->weight = htonl (weight);
+ mp->type = type;
+ mp->n_segments = n_segments;
+ memcpy (mp->segments, segments, sizeof (u32) * n_segments);
+ vec_free (segments);
+
+ /* send it... */
+ S (mp);
+
+ /* Wait for a reply... */
+ W (ret);
+ return ret;
+}
+
+static int
+api_sr_mpls_policy_del (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_sr_mpls_policy_del_t *mp;
+ u32 bsid = 0;
+ int ret;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "bsid %d", &bsid))
+ ;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (bsid == 0)
+ {
+ errmsg ("bsid not set");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M (SR_MPLS_POLICY_DEL, mp);
+
+ mp->bsid = htonl (bsid);
+
+ /* send it... */
+ S (mp);
+
+ /* Wait for a reply... */
+ W (ret);
+ return ret;
+}
+
+static int
+api_bier_table_add_del (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_bier_table_add_del_t *mp;
+ u8 is_add = 1;
+ u32 set = 0, sub_domain = 0, hdr_len = 3;
+ mpls_label_t local_label = MPLS_LABEL_INVALID;
+ int ret;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "sub-domain %d", &sub_domain))
+ ;
+ else if (unformat (i, "set %d", &set))
+ ;
+ else if (unformat (i, "label %d", &local_label))
+ ;
+ else if (unformat (i, "hdr-len %d", &hdr_len))
+ ;
+ else if (unformat (i, "add"))
+ is_add = 1;
+ else if (unformat (i, "del"))
+ is_add = 0;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (MPLS_LABEL_INVALID == local_label)
+ {
+ errmsg ("missing label\n");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M (BIER_TABLE_ADD_DEL, mp);
+
+ mp->bt_is_add = is_add;
+ mp->bt_label = ntohl (local_label);
+ mp->bt_tbl_id.bt_set = set;
+ mp->bt_tbl_id.bt_sub_domain = sub_domain;
+ mp->bt_tbl_id.bt_hdr_len_id = hdr_len;
+
+ /* send it... */
+ S (mp);
+
+ /* Wait for a reply... */
+ W (ret);
+
+ return (ret);
+}
+
+static int
+api_bier_route_add_del (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_bier_route_add_del_t *mp;
+ u8 is_add = 1;
+ u32 set = 0, sub_domain = 0, hdr_len = 3, bp = 0;
+ ip4_address_t v4_next_hop_address;
+ ip6_address_t v6_next_hop_address;
+ u8 next_hop_set = 0;
+ u8 next_hop_proto_is_ip4 = 1;
+ mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID;
+ int ret;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", unformat_ip4_address, &v4_next_hop_address))
+ {
+ next_hop_proto_is_ip4 = 1;
+ next_hop_set = 1;
+ }
+ else if (unformat (i, "%U", unformat_ip6_address, &v6_next_hop_address))
+ {
+ next_hop_proto_is_ip4 = 0;
+ next_hop_set = 1;
+ }
+ if (unformat (i, "sub-domain %d", &sub_domain))
+ ;
+ else if (unformat (i, "set %d", &set))
+ ;
+ else if (unformat (i, "hdr-len %d", &hdr_len))
+ ;
+ else if (unformat (i, "bp %d", &bp))
+ ;
+ else if (unformat (i, "add"))
+ is_add = 1;
+ else if (unformat (i, "del"))
+ is_add = 0;
+ else if (unformat (i, "out-label %d", &next_hop_out_label))
+ ;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (!next_hop_set || (MPLS_LABEL_INVALID == next_hop_out_label))
+ {
+ errmsg ("next hop / label set\n");
+ return -99;
+ }
+ if (0 == bp)
+ {
+ errmsg ("bit=position not set\n");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M2 (BIER_ROUTE_ADD_DEL, mp, sizeof (vl_api_fib_path_t));
+
+ mp->br_is_add = is_add;
+ mp->br_tbl_id.bt_set = set;
+ mp->br_tbl_id.bt_sub_domain = sub_domain;
+ mp->br_tbl_id.bt_hdr_len_id = hdr_len;
+ mp->br_bp = ntohs (bp);
+ mp->br_n_paths = 1;
+ mp->br_paths[0].n_labels = 1;
+ mp->br_paths[0].label_stack[0].label = ntohl (next_hop_out_label);
+ mp->br_paths[0].afi = (next_hop_proto_is_ip4 ? 0 : 1);
+
+ if (next_hop_proto_is_ip4)
+ {
+ clib_memcpy (mp->br_paths[0].next_hop,
+ &v4_next_hop_address, sizeof (v4_next_hop_address));
+ }
+ else
+ {
+ clib_memcpy (mp->br_paths[0].next_hop,
+ &v6_next_hop_address, sizeof (v6_next_hop_address));
+ }
+
+ /* send it... */
+ S (mp);
+
+ /* Wait for a reply... */
+ W (ret);
+
+ return (ret);
+}
+
+static int
+api_proxy_arp_add_del (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_proxy_arp_add_del_t *mp;
+ u32 vrf_id = 0;
+ u8 is_add = 1;
+ ip4_address_t lo, hi;
+ u8 range_set = 0;
+ int ret;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "vrf %d", &vrf_id))
+ ;
+ else if (unformat (i, "%U - %U", unformat_ip4_address, &lo,
+ unformat_ip4_address, &hi))
+ range_set = 1;
+ else if (unformat (i, "del"))
+ is_add = 0;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (range_set == 0)
+ {
+ errmsg ("address range not set");
+ return -99;
+ }
+
+ M (PROXY_ARP_ADD_DEL, mp);
+
+ mp->proxy.vrf_id = ntohl (vrf_id);
+ mp->is_add = is_add;
+ clib_memcpy (mp->proxy.low_address, &lo, sizeof (mp->proxy.low_address));
+ clib_memcpy (mp->proxy.hi_address, &hi, sizeof (mp->proxy.hi_address));
+
+ S (mp);
+ W (ret);
+ return ret;
+}
+
+static int
+api_proxy_arp_intfc_enable_disable (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_proxy_arp_intfc_enable_disable_t *mp;
+ u32 sw_if_index;
+ u8 enable = 1;