Add GPE CLI/API for setting encap mode 66/5466/6
authorFilip Tehlar <ftehlar@cisco.com>
Tue, 21 Feb 2017 17:28:34 +0000 (18:28 +0100)
committerFlorin Coras <florin.coras@gmail.com>
Mon, 27 Feb 2017 10:20:50 +0000 (10:20 +0000)
Change-Id: Id89e23fb5d275572b2356c073dfa0f55719e1a76
Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
src/vat/api_format.c
src/vnet/api_errno.h
src/vnet/lisp-gpe/decap.c
src/vnet/lisp-gpe/lisp_gpe.api
src/vnet/lisp-gpe/lisp_gpe.c
src/vnet/lisp-gpe/lisp_gpe.h
src/vnet/lisp-gpe/lisp_gpe_api.c
src/vnet/lisp-gpe/lisp_gpe_tunnel.c

index 226e129..999f986 100644 (file)
@@ -2729,6 +2729,53 @@ static void
     }
 }
 
+static u8 *
+format_gpe_encap_mode (u8 * s, va_list * args)
+{
+  u32 mode = va_arg (*args, u32);
+
+  switch (mode)
+    {
+    case 0:
+      return format (s, "lisp");
+    case 1:
+      return format (s, "vxlan");
+    }
+  return 0;
+}
+
+static void
+  vl_api_gpe_get_encap_mode_reply_t_handler
+  (vl_api_gpe_get_encap_mode_reply_t * mp)
+{
+  vat_main_t *vam = &vat_main;
+
+  print (vam->ofp, "gpe mode: %U", format_gpe_encap_mode, mp->encap_mode);
+  vam->retval = ntohl (mp->retval);
+  vam->result_ready = 1;
+}
+
+static void
+  vl_api_gpe_get_encap_mode_reply_t_handler_json
+  (vl_api_gpe_get_encap_mode_reply_t * mp)
+{
+  vat_main_t *vam = &vat_main;
+  vat_json_node_t node;
+
+  u8 *encap_mode = format (0, "%U", format_gpe_encap_mode, mp->encap_mode);
+  vec_add1 (encap_mode, 0);
+
+  vat_json_init_object (&node);
+  vat_json_object_add_string_copy (&node, "gpe_mode", encap_mode);
+
+  vec_free (encap_mode);
+  vat_json_print (vam->ofp, &node);
+  vat_json_free (&node);
+
+  vam->retval = ntohl (mp->retval);
+  vam->result_ready = 1;
+}
+
 static void
   vl_api_gpe_fwd_entry_path_details_t_handler
   (vl_api_gpe_fwd_entry_path_details_t * mp)
@@ -3900,6 +3947,7 @@ _(one_add_del_map_request_itr_rlocs_reply)              \
 _(one_eid_table_add_del_map_reply)                      \
 _(gpe_add_del_fwd_entry_reply)                          \
 _(gpe_enable_disable_reply)                             \
+_(gpe_set_encap_mode_reply)                             \
 _(gpe_add_del_iface_reply)                              \
 _(vxlan_gpe_add_del_tunnel_reply)                       \
 _(af_packet_delete_reply)                               \
@@ -4160,6 +4208,8 @@ _(ONE_EID_TABLE_VNI_DETAILS, one_eid_table_vni_details)                 \
 _(ONE_MAP_RESOLVER_DETAILS, one_map_resolver_details)                   \
 _(ONE_MAP_SERVER_DETAILS, one_map_server_details)                       \
 _(ONE_ADJACENCIES_GET_REPLY, one_adjacencies_get_reply)                 \
+_(GPE_SET_ENCAP_MODE_REPLY, gpe_set_encap_mode_reply)                   \
+_(GPE_GET_ENCAP_MODE_REPLY, gpe_get_encap_mode_reply)                   \
 _(GPE_ADD_DEL_IFACE_REPLY, gpe_add_del_iface_reply)                     \
 _(GPE_ENABLE_DISABLE_REPLY, gpe_enable_disable_reply)                   \
 _(GPE_ADD_DEL_FWD_ENTRY_REPLY, gpe_add_del_fwd_entry_reply)             \
@@ -14863,6 +14913,68 @@ api_one_add_del_adjacency (vat_main_t * vam)
 
 #define api_lisp_add_del_adjacency api_one_add_del_adjacency
 
+uword
+unformat_gpe_encap_mode (unformat_input_t * input, va_list * args)
+{
+  u32 *mode = va_arg (*args, u32 *);
+
+  if (unformat (input, "lisp"))
+    *mode = 0;
+  else if (unformat (input, "vxlan"))
+    *mode = 1;
+  else
+    return 0;
+
+  return 1;
+}
+
+static int
+api_gpe_get_encap_mode (vat_main_t * vam)
+{
+  vl_api_gpe_get_encap_mode_t *mp;
+  int ret;
+
+  /* Construct the API message */
+  M (GPE_GET_ENCAP_MODE, mp);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+  return ret;
+}
+
+static int
+api_gpe_set_encap_mode (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+  vl_api_gpe_set_encap_mode_t *mp;
+  int ret;
+  u32 mode = 0;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "%U", unformat_gpe_encap_mode, &mode))
+       ;
+      else
+       break;
+    }
+
+  /* Construct the API message */
+  M (GPE_SET_ENCAP_MODE, mp);
+
+  mp->mode = mode;
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+  return ret;
+}
+
 static int
 api_lisp_gpe_add_del_iface (vat_main_t * vam)
 {
@@ -18471,6 +18583,8 @@ _(lisp_map_server_dump, "")                                             \
 _(lisp_adjacencies_get, "vni <vni>")                                    \
 _(lisp_gpe_fwd_entries_get, "vni <vni>")                                \
 _(lisp_gpe_fwd_entry_path_dump, "index <fwd_entry_index>")              \
+_(gpe_set_encap_mode, "lisp|vxlan")                                     \
+_(gpe_get_encap_mode, "")                                               \
 _(lisp_gpe_add_del_iface, "up|down")                                    \
 _(lisp_gpe_enable_disable, "enable|disable")                            \
 _(lisp_gpe_add_del_fwd_entry, "reid <eid> [leid <eid>] vni <vni>"       \
index 0daba16..8680ef7 100644 (file)
@@ -96,7 +96,9 @@ _(BFD_ENOENT, -102, "No such BFD object") \
 _(BFD_EINUSE, -103, "BFD object in use") \
 _(BFD_NOTSUPP, -104, "BFD feature not supported") \
 _(LISP_RLOC_LOCAL, -105, "RLOC address is local") \
-_(BFD_EAGAIN, -106, "BFD object cannot be manipulated at this time")
+_(BFD_EAGAIN, -106, "BFD object cannot be manipulated at this time")    \
+_(INVALID_GPE_MODE, -107, "Invalid GPE mode")                           \
+_(LISP_GPE_ENTRIES_PRESENT, -108, "LISP GPE entries are present")
 
 typedef enum
 {
index 5fd449c..9c5234e 100644 (file)
@@ -62,10 +62,17 @@ static u32 next_proto_to_next_index[LISP_GPE_NEXT_PROTOS] = {
 always_inline u32
 next_protocol_to_next_index (lisp_gpe_header_t * lgh, u8 * next_header)
 {
+  lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
+
   /* lisp-gpe router */
   if (PREDICT_TRUE ((lgh->flags & LISP_GPE_FLAGS_P)
-                   && lgh->next_protocol < LISP_GPE_NEXT_PROTOS))
-    return next_proto_to_next_index[lgh->next_protocol];
+                   || GPE_ENCAP_VXLAN == lgm->encap_mode))
+    {
+      if (PREDICT_FALSE (lgh->next_protocol > LISP_GPE_NEXT_PROTOS))
+       return LISP_GPE_INPUT_NEXT_DROP;
+
+      return next_proto_to_next_index[lgh->next_protocol];
+    }
   /* legacy lisp router */
   else if ((lgh->flags & LISP_GPE_FLAGS_P) == 0)
     {
index d603bd4..43a6a6c 100644 (file)
@@ -158,6 +158,51 @@ manual_endian manual_print define gpe_fwd_entry_path_details
   vl_api_gpe_locator_t rmt_loc;
 };
 
+/** \brief Set GPE encapsulation mode
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param mode - LISP (value 0) or VXLAN (value 1)
+*/
+define gpe_set_encap_mode
+{
+  u32 client_index;
+  u32 context;
+  u8 mode;
+};
+
+/** \brief Reply for set_encap_mode
+    @param context - returned sender context, to match reply w/ request
+    @param retval - return code
+*/
+define gpe_set_encap_mode_reply
+{
+  u32 context;
+  i32 retval;
+};
+
+/** \brief get GPE encapsulation mode
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param mode - LISP (value 0) or VXLAN (value 1)
+*/
+define gpe_get_encap_mode
+{
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Reply for set_encap_mode
+    @param context - returned sender context, to match reply w/ request
+    @param retval - return code
+    @param encap_mode - GPE encapsulation mode
+*/
+define gpe_get_encap_mode_reply
+{
+  u32 context;
+  i32 retval;
+  u8 encap_mode;
+};
+
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
index 479a626..446ad44 100644 (file)
@@ -209,6 +209,102 @@ vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a)
   return 0;
 }
 
+/** Set GPE encapsulation mode. */
+int
+vnet_gpe_set_encap_mode (gpe_encap_mode_t mode)
+{
+  lisp_gpe_main_t *lgm = &lisp_gpe_main;
+
+  if (mode >= GPE_ENCAP_COUNT)
+    return VNET_API_ERROR_INVALID_GPE_MODE;
+
+  if (pool_elts (lgm->lisp_fwd_entry_pool) != 0)
+    return VNET_API_ERROR_LISP_GPE_ENTRIES_PRESENT;
+
+  lgm->encap_mode = mode;
+  return 0;
+}
+
+/** CLI command to set GPE encap */
+static clib_error_t *
+gpe_set_encap_mode_command_fn (vlib_main_t * vm,
+                              unformat_input_t * input,
+                              vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  gpe_encap_mode_t mode = GPE_ENCAP_COUNT;
+  vnet_api_error_t rv;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "lisp"))
+       mode = GPE_ENCAP_LISP;
+      else if (unformat (line_input, "vxlan"))
+       mode = GPE_ENCAP_VXLAN;
+      else
+       {
+         return clib_error_return (0, "parse error: '%U'",
+                                   format_unformat_error, line_input);
+       }
+    }
+  rv = vnet_gpe_set_encap_mode (mode);
+  if (rv)
+    {
+      return clib_error_return (0,
+                               "Error: invalid mode or GPE entries are present!");
+    }
+
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (gpe_set_encap_mode_command, static) = {
+  .path = "gpe encap",
+  .short_help = "gpe encap [lisp|vxlan]",
+  .function = gpe_set_encap_mode_command_fn,
+};
+/* *INDENT-ON* */
+
+/** Format GPE encap mode. */
+u8 *
+format_vnet_gpe_encap_mode (u8 * s, va_list * args)
+{
+  lisp_gpe_main_t *lgm = &lisp_gpe_main;
+
+  switch (lgm->encap_mode)
+    {
+    case GPE_ENCAP_LISP:
+      return format (s, "lisp");
+    case GPE_ENCAP_VXLAN:
+      return format (s, "vxlan");
+    default:
+      return 0;
+    }
+  return 0;
+}
+
+/** CLI command to show GPE encap */
+static clib_error_t *
+gpe_show_encap_mode_command_fn (vlib_main_t * vm,
+                               unformat_input_t * input,
+                               vlib_cli_command_t * cmd)
+{
+  vlib_cli_output (vm, "encap mode: %U", format_vnet_gpe_encap_mode);
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (gpe_show_encap_mode_command, static) = {
+  .path = "show gpe encap",
+  .short_help = "show GPE encapulation mode",
+  .function = gpe_show_encap_mode_command_fn,
+};
+/* *INDENT-ON* */
+
 /** CLI command to enable/disable LISP-GPE. */
 static clib_error_t *
 lisp_gpe_enable_disable_command_fn (vlib_main_t * vm,
@@ -318,6 +414,7 @@ lisp_gpe_init (vlib_main_t * vm)
   lgm->im6 = &ip6_main;
   lgm->lm4 = &ip4_main.lookup_main;
   lgm->lm6 = &ip6_main.lookup_main;
+  lgm->encap_mode = GPE_ENCAP_LISP;
 
   lgm->lisp_gpe_fwd_entries =
     hash_create_mem (0, sizeof (lisp_gpe_fwd_entry_key_t), sizeof (uword));
@@ -330,6 +427,13 @@ lisp_gpe_init (vlib_main_t * vm)
   return 0;
 }
 
+gpe_encap_mode_t
+vnet_gpe_get_encap_mode (void)
+{
+  lisp_gpe_main_t *lgm = &lisp_gpe_main;
+  return lgm->encap_mode;
+}
+
 VLIB_INIT_FUNCTION (lisp_gpe_init);
 
 /*
index c498b7c..c898a7d 100644 (file)
@@ -88,6 +88,14 @@ typedef struct tunnel_lookup
   uword *vni_by_sw_if_index;
 } tunnel_lookup_t;
 
+
+typedef enum gpe_encap_mode_e
+{
+  GPE_ENCAP_LISP,
+  GPE_ENCAP_VXLAN,
+  GPE_ENCAP_COUNT
+} gpe_encap_mode_t;
+
 /** LISP-GPE global state*/
 typedef struct lisp_gpe_main
 {
@@ -131,6 +139,8 @@ typedef struct lisp_gpe_main
 
   const dpo_id_t *nsh_cp_lkup;
 
+  gpe_encap_mode_t encap_mode;
+
   /** convenience */
   vlib_main_t *vlib_main;
   vnet_main_t *vnet_main;
@@ -268,6 +278,8 @@ typedef enum lgpe_ip6_lookup_next
 u8 *format_vnet_lisp_gpe_status (u8 * s, va_list * args);
 
 lisp_api_gpe_fwd_entry_t *vnet_lisp_gpe_fwd_entries_get_by_vni (u32 vni);
+gpe_encap_mode_t vnet_gpe_get_encap_mode (void);
+int vnet_gpe_set_encap_mode (gpe_encap_mode_t mode);
 
 #endif /* included_vnet_lisp_gpe_h */
 
index 8d19f8c..f6bd544 100644 (file)
@@ -56,7 +56,9 @@ _(GPE_ADD_DEL_FWD_ENTRY, gpe_add_del_fwd_entry)               \
 _(GPE_FWD_ENTRIES_GET, gpe_fwd_entries_get)                   \
 _(GPE_FWD_ENTRY_PATH_DUMP, gpe_fwd_entry_path_dump)           \
 _(GPE_ENABLE_DISABLE, gpe_enable_disable)                     \
-_(GPE_ADD_DEL_IFACE, gpe_add_del_iface)
+_(GPE_ADD_DEL_IFACE, gpe_add_del_iface)                       \
+_(GPE_SET_ENCAP_MODE, gpe_set_encap_mode)                     \
+_(GPE_GET_ENCAP_MODE, gpe_get_encap_mode)
 
 static locator_pair_t *
 unformat_gpe_loc_pairs (void *locs, u32 rloc_num)
@@ -373,6 +375,30 @@ vl_api_gpe_add_del_iface_t_handler (vl_api_gpe_add_del_iface_t * mp)
   REPLY_MACRO (VL_API_GPE_ADD_DEL_IFACE_REPLY);
 }
 
+static void
+vl_api_gpe_set_encap_mode_t_handler (vl_api_gpe_set_encap_mode_t * mp)
+{
+  vl_api_gpe_set_encap_mode_reply_t *rmp;
+  int rv = 0;
+
+  rv = vnet_gpe_set_encap_mode (mp->mode);
+  REPLY_MACRO (VL_API_GPE_SET_ENCAP_MODE_REPLY);
+}
+
+static void
+vl_api_gpe_get_encap_mode_t_handler (vl_api_gpe_get_encap_mode_t * mp)
+{
+  vl_api_gpe_get_encap_mode_reply_t *rmp;
+  int rv = 0;
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_GPE_GET_ENCAP_MODE_REPLY,
+  ({
+    rmp->encap_mode = vnet_gpe_get_encap_mode ();
+  }));
+  /* *INDENT-ON* */
+}
+
 /*
  * gpe_api_hookup
  * Add vpe's API message handlers to the table.
index 2ce4e8b..444bfe1 100644 (file)
@@ -50,6 +50,7 @@ lisp_gpe_tunnel_build_rewrite (const lisp_gpe_tunnel_t * lgt,
   lisp_gpe_header_t *lisp0;
   u8 *rw = 0;
   int len;
+  gpe_encap_mode_t encap_mode = vnet_gpe_get_encap_mode ();
 
   if (IP4 == ip_addr_version (&lgt->key->lcl))
     {
@@ -111,6 +112,10 @@ lisp_gpe_tunnel_build_rewrite (const lisp_gpe_tunnel_t * lgt,
     }
 
   lisp0->flags = ladj->flags;
+  if (GPE_ENCAP_VXLAN == encap_mode)
+    /* unset P flag */
+    lisp0->flags &= ~LISP_GPE_FLAGS_P;
+
   lisp0->ver_res = 0;
   lisp0->res = 0;
   lisp0->next_protocol = payload_proto;