NAT44: add opaque string tag to static mapping APIs (VPP-1147)

Change-Id: I620e2081285ca8ac5c2da8efc12fe6f540ea4fd1
Signed-off-by: Matus Fabian <matfabia@cisco.com>
diff --git a/src/plugins/nat/nat.api b/src/plugins/nat/nat.api
index 02c1627..aff8f1d 100644
--- a/src/plugins/nat/nat.api
+++ b/src/plugins/nat/nat.api
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-option version = "2.3.0";
+option version = "2.4.0";
 
 /**
  * @file nat.api
@@ -353,6 +353,7 @@
     @param twice_nat - if 1 translate external host address and port, only for
                        1:1 NAPT (addr_only must be 0)
     @param out2in_only - if 1 rule match only out2in direction
+    @param tag - opaque string tag
 */
 autoreply define nat44_add_del_static_mapping {
   u32 client_index;
@@ -368,6 +369,7 @@
   u32 vrf_id;
   u8 twice_nat;
   u8 out2in_only;
+  u8 tag[64];
 };
 
 /** \brief Dump NAT44 static mappings
@@ -391,6 +393,7 @@
     @param vfr_id - VRF ID
     @param twice_nat - if 1 translate external host address and port
     @param out2in_only - if 1 rule match only out2in direction
+    @param tag - opaque string tag
 */
 define nat44_static_mapping_details {
   u32 context;
@@ -404,6 +407,7 @@
   u32 vrf_id;
   u8 twice_nat;
   u8 out2in_only;
+  u8 tag[64];
 };
 
 /** \brief Add/delete NAT44 identity mapping
@@ -417,6 +421,7 @@
     @param sw_if_index - interface (if set ip_address is ignored, ~0 means not
                                     used)
     @param vfr_id - VRF ID (if ~0 use default VRF)
+    @param tag - opaque string tag
 */
 autoreply define nat44_add_del_identity_mapping {
   u32 client_index;
@@ -428,6 +433,7 @@
   u16 port;
   u32 sw_if_index;
   u32 vrf_id;
+  u8 tag[64];
 };
 
 /** \brief Dump NAT44 identity mappings
@@ -447,6 +453,7 @@
     @param port - port number
     @param sw_if_index - interface
     @param vfr_id - VRF ID
+    @param tag - opaque string tag
 */
 define nat44_identity_mapping_details {
   u32 context;
@@ -456,6 +463,7 @@
   u16 port;
   u32 sw_if_index;
   u32 vrf_id;
+  u8 tag[64];
 };
 
 /** \brief Add/delete NAT44 pool address from specific interfce
@@ -572,6 +580,7 @@
   u32 vrf_id;
   u8 twice_nat;
   u8 out2in_only;
+  u8 tag[64];
   u8 local_num;
   vl_api_nat44_lb_addr_port_t locals[local_num];
 };
@@ -589,6 +598,7 @@
   u32 vrf_id;
   u8 twice_nat;
   u8 out2in_only;
+  u8 tag[64];
   u8 local_num;
   vl_api_nat44_lb_addr_port_t locals[local_num];
 };
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index 5c324f2..95004da 100644
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -623,7 +623,8 @@
                                        u32 vrf_id,
                                        snat_protocol_t proto,
                                        int addr_only,
-                                       int is_add)
+                                       int is_add,
+                                       u8 * tag)
 {
   snat_static_map_resolve_t *rp;
 
@@ -636,6 +637,7 @@
   rp->proto = proto;
   rp->addr_only = addr_only;
   rp->is_add = is_add;
+  rp->tag = vec_dup (tag);
 }
 
 /**
@@ -653,13 +655,14 @@
  * @param is_add If 0 delete static mapping, otherwise add.
  * @param twice_nat If 1 translate external host address and port.
  * @param out2in_only If 1 rule match only out2in direction
+ * @param tag - opaque string tag
  *
  * @returns
  */
 int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                             u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
                             u32 sw_if_index, snat_protocol_t proto, int is_add,
-                            u8 twice_nat, u8 out2in_only)
+                            u8 twice_nat, u8 out2in_only, u8 * tag)
 {
   snat_main_t * sm = &snat_main;
   snat_static_mapping_t *m;
@@ -686,7 +689,7 @@
         {
           snat_add_static_mapping_when_resolved
             (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
-             addr_only,  is_add);
+             addr_only,  is_add, tag);
           return 0;
         }
         else
@@ -770,6 +773,7 @@
 
       pool_get (sm->static_mappings, m);
       memset (m, 0, sizeof (*m));
+      m->tag = vec_dup (tag);
       m->local_addr = l_addr;
       m->external_addr = e_addr;
       m->addr_only = addr_only;
@@ -955,6 +959,7 @@
             }
         }
 
+      vec_free (m->tag);
       /* Delete static mapping from pool */
       pool_put (sm->static_mappings, m);
     }
@@ -986,7 +991,7 @@
 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                                      snat_protocol_t proto, u32 vrf_id,
                                      nat44_lb_addr_port_t *locals, u8 is_add,
-                                     u8 twice_nat, u8 out2in_only)
+                                     u8 twice_nat, u8 out2in_only, u8 *tag)
 {
   snat_main_t * sm = &snat_main;
   snat_static_mapping_t *m;
@@ -1064,6 +1069,7 @@
 
       pool_get (sm->static_mappings, m);
       memset (m, 0, sizeof (*m));
+      m->tag = vec_dup (tag);
       m->external_addr = e_addr;
       m->addr_only = 0;
       m->vrf_id = vrf_id;
@@ -1243,6 +1249,7 @@
             }
         }
       vec_free(m->locals);
+      vec_free(m->tag);
 
       pool_put (sm->static_mappings, m);
     }
@@ -1287,7 +1294,7 @@
                                             m->local_port, m->external_port,
                                             m->vrf_id, m->addr_only, ~0,
                                             m->proto, 0, m->twice_nat,
-                                            m->out2in_only);
+                                            m->out2in_only, m->tag);
       }));
     }
   else
@@ -2661,10 +2668,11 @@
                                             ~0 /* sw_if_index */,
                                             rp->proto,
                                             rp->is_add,
-                                            0, 0);
+                                            0, 0, rp->tag);
               if (rv)
                 clib_warning ("snat_add_static_mapping returned %d",
                               rv);
+              vec_free (rp->tag);
               vec_add1 (indices_to_delete, j);
             }
         }
diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h
index bf975a1..58bf8b3 100644
--- a/src/plugins/nat/nat.h
+++ b/src/plugins/nat/nat.h
@@ -222,6 +222,7 @@
   u32 fib_index;
   snat_protocol_t proto;
   u32 worker_index;
+  u8 *tag;
   nat44_lb_addr_port_t *locals;
 } snat_static_mapping_t;
 
@@ -240,6 +241,7 @@
   int addr_only;
   int twice_nat;
   int is_add;
+  u8 *tag;
 } snat_static_map_resolve_t;
 
 typedef struct {
@@ -548,7 +550,7 @@
 int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                             u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
                             u32 sw_if_index, snat_protocol_t proto, int is_add,
-                            u8 twice_nat, u8 out2in_only);
+                            u8 twice_nat, u8 out2in_only, u8 *tag);
 clib_error_t * snat_api_init(vlib_main_t * vm, snat_main_t * sm);
 int snat_set_workers (uword * bitmap);
 int snat_interface_add_del(u32 sw_if_index, u8 is_inside, int is_del);
@@ -561,7 +563,7 @@
 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                                      snat_protocol_t proto, u32 vrf_id,
                                      nat44_lb_addr_port_t *locals, u8 is_add,
-                                     u8 twice_nat, u8 out2in_only);
+                                     u8 twice_nat, u8 out2in_only, u8 *tag);
 int nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
                        snat_protocol_t proto, u32 vrf_id, int is_in);
 void nat_free_session_data (snat_main_t * sm, snat_session_t * s,
diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c
index 0aac1c0..5114615 100644
--- a/src/plugins/nat/nat44_cli.c
+++ b/src/plugins/nat/nat44_cli.c
@@ -543,7 +543,7 @@
 
   rv = snat_add_static_mapping (l_addr, e_addr, (u16) l_port, (u16) e_port,
 				vrf_id, addr_only, sw_if_index, proto, is_add,
-				twice_nat, out2in_only);
+				twice_nat, out2in_only, 0);
 
   switch (rv)
     {
@@ -618,7 +618,7 @@
 
   rv = snat_add_static_mapping (addr, addr, (u16) port, (u16) port,
 				vrf_id, addr_only, sw_if_index, proto, is_add,
-				0, 0);
+				0, 0, 0);
 
   switch (rv)
     {
@@ -715,7 +715,7 @@
 
   rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
 					locals, is_add, twice_nat,
-					out2in_only);
+					out2in_only, 0);
 
   switch (rv)
     {
diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c
index f23efa8..3cb7399 100644
--- a/src/plugins/nat/nat_api.c
+++ b/src/plugins/nat/nat_api.c
@@ -696,6 +696,7 @@
   u32 vrf_id, external_sw_if_index;
   int rv = 0;
   snat_protocol_t proto;
+  u8 *tag = 0;
 
   memcpy (&local_addr.as_u8, mp->local_ip_address, 4);
   memcpy (&external_addr.as_u8, mp->external_ip_address, 4);
@@ -707,11 +708,16 @@
   vrf_id = clib_net_to_host_u32 (mp->vrf_id);
   external_sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index);
   proto = ip_proto_to_snat_proto (mp->protocol);
+  mp->tag[sizeof (mp->tag) - 1] = 0;
+  tag = format (0, "%s", mp->tag);
+  vec_terminate_c_string (tag);
 
   rv = snat_add_static_mapping (local_addr, external_addr, local_port,
 				external_port, vrf_id, mp->addr_only,
 				external_sw_if_index, proto, mp->is_add,
-				mp->twice_nat, mp->out2in_only);
+				mp->twice_nat, mp->out2in_only, tag);
+
+  vec_free (tag);
 
   REPLY_MACRO (VL_API_NAT44_ADD_DEL_STATIC_MAPPING_REPLY);
 }
@@ -766,6 +772,8 @@
   rmp->context = context;
   rmp->twice_nat = m->twice_nat;
   rmp->out2in_only = m->out2in_only;
+  if (m->tag)
+    strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
 
   vl_api_send_msg (reg, (u8 *) rmp);
 }
@@ -791,6 +799,8 @@
   rmp->protocol = snat_proto_to_ip_proto (m->proto);
   rmp->context = context;
   rmp->twice_nat = m->twice_nat;
+  if (m->tag)
+    strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
 
   vl_api_send_msg (reg, (u8 *) rmp);
 }
@@ -847,6 +857,7 @@
   u32 vrf_id, sw_if_index;
   int rv = 0;
   snat_protocol_t proto = ~0;
+  u8 *tag = 0;
 
   if (mp->addr_only == 0)
     {
@@ -859,11 +870,15 @@
     addr.as_u32 = 0;
   else
     memcpy (&addr.as_u8, mp->ip_address, 4);
-
+  mp->tag[sizeof (mp->tag) - 1] = 0;
+  tag = format (0, "%s", mp->tag);
+  vec_terminate_c_string (tag);
 
   rv =
     snat_add_static_mapping (addr, addr, port, port, vrf_id, mp->addr_only,
-			     sw_if_index, proto, mp->is_add, 0, 0);
+			     sw_if_index, proto, mp->is_add, 0, 0, tag);
+
+  vec_free (tag);
 
   REPLY_MACRO (VL_API_NAT44_ADD_DEL_IDENTITY_MAPPING_REPLY);
 }
@@ -908,6 +923,8 @@
   rmp->vrf_id = htonl (m->vrf_id);
   rmp->protocol = snat_proto_to_ip_proto (m->proto);
   rmp->context = context;
+  if (m->tag)
+    strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
 
   vl_api_send_msg (reg, (u8 *) rmp);
 }
@@ -930,6 +947,8 @@
   rmp->vrf_id = htonl (m->vrf_id);
   rmp->protocol = snat_proto_to_ip_proto (m->proto);
   rmp->context = context;
+  if (m->tag)
+    strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
 
   vl_api_send_msg (reg, (u8 *) rmp);
 }
@@ -1238,19 +1257,24 @@
   nat44_lb_addr_port_t *locals = 0;
   ip4_address_t e_addr;
   snat_protocol_t proto;
+  u8 *tag = 0;
 
   locals = unformat_nat44_lb_addr_port (mp->locals, mp->local_num);
   clib_memcpy (&e_addr, mp->external_addr, 4);
   proto = ip_proto_to_snat_proto (mp->protocol);
+  mp->tag[sizeof (mp->tag) - 1] = 0;
+  tag = format (0, "%s", mp->tag);
+  vec_terminate_c_string (tag);
 
   rv =
     nat44_add_del_lb_static_mapping (e_addr,
 				     clib_net_to_host_u16 (mp->external_port),
 				     proto, clib_net_to_host_u32 (mp->vrf_id),
 				     locals, mp->is_add, mp->twice_nat,
-				     mp->out2in_only);
+				     mp->out2in_only, tag);
 
   vec_free (locals);
+  vec_free (tag);
 
   REPLY_MACRO (VL_API_NAT44_ADD_DEL_LB_STATIC_MAPPING_REPLY);
 }
@@ -1291,6 +1315,8 @@
   rmp->context = context;
   rmp->twice_nat = m->twice_nat;
   rmp->out2in_only = m->out2in_only;
+  if (m->tag)
+    strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
 
   locals = (vl_api_nat44_lb_addr_port_t *) rmp->locals;
   vec_foreach (ap, m->locals)
diff --git a/test/test_nat.py b/test/test_nat.py
index 46a6d42..f0614da 100644
--- a/test/test_nat.py
+++ b/test/test_nat.py
@@ -1030,6 +1030,7 @@
                 protocol=sm.protocol,
                 twice_nat=sm.twice_nat,
                 out2in_only=sm.out2in_only,
+                tag=sm.tag,
                 is_add=0)
 
         lb_static_mappings = self.vapi.nat44_lb_static_mapping_dump()
@@ -1041,6 +1042,7 @@
                 vrf_id=lb_sm.vrf_id,
                 twice_nat=lb_sm.twice_nat,
                 out2in_only=lb_sm.out2in_only,
+                tag=lb_sm.tag,
                 is_add=0,
                 local_num=0,
                 locals=[])
@@ -1069,7 +1071,7 @@
     def nat44_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
                                  local_port=0, external_port=0, vrf_id=0,
                                  is_add=1, external_sw_if_index=0xFFFFFFFF,
-                                 proto=0, twice_nat=0, out2in_only=0):
+                                 proto=0, twice_nat=0, out2in_only=0, tag=""):
         """
         Add/delete NAT44 static mapping
 
@@ -1083,6 +1085,7 @@
         :param proto: IP protocol (Mandatory if port specified)
         :param twice_nat: 1 if translate external host address and port
         :param out2in_only: if 1 rule is matching only out2in direction
+        :param tag: Opaque string tag
         """
         addr_only = 1
         if local_port and external_port:
@@ -1100,6 +1103,7 @@
             proto,
             twice_nat,
             out2in_only,
+            tag,
             is_add)
 
     def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF, twice_nat=0):
@@ -1376,6 +1380,9 @@
         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
                                                   is_inside=0)
+        sm = self.vapi.nat44_static_mapping_dump()
+        self.assertEqual(len(sm), 1)
+        self.assertEqual((sm[0].tag).split('\0', 1)[0], '')
 
         # in2out
         pkts = self.create_stream_in(self.pg0, self.pg1)
@@ -1400,11 +1407,15 @@
         self.tcp_port_out = 6303
         self.udp_port_out = 6304
         self.icmp_id_out = 6305
+        tag = "testTAG"
 
-        self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
+        self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip, tag=tag)
         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
                                                   is_inside=0)
+        sm = self.vapi.nat44_static_mapping_dump()
+        self.assertEqual(len(sm), 1)
+        self.assertEqual((sm[0].tag).split('\0', 1)[0], tag)
 
         # out2in
         pkts = self.create_stream_out(self.pg1, nat_ip)
@@ -2338,16 +2349,20 @@
 
     def test_interface_addr_static_mapping(self):
         """ Static mapping with addresses from interface """
+        tag = "testTAG"
+
         self.vapi.nat44_add_interface_addr(self.pg7.sw_if_index)
         self.nat44_add_static_mapping(
             '1.2.3.4',
-            external_sw_if_index=self.pg7.sw_if_index)
+            external_sw_if_index=self.pg7.sw_if_index,
+            tag=tag)
 
         # static mappings with external interface
         static_mappings = self.vapi.nat44_static_mapping_dump()
         self.assertEqual(1, len(static_mappings))
         self.assertEqual(self.pg7.sw_if_index,
                          static_mappings[0].external_sw_if_index)
+        self.assertEqual((static_mappings[0].tag).split('\0', 1)[0], tag)
 
         # configure interface address and check static mappings
         self.pg7.config_ip4()
@@ -2356,6 +2371,7 @@
         self.assertEqual(static_mappings[0].external_ip_address[0:4],
                          self.pg7.local_ip4n)
         self.assertEqual(0xFFFFFFFF, static_mappings[0].external_sw_if_index)
+        self.assertEqual((static_mappings[0].tag).split('\0', 1)[0], tag)
 
         # remove interface address and check static mappings
         self.pg7.unconfig_ip4()
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index db0f8e6..b791444 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -1236,6 +1236,7 @@
             protocol=0,
             twice_nat=0,
             out2in_only=0,
+            tag="",
             is_add=1):
         """Add/delete NAT44 static mapping
 
@@ -1249,6 +1250,7 @@
         :param protocol: IP protocol (Default value = 0)
         :param twice_nat: 1 if translate external host address and port
         :param out2in_only: if 1 rule is matching only out2in direction
+        :param tag: Opaque string tag
         :param is_add: 1 if add, 0 if delete (Default value = 1)
         """
         return self.api(
@@ -1263,7 +1265,8 @@
              'vrf_id': vrf_id,
              'protocol': protocol,
              'twice_nat': twice_nat,
-             'out2in_only': out2in_only})
+             'out2in_only': out2in_only,
+             'tag': tag})
 
     def nat44_add_del_identity_mapping(
             self,
@@ -1273,6 +1276,7 @@
             addr_only=1,
             vrf_id=0,
             protocol=0,
+            tag='',
             is_add=1):
         """Add/delete NAT44 identity mapping
 
@@ -1282,6 +1286,7 @@
         :param addr_only: 1 if address only mapping, 0 if address and port
         :param vrf_id: VRF ID
         :param protocol: IP protocol (Default value = 0)
+        :param tag: Opaque string tag
         :param is_add: 1 if add, 0 if delete (Default value = 1)
         """
         return self.api(
@@ -1292,6 +1297,7 @@
              'port': port,
              'sw_if_index': sw_if_index,
              'vrf_id': vrf_id,
+             'tag': tag,
              'protocol': protocol})
 
     def nat44_add_del_address_range(
@@ -1424,12 +1430,14 @@
             vrf_id=0,
             twice_nat=0,
             out2in_only=0,
+            tag='',
             local_num=0,
             locals=[],
             is_add=1):
         """Add/delete NAT44 load balancing static mapping
 
         :param twice_nat: 1 if translate external host address and port
+        :param tag: Opaque string tag
         :param is_add - 1 if add, 0 if delete
         """
         return self.api(
@@ -1441,6 +1449,7 @@
              'vrf_id': vrf_id,
              'twice_nat': twice_nat,
              'out2in_only': out2in_only,
+             'tag': tag,
              'local_num': local_num,
              'locals': locals})