GRE: API update

Change-Id: I5010cd34123c6498230dedac6ba8dd774a1085f9
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vnet/gre/gre.api b/src/vnet/gre/gre.api
index 28c9701..17552cf 100644
--- a/src/vnet/gre/gre.api
+++ b/src/vnet/gre/gre.api
@@ -1,5 +1,6 @@
+/* Hey Emacs use -*- mode: C -*- */
 /*
- * Copyright (c) 2015-2016 Cisco and/or its affiliates.
+ * Copyright (c) 2015-2019 Cisco and/or its affiliates.
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
@@ -13,35 +14,54 @@
  * limitations under the License.
  */
 
-option version = "1.0.1";
+option version = "2.0.0";
 
-/** \brief Create or delete a GRE tunnel
+import "vnet/ip/ip_types.api";
+
+/** \brief A GRE tunnel type
+*/
+enum gre_tunnel_type
+{
+  GRE_API_TUNNEL_TYPE_L3,
+  GRE_API_TUNNEL_TYPE_TEB,
+  GRE_API_TUNNEL_TYPE_ERSPAN,
+};
+
+/** \brief A GRE tunnel
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
-    @param is_add - Use 1 to create the tunnel, 0 to remove it
-    @param is_ipv6 - Use 0 for IPv4, 1 for IPv6
     @param tunnel_type - 0: L3, 1: TEB, 2: ERSPAN
     @param instance - optional unique custom device instance, else ~0.
-    @param src_address - Source IP address
-    @param dst_address - Destination IP address, can be multicast
+    @param src - Source IP address
+    @param dst - Destination IP address, can be multicast
     @param outer_fib_id - Encap FIB table ID
     @param session_id - session for ERSPAN tunnel, range 0-1023
+    @param sw_if_index - ignored on create/delete, present in details.
 */
-define gre_add_del_tunnel
+typedef gre_tunnel
 {
   u32 client_index;
   u32 context;
   u8 is_add;
   u8 is_ipv6;
-  u8 tunnel_type;
-  u32 instance;		/* If non-~0, specifies a custom dev instance */
-  u8 src_address[16];
-  u8 dst_address[16];
-  u32 outer_fib_id;
   u16 session_id;
+  vl_api_gre_tunnel_type_t type;
+  u32 instance;
+  u32 outer_fib_id;
+  u32 sw_if_index;
+  vl_api_address_t src;
+  vl_api_address_t dst;
 };
 
-define gre_add_del_tunnel_reply
+define gre_tunnel_add_del
+{
+  u32 client_index;
+  u32 context;
+  u8 is_add;
+  vl_api_gre_tunnel_t tunnel;
+};
+
+define gre_tunnel_add_del_reply
 {
   u32 context;
   i32 retval;
@@ -58,14 +78,7 @@
 define gre_tunnel_details
 {
   u32 context;
-  u32 sw_if_index;
-  u32 instance;
-  u8 is_ipv6;
-  u8 tunnel_type;
-  u8 src_address[16];
-  u8 dst_address[16];
-  u32 outer_fib_id;
-  u16 session_id;
+  vl_api_gre_tunnel_t tunnel;
 };
 
 /*
diff --git a/src/vnet/gre/gre.h b/src/vnet/gre/gre.h
index a1a03df..99fe4ac 100644
--- a/src/vnet/gre/gre.h
+++ b/src/vnet/gre/gre.h
@@ -55,10 +55,10 @@
    * receiving ERSPAN packets from a GRE ERSPAN tunnel in VPP.
    */
   GRE_TUNNEL_TYPE_ERSPAN = 2,
-
-  GRE_TUNNEL_TYPE_N
 } gre_tunnel_type_t;
 
+#define GRE_TUNNEL_TYPE_N (GRE_TUNNEL_TYPE_ERSPAN + 1)
+
 #define GRE_TUNNEL_TYPE_NAMES {    \
     [GRE_TUNNEL_TYPE_L3] = "L3",   \
     [GRE_TUNNEL_TYPE_TEB] = "TEB", \
@@ -347,16 +347,16 @@
 typedef struct
 {
   u8 is_add;
-  u8 tunnel_type;
+  gre_tunnel_type_t type;
   u8 is_ipv6;
   u32 instance;
   ip46_address_t src, dst;
   u32 outer_fib_id;
   u16 session_id;
-} vnet_gre_add_del_tunnel_args_t;
+} vnet_gre_tunnel_add_del_args_t;
 
-int vnet_gre_add_del_tunnel
-  (vnet_gre_add_del_tunnel_args_t * a, u32 * sw_if_indexp);
+extern int vnet_gre_tunnel_add_del (vnet_gre_tunnel_add_del_args_t * a,
+				    u32 * sw_if_indexp);
 
 static inline void
 gre_mk_key4 (ip4_address_t src,
diff --git a/src/vnet/gre/gre_api.c b/src/vnet/gre/gre_api.c
index 0de6a9f..0d6c33b 100644
--- a/src/vnet/gre/gre_api.c
+++ b/src/vnet/gre/gre_api.c
@@ -25,6 +25,7 @@
 
 #include <vnet/gre/gre.h>
 #include <vnet/fib/fib_table.h>
+#include <vnet/ip/ip_types_api.h>
 
 #include <vnet/vnet_msg_enum.h>
 
@@ -45,50 +46,93 @@
 #include <vlibapi/api_helper_macros.h>
 
 #define foreach_vpe_api_msg                             \
-_(GRE_ADD_DEL_TUNNEL, gre_add_del_tunnel)               \
+_(GRE_TUNNEL_ADD_DEL, gre_tunnel_add_del)               \
 _(GRE_TUNNEL_DUMP, gre_tunnel_dump)
 
-static void vl_api_gre_add_del_tunnel_t_handler
-  (vl_api_gre_add_del_tunnel_t * mp)
+static int
+gre_tunnel_type_decode (vl_api_gre_tunnel_type_t in, gre_tunnel_type_t * out)
 {
-  vl_api_gre_add_del_tunnel_reply_t *rmp;
-  int rv = 0;
-  vnet_gre_add_del_tunnel_args_t _a, *a = &_a;
-  u32 sw_if_index = ~0;
+  in = clib_net_to_host_u32 (in);
 
-  /* Check src & dst are different */
-  if ((mp->is_ipv6 && memcmp (mp->src_address, mp->dst_address, 16) == 0) ||
-      (!mp->is_ipv6 && memcmp (mp->src_address, mp->dst_address, 4) == 0))
+  switch (in)
+    {
+    case GRE_API_TUNNEL_TYPE_L3:
+      *out = GRE_TUNNEL_TYPE_L3;
+      return (0);
+    case GRE_API_TUNNEL_TYPE_TEB:
+      *out = GRE_TUNNEL_TYPE_TEB;
+      return (0);
+    case GRE_API_TUNNEL_TYPE_ERSPAN:
+      *out = GRE_TUNNEL_TYPE_ERSPAN;
+      return (0);
+    }
+
+  return (VNET_API_ERROR_INVALID_VALUE);
+}
+
+static vl_api_gre_tunnel_type_t
+gre_tunnel_type_encode (gre_tunnel_type_t in)
+{
+  vl_api_gre_tunnel_type_t out = GRE_API_TUNNEL_TYPE_L3;
+
+  switch (in)
+    {
+    case GRE_TUNNEL_TYPE_L3:
+      out = GRE_API_TUNNEL_TYPE_L3;
+      break;
+    case GRE_TUNNEL_TYPE_TEB:
+      out = GRE_API_TUNNEL_TYPE_TEB;
+      break;
+    case GRE_TUNNEL_TYPE_ERSPAN:
+      out = GRE_API_TUNNEL_TYPE_ERSPAN;
+      break;
+    }
+
+  out = clib_net_to_host_u32 (out);
+
+  return (out);
+}
+
+static void vl_api_gre_tunnel_add_del_t_handler
+  (vl_api_gre_tunnel_add_del_t * mp)
+{
+  vnet_gre_tunnel_add_del_args_t _a = { }, *a = &_a;
+  vl_api_gre_tunnel_add_del_reply_t *rmp;
+  u32 sw_if_index = ~0;
+  ip46_type_t itype[2];
+  int rv = 0;
+
+  itype[0] = ip_address_decode (&mp->tunnel.src, &a->src);
+  itype[1] = ip_address_decode (&mp->tunnel.dst, &a->dst);
+
+  if (itype[0] != itype[1])
+    {
+      rv = VNET_API_ERROR_INVALID_PROTOCOL;
+      goto out;
+    }
+
+  if (ip46_address_is_equal (&a->src, &a->dst))
     {
       rv = VNET_API_ERROR_SAME_SRC_DST;
       goto out;
     }
-  clib_memset (a, 0, sizeof (*a));
+
+  rv = gre_tunnel_type_decode (mp->tunnel.type, &a->type);
+
+  if (rv)
+    goto out;
 
   a->is_add = mp->is_add;
-  a->tunnel_type = mp->tunnel_type;
-  a->is_ipv6 = mp->is_ipv6;
-  a->instance = ntohl (mp->instance);
-  a->session_id = ntohs (mp->session_id);
+  a->is_ipv6 = (itype[0] == IP46_TYPE_IP6);
+  a->instance = ntohl (mp->tunnel.instance);
+  a->session_id = ntohs (mp->tunnel.session_id);
+  a->outer_fib_id = ntohl (mp->tunnel.outer_fib_id);
 
-  /* ip addresses sent in network byte order */
-  if (!mp->is_ipv6)
-    {
-      clib_memcpy (&(a->src.ip4), mp->src_address, 4);
-      clib_memcpy (&(a->dst.ip4), mp->dst_address, 4);
-    }
-  else
-    {
-      clib_memcpy (&(a->src.ip6), mp->src_address, 16);
-      clib_memcpy (&(a->dst.ip6), mp->dst_address, 16);
-    }
-
-  a->outer_fib_id = ntohl (mp->outer_fib_id);
-  rv = vnet_gre_add_del_tunnel (a, &sw_if_index);
+  rv = vnet_gre_tunnel_add_del (a, &sw_if_index);
 
 out:
   /* *INDENT-OFF* */
-  REPLY_MACRO2(VL_API_GRE_ADD_DEL_TUNNEL_REPLY,
+  REPLY_MACRO2(VL_API_GRE_TUNNEL_ADD_DEL_REPLY,
   ({
     rmp->sw_if_index = ntohl (sw_if_index);
   }));
@@ -99,32 +143,23 @@
   (gre_tunnel_t * t, vl_api_registration_t * reg, u32 context)
 {
   vl_api_gre_tunnel_details_t *rmp;
-  u8 is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
-  fib_table_t *ft;
 
   rmp = vl_msg_api_alloc (sizeof (*rmp));
   clib_memset (rmp, 0, sizeof (*rmp));
   rmp->_vl_msg_id = htons (VL_API_GRE_TUNNEL_DETAILS);
-  if (!is_ipv6)
-    {
-      clib_memcpy (rmp->src_address, &(t->tunnel_src.ip4.as_u8), 4);
-      clib_memcpy (rmp->dst_address, &(t->tunnel_dst.fp_addr.ip4.as_u8), 4);
-      ft = fib_table_get (t->outer_fib_index, FIB_PROTOCOL_IP4);
-      rmp->outer_fib_id = htonl (ft->ft_table_id);
-    }
-  else
-    {
-      clib_memcpy (rmp->src_address, &(t->tunnel_src.ip6.as_u8), 16);
-      clib_memcpy (rmp->dst_address, &(t->tunnel_dst.fp_addr.ip6.as_u8), 16);
-      ft = fib_table_get (t->outer_fib_index, FIB_PROTOCOL_IP6);
-      rmp->outer_fib_id = htonl (ft->ft_table_id);
-    }
-  rmp->tunnel_type = t->type;
-  rmp->instance = htonl (t->user_instance);
-  rmp->sw_if_index = htonl (t->sw_if_index);
-  rmp->session_id = htons (t->session_id);
+
+  ip_address_encode (&t->tunnel_src, IP46_TYPE_ANY, &rmp->tunnel.src);
+  ip_address_encode (&t->tunnel_dst.fp_addr, IP46_TYPE_ANY, &rmp->tunnel.dst);
+
+  rmp->tunnel.outer_fib_id =
+    htonl (fib_table_get_table_id
+	   (t->outer_fib_index, t->tunnel_dst.fp_proto));
+
+  rmp->tunnel.type = gre_tunnel_type_encode (t->type);
+  rmp->tunnel.instance = htonl (t->user_instance);
+  rmp->tunnel.sw_if_index = htonl (t->sw_if_index);
+  rmp->tunnel.session_id = htons (t->session_id);
   rmp->context = context;
-  rmp->is_ipv6 = is_ipv6;
 
   vl_api_send_msg (reg, (u8 *) rmp);
 }
diff --git a/src/vnet/gre/interface.c b/src/vnet/gre/interface.c
index 4f5f528..2025838 100644
--- a/src/vnet/gre/interface.c
+++ b/src/vnet/gre/interface.c
@@ -51,7 +51,7 @@
 }
 
 static gre_tunnel_t *
-gre_tunnel_db_find (const vnet_gre_add_del_tunnel_args_t * a,
+gre_tunnel_db_find (const vnet_gre_tunnel_add_del_args_t * a,
 		    u32 outer_fib_index, gre_tunnel_key_t * key)
 {
   gre_main_t *gm = &gre_main;
@@ -60,13 +60,13 @@
   if (!a->is_ipv6)
     {
       gre_mk_key4 (a->src.ip4, a->dst.ip4, outer_fib_index,
-		   a->tunnel_type, a->session_id, &key->gtk_v4);
+		   a->type, a->session_id, &key->gtk_v4);
       p = hash_get_mem (gm->tunnel_by_key4, &key->gtk_v4);
     }
   else
     {
       gre_mk_key6 (&a->src.ip6, &a->dst.ip6, outer_fib_index,
-		   a->tunnel_type, a->session_id, &key->gtk_v6);
+		   a->type, a->session_id, &key->gtk_v6);
       p = hash_get_mem (gm->tunnel_by_key6, &key->gtk_v6);
     }
 
@@ -172,7 +172,7 @@
 }
 
 static int
-vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t * a,
+vnet_gre_tunnel_add (vnet_gre_tunnel_add_del_args_t * a,
 		     u32 outer_fib_index, u32 * sw_if_indexp)
 {
   gre_main_t *gm = &gre_main;
@@ -208,7 +208,7 @@
   t->dev_instance = t_idx;	/* actual */
   t->user_instance = u_idx;	/* name */
 
-  t->type = a->tunnel_type;
+  t->type = a->type;
   if (t->type == GRE_TUNNEL_TYPE_ERSPAN)
     t->session_id = a->session_id;
 
@@ -310,7 +310,7 @@
 }
 
 static int
-vnet_gre_tunnel_delete (vnet_gre_add_del_tunnel_args_t * a,
+vnet_gre_tunnel_delete (vnet_gre_tunnel_add_del_args_t * a,
 			u32 outer_fib_index, u32 * sw_if_indexp)
 {
   gre_main_t *gm = &gre_main;
@@ -362,7 +362,7 @@
 }
 
 int
-vnet_gre_add_del_tunnel (vnet_gre_add_del_tunnel_args_t * a,
+vnet_gre_tunnel_add_del (vnet_gre_tunnel_add_del_args_t * a,
 			 u32 * sw_if_indexp)
 {
   u32 outer_fib_index;
@@ -423,7 +423,7 @@
 			      vlib_cli_command_t * cmd)
 {
   unformat_input_t _line_input, *line_input = &_line_input;
-  vnet_gre_add_del_tunnel_args_t _a, *a = &_a;
+  vnet_gre_tunnel_add_del_args_t _a, *a = &_a;
   ip46_address_t src, dst;
   u32 instance = ~0;
   u32 outer_fib_id = 0;
@@ -512,7 +512,7 @@
   clib_memset (a, 0, sizeof (*a));
   a->is_add = is_add;
   a->outer_fib_id = outer_fib_id;
-  a->tunnel_type = t_type;
+  a->type = t_type;
   a->session_id = session_id;
   a->is_ipv6 = ipv6_set;
   a->instance = instance;
@@ -527,7 +527,7 @@
       clib_memcpy (&a->dst.ip6, &dst.ip6, sizeof (dst.ip6));
     }
 
-  rv = vnet_gre_add_del_tunnel (a, &sw_if_index);
+  rv = vnet_gre_tunnel_add_del (a, &sw_if_index);
 
   switch (rv)
     {
@@ -554,7 +554,7 @@
       goto done;
     default:
       error =
-	clib_error_return (0, "vnet_gre_add_del_tunnel returned %d", rv);
+	clib_error_return (0, "vnet_gre_tunnel_add_del returned %d", rv);
       goto done;
     }