VCL: add session namespace support.

Change-Id: I04f1b63e66260d99c0dd180b0295a55a9b750df7
Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
diff --git a/src/vcl/vppcom_test.conf b/src/vcl/vcl_test.conf
similarity index 70%
rename from src/vcl/vppcom_test.conf
rename to src/vcl/vcl_test.conf
index e5ac463..da8e818 100644
--- a/src/vcl/vppcom_test.conf
+++ b/src/vcl/vcl_test.conf
@@ -1,5 +1,5 @@
 # Test VPPCOM config file
-vppcom {
+vcl {
   heapsize 1
   api-prefix daw  # this is a comment
   uid 1020 this is also a comment.
@@ -22,4 +22,10 @@
   app-timeout 54.3
   session-timeout 66.6
   accept-timeout 0.1
+  session-scope-local
+  session-scope-global
+  namespace-id 0123456789012345678901234567890123456789012345678901234567890123456789
+  namespace-id Oh_Bother!_Said_Winnie-The-Pooh
+  namespace-secret 0x42bada55e5
+  namespace-secret 42
 }
diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c
index de46273..72b5277 100644
--- a/src/vcl/vppcom.c
+++ b/src/vcl/vppcom.c
@@ -127,6 +127,10 @@
   u32 tx_fifo_size;
   u32 event_queue_size;
   u32 listen_queue_size;
+  u8 session_scope_local;
+  u8 session_scope_global;
+  u8 *namespace_id;
+  u64 namespace_secret;
   f64 app_timeout;
   f64 session_timeout;
   f64 accept_timeout;
@@ -455,6 +459,8 @@
 {
   vppcom_main_t *vcm = &vppcom_main;
   vl_api_application_attach_t *bmp;
+  u8 nsid_len = vec_len (vcm->cfg.namespace_id);
+
   bmp = vl_msg_api_alloc (sizeof (*bmp));
   memset (bmp, 0, sizeof (*bmp));
 
@@ -463,11 +469,18 @@
   bmp->context = htonl (0xfeedface);
   bmp->options[APP_OPTIONS_FLAGS] =
     APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT |
-    APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE | APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
+    (vcm->cfg.session_scope_local ? APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE : 0) |
+    (vcm->cfg.session_scope_global ? APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE : 0);
   bmp->options[SESSION_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size;
   bmp->options[SESSION_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size;
   bmp->options[SESSION_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size;
   bmp->options[SESSION_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size;
+  if (nsid_len)
+    {
+      bmp->namespace_id_len = nsid_len;
+      clib_memcpy (bmp->namespace_id, vcm->cfg.namespace_id, nsid_len);
+      bmp->options[APP_OPTIONS_NAMESPACE_SECRET] = vcm->cfg.namespace_secret;
+    }
   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
 }
 
@@ -1509,7 +1522,7 @@
       (void) unformat_user (input, unformat_line_input, line_input);
       unformat_skip_white_space (line_input);
 
-      if (unformat (line_input, "vppcom {"))
+      if (unformat (line_input, "vcl {"))
 	{
 	  vc_cfg_input = 1;
 	  continue;
@@ -1548,11 +1561,11 @@
 	      if (VPPCOM_DEBUG > 0)
 		clib_warning ("[%d] configured gid %d", vcm->my_pid, gid);
 	    }
-	  else if (unformat (line_input, "segment-baseva 0x%llx",
+	  else if (unformat (line_input, "segment-baseva 0x%lx",
 			     &vcl_cfg->segment_baseva))
 	    {
 	      if (VPPCOM_DEBUG > 0)
-		clib_warning ("[%d] configured segment_baseva 0x%llx",
+		clib_warning ("[%d] configured segment_baseva 0x%lx",
 			      vcm->my_pid, vcl_cfg->segment_baseva);
 	    }
 	  else if (unformat (line_input, "segment-size 0x%lx",
@@ -1683,6 +1696,57 @@
 		clib_warning ("[%d] configured accept_timeout %f",
 			      vcm->my_pid, vcl_cfg->accept_timeout);
 	    }
+	  else if (unformat (line_input, "session-scope-local"))
+	    {
+	      vcl_cfg->session_scope_local = 1;
+	      if (VPPCOM_DEBUG > 0)
+		clib_warning ("[%d] configured session_scope_local (%d)",
+			      vcm->my_pid, vcl_cfg->session_scope_local);
+	    }
+	  else if (unformat (line_input, "session-scope-global"))
+	    {
+	      vcl_cfg->session_scope_global = 1;
+	      if (VPPCOM_DEBUG > 0)
+		clib_warning ("[%d] configured session_scope_global (%d)",
+			      vcm->my_pid, vcl_cfg->session_scope_global);
+	    }
+	  else if (unformat (line_input, "namespace-secret 0x%lx",
+			     &vcl_cfg->namespace_secret))
+	    {
+	      if (VPPCOM_DEBUG > 0)
+		clib_warning
+		  ("[%d] configured namespace_secret 0x%lx (%lu)",
+		   vcm->my_pid, vcl_cfg->namespace_secret,
+		   vcl_cfg->namespace_secret);
+	    }
+	  else if (unformat (line_input, "namespace-secret %lu",
+			     &vcl_cfg->namespace_secret))
+	    {
+	      if (VPPCOM_DEBUG > 0)
+		clib_warning
+		  ("[%d] configured namespace_secret %lu (0x%lx)",
+		   vcm->my_pid, vcl_cfg->namespace_secret,
+		   vcl_cfg->namespace_secret);
+	    }
+	  else if (unformat (line_input, "namespace-id %v",
+			     &vcl_cfg->namespace_id))
+	    {
+	      vl_api_application_attach_t *mp;
+	      u32 max_nsid_vec_len = sizeof (mp->namespace_id) - 1;
+	      u32 nsid_vec_len = vec_len (vcl_cfg->namespace_id);
+	      if (nsid_vec_len > max_nsid_vec_len)
+		{
+		  _vec_len (vcl_cfg->namespace_id) = max_nsid_vec_len;
+		  if (VPPCOM_DEBUG > 0)
+		    clib_warning ("[%d] configured namespace_id is too long,"
+				  " truncated to %d characters!", vcm->my_pid,
+				  max_nsid_vec_len);
+		}
+
+	      if (VPPCOM_DEBUG > 0)
+		clib_warning ("[%d] configured namespace_id %v",
+			      vcm->my_pid, vcl_cfg->namespace_id);
+	    }
 	  else if (unformat (line_input, "}"))
 	    {
 	      vc_cfg_input = 0;
@@ -1726,22 +1790,72 @@
   if (!vcm->init)
     {
       char *conf_fname;
+      char *env_var_str;
 
       vcm->init = 1;
       vcm->my_pid = getpid ();
       clib_fifo_validate (vcm->client_session_index_fifo,
 			  vcm->cfg.listen_queue_size);
       vppcom_cfg_init (vcl_cfg);
-      conf_fname = getenv (VPPCOM_CONF_ENV);
+      conf_fname = getenv (VPPCOM_ENV_CONF);
       if (!conf_fname)
 	{
 	  conf_fname = VPPCOM_CONF_DEFAULT;
 	  if (VPPCOM_DEBUG > 0)
 	    clib_warning ("[%d] getenv '%s' failed!", vcm->my_pid,
-			  VPPCOM_CONF_ENV);
+			  VPPCOM_ENV_CONF);
 	}
       vppcom_cfg_heapsize (conf_fname);
       vppcom_cfg_read (conf_fname);
+      env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_ID);
+      if (env_var_str)
+	{
+	  u32 ns_id_vec_len = strlen (env_var_str);
+
+	  vec_reset_length (vcm->cfg.namespace_id);
+	  vec_validate (vcm->cfg.namespace_id, ns_id_vec_len - 1);
+	  clib_memcpy (vcm->cfg.namespace_id, env_var_str, ns_id_vec_len);
+
+	  if (VPPCOM_DEBUG > 0)
+	    clib_warning ("[%d] configured namespace_id (%v) from "
+			  VPPCOM_ENV_APP_NAMESPACE_ID "!", vcm->my_pid,
+			  vcm->cfg.namespace_id);
+	}
+      env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_SECRET);
+      if (env_var_str)
+	{
+	  u64 tmp;
+	  if (sscanf (env_var_str, "%lu", &tmp) != 1)
+	    clib_warning ("[%d] Invalid namespace secret specified in "
+			  "the environment variable "
+			  VPPCOM_ENV_APP_NAMESPACE_SECRET
+			  " (%s)!\n", vcm->my_pid, env_var_str);
+	  else
+	    {
+	      vcm->cfg.namespace_secret = tmp;
+	      if (VPPCOM_DEBUG > 0)
+		clib_warning ("[%d] configured namespace secret (%lu) from "
+			      VPPCOM_ENV_APP_NAMESPACE_ID "!", vcm->my_pid,
+			      vcm->cfg.namespace_secret);
+	    }
+	}
+      if (getenv (VPPCOM_ENV_SESSION_SCOPE_LOCAL))
+	{
+	  vcm->cfg.session_scope_local = 1;
+	  if (VPPCOM_DEBUG > 0)
+	    clib_warning ("[%d] configured session_scope_local (%u) from "
+			  VPPCOM_ENV_SESSION_SCOPE_LOCAL "!", vcm->my_pid,
+			  vcm->cfg.session_scope_local);
+	}
+      if (getenv (VPPCOM_ENV_SESSION_SCOPE_GLOBAL))
+	{
+	  vcm->cfg.session_scope_global = 1;
+	  if (VPPCOM_DEBUG > 0)
+	    clib_warning ("[%d] configured session_scope_global (%u) from "
+			  VPPCOM_ENV_SESSION_SCOPE_GLOBAL "!", vcm->my_pid,
+			  vcm->cfg.session_scope_global);
+	}
+
       vcm->bind_session_index = ~0;
       vcm->main_cpu = os_get_thread_index ();
       heap = clib_mem_get_per_cpu_heap ();
diff --git a/src/vcl/vppcom.h b/src/vcl/vppcom.h
index d9ed22f..85c06f1 100644
--- a/src/vcl/vppcom.h
+++ b/src/vcl/vppcom.h
@@ -23,10 +23,14 @@
 /*
  * VPPCOM Public API Definitions, Enums, and Data Structures
  */
-#define INVALID_SESSION_ID   (~0)
-#define VPPCOM_VRF_DEFAULT   0
-#define VPPCOM_CONF_ENV      "VPPCOM_CONF"
-#define VPPCOM_CONF_DEFAULT  "/etc/vpp/vppcom.conf"
+#define INVALID_SESSION_ID               (~0)
+#define VPPCOM_VRF_DEFAULT               0
+#define VPPCOM_CONF_DEFAULT              "/etc/vpp/vppcom.conf"
+#define VPPCOM_ENV_CONF                  "VCL_CONFIG"
+#define VPPCOM_ENV_APP_NAMESPACE_ID      "VCL_APP_NAMESPACE_ID"
+#define VPPCOM_ENV_APP_NAMESPACE_SECRET  "VCL_APP_NAMESPACE_SECRET"
+#define VPPCOM_ENV_SESSION_SCOPE_LOCAL   "VCL_SESSION_SCOPE_LOCAL"
+#define VPPCOM_ENV_SESSION_SCOPE_GLOBAL  "VCL_SESSION_SCOPE_GLOBAL"
 
 typedef enum
 {
diff --git a/src/vnet/session/application_namespace.c b/src/vnet/session/application_namespace.c
index 7f90943..a827551 100644
--- a/src/vnet/session/application_namespace.c
+++ b/src/vnet/session/application_namespace.c
@@ -160,6 +160,7 @@
 app_ns_fn (vlib_main_t * vm, unformat_input_t * input,
 	   vlib_cli_command_t * cmd)
 {
+  unformat_input_t _line_input, *line_input = &_line_input;
   u8 is_add = 0, *ns_id = 0, secret_set = 0, sw_if_index_set = 0;
   u32 sw_if_index, fib_id = APP_NAMESPACE_INVALID_INDEX;
   u64 secret;
@@ -167,22 +168,30 @@
 
   session_cli_return_if_not_enabled ();
 
-  while (unformat_check_input (input) != UNFORMAT_END_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 (input, "add"))
+      if (unformat (line_input, "add"))
 	is_add = 1;
-      else if (unformat (input, "id %_%v%_", &ns_id))
+      else if (unformat (line_input, "id %_%v%_", &ns_id))
 	;
-      else if (unformat (input, "secret %lu", &secret))
+      else if (unformat (line_input, "secret %lu", &secret))
 	secret_set = 1;
-      else if (unformat (input, "sw_if_index %u", &sw_if_index))
+      else if (unformat (line_input, "sw_if_index %u", &sw_if_index))
 	sw_if_index_set = 1;
-      else if (unformat (input, "fib_id", &fib_id))
+      else if (unformat (line_input, "fib_id", &fib_id))
 	;
       else
-	return clib_error_return (0, "unknown input `%U'",
-				  format_unformat_error, input);
+	{
+	  error = clib_error_return (0, "unknown input `%U'",
+				     format_unformat_error, line_input);
+	  unformat_free (line_input);
+	  return error;
+	}
     }
+  unformat_free (line_input);
 
   if (!ns_id || !secret_set || !sw_if_index_set)
     {
@@ -235,13 +244,17 @@
 
   session_cli_return_if_not_enabled ();
 
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+  if (unformat_peek_input (input) != UNFORMAT_END_OF_INPUT)
     {
       if (unformat (input, "table %_%v%_", &ns_id))
 	do_table = 1;
       else
-	return clib_error_return (0, "unknown input `%U'",
-				  format_unformat_error, input);
+	{
+	  vlib_cli_output (vm, "unknown input [%U]",
+			   format_unformat_error, input);
+	  return clib_error_return (0, "unknown input `%U'",
+				    format_unformat_error, input);
+	}
     }
 
   if (do_table)
diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c
index 812d727..e8fa8aa 100755
--- a/src/vnet/session/session_api.c
+++ b/src/vnet/session/session_api.c
@@ -322,7 +322,7 @@
 
   if (mp->namespace_id_len)
     {
-      vec_validate (a->namespace_id, mp->namespace_id_len);
+      vec_validate (a->namespace_id, mp->namespace_id_len - 1);
       clib_memcpy (a->namespace_id, mp->namespace_id, mp->namespace_id_len);
     }
 
diff --git a/src/vnet/session/session_cli.c b/src/vnet/session/session_cli.c
index f0f490d..95fc48d 100755
--- a/src/vnet/session/session_cli.c
+++ b/src/vnet/session/session_cli.c
@@ -455,19 +455,29 @@
 session_enable_disable_fn (vlib_main_t * vm, unformat_input_t * input,
 			   vlib_cli_command_t * cmd)
 {
+  unformat_input_t _line_input, *line_input = &_line_input;
   u8 is_en = 1;
+  clib_error_t *error;
 
-  while (unformat_check_input (input) != UNFORMAT_END_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 (input, "enable"))
+      if (unformat (line_input, "enable"))
 	is_en = 1;
-      else if (unformat (input, "disable"))
+      else if (unformat (line_input, "disable"))
 	is_en = 0;
       else
-	return clib_error_return (0, "unknown input `%U'",
-				  format_unformat_error, input);
+	{
+	  error = clib_error_return (0, "unknown input `%U'",
+				     format_unformat_error, line_input);
+	  unformat_free (line_input);
+	  return error;
+	}
     }
 
+  unformat_free (line_input);
   return vnet_session_enable_disable (vm, is_en);
 }