l2: Add bridge_domain_add_del_v2 to l2 api

https://jira.fd.io/browse/VPP-2034

Type: fix
Signed-off-by: Laszlo Kiraly <laszlo.kiraly@est.tech>
Change-Id: Ieb6919f958f437fc603d5e1f48cab01de780951d
diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api
index b0ac23f..ccba9aa 100644
--- a/src/vnet/l2/l2.api
+++ b/src/vnet/l2/l2.api
@@ -1,6 +1,7 @@
 /* Hey Emacs use -*- mode: C -*- */
 /*
  * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Copyright (c) 2022 Nordix Foundation.
  * 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:
@@ -14,7 +15,7 @@
  * limitations under the License.
  */
 
-option version = "3.1.0";
+option version = "3.2.0";
 
 import "vnet/ip/ip_types.api";
 import "vnet/ethernet/ethernet_types.api";
@@ -304,7 +305,7 @@
   u32 learn_limit;
 };
 
-/** \brief L2 bridge domain add or delete request
+/** \brief L2 bridge domain add or delete request - will be deprecated
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
     @param bd_id - the bridge domain to create
@@ -319,6 +320,7 @@
 */
 autoreply define bridge_domain_add_del
 {
+  option deprecated;
   u32 client_index;
   u32 context;
   u32 bd_id;
@@ -333,6 +335,49 @@
   bool is_add [default=true];
 };
 
+/** \brief L2 bridge domain add delete request version 2
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param bd_id -  if the id == ~0 creates a bridge domain with an unused id
+              if the id != ~0 the id of the bridge domain to create/delete
+    @param flood - enable/disable bcast/mcast flooding in the bd
+    @param uu_flood - enable/disable unknown unicast flood in the bd
+    @param forward - enable/disable forwarding on all interfaces in the bd
+    @param learn - enable/disable learning on all interfaces in the bd
+    @param arp_term - enable/disable arp termination in the bd
+    @param arp_ufwd - enable/disable arp unicast forwarding in the bd
+    @param mac_age - mac aging time in min, 0 for disabled
+    @param is_add - add or delete flag
+*/
+define bridge_domain_add_del_v2
+{
+  u32 client_index;
+  u32 context;
+  u32 bd_id;
+  bool flood;
+  bool uu_flood;
+  bool forward;
+  bool learn;
+  bool arp_term;
+  bool arp_ufwd;
+  u8 mac_age;
+  string bd_tag[64];
+  bool is_add [default=true];
+};
+
+/** \brief L2 bridge domain add delete version 2 response
+    @param context - sender context, to match reply w/ request
+    @param retval - return code for the set bridge flags request
+    @param resulting_id - the id for the new bridge domain
+*/
+define bridge_domain_add_del_v2_reply
+{
+  u32 context;
+  i32 retval;
+  u32 bd_id;
+};
+
+
 /** \brief L2 bridge domain request operational state details
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c
index c555a17..cb22547 100644
--- a/src/vnet/l2/l2_api.c
+++ b/src/vnet/l2/l2_api.c
@@ -3,6 +3,7 @@
  * l2_api.c - layer 2 forwarding api
  *
  * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Copyright (c) 2022 Nordix Foundation.
  * 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:
@@ -511,6 +512,37 @@
 }
 
 static void
+vl_api_bridge_domain_add_del_v2_t_handler (
+  vl_api_bridge_domain_add_del_v2_t *mp)
+{
+  vl_api_bridge_domain_add_del_v2_reply_t *rmp;
+  u32 bd_id = ntohl (mp->bd_id);
+  int rv = 0;
+
+  if ((~0 == bd_id) && (mp->is_add))
+    bd_id = bd_get_unused_id ();
+
+  if ((~0 == bd_id) && (mp->is_add))
+    rv = VNET_API_ERROR_EAGAIN;
+  else
+    {
+      l2_bridge_domain_add_del_args_t a = { .is_add = mp->is_add,
+					    .flood = mp->flood,
+					    .uu_flood = mp->uu_flood,
+					    .forward = mp->forward,
+					    .learn = mp->learn,
+					    .arp_term = mp->arp_term,
+					    .arp_ufwd = mp->arp_ufwd,
+					    .mac_age = mp->mac_age,
+					    .bd_id = bd_id,
+					    .bd_tag = mp->bd_tag };
+      rv = bd_add_del (&a);
+    }
+  REPLY_MACRO2 (VL_API_BRIDGE_DOMAIN_ADD_DEL_V2_REPLY,
+		({ rmp->bd_id = htonl (bd_id); }));
+}
+
+static void
 send_bridge_domain_details (l2input_main_t * l2im,
 			    vl_api_registration_t * reg,
 			    l2_bridge_domain_t * bd_config,
diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c
index 7e6ea60..a842917 100644
--- a/src/vnet/l2/l2_bd.c
+++ b/src/vnet/l2/l2_bd.c
@@ -1493,8 +1493,15 @@
 
   if (bd_id == ~0)
     {
-      error = clib_error_return (0, "bridge-domain-id not specified");
-      goto done;
+      if (is_add)
+	{
+	  bd_id = bd_get_unused_id ();
+	}
+      else
+	{
+	  error = clib_error_return (0, "bridge-domain-id not specified");
+	  goto done;
+	}
     }
 
   if (bd_id == 0)
@@ -1597,7 +1604,40 @@
 };
 /* *INDENT-ON* */
 
+/*
+ * Returns an unused bridge domain id, and ~0 if it can't find one.
+ */
+u32
+bd_get_unused_id ()
+{
+  bd_main_t *bdm = &bd_main;
+  int i, j;
+  int is_seed_low = 0;
+  static u32 seed = 0;
+  /* limit to 1M tries */
+  for (j = 0; j < 1 << 10; j++)
+    {
+      seed = random_u32 (&seed) & L2_BD_ID_MAX;
+      if (seed == 0)
+	continue;
+      if (seed < L2_BD_ID_MAX % 2)
+	is_seed_low = 1;
+      for (i = 0; i < L2_BD_ID_MAX % 2; i++)
+	{
+	  /* look around randomly generated id */
+	  if (is_seed_low)
+	    seed += (2 * (i % 2) - 1) * i;
+	  else
+	    seed -= (2 * (i % 2) - 1) * i;
+	  if (seed == ~0 || seed == 0)
+	    continue;
+	  if (bd_find_index (bdm, seed) == ~0)
+	    return seed;
+	}
+    }
 
+  return ~0;
+}
 
 /*
  * fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h
index 0d77292..082d210 100644
--- a/src/vnet/l2/l2_bd.h
+++ b/src/vnet/l2/l2_bd.h
@@ -2,6 +2,7 @@
  * l2_bd.h : layer 2 bridge domain
  *
  * Copyright (c) 2013 Cisco and/or its affiliates.
+ * Copyright (c) 2022 Nordix Foundation.
  * 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:
@@ -166,7 +167,7 @@
 void bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age);
 void bd_set_learn_limit (vlib_main_t *vm, u32 bd_index, u32 learn_limit);
 int bd_add_del (l2_bridge_domain_add_del_args_t * args);
-
+u32 bd_get_unused_id (void);
 /**
  * \brief Get a bridge domain.
  *
diff --git a/src/vnet/l2/l2_test.c b/src/vnet/l2/l2_test.c
index 3be4a46..b78e388 100644
--- a/src/vnet/l2/l2_test.c
+++ b/src/vnet/l2/l2_test.c
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: Apache-2.0
  * Copyright(c) 2021 Cisco Systems, Inc.
+ * Copyright(c) 2022 Nordix Foundation.
  */
 
 #include <vat/vat.h>
@@ -634,6 +635,18 @@
   return ret;
 }
 
+static int
+api_bridge_domain_add_del_v2 (vat_main_t *vam)
+{
+  return -1;
+}
+
+static void
+vl_api_bridge_domain_add_del_v2_reply_t_handler (
+  vl_api_bridge_domain_add_del_v2_reply_t *mp)
+{
+}
+
 #define foreach_pbb_vtr_op                                                    \
   _ ("disable", L2_VTR_DISABLED)                                              \
   _ ("pop", L2_VTR_POP_2)                                                     \