Enforce Bridge Domain ID range to match 24-bit VNI range

Enforce bridge domain ID range to allow a maximum value of 16M
which matches the range of 24-bit VNI used for virtual overlay
network ID.
Fix "show bridge-domain" output to allow full 16M BD ID range
to be displayed using 8-digit spaces.

Change-Id: I80d9c76ea7c001bcccd3c19df1f3e55d2970f01c
Signed-off-by: John Lo <loj@cisco.com>
diff --git a/src/vlibapi/api_helper_macros.h b/src/vlibapi/api_helper_macros.h
index a492c3f..2e29d4d 100644
--- a/src/vlibapi/api_helper_macros.h
+++ b/src/vlibapi/api_helper_macros.h
@@ -155,6 +155,20 @@
     ;                                           \
 } while (0);
 
+#define VALIDATE_BD_ID(mp)			\
+ do { u32 __rx_bd_id = ntohl(mp->bd_id);	\
+    if (__rx_bd_id > L2_BD_ID_MAX) {     	\
+        rv = VNET_API_ERROR_BD_ID_EXCEED_MAX;	\
+        goto bad_bd_id;				\
+    }						\
+} while(0);
+
+#define BAD_BD_ID_LABEL				\
+do {                                            \
+bad_bd_id:					\
+    ;                                           \
+} while (0);
+
 #define pub_sub_handler(lca,UCA)                                        \
 static void vl_api_want_##lca##_t_handler (                             \
     vl_api_want_##lca##_t *mp)                                          \
diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h
index e694fbf..b22bb3a 100644
--- a/src/vnet/api_errno.h
+++ b/src/vnet/api_errno.h
@@ -110,8 +110,9 @@
 _(APPLICATION_NOT_ATTACHED, -118, "application not attached")           \
 _(BD_ALREADY_EXISTS, -119, "Bridge domain already exists")              \
 _(BD_IN_USE, -120, "Bridge domain has member interfaces")		\
-_(BD_NOT_MODIFIABLE, -121, "Default bridge domain 0 can be neither deleted nor modified") \
-_(UNSUPPORTED, -122, "Unsupported")
+_(BD_NOT_MODIFIABLE, -121, "Bridge domain 0 can't be deleted/modified") \
+_(BD_ID_EXCEED_MAX, -122, "Bridge domain ID exceed 16M limit")		\
+_(UNSUPPORTED, -123, "Unsupported")
 
 typedef enum
 {
diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c
index 351e698..f68b663 100644
--- a/src/vnet/l2/l2_bd.c
+++ b/src/vnet/l2/l2_bd.c
@@ -984,10 +984,10 @@
 	    {
 	      printed = 1;
 	      vlib_cli_output (vm,
-			       "%=5s %=7s %=4s %=9s %=9s %=9s %=9s %=9s %=9s %=9s",
-			       "ID", "Index", "BSN", "Age(min)", "Learning",
-			       "U-Forwrd", "UU-Flood", "Flooding", "ARP-Term",
-			       "BVI-Intf");
+			       "%=8s %=7s %=4s %=9s %=9s %=9s %=9s %=9s %=9s %=9s",
+			       "BD-ID", "Index", "BSN", "Age(min)",
+			       "Learning", "U-Forwrd", "UU-Flood", "Flooding",
+			       "ARP-Term", "BVI-Intf");
 	    }
 
 	  if (bd_config->mac_age)
@@ -995,7 +995,7 @@
 	  else
 	    as = format (as, "off");
 	  vlib_cli_output (vm,
-			   "%=5d %=7d %=4d %=9v %=9s %=9s %=9s %=9s %=9s %=9U",
+			   "%=8d %=7d %=4d %=9v %=9s %=9s %=9s %=9s %=9s %=9U",
 			   bd_config->bd_id, bd_index, bd_config->seq_num, as,
 			   bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ?
 			   "on" : "off",
@@ -1123,6 +1123,8 @@
     {
       if (bd_index != ~0)
 	return VNET_API_ERROR_BD_ALREADY_EXISTS;
+      if (a->bd_id > L2_BD_ID_MAX)
+	return VNET_API_ERROR_BD_ID_EXCEED_MAX;
       bd_index = bd_add_bd_index (bdm, a->bd_id);
 
       u32 enable_flags = 0, disable_flags = 0;
@@ -1262,11 +1264,14 @@
       error = clib_error_return (0, "bridge domain in use - remove members");
       goto done;
     case VNET_API_ERROR_NO_SUCH_ENTRY:
-      error = clib_error_return (0, "bridge domain id does not exist");
+      error = clib_error_return (0, "bridge domain ID does not exist");
       goto done;
     case VNET_API_ERROR_BD_NOT_MODIFIABLE:
       error = clib_error_return (0, "bridge domain 0 can not be modified");
       goto done;
+    case VNET_API_ERROR_BD_ID_EXCEED_MAX:
+      error = clib_error_return (0, "bridge domain ID exceed 16M limit");
+      goto done;
     default:
       error = clib_error_return (0, "bd_add_del returned %d", rv);
       goto done;
diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h
index e502d49..93ed1a8 100644
--- a/src/vnet/l2/l2_bd.h
+++ b/src/vnet/l2/l2_bd.h
@@ -49,7 +49,6 @@
   u16 spare;
 } l2_flood_member_t;
 
-
 /* Per-bridge domain configuration */
 
 typedef struct
@@ -91,6 +90,9 @@
 
 } l2_bridge_domain_t;
 
+/* Limit Bridge Domain ID to 24 bits to match 24-bit VNI range */
+#define L2_BD_ID_MAX ((1<<24)-1)
+
 typedef struct
 {
   u32 bd_id;
diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c
index 41a93f5..aca23fe 100644
--- a/src/vnet/l2/l2_input.c
+++ b/src/vnet/l2/l2_input.c
@@ -791,6 +791,12 @@
       goto done;
     }
 
+  if (bd_id > L2_BD_ID_MAX)
+    {
+      error = clib_error_return (0, "bridge domain ID exceed 16M limit",
+				 format_unformat_error, input);
+      goto done;
+    }
   bd_index = bd_find_or_add_bd_index (&bd_main, bd_id);
 
   /* optional bvi  */
diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c
index ff75056..94703ab 100644
--- a/src/vnet/lisp-gpe/interface.c
+++ b/src/vnet/lisp-gpe/interface.c
@@ -653,6 +653,12 @@
   uword *hip, *si;
   u16 bd_index;
 
+  if (bd_id > L2_BD_ID_MAX)
+    {
+      clib_warning ("bridge domain ID %d exceed 16M limit", bd_id);
+      return ~0;
+    }
+
   bd_index = bd_find_or_add_bd_index (&bd_main, bd_id);
   hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index);
 
diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c
index 16d5122..7e4c341 100644
--- a/src/vpp/api/api.c
+++ b/src/vpp/api/api.c
@@ -419,6 +419,7 @@
 
   if (mp->enable)
     {
+      VALIDATE_BD_ID (mp);
       u32 bd_id = ntohl (mp->bd_id);
       u32 bd_index = bd_find_or_add_bd_index (bdm, bd_id);
       u32 bvi = mp->bvi;
@@ -432,6 +433,7 @@
     }
 
   BAD_RX_SW_IF_INDEX_LABEL;
+  BAD_BD_ID_LABEL;
 
   REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_BRIDGE_REPLY);
 }