gre: Multi-point interfaces
Type: feature
Change-Id: I0129ad6ace44a50a8a3b26db8e445cd06b2b49e8
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vnet/gre/interface.c b/src/vnet/gre/interface.c
index ea93536..927f34e 100644
--- a/src/vnet/gre/interface.c
+++ b/src/vnet/gre/interface.c
@@ -26,7 +26,39 @@
#include <vnet/mpls/mpls.h>
#include <vnet/l2/l2_input.h>
-static const char *gre_tunnel_type_names[] = GRE_TUNNEL_TYPE_NAMES;
+u8 *
+format_gre_tunnel_type (u8 * s, va_list * args)
+{
+ gre_tunnel_type_t type = va_arg (*args, int);
+
+ switch (type)
+ {
+#define _(n, v) case GRE_TUNNEL_TYPE_##n: \
+ s = format (s, "%s", v); \
+ break;
+ foreach_gre_tunnel_type
+#undef _
+ }
+
+ return (s);
+}
+
+u8 *
+format_gre_tunnel_mode (u8 * s, va_list * args)
+{
+ gre_tunnel_mode_t mode = va_arg (*args, int);
+
+ switch (mode)
+ {
+#define _(n, v) case GRE_TUNNEL_MODE_##n: \
+ s = format (s, "%s", v); \
+ break;
+ foreach_gre_tunnel_mode
+#undef _
+ }
+
+ return (s);
+}
static u8 *
format_gre_tunnel (u8 * s, va_list * args)
@@ -39,7 +71,8 @@
format_ip46_address, &t->tunnel_dst.fp_addr, IP46_TYPE_ANY,
t->outer_fib_index, t->sw_if_index);
- s = format (s, "payload %s ", gre_tunnel_type_names[t->type]);
+ s = format (s, "payload %U ", format_gre_tunnel_type, t->type);
+ s = format (s, "%U ", format_gre_tunnel_mode, t->mode);
if (t->type == GRE_TUNNEL_TYPE_ERSPAN)
s = format (s, "session %d ", t->session_id);
@@ -209,13 +242,21 @@
t->user_instance = u_idx; /* name */
t->type = a->type;
+ t->mode = a->mode;
if (t->type == GRE_TUNNEL_TYPE_ERSPAN)
t->session_id = a->session_id;
if (t->type == GRE_TUNNEL_TYPE_L3)
- hw_if_index = vnet_register_interface (vnm, gre_device_class.index, t_idx,
- gre_hw_interface_class.index,
- t_idx);
+ {
+ if (t->mode == GRE_TUNNEL_MODE_P2P)
+ hw_if_index =
+ vnet_register_interface (vnm, gre_device_class.index, t_idx,
+ gre_hw_interface_class.index, t_idx);
+ else
+ hw_if_index =
+ vnet_register_interface (vnm, gre_device_class.index, t_idx,
+ mgre_hw_interface_class.index, t_idx);
+ }
else
{
/* Default MAC address (d00b:eed0:0000 + sw_if_index) */
@@ -372,9 +413,9 @@
u32 outer_fib_index;
if (!a->is_ipv6)
- outer_fib_index = ip4_fib_index_from_table_id (a->outer_fib_id);
+ outer_fib_index = ip4_fib_index_from_table_id (a->outer_table_id);
else
- outer_fib_index = ip6_fib_index_from_table_id (a->outer_fib_id);
+ outer_fib_index = ip6_fib_index_from_table_id (a->outer_table_id);
if (~0 == outer_fib_index)
return VNET_API_ERROR_NO_SUCH_FIB;
@@ -428,18 +469,17 @@
{
unformat_input_t _line_input, *line_input = &_line_input;
vnet_gre_tunnel_add_del_args_t _a, *a = &_a;
- ip46_address_t src, dst;
+ ip46_address_t src = ip46_address_initializer, dst =
+ ip46_address_initializer;
u32 instance = ~0;
- u32 outer_fib_id = 0;
+ u32 outer_table_id = 0;
gre_tunnel_type_t t_type = GRE_TUNNEL_TYPE_L3;
+ gre_tunnel_mode_t t_mode = GRE_TUNNEL_MODE_P2P;
u32 session_id = 0;
int rv;
- u32 num_m_args = 0;
u8 is_add = 1;
u32 sw_if_index;
clib_error_t *error = NULL;
- u8 ipv4_set = 0;
- u8 ipv6_set = 0;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
@@ -451,32 +491,14 @@
is_add = 0;
else if (unformat (line_input, "instance %d", &instance))
;
- else
- if (unformat (line_input, "src %U", unformat_ip4_address, &src.ip4))
- {
- num_m_args++;
- ipv4_set = 1;
- }
- else
- if (unformat (line_input, "dst %U", unformat_ip4_address, &dst.ip4))
- {
- num_m_args++;
- ipv4_set = 1;
- }
- else
- if (unformat (line_input, "src %U", unformat_ip6_address, &src.ip6))
- {
- num_m_args++;
- ipv6_set = 1;
- }
- else
- if (unformat (line_input, "dst %U", unformat_ip6_address, &dst.ip6))
- {
- num_m_args++;
- ipv6_set = 1;
- }
- else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
+ else if (unformat (line_input, "src %U", unformat_ip46_address, &src))
;
+ else if (unformat (line_input, "dst %U", unformat_ip46_address, &dst))
+ ;
+ else if (unformat (line_input, "outer-table-id %d", &outer_table_id))
+ ;
+ else if (unformat (line_input, "multipoint"))
+ t_mode = GRE_TUNNEL_MODE_MP;
else if (unformat (line_input, "teb"))
t_type = GRE_TUNNEL_TYPE_TEB;
else if (unformat (line_input, "erspan %d", &session_id))
@@ -489,47 +511,41 @@
}
}
- if (num_m_args < 2)
- {
- error = clib_error_return (0, "mandatory argument(s) missing");
- goto done;
- }
-
- if ((ipv4_set && memcmp (&src.ip4, &dst.ip4, sizeof (src.ip4)) == 0) ||
- (ipv6_set && memcmp (&src.ip6, &dst.ip6, sizeof (src.ip6)) == 0))
+ if (ip46_address_is_equal (&src, &dst))
{
error = clib_error_return (0, "src and dst are identical");
goto done;
}
- if (ipv4_set && ipv6_set)
- return clib_error_return (0, "both IPv4 and IPv6 addresses specified");
-
- if ((ipv4_set && memcmp (&dst.ip4, &zero_addr.ip4, sizeof (dst.ip4)) == 0)
- || (ipv6_set
- && memcmp (&dst.ip6, &zero_addr.ip6, sizeof (dst.ip6)) == 0))
+ if (t_mode != GRE_TUNNEL_MODE_MP && ip46_address_is_zero (&dst))
{
- error = clib_error_return (0, "dst address cannot be zero");
+ error = clib_error_return (0, "destination address not specified");
+ goto done;
+ }
+
+ if (ip46_address_is_zero (&src))
+ {
+ error = clib_error_return (0, "source address not specified");
+ goto done;
+ }
+
+ if (ip46_address_is_ip4 (&src) != ip46_address_is_ip4 (&dst))
+ {
+ error =
+ clib_error_return (0, "src and dst address must be the same AF");
goto done;
}
clib_memset (a, 0, sizeof (*a));
a->is_add = is_add;
- a->outer_fib_id = outer_fib_id;
+ a->outer_table_id = outer_table_id;
a->type = t_type;
+ a->mode = t_mode;
a->session_id = session_id;
- a->is_ipv6 = ipv6_set;
+ a->is_ipv6 = !ip46_address_is_ip4 (&src);
a->instance = instance;
- if (!ipv6_set)
- {
- clib_memcpy (&a->src.ip4, &src.ip4, sizeof (src.ip4));
- clib_memcpy (&a->dst.ip4, &dst.ip4, sizeof (dst.ip4));
- }
- else
- {
- clib_memcpy (&a->src.ip6, &src.ip6, sizeof (src.ip6));
- clib_memcpy (&a->dst.ip6, &dst.ip6, sizeof (dst.ip6));
- }
+ clib_memcpy (&a->src, &src, sizeof (a->src));
+ clib_memcpy (&a->dst, &dst, sizeof (a->dst));
rv = vnet_gre_tunnel_add_del (a, &sw_if_index);
@@ -543,8 +559,8 @@
error = clib_error_return (0, "GRE tunnel already exists...");
goto done;
case VNET_API_ERROR_NO_SUCH_FIB:
- error = clib_error_return (0, "outer fib ID %d doesn't exist\n",
- outer_fib_id);
+ error = clib_error_return (0, "outer table ID %d doesn't exist\n",
+ outer_table_id);
goto done;
case VNET_API_ERROR_NO_SUCH_ENTRY:
error = clib_error_return (0, "GRE tunnel doesn't exist");