#include <vnet/l2/l2_input.h>
#include <vnet/l2tp/l2tp.h>
#include <vnet/vxlan/vxlan.h>
+#include <vnet/gre/gre.h>
#include <vnet/nsh-gre/nsh_gre.h>
#include <vnet/nsh-vxlan-gpe/nsh_vxlan_gpe.h>
#include <vnet/lisp-gpe/lisp_gpe.h>
return s;
}
+/* Format an IP46 address. */
+u8 * format_ip46_address (u8 * s, va_list * args)
+{
+ ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
+ return ip46_address_is_ip4(ip46)?
+ format(s, "%U", format_ip4_address, &ip46->ip4):
+ format(s, "%U", format_ip6_address, &ip46->ip6);
+}
+
u8 * format_ethernet_address (u8 * s, va_list * args)
{
u8 * a = va_arg (*args, u8 *);
vam->result_ready = 1;
}
+static void vl_api_gre_add_del_tunnel_reply_t_handler
+(vl_api_gre_add_del_tunnel_reply_t * mp)
+{
+ vat_main_t * vam = &vat_main;
+ i32 retval = ntohl(mp->retval);
+ if (vam->async_mode) {
+ vam->async_errors += (retval < 0);
+ } else {
+ vam->retval = retval;
+ vam->result_ready = 1;
+ }
+}
+
+static void vl_api_gre_add_del_tunnel_reply_t_handler_json
+(vl_api_gre_add_del_tunnel_reply_t * mp)
+{
+ vat_main_t * vam = &vat_main;
+ vat_json_node_t node;
+
+ vat_json_init_object(&node);
+ vat_json_object_add_int(&node, "retval", ntohl(mp->retval));
+ vat_json_object_add_uint(&node, "sw_if_index", ntohl(mp->sw_if_index));
+
+ vat_json_print(vam->ofp, &node);
+ vat_json_free(&node);
+
+ vam->retval = ntohl(mp->retval);
+ vam->result_ready = 1;
+}
+
static void vl_api_create_vhost_user_if_reply_t_handler
(vl_api_create_vhost_user_if_reply_t * mp)
{
_(set_arp_neighbor_limit_reply) \
_(l2_patch_add_del_reply) \
_(sr_tunnel_add_del_reply) \
+_(sr_policy_add_del_reply) \
+_(sr_multicast_map_add_del_reply) \
_(classify_add_del_session_reply) \
_(classify_set_interface_ip_table_reply) \
_(classify_set_interface_l2_tables_reply) \
_(SET_ARP_NEIGHBOR_LIMIT_REPLY, set_arp_neighbor_limit_reply) \
_(L2_PATCH_ADD_DEL_REPLY, l2_patch_add_del_reply) \
_(SR_TUNNEL_ADD_DEL_REPLY, sr_tunnel_add_del_reply) \
+_(SR_POLICY_ADD_DEL_REPLY, sr_policy_add_del_reply) \
+_(SR_MULTICAST_MAP_ADD_DEL_REPLY, sr_multicast_map_add_del_reply) \
_(CLASSIFY_ADD_DEL_TABLE_REPLY, classify_add_del_table_reply) \
_(CLASSIFY_ADD_DEL_SESSION_REPLY, classify_add_del_session_reply) \
_(CLASSIFY_SET_INTERFACE_IP_TABLE_REPLY, \
_(SW_IF_L2TPV3_TUNNEL_DETAILS, sw_if_l2tpv3_tunnel_details) \
_(VXLAN_ADD_DEL_TUNNEL_REPLY, vxlan_add_del_tunnel_reply) \
_(VXLAN_TUNNEL_DETAILS, vxlan_tunnel_details) \
+_(GRE_ADD_DEL_TUNNEL_REPLY, gre_add_del_tunnel_reply) \
+_(GRE_TUNNEL_DETAILS, gre_tunnel_details) \
_(L2_FIB_CLEAR_TABLE_REPLY, l2_fib_clear_table_reply) \
_(L2_INTERFACE_EFP_FILTER_REPLY, l2_interface_efp_filter_reply) \
_(L2_INTERFACE_VLAN_TAG_REWRITE_REPLY, l2_interface_vlan_tag_rewrite_reply) \
S; W;
return 0;
}
+
static int api_sr_tunnel_add_del (vat_main_t * vam)
{
unformat_input_t * i = vam->input;
ip6_address_t * tags = 0;
ip6_address_t * this_tag;
ip6_address_t next_address, tag;
+ u8 * name = 0;
+ u8 * policy_name = 0;
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "del"))
is_del = 1;
+ else if (unformat (i, "name %s", &name))
+ ;
+ else if (unformat (i, "policy %s", &policy_name))
+ ;
else if (unformat (i, "rx_fib_id %d", &rx_table_id))
;
else if (unformat (i, "tx_fib_id %d", &tx_table_id))
mp->outer_vrf_id = ntohl (rx_table_id);
mp->inner_vrf_id = ntohl (tx_table_id);
+ memcpy (mp->name, name, vec_len(name));
+ memcpy (mp->policy_name, policy_name, vec_len(policy_name));
vec_free (segments);
vec_free (tags);
/* NOTREACHED */
}
+static int api_sr_policy_add_del (vat_main_t * vam)
+{
+ unformat_input_t * input = vam->input;
+ vl_api_sr_policy_add_del_t *mp;
+ f64 timeout;
+ int is_del = 0;
+ u8 * name = 0;
+ u8 * tunnel_name = 0;
+ u8 ** tunnel_names = 0;
+
+ int name_set = 0 ;
+ int tunnel_set = 0;
+ int j = 0;
+ int tunnel_names_length = 1; // Init to 1 to offset the #tunnel_names counter byte
+ int tun_name_len = 0; // Different naming convention used as confusing these would be "bad" (TM)
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "del"))
+ is_del = 1;
+ else if (unformat (input, "name %s", &name))
+ name_set = 1;
+ else if (unformat (input, "tunnel %s", &tunnel_name))
+ {
+ if (tunnel_name)
+ {
+ vec_add1 (tunnel_names, tunnel_name);
+ /* For serializer:
+ - length = #bytes to store in serial vector
+ - +1 = byte to store that length
+ */
+ tunnel_names_length += (vec_len (tunnel_name) + 1);
+ tunnel_set = 1;
+ tunnel_name = 0;
+ }
+ }
+ else
+ break;
+ }
+
+ if (!name_set)
+ {
+ errmsg ("policy name required\n");
+ return -99;
+ }
+
+ if ((!tunnel_set) && (!is_del))
+ {
+ errmsg ("tunnel name required\n");
+ return -99;
+ }
+
+ M2(SR_POLICY_ADD_DEL, sr_policy_add_del, tunnel_names_length);
+
+
+
+ mp->is_add = !is_del;
+
+ memcpy (mp->name, name, vec_len(name));
+ // Since mp->tunnel_names is of type u8[0] and not a u8 *, u8 ** needs to be serialized
+ u8 * serial_orig = 0;
+ vec_validate (serial_orig, tunnel_names_length);
+ *serial_orig = vec_len(tunnel_names); // Store the number of tunnels as length in first byte of serialized vector
+ serial_orig += 1; // Move along one byte to store the length of first tunnel_name
+
+ for (j=0; j < vec_len(tunnel_names); j++)
+ {
+ tun_name_len = vec_len (tunnel_names[j]);
+ *serial_orig = tun_name_len; // Store length of tunnel name in first byte of Length/Value pair
+ serial_orig += 1; // Move along one byte to store the actual tunnel name
+ memcpy (serial_orig, tunnel_names[j], tun_name_len);
+ serial_orig += tun_name_len; // Advance past the copy
+ }
+ memcpy (mp->tunnel_names, serial_orig - tunnel_names_length, tunnel_names_length); // Regress serial_orig to head then copy fwd
+
+ vec_free (tunnel_names);
+ vec_free (tunnel_name);
+
+ S; W;
+ /* NOTREACHED */
+}
+
+static int api_sr_multicast_map_add_del (vat_main_t * vam)
+{
+ unformat_input_t * input = vam->input;
+ vl_api_sr_multicast_map_add_del_t *mp;
+ f64 timeout;
+ int is_del = 0;
+ ip6_address_t multicast_address;
+ u8 * policy_name = 0;
+ int multicast_address_set = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "del"))
+ is_del = 1;
+ else if (unformat (input, "address %U", unformat_ip6_address, &multicast_address))
+ multicast_address_set = 1;
+ else if (unformat (input, "sr-policy %s", &policy_name))
+ ;
+ else
+ break;
+ }
+
+ if (!is_del && !policy_name)
+ {
+ errmsg ("sr-policy name required\n");
+ return -99;
+ }
+
+
+ if (!multicast_address_set)
+ {
+ errmsg ("address required\n");
+ return -99;
+ }
+
+ M(SR_MULTICAST_MAP_ADD_DEL, sr_multicast_map_add_del);
+
+ mp->is_add = !is_del;
+ memcpy (mp->policy_name, policy_name, vec_len(policy_name));
+ clib_memcpy (mp->multicast_address, &multicast_address, sizeof (mp->multicast_address));
+
+
+ vec_free (policy_name);
+
+ S; W;
+ /* NOTREACHED */
+}
+
#define foreach_ip4_proto_field \
_(src_address) \
unformat_input_t * line_input = vam->input;
vl_api_vxlan_add_del_tunnel_t *mp;
f64 timeout;
- ip4_address_t src, dst;
+ 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;
if (unformat (line_input, "del"))
is_add = 0;
else if (unformat (line_input, "src %U",
- unformat_ip4_address, &src))
+ unformat_ip4_address, &src4))
+ {
+ ipv4_set = 1;
src_set = 1;
+ }
else if (unformat (line_input, "dst %U",
- unformat_ip4_address, &dst))
+ 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",
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);
-
- mp->src_address = src.as_u32;
- mp->dst_address = dst.as_u32;
+
+ if (ipv6_set) {
+ clib_memcpy(&mp->dst_address, &src6, sizeof(src6));
+ clib_memcpy(&mp->dst_address, &src6, 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 */
{
vat_main_t * vam = &vat_main;
- fformat(vam->ofp, "%11d%13U%13U%14d%18d%13d\n",
+ fformat(vam->ofp, "%11d%24U%24U%14d%18d%13d\n",
ntohl(mp->sw_if_index),
- format_ip4_address, &mp->src_address,
- format_ip4_address, &mp->dst_address,
+ format_ip46_address, &(mp->src_address[0]),
+ format_ip46_address, &(mp->dst_address[0]),
ntohl(mp->encap_vrf_id),
ntohl(mp->decap_next_index),
ntohl(mp->vni));
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_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);
+ 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)
}
if (!vam->json_output) {
- fformat(vam->ofp, "%11s%13s%13s%14s%18s%13s\n",
+ 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 l2tpv3-tunnel interfaces */
+ /* Get list of vxlan-tunnel interfaces */
M(VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump);
mp->sw_if_index = htonl(sw_if_index);
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_table_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_table_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_table_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;
"inner_vrf_id <n> outer_vrf_id <n> next-hop <ip4-addr>\n" \
"resolve-attempts <n> resolve-if-needed 0 | 1 [del]") \
_(sr_tunnel_add_del, \
- "src <ip6-addr> dst <ip6-addr>/<mw> (next <ip6-addr>)+\n" \
- " [tag <ip6-addr>]* [clean] [reroute]") \
+ "[name <name>] src <ip6-addr> dst <ip6-addr>/<mw> \n" \
+ "(next <ip6-addr>)+ [tag <ip6-addr>]* [clean] [reroute] \n" \
+ "[policy <policy_name>]") \
+_(sr_policy_add_del, \
+ "name <name> tunnel <tunnel-name> [tunnel <tunnel-name>]* [del]") \
+_(sr_multicast_map_add_del, \
+ "address [ip6 multicast address] sr-policy [policy name] [del]") \
_(classify_add_del_table, \
"buckets <nn> [skip <n>] [match <n>] [memory_size <nn-bytes>]\n" \
"[del] mask <mask-value>\n" \
"lookup_v6_src | lookup_v6_dst | lookup_session_id") \
_(sw_if_l2tpv3_tunnel_dump, "") \
_(vxlan_add_del_tunnel, \
- "src <ip4-addr> dst <ip4-addr> vni [encap-vrf-id <nn>]\n" \
+ "src <ip4-addr> dst <ip4-addr> vni <vni> [encap-vrf-id <nn>]\n" \
" [decap-next l2|ip4|ip6] [del]") \
_(vxlan_tunnel_dump, "[<intfc> | sw_if_index <nn>]") \
+_(gre_add_del_tunnel, \
+ "src <ip4-addr> dst <ip4-addr> [outer-fib-id <nn>] [del]\n") \
+_(gre_tunnel_dump, "[<intfc> | sw_if_index <nn>]") \
_(l2_fib_clear_table, "") \
_(l2_interface_efp_filter, "sw_if_index <nn> enable | disable") \
_(l2_interface_vlan_tag_rewrite, \