+uword
+unformat_classify_mask (unformat_input_t * input, va_list * args)
+{
+ u8 **maskp = va_arg (*args, u8 **);
+ u32 *skipp = va_arg (*args, u32 *);
+ u32 *matchp = va_arg (*args, u32 *);
+ u32 match;
+ u8 *mask = 0;
+ u8 *l2 = 0;
+ u8 *l3 = 0;
+ int i;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "hex %U", unformat_hex_string, &mask))
+ ;
+ else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
+ ;
+ else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
+ ;
+ else
+ break;
+ }
+
+ if (mask || l2 || l3)
+ {
+ if (l2 || l3)
+ {
+ /* "With a free Ethernet header in every package" */
+ if (l2 == 0)
+ vec_validate (l2, 13);
+ mask = l2;
+ if (vec_len (l3))
+ {
+ vec_append (mask, l3);
+ vec_free (l3);
+ }
+ }
+
+ /* Scan forward looking for the first significant mask octet */
+ for (i = 0; i < vec_len (mask); i++)
+ if (mask[i])
+ break;
+
+ /* compute (skip, match) params */
+ *skipp = i / sizeof (u32x4);
+ vec_delete (mask, *skipp * sizeof (u32x4), 0);
+
+ /* Pad mask to an even multiple of the vector size */
+ while (vec_len (mask) % sizeof (u32x4))
+ vec_add1 (mask, 0);
+
+ match = vec_len (mask) / sizeof (u32x4);
+
+ for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
+ {
+ u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
+ if (*tmp || *(tmp + 1))
+ break;
+ match--;
+ }
+ if (match == 0)
+ clib_warning ("BUG: match 0");
+
+ _vec_len (mask) = match * sizeof (u32x4);
+
+ *matchp = match;
+ *maskp = mask;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+#define foreach_l2_next \
+_(drop, DROP) \
+_(ethernet, ETHERNET_INPUT) \
+_(ip4, IP4_INPUT) \
+_(ip6, IP6_INPUT)
+
+uword
+unformat_l2_next_index (unformat_input_t * input, va_list * args)
+{
+ u32 *miss_next_indexp = va_arg (*args, u32 *);
+ u32 next_index = 0;
+ u32 tmp;
+
+#define _(n,N) \
+ if (unformat (input, #n)) { next_index = L2_CLASSIFY_NEXT_##N; goto out;}
+ foreach_l2_next;
+#undef _
+
+ if (unformat (input, "%d", &tmp))
+ {
+ next_index = tmp;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *miss_next_indexp = next_index;
+ return 1;
+}
+
+#define foreach_ip_next \
+_(miss, MISS) \
+_(drop, DROP) \
+_(local, LOCAL) \
+_(rewrite, REWRITE)
+
+uword
+unformat_ip_next_index (unformat_input_t * input, va_list * args)
+{
+ u32 *miss_next_indexp = va_arg (*args, u32 *);
+ u32 next_index = 0;
+ u32 tmp;
+
+#define _(n,N) \
+ if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
+ foreach_ip_next;
+#undef _
+
+ if (unformat (input, "%d", &tmp))
+ {
+ next_index = tmp;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *miss_next_indexp = next_index;
+ return 1;
+}
+
+#define foreach_acl_next \
+_(deny, DENY)
+
+uword
+unformat_acl_next_index (unformat_input_t * input, va_list * args)
+{
+ u32 *miss_next_indexp = va_arg (*args, u32 *);
+ u32 next_index = 0;
+ u32 tmp;
+
+#define _(n,N) \
+ if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
+ foreach_acl_next;
+#undef _
+
+ if (unformat (input, "permit"))
+ {
+ next_index = ~0;
+ goto out;
+ }
+ else if (unformat (input, "%d", &tmp))
+ {
+ next_index = tmp;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *miss_next_indexp = next_index;
+ return 1;
+}
+
+uword
+unformat_policer_precolor (unformat_input_t * input, va_list * args)
+{
+ u32 *r = va_arg (*args, u32 *);
+
+ if (unformat (input, "conform-color"))
+ *r = POLICE_CONFORM;
+ else if (unformat (input, "exceed-color"))
+ *r = POLICE_EXCEED;
+ else
+ return 0;
+
+ return 1;
+}
+
+static int
+api_classify_add_del_table (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_classify_add_del_table_t *mp;
+
+ u32 nbuckets = 2;
+ u32 skip = ~0;
+ u32 match = ~0;
+ int is_add = 1;
+ u32 table_index = ~0;
+ u32 next_table_index = ~0;
+ u32 miss_next_index = ~0;
+ u32 memory_size = 32 << 20;
+ u8 *mask = 0;
+ f64 timeout;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "del"))
+ is_add = 0;
+ else if (unformat (i, "buckets %d", &nbuckets))
+ ;
+ else if (unformat (i, "memory_size %d", &memory_size))
+ ;
+ else if (unformat (i, "skip %d", &skip))
+ ;
+ else if (unformat (i, "match %d", &match))
+ ;
+ else if (unformat (i, "table %d", &table_index))
+ ;
+ else if (unformat (i, "mask %U", unformat_classify_mask,
+ &mask, &skip, &match))
+ ;
+ else if (unformat (i, "next-table %d", &next_table_index))
+ ;
+ else if (unformat (i, "miss-next %U", unformat_ip_next_index,
+ &miss_next_index))
+ ;
+ else if (unformat (i, "l2-miss-next %U", unformat_l2_next_index,
+ &miss_next_index))
+ ;
+ else if (unformat (i, "acl-miss-next %U", unformat_acl_next_index,
+ &miss_next_index))
+ ;
+ else
+ break;
+ }
+
+ if (is_add && mask == 0)
+ {
+ errmsg ("Mask required\n");
+ return -99;
+ }
+
+ if (is_add && skip == ~0)
+ {
+ errmsg ("skip count required\n");
+ return -99;
+ }
+
+ if (is_add && match == ~0)
+ {
+ errmsg ("match count required\n");
+ return -99;
+ }
+
+ if (!is_add && table_index == ~0)
+ {
+ errmsg ("table index required for delete\n");
+ return -99;
+ }
+
+ M2 (CLASSIFY_ADD_DEL_TABLE, classify_add_del_table, vec_len (mask));
+
+ mp->is_add = is_add;
+ mp->table_index = ntohl (table_index);
+ mp->nbuckets = ntohl (nbuckets);
+ mp->memory_size = ntohl (memory_size);
+ mp->skip_n_vectors = ntohl (skip);
+ mp->match_n_vectors = ntohl (match);
+ mp->next_table_index = ntohl (next_table_index);
+ mp->miss_next_index = ntohl (miss_next_index);
+ clib_memcpy (mp->mask, mask, vec_len (mask));
+
+ vec_free (mask);
+
+ S;
+ W;
+ /* NOTREACHED */
+}
+
+uword
+unformat_ip4_match (unformat_input_t * input, va_list * args)
+{
+ u8 **matchp = va_arg (*args, u8 **);
+ u8 *match = 0;
+ ip4_header_t *ip;
+ int version = 0;
+ u32 version_val;
+ int hdr_length = 0;
+ u32 hdr_length_val;
+ int src = 0, dst = 0;
+ ip4_address_t src_val, dst_val;
+ int proto = 0;
+ u32 proto_val;
+ int tos = 0;
+ u32 tos_val;
+ int length = 0;
+ u32 length_val;
+ int fragment_id = 0;
+ u32 fragment_id_val;
+ int ttl = 0;
+ int ttl_val;
+ int checksum = 0;
+ u32 checksum_val;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "version %d", &version_val))
+ version = 1;
+ else if (unformat (input, "hdr_length %d", &hdr_length_val))
+ hdr_length = 1;
+ else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
+ src = 1;
+ else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
+ dst = 1;
+ else if (unformat (input, "proto %d", &proto_val))
+ proto = 1;
+ else if (unformat (input, "tos %d", &tos_val))
+ tos = 1;
+ else if (unformat (input, "length %d", &length_val))
+ length = 1;
+ else if (unformat (input, "fragment_id %d", &fragment_id_val))
+ fragment_id = 1;
+ else if (unformat (input, "ttl %d", &ttl_val))
+ ttl = 1;
+ else if (unformat (input, "checksum %d", &checksum_val))
+ checksum = 1;
+ else
+ break;
+ }
+
+ if (version + hdr_length + src + dst + proto + tos + length + fragment_id
+ + ttl + checksum == 0)
+ return 0;
+
+ /*
+ * Aligned because we use the real comparison functions
+ */
+ vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
+
+ ip = (ip4_header_t *) match;
+
+ /* These are realistically matched in practice */
+ if (src)
+ ip->src_address.as_u32 = src_val.as_u32;
+
+ if (dst)
+ ip->dst_address.as_u32 = dst_val.as_u32;
+
+ if (proto)
+ ip->protocol = proto_val;
+
+
+ /* These are not, but they're included for completeness */
+ if (version)
+ ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
+
+ if (hdr_length)
+ ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
+
+ if (tos)
+ ip->tos = tos_val;
+
+ if (length)
+ ip->length = length_val;
+
+ if (ttl)
+ ip->ttl = ttl_val;
+
+ if (checksum)
+ ip->checksum = checksum_val;
+
+ *matchp = match;
+ return 1;
+}
+
+uword
+unformat_ip6_match (unformat_input_t * input, va_list * args)
+{
+ u8 **matchp = va_arg (*args, u8 **);
+ u8 *match = 0;
+ ip6_header_t *ip;
+ int version = 0;
+ u32 version_val;
+ u8 traffic_class = 0;
+ u32 traffic_class_val = 0;
+ u8 flow_label = 0;
+ u8 flow_label_val;
+ int src = 0, dst = 0;
+ ip6_address_t src_val, dst_val;
+ int proto = 0;
+ u32 proto_val;
+ int payload_length = 0;
+ u32 payload_length_val;
+ int hop_limit = 0;
+ int hop_limit_val;
+ u32 ip_version_traffic_class_and_flow_label;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "version %d", &version_val))
+ version = 1;
+ else if (unformat (input, "traffic_class %d", &traffic_class_val))
+ traffic_class = 1;
+ else if (unformat (input, "flow_label %d", &flow_label_val))
+ flow_label = 1;
+ else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
+ src = 1;
+ else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
+ dst = 1;
+ else if (unformat (input, "proto %d", &proto_val))
+ proto = 1;
+ else if (unformat (input, "payload_length %d", &payload_length_val))
+ payload_length = 1;
+ else if (unformat (input, "hop_limit %d", &hop_limit_val))
+ hop_limit = 1;
+ else
+ break;
+ }
+
+ if (version + traffic_class + flow_label + src + dst + proto +
+ payload_length + hop_limit == 0)
+ return 0;
+
+ /*
+ * Aligned because we use the real comparison functions
+ */
+ vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
+
+ ip = (ip6_header_t *) match;
+
+ if (src)
+ clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address));
+
+ if (dst)
+ clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
+
+ if (proto)
+ ip->protocol = proto_val;
+
+ ip_version_traffic_class_and_flow_label = 0;
+
+ if (version)
+ ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
+
+ if (traffic_class)
+ ip_version_traffic_class_and_flow_label |=
+ (traffic_class_val & 0xFF) << 20;
+
+ if (flow_label)
+ ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
+
+ ip->ip_version_traffic_class_and_flow_label =
+ clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
+
+ if (payload_length)
+ ip->payload_length = clib_host_to_net_u16 (payload_length_val);
+
+ if (hop_limit)
+ ip->hop_limit = hop_limit_val;
+
+ *matchp = match;
+ return 1;
+}
+
+uword
+unformat_l3_match (unformat_input_t * input, va_list * args)
+{
+ u8 **matchp = va_arg (*args, u8 **);
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
+ return 1;
+ else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
+ return 1;
+ else
+ break;
+ }
+ return 0;
+}
+
+uword
+unformat_vlan_tag (unformat_input_t * input, va_list * args)
+{
+ u8 *tagp = va_arg (*args, u8 *);
+ u32 tag;
+
+ if (unformat (input, "%d", &tag))
+ {
+ tagp[0] = (tag >> 8) & 0x0F;
+ tagp[1] = tag & 0xFF;
+ return 1;
+ }
+
+ return 0;
+}
+
+uword
+unformat_l2_match (unformat_input_t * input, va_list * args)
+{
+ u8 **matchp = va_arg (*args, u8 **);
+ u8 *match = 0;
+ u8 src = 0;
+ u8 src_val[6];
+ u8 dst = 0;
+ u8 dst_val[6];
+ u8 proto = 0;
+ u16 proto_val;
+ u8 tag1 = 0;
+ u8 tag1_val[2];
+ u8 tag2 = 0;
+ u8 tag2_val[2];
+ int len = 14;
+ u8 ignore_tag1 = 0;
+ u8 ignore_tag2 = 0;
+ u8 cos1 = 0;
+ u8 cos2 = 0;
+ u32 cos1_val = 0;
+ u32 cos2_val = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
+ src = 1;
+ else
+ if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
+ dst = 1;
+ else if (unformat (input, "proto %U",
+ unformat_ethernet_type_host_byte_order, &proto_val))
+ proto = 1;
+ else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
+ tag1 = 1;
+ else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
+ tag2 = 1;
+ else if (unformat (input, "ignore-tag1"))
+ ignore_tag1 = 1;
+ else if (unformat (input, "ignore-tag2"))
+ ignore_tag2 = 1;
+ else if (unformat (input, "cos1 %d", &cos1_val))
+ cos1 = 1;
+ else if (unformat (input, "cos2 %d", &cos2_val))
+ cos2 = 1;
+ else
+ break;
+ }
+ if ((src + dst + proto + tag1 + tag2 +
+ ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
+ return 0;
+
+ if (tag1 || ignore_tag1 || cos1)
+ len = 18;
+ if (tag2 || ignore_tag2 || cos2)
+ len = 22;
+
+ vec_validate_aligned (match, len - 1, sizeof (u32x4));
+
+ if (dst)
+ clib_memcpy (match, dst_val, 6);
+
+ if (src)
+ clib_memcpy (match + 6, src_val, 6);
+
+ if (tag2)
+ {
+ /* inner vlan tag */
+ match[19] = tag2_val[1];
+ match[18] = tag2_val[0];
+ if (cos2)
+ match[18] |= (cos2_val & 0x7) << 5;
+ if (proto)
+ {
+ match[21] = proto_val & 0xff;
+ match[20] = proto_val >> 8;
+ }
+ if (tag1)
+ {
+ match[15] = tag1_val[1];
+ match[14] = tag1_val[0];
+ }
+ if (cos1)
+ match[14] |= (cos1_val & 0x7) << 5;
+ *matchp = match;
+ return 1;
+ }
+ if (tag1)
+ {
+ match[15] = tag1_val[1];
+ match[14] = tag1_val[0];
+ if (proto)
+ {
+ match[17] = proto_val & 0xff;
+ match[16] = proto_val >> 8;
+ }
+ if (cos1)
+ match[14] |= (cos1_val & 0x7) << 5;
+
+ *matchp = match;
+ return 1;
+ }
+ if (cos2)
+ match[18] |= (cos2_val & 0x7) << 5;
+ if (cos1)
+ match[14] |= (cos1_val & 0x7) << 5;
+ if (proto)
+ {
+ match[13] = proto_val & 0xff;
+ match[12] = proto_val >> 8;
+ }
+
+ *matchp = match;
+ return 1;
+}
+
+
+uword
+unformat_classify_match (unformat_input_t * input, va_list * args)
+{
+ u8 **matchp = va_arg (*args, u8 **);
+ u32 skip_n_vectors = va_arg (*args, u32);
+ u32 match_n_vectors = va_arg (*args, u32);
+
+ u8 *match = 0;
+ u8 *l2 = 0;
+ u8 *l3 = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "hex %U", unformat_hex_string, &match))
+ ;
+ else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
+ ;
+ else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
+ ;
+ else
+ break;
+ }
+
+ if (match || l2 || l3)
+ {
+ if (l2 || l3)
+ {
+ /* "Win a free Ethernet header in every packet" */
+ if (l2 == 0)
+ vec_validate_aligned (l2, 13, sizeof (u32x4));
+ match = l2;
+ if (vec_len (l3))
+ {
+ vec_append_aligned (match, l3, sizeof (u32x4));
+ vec_free (l3);
+ }
+ }
+
+ /* Make sure the vector is big enough even if key is all 0's */
+ vec_validate_aligned
+ (match, ((match_n_vectors + skip_n_vectors) * sizeof (u32x4)) - 1,
+ sizeof (u32x4));
+
+ /* Set size, include skipped vectors */
+ _vec_len (match) = (match_n_vectors + skip_n_vectors) * sizeof (u32x4);
+
+ *matchp = match;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+api_classify_add_del_session (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_classify_add_del_session_t *mp;
+ int is_add = 1;
+ u32 table_index = ~0;
+ u32 hit_next_index = ~0;
+ u32 opaque_index = ~0;
+ u8 *match = 0;
+ i32 advance = 0;
+ f64 timeout;
+ u32 skip_n_vectors = 0;
+ u32 match_n_vectors = 0;
+
+ /*
+ * Warning: you have to supply skip_n and match_n
+ * because the API client cant simply look at the classify
+ * table object.
+ */
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "del"))
+ is_add = 0;
+ else if (unformat (i, "hit-next %U", unformat_ip_next_index,
+ &hit_next_index))
+ ;
+ else if (unformat (i, "l2-hit-next %U", unformat_l2_next_index,
+ &hit_next_index))
+ ;
+ else if (unformat (i, "acl-hit-next %U", unformat_acl_next_index,
+ &hit_next_index))
+ ;
+ else if (unformat (i, "policer-hit-next %d", &hit_next_index))
+ ;
+ else if (unformat (i, "%U", unformat_policer_precolor, &opaque_index))
+ ;
+ else if (unformat (i, "opaque-index %d", &opaque_index))
+ ;
+ else if (unformat (i, "skip_n %d", &skip_n_vectors))
+ ;
+ else if (unformat (i, "match_n %d", &match_n_vectors))
+ ;
+ else if (unformat (i, "match %U", unformat_classify_match,
+ &match, skip_n_vectors, match_n_vectors))
+ ;
+ else if (unformat (i, "advance %d", &advance))
+ ;
+ else if (unformat (i, "table-index %d", &table_index))
+ ;
+ else
+ break;
+ }
+
+ if (table_index == ~0)
+ {
+ errmsg ("Table index required\n");
+ return -99;
+ }
+
+ if (is_add && match == 0)
+ {
+ errmsg ("Match value required\n");
+ return -99;
+ }
+
+ M2 (CLASSIFY_ADD_DEL_SESSION, classify_add_del_session, vec_len (match));
+
+ mp->is_add = is_add;
+ mp->table_index = ntohl (table_index);
+ mp->hit_next_index = ntohl (hit_next_index);
+ mp->opaque_index = ntohl (opaque_index);
+ mp->advance = ntohl (advance);
+ clib_memcpy (mp->match, match, vec_len (match));
+ vec_free (match);
+
+ S;
+ W;
+ /* NOTREACHED */
+}
+
+static int
+api_classify_set_interface_ip_table (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_classify_set_interface_ip_table_t *mp;
+ f64 timeout;
+ u32 sw_if_index;
+ int sw_if_index_set;
+ u32 table_index = ~0;
+ u8 is_ipv6 = 0;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "table %d", &table_index))
+ ;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (sw_if_index_set == 0)
+ {
+ errmsg ("missing interface name or sw_if_index\n");
+ return -99;
+ }
+
+
+ M (CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table);
+
+ mp->sw_if_index = ntohl (sw_if_index);
+ mp->table_index = ntohl (table_index);
+ mp->is_ipv6 = is_ipv6;
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+api_classify_set_interface_l2_tables (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_classify_set_interface_l2_tables_t *mp;
+ f64 timeout;
+ u32 sw_if_index;
+ int sw_if_index_set;
+ u32 ip4_table_index = ~0;
+ u32 ip6_table_index = ~0;
+ u32 other_table_index = ~0;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "ip4-table %d", &ip4_table_index))
+ ;
+ else if (unformat (i, "ip6-table %d", &ip6_table_index))
+ ;
+ else if (unformat (i, "other-table %d", &other_table_index))
+ ;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (sw_if_index_set == 0)
+ {
+ errmsg ("missing interface name or sw_if_index\n");
+ return -99;
+ }
+
+
+ M (CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables);
+
+ mp->sw_if_index = ntohl (sw_if_index);
+ mp->ip4_table_index = ntohl (ip4_table_index);
+ mp->ip6_table_index = ntohl (ip6_table_index);
+ mp->other_table_index = ntohl (other_table_index);
+
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+api_ipfix_enable (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_ipfix_enable_t *mp;
+ ip4_address_t collector_address;
+ u8 collector_address_set = 0;
+ u32 collector_port = ~0;
+ ip4_address_t src_address;
+ u8 src_address_set = 0;
+ u32 vrf_id = ~0;
+ u32 path_mtu = ~0;
+ u32 template_interval = ~0;
+ f64 timeout;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "collector_address %U", unformat_ip4_address,
+ &collector_address))
+ collector_address_set = 1;
+ else if (unformat (i, "collector_port %d", &collector_port))
+ ;
+ else if (unformat (i, "src_address %U", unformat_ip4_address,
+ &src_address))
+ src_address_set = 1;
+ else if (unformat (i, "vrf_id %d", &vrf_id))
+ ;
+ else if (unformat (i, "path_mtu %d", &path_mtu))
+ ;
+ else if (unformat (i, "template_interval %d", &template_interval))
+ ;
+ else
+ break;
+ }
+
+ if (collector_address_set == 0)
+ {
+ errmsg ("collector_address required\n");
+ return -99;
+ }
+
+ if (src_address_set == 0)
+ {
+ errmsg ("src_address required\n");
+ return -99;
+ }
+
+ M (IPFIX_ENABLE, ipfix_enable);
+
+ memcpy (mp->collector_address, collector_address.data,
+ sizeof (collector_address.data));
+ mp->collector_port = htons ((u16) collector_port);
+ memcpy (mp->src_address, src_address.data, sizeof (src_address.data));
+ mp->vrf_id = htonl (vrf_id);
+ mp->path_mtu = htonl (path_mtu);
+ mp->template_interval = htonl (template_interval);
+
+ S;
+ W;
+ /* NOTREACHED */
+}
+
+static int
+api_get_node_index (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_get_node_index_t *mp;
+ f64 timeout;
+ u8 *name = 0;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "node %s", &name))
+ ;
+ else
+ break;
+ }
+ if (name == 0)
+ {
+ errmsg ("node name required\n");
+ return -99;
+ }
+ if (vec_len (name) >= ARRAY_LEN (mp->node_name))
+ {
+ errmsg ("node name too long, max %d\n", ARRAY_LEN (mp->node_name));
+ return -99;
+ }
+
+ M (GET_NODE_INDEX, get_node_index);
+ clib_memcpy (mp->node_name, name, vec_len (name));
+ vec_free (name);
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+api_get_next_index (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_get_next_index_t *mp;
+ f64 timeout;
+ u8 *node_name = 0, *next_node_name = 0;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "node-name %s", &node_name))
+ ;
+ else if (unformat (i, "next-node-name %s", &next_node_name))
+ break;
+ }
+
+ if (node_name == 0)
+ {
+ errmsg ("node name required\n");
+ return -99;
+ }
+ if (vec_len (node_name) >= ARRAY_LEN (mp->node_name))
+ {
+ errmsg ("node name too long, max %d\n", ARRAY_LEN (mp->node_name));
+ return -99;
+ }
+
+ if (next_node_name == 0)
+ {
+ errmsg ("next node name required\n");
+ return -99;
+ }
+ if (vec_len (next_node_name) >= ARRAY_LEN (mp->next_name))
+ {
+ errmsg ("next node name too long, max %d\n", ARRAY_LEN (mp->next_name));
+ return -99;
+ }
+
+ M (GET_NEXT_INDEX, get_next_index);
+ clib_memcpy (mp->node_name, node_name, vec_len (node_name));
+ clib_memcpy (mp->next_name, next_node_name, vec_len (next_node_name));
+ vec_free (node_name);
+ vec_free (next_node_name);
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+api_add_node_next (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_add_node_next_t *mp;
+ f64 timeout;
+ u8 *name = 0;
+ u8 *next = 0;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "node %s", &name))
+ ;
+ else if (unformat (i, "next %s", &next))
+ ;
+ else
+ break;
+ }
+ if (name == 0)
+ {
+ errmsg ("node name required\n");
+ return -99;
+ }
+ if (vec_len (name) >= ARRAY_LEN (mp->node_name))
+ {
+ errmsg ("node name too long, max %d\n", ARRAY_LEN (mp->node_name));
+ return -99;
+ }
+ if (next == 0)
+ {
+ errmsg ("next node required\n");
+ return -99;
+ }
+ if (vec_len (next) >= ARRAY_LEN (mp->next_name))
+ {
+ errmsg ("next name too long, max %d\n", ARRAY_LEN (mp->next_name));
+ return -99;
+ }
+
+ M (ADD_NODE_NEXT, add_node_next);
+ clib_memcpy (mp->node_name, name, vec_len (name));
+ clib_memcpy (mp->next_name, next, vec_len (next));
+ vec_free (name);
+ vec_free (next);
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+api_l2tpv3_create_tunnel (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ ip6_address_t client_address, our_address;
+ int client_address_set = 0;
+ int our_address_set = 0;
+ u32 local_session_id = 0;
+ u32 remote_session_id = 0;
+ u64 local_cookie = 0;
+ u64 remote_cookie = 0;
+ u8 l2_sublayer_present = 0;
+ vl_api_l2tpv3_create_tunnel_t *mp;
+ f64 timeout;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "client_address %U", unformat_ip6_address,
+ &client_address))
+ client_address_set = 1;
+ else if (unformat (i, "our_address %U", unformat_ip6_address,
+ &our_address))
+ our_address_set = 1;
+ else if (unformat (i, "local_session_id %d", &local_session_id))
+ ;
+ else if (unformat (i, "remote_session_id %d", &remote_session_id))
+ ;
+ else if (unformat (i, "local_cookie %lld", &local_cookie))
+ ;
+ else if (unformat (i, "remote_cookie %lld", &remote_cookie))
+ ;
+ else if (unformat (i, "l2-sublayer-present"))
+ l2_sublayer_present = 1;
+ else
+ break;
+ }
+
+ if (client_address_set == 0)
+ {
+ errmsg ("client_address required\n");
+ return -99;
+ }
+
+ if (our_address_set == 0)
+ {
+ errmsg ("our_address required\n");
+ return -99;
+ }
+
+ M (L2TPV3_CREATE_TUNNEL, l2tpv3_create_tunnel);
+
+ clib_memcpy (mp->client_address, client_address.as_u8,
+ sizeof (mp->client_address));
+
+ clib_memcpy (mp->our_address, our_address.as_u8, sizeof (mp->our_address));
+
+ mp->local_session_id = ntohl (local_session_id);
+ mp->remote_session_id = ntohl (remote_session_id);
+ mp->local_cookie = clib_host_to_net_u64 (local_cookie);
+ mp->remote_cookie = clib_host_to_net_u64 (remote_cookie);
+ mp->l2_sublayer_present = l2_sublayer_present;
+ mp->is_ipv6 = 1;
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+api_l2tpv3_set_tunnel_cookies (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ u32 sw_if_index;
+ u8 sw_if_index_set = 0;
+ u64 new_local_cookie = 0;
+ u64 new_remote_cookie = 0;
+ vl_api_l2tpv3_set_tunnel_cookies_t *mp;
+ f64 timeout;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "new_local_cookie %lld", &new_local_cookie))
+ ;
+ else if (unformat (i, "new_remote_cookie %lld", &new_remote_cookie))
+ ;
+ else
+ break;
+ }
+
+ if (sw_if_index_set == 0)
+ {
+ errmsg ("missing interface name or sw_if_index\n");
+ return -99;
+ }
+
+ M (L2TPV3_SET_TUNNEL_COOKIES, l2tpv3_set_tunnel_cookies);
+
+ mp->sw_if_index = ntohl (sw_if_index);
+ mp->new_local_cookie = clib_host_to_net_u64 (new_local_cookie);
+ mp->new_remote_cookie = clib_host_to_net_u64 (new_remote_cookie);
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+api_l2tpv3_interface_enable_disable (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_l2tpv3_interface_enable_disable_t *mp;
+ f64 timeout;
+ u32 sw_if_index;
+ u8 sw_if_index_set = 0;
+ u8 enable_disable = 1;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "enable"))
+ enable_disable = 1;
+ else if (unformat (i, "disable"))
+ enable_disable = 0;
+ else
+ break;
+ }
+
+ if (sw_if_index_set == 0)
+ {
+ errmsg ("missing interface name or sw_if_index\n");
+ return -99;
+ }
+
+ M (L2TPV3_INTERFACE_ENABLE_DISABLE, l2tpv3_interface_enable_disable);
+
+ mp->sw_if_index = ntohl (sw_if_index);
+ mp->enable_disable = enable_disable;
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+api_l2tpv3_set_lookup_key (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_l2tpv3_set_lookup_key_t *mp;
+ f64 timeout;
+ u8 key = ~0;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "lookup_v6_src"))
+ key = L2T_LOOKUP_SRC_ADDRESS;
+ else if (unformat (i, "lookup_v6_dst"))
+ key = L2T_LOOKUP_DST_ADDRESS;
+ else if (unformat (i, "lookup_session_id"))
+ key = L2T_LOOKUP_SESSION_ID;
+ else
+ break;
+ }
+
+ if (key == (u8) ~ 0)
+ {
+ errmsg ("l2tp session lookup key unset\n");
+ return -99;
+ }
+
+ M (L2TPV3_SET_LOOKUP_KEY, l2tpv3_set_lookup_key);
+
+ mp->key = key;
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static void vl_api_sw_if_l2tpv3_tunnel_details_t_handler
+ (vl_api_sw_if_l2tpv3_tunnel_details_t * mp)
+{
+ vat_main_t *vam = &vat_main;
+
+ fformat (vam->ofp, "* %U (our) %U (client) (sw_if_index %d)\n",
+ format_ip6_address, mp->our_address,
+ format_ip6_address, mp->client_address,
+ clib_net_to_host_u32 (mp->sw_if_index));
+
+ fformat (vam->ofp,
+ " local cookies %016llx %016llx remote cookie %016llx\n",
+ clib_net_to_host_u64 (mp->local_cookie[0]),
+ clib_net_to_host_u64 (mp->local_cookie[1]),
+ clib_net_to_host_u64 (mp->remote_cookie));
+
+ fformat (vam->ofp, " local session-id %d remote session-id %d\n",
+ clib_net_to_host_u32 (mp->local_session_id),
+ clib_net_to_host_u32 (mp->remote_session_id));
+
+ fformat (vam->ofp, " l2 specific sublayer %s\n\n",
+ mp->l2_sublayer_present ? "preset" : "absent");
+
+}
+
+static void vl_api_sw_if_l2tpv3_tunnel_details_t_handler_json
+ (vl_api_sw_if_l2tpv3_tunnel_details_t * mp)
+{
+ vat_main_t *vam = &vat_main;
+ vat_json_node_t *node = NULL;
+ struct in6_addr addr;
+
+ if (VAT_JSON_ARRAY != vam->json_tree.type)
+ {
+ ASSERT (VAT_JSON_NONE == vam->json_tree.type);
+ vat_json_init_array (&vam->json_tree);
+ }
+ node = vat_json_array_add (&vam->json_tree);
+
+ vat_json_init_object (node);
+
+ clib_memcpy (&addr, mp->our_address, sizeof (addr));
+ vat_json_object_add_ip6 (node, "our_address", addr);
+ clib_memcpy (&addr, mp->client_address, sizeof (addr));
+ vat_json_object_add_ip6 (node, "client_address", addr);
+
+ vat_json_node_t *lc = vat_json_object_add (node, "local_cookie");
+ vat_json_init_array (lc);
+ vat_json_array_add_uint (lc, clib_net_to_host_u64 (mp->local_cookie[0]));
+ vat_json_array_add_uint (lc, clib_net_to_host_u64 (mp->local_cookie[1]));
+ vat_json_object_add_uint (node, "remote_cookie",
+ clib_net_to_host_u64 (mp->remote_cookie));
+
+ printf ("local id: %u", clib_net_to_host_u32 (mp->local_session_id));
+ vat_json_object_add_uint (node, "local_session_id",
+ clib_net_to_host_u32 (mp->local_session_id));
+ vat_json_object_add_uint (node, "remote_session_id",
+ clib_net_to_host_u32 (mp->remote_session_id));
+ vat_json_object_add_string_copy (node, "l2_sublayer",
+ mp->l2_sublayer_present ? (u8 *) "present"
+ : (u8 *) "absent");
+}
+
+static int
+api_sw_if_l2tpv3_tunnel_dump (vat_main_t * vam)
+{
+ vl_api_sw_if_l2tpv3_tunnel_dump_t *mp;
+ f64 timeout;
+
+ /* Get list of l2tpv3-tunnel interfaces */
+ M (SW_IF_L2TPV3_TUNNEL_DUMP, sw_if_l2tpv3_tunnel_dump);
+ S;
+
+ /* Use a control ping for synchronization */
+ {
+ vl_api_control_ping_t *mp;
+ M (CONTROL_PING, control_ping);
+ S;
+ }
+ W;
+}
+
+
+static void vl_api_sw_interface_tap_details_t_handler
+ (vl_api_sw_interface_tap_details_t * mp)
+{
+ vat_main_t *vam = &vat_main;
+
+ fformat (vam->ofp, "%-16s %d\n",
+ mp->dev_name, clib_net_to_host_u32 (mp->sw_if_index));
+}
+
+static void vl_api_sw_interface_tap_details_t_handler_json
+ (vl_api_sw_interface_tap_details_t * mp)
+{
+ vat_main_t *vam = &vat_main;
+ vat_json_node_t *node = NULL;
+
+ if (VAT_JSON_ARRAY != vam->json_tree.type)
+ {
+ ASSERT (VAT_JSON_NONE == vam->json_tree.type);
+ vat_json_init_array (&vam->json_tree);
+ }
+ node = vat_json_array_add (&vam->json_tree);
+
+ vat_json_init_object (node);
+ vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index));
+ vat_json_object_add_string_copy (node, "dev_name", mp->dev_name);
+}
+
+static int
+api_sw_interface_tap_dump (vat_main_t * vam)
+{
+ vl_api_sw_interface_tap_dump_t *mp;
+ f64 timeout;
+
+ fformat (vam->ofp, "\n%-16s %s\n", "dev_name", "sw_if_index");
+ /* Get list of tap interfaces */
+ M (SW_INTERFACE_TAP_DUMP, sw_interface_tap_dump);
+ S;
+
+ /* Use a control ping for synchronization */
+ {
+ vl_api_control_ping_t *mp;
+ M (CONTROL_PING, control_ping);
+ S;
+ }
+ W;
+}
+
+static uword unformat_vxlan_decap_next
+ (unformat_input_t * input, va_list * args)
+{
+ u32 *result = va_arg (*args, u32 *);
+ u32 tmp;
+
+ if (unformat (input, "drop"))
+ *result = VXLAN_INPUT_NEXT_DROP;
+ else if (unformat (input, "ip4"))
+ *result = VXLAN_INPUT_NEXT_IP4_INPUT;
+ else if (unformat (input, "ip6"))
+ *result = VXLAN_INPUT_NEXT_IP6_INPUT;
+ else if (unformat (input, "l2"))
+ *result = VXLAN_INPUT_NEXT_L2_INPUT;
+ else if (unformat (input, "%d", &tmp))
+ *result = tmp;
+ else
+ return 0;
+ return 1;
+}
+
+static int
+api_vxlan_add_del_tunnel (vat_main_t * vam)
+{
+ unformat_input_t *line_input = vam->input;
+ vl_api_vxlan_add_del_tunnel_t *mp;
+ f64 timeout;
+ ip4_address_t src4, dst4;
+ ip6_address_t src6, dst6;
+ u8 is_add = 1;
+ u8 ipv4_set = 0, ipv6_set = 0;
+ u8 src_set = 0;
+ u8 dst_set = 0;
+ u32 encap_vrf_id = 0;
+ u32 decap_next_index = ~0;
+ u32 vni = 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "del"))
+ is_add = 0;
+ else if (unformat (line_input, "src %U", unformat_ip4_address, &src4))
+ {
+ ipv4_set = 1;
+ src_set = 1;
+ }
+ else if (unformat (line_input, "dst %U", unformat_ip4_address, &dst4))
+ {
+ ipv4_set = 1;
+ dst_set = 1;
+ }
+ else if (unformat (line_input, "src %U", unformat_ip6_address, &src6))
+ {
+ ipv6_set = 1;
+ src_set = 1;
+ }
+ else if (unformat (line_input, "dst %U", unformat_ip6_address, &dst6))
+ {
+ ipv6_set = 1;
+ dst_set = 1;
+ }
+ else if (unformat (line_input, "encap-vrf-id %d", &encap_vrf_id))
+ ;
+ else if (unformat (line_input, "decap-next %U",
+ unformat_vxlan_decap_next, &decap_next_index))
+ ;
+ else if (unformat (line_input, "vni %d", &vni))
+ ;
+ else
+ {
+ errmsg ("parse error '%U'\n", format_unformat_error, line_input);
+ return -99;
+ }
+ }
+
+ if (src_set == 0)
+ {
+ errmsg ("tunnel src address not specified\n");
+ return -99;
+ }
+ if (dst_set == 0)
+ {
+ errmsg ("tunnel dst address not specified\n");
+ return -99;
+ }
+
+ if (ipv4_set && ipv6_set)
+ {
+ errmsg ("both IPv4 and IPv6 addresses specified");
+ return -99;
+ }
+
+ if ((vni == 0) || (vni >> 24))
+ {
+ errmsg ("vni not specified or out of range\n");
+ return -99;
+ }
+
+ M (VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel);
+
+ if (ipv6_set)
+ {
+ clib_memcpy (&mp->src_address, &src6, sizeof (src6));
+ clib_memcpy (&mp->dst_address, &dst6, sizeof (dst6));
+ }
+ else
+ {
+ clib_memcpy (&mp->src_address, &src4, sizeof (src4));
+ clib_memcpy (&mp->dst_address, &dst4, sizeof (dst4));
+ }
+ mp->encap_vrf_id = ntohl (encap_vrf_id);
+ mp->decap_next_index = ntohl (decap_next_index);
+ mp->vni = ntohl (vni);
+ mp->is_add = is_add;
+ mp->is_ipv6 = ipv6_set;
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static void vl_api_vxlan_tunnel_details_t_handler
+ (vl_api_vxlan_tunnel_details_t * mp)
+{
+ vat_main_t *vam = &vat_main;
+
+ fformat (vam->ofp, "%11d%24U%24U%14d%18d%13d\n",
+ ntohl (mp->sw_if_index),
+ format_ip46_address, &(mp->src_address[0]),
+ IP46_TYPE_ANY,
+ format_ip46_address, &(mp->dst_address[0]),
+ IP46_TYPE_ANY,
+ ntohl (mp->encap_vrf_id),
+ ntohl (mp->decap_next_index), ntohl (mp->vni));
+}
+
+static void vl_api_vxlan_tunnel_details_t_handler_json
+ (vl_api_vxlan_tunnel_details_t * mp)
+{
+ vat_main_t *vam = &vat_main;
+ vat_json_node_t *node = NULL;
+ struct in_addr ip4;
+ struct in6_addr ip6;
+
+ if (VAT_JSON_ARRAY != vam->json_tree.type)
+ {
+ ASSERT (VAT_JSON_NONE == vam->json_tree.type);
+ vat_json_init_array (&vam->json_tree);
+ }
+ node = vat_json_array_add (&vam->json_tree);
+
+ vat_json_init_object (node);
+ vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index));
+ if (mp->is_ipv6)
+ {
+ clib_memcpy (&ip6, &(mp->src_address[0]), sizeof (ip6));
+ vat_json_object_add_ip6 (node, "src_address", ip6);
+ clib_memcpy (&ip6, &(mp->dst_address[0]), sizeof (ip6));
+ vat_json_object_add_ip6 (node, "dst_address", ip6);
+ }
+ else
+ {
+ clib_memcpy (&ip4, &(mp->src_address[0]), sizeof (ip4));
+ vat_json_object_add_ip4 (node, "src_address", ip4);
+ clib_memcpy (&ip4, &(mp->dst_address[0]), sizeof (ip4));
+ vat_json_object_add_ip4 (node, "dst_address", ip4);
+ }
+ vat_json_object_add_uint (node, "encap_vrf_id", ntohl (mp->encap_vrf_id));
+ vat_json_object_add_uint (node, "decap_next_index",
+ ntohl (mp->decap_next_index));
+ vat_json_object_add_uint (node, "vni", ntohl (mp->vni));
+ vat_json_object_add_uint (node, "is_ipv6", mp->is_ipv6 ? 1 : 0);
+}
+
+static int
+api_vxlan_tunnel_dump (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_vxlan_tunnel_dump_t *mp;
+ f64 timeout;
+ u32 sw_if_index;
+ u8 sw_if_index_set = 0;
+
+ /* 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))
+ sw_if_index_set = 1;
+ else
+ break;
+ }
+
+ if (sw_if_index_set == 0)
+ {
+ sw_if_index = ~0;
+ }
+
+ if (!vam->json_output)
+ {
+ fformat (vam->ofp, "%11s%24s%24s%14s%18s%13s\n",
+ "sw_if_index", "src_address", "dst_address",
+ "encap_vrf_id", "decap_next_index", "vni");
+ }
+
+ /* Get list of vxlan-tunnel interfaces */
+ M (VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump);
+
+ mp->sw_if_index = htonl (sw_if_index);
+
+ S;
+
+ /* Use a control ping for synchronization */
+ {
+ vl_api_control_ping_t *mp;
+ M (CONTROL_PING, control_ping);
+ S;
+ }
+ W;
+}
+
+static int
+api_gre_add_del_tunnel (vat_main_t * vam)
+{
+ unformat_input_t *line_input = vam->input;
+ vl_api_gre_add_del_tunnel_t *mp;
+ f64 timeout;
+ ip4_address_t src4, dst4;
+ u8 is_add = 1;
+ u8 src_set = 0;
+ u8 dst_set = 0;
+ u32 outer_fib_id = 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "del"))
+ is_add = 0;
+ else if (unformat (line_input, "src %U", unformat_ip4_address, &src4))
+ src_set = 1;
+ else if (unformat (line_input, "dst %U", unformat_ip4_address, &dst4))
+ dst_set = 1;
+ else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
+ ;
+ else
+ {
+ errmsg ("parse error '%U'\n", format_unformat_error, line_input);
+ return -99;
+ }
+ }
+
+ if (src_set == 0)
+ {
+ errmsg ("tunnel src address not specified\n");
+ return -99;
+ }
+ if (dst_set == 0)
+ {
+ errmsg ("tunnel dst address not specified\n");
+ return -99;
+ }
+
+
+ M (GRE_ADD_DEL_TUNNEL, gre_add_del_tunnel);
+
+ clib_memcpy (&mp->src_address, &src4, sizeof (src4));
+ clib_memcpy (&mp->dst_address, &dst4, sizeof (dst4));
+ mp->outer_fib_id = ntohl (outer_fib_id);
+ mp->is_add = is_add;
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static void vl_api_gre_tunnel_details_t_handler
+ (vl_api_gre_tunnel_details_t * mp)
+{
+ vat_main_t *vam = &vat_main;
+
+ fformat (vam->ofp, "%11d%15U%15U%14d\n",
+ ntohl (mp->sw_if_index),
+ format_ip4_address, &mp->src_address,
+ format_ip4_address, &mp->dst_address, ntohl (mp->outer_fib_id));
+}
+
+static void vl_api_gre_tunnel_details_t_handler_json
+ (vl_api_gre_tunnel_details_t * mp)
+{
+ vat_main_t *vam = &vat_main;
+ vat_json_node_t *node = NULL;
+ struct in_addr ip4;
+
+ if (VAT_JSON_ARRAY != vam->json_tree.type)
+ {
+ ASSERT (VAT_JSON_NONE == vam->json_tree.type);
+ vat_json_init_array (&vam->json_tree);
+ }
+ node = vat_json_array_add (&vam->json_tree);
+
+ vat_json_init_object (node);
+ vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index));
+ clib_memcpy (&ip4, &mp->src_address, sizeof (ip4));
+ vat_json_object_add_ip4 (node, "src_address", ip4);
+ clib_memcpy (&ip4, &mp->dst_address, sizeof (ip4));
+ vat_json_object_add_ip4 (node, "dst_address", ip4);
+ vat_json_object_add_uint (node, "outer_fib_id", ntohl (mp->outer_fib_id));
+}
+
+static int
+api_gre_tunnel_dump (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_gre_tunnel_dump_t *mp;
+ f64 timeout;
+ u32 sw_if_index;
+ u8 sw_if_index_set = 0;
+
+ /* 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))
+ sw_if_index_set = 1;
+ else
+ break;
+ }
+
+ if (sw_if_index_set == 0)
+ {
+ sw_if_index = ~0;
+ }
+
+ if (!vam->json_output)
+ {
+ fformat (vam->ofp, "%11s%15s%15s%14s\n",
+ "sw_if_index", "src_address", "dst_address", "outer_fib_id");
+ }
+
+ /* Get list of gre-tunnel interfaces */
+ M (GRE_TUNNEL_DUMP, gre_tunnel_dump);
+
+ mp->sw_if_index = htonl (sw_if_index);
+
+ S;
+
+ /* Use a control ping for synchronization */
+ {
+ vl_api_control_ping_t *mp;
+ M (CONTROL_PING, control_ping);
+ S;
+ }
+ W;
+}
+
+static int
+api_l2_fib_clear_table (vat_main_t * vam)
+{
+// unformat_input_t * i = vam->input;
+ vl_api_l2_fib_clear_table_t *mp;
+ f64 timeout;
+
+ M (L2_FIB_CLEAR_TABLE, l2_fib_clear_table);
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+api_l2_interface_efp_filter (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_l2_interface_efp_filter_t *mp;
+ f64 timeout;
+ u32 sw_if_index;
+ u8 enable = 1;
+ u8 sw_if_index_set = 0;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "enable"))
+ enable = 1;
+ else if (unformat (i, "disable"))
+ enable = 0;
+ else
+ {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (sw_if_index_set == 0)
+ {
+ errmsg ("missing sw_if_index\n");
+ return -99;
+ }
+
+ M (L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter);
+
+ mp->sw_if_index = ntohl (sw_if_index);
+ mp->enable_disable = enable;
+
+ S;
+ W;
+ /* NOTREACHED */
+ return 0;
+}
+
+#define foreach_vtr_op \
+_("disable", L2_VTR_DISABLED) \
+_("push-1", L2_VTR_PUSH_1) \
+_("push-2", L2_VTR_PUSH_2) \
+_("pop-1", L2_VTR_POP_1) \
+_("pop-2", L2_VTR_POP_2) \
+_("translate-1-1", L2_VTR_TRANSLATE_1_1) \
+_("translate-1-2", L2_VTR_TRANSLATE_1_2) \
+_("translate-2-1", L2_VTR_TRANSLATE_2_1) \
+_("translate-2-2", L2_VTR_TRANSLATE_2_2)
+
+static int
+api_l2_interface_vlan_tag_rewrite (vat_main_t * vam)