NAT44: LB NAT - local backends in multiple VRFs (VPP-1345) 79/13579/3
authorMatus Fabian <matfabia@cisco.com>
Fri, 20 Jul 2018 05:45:25 +0000 (22:45 -0700)
committerDamjan Marion <dmarion@me.com>
Thu, 2 Aug 2018 17:17:47 +0000 (17:17 +0000)
Add support for local backends in multiple VRFs for load-balancing NAT rules.

Change-Id: I64e6818bd67a7e69985003498cf1f16f7200c334
Signed-off-by: Matus Fabian <matfabia@cisco.com>
src/plugins/nat/nat.api
src/plugins/nat/nat.c
src/plugins/nat/nat.h
src/plugins/nat/nat44_cli.c
src/plugins/nat/nat_api.c
test/test_nat.py
test/vpp_papi_provider.py

index 4192cf1..26d0fba 100644 (file)
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-option version = "2.6.0";
+option version = "3.0.0";
 
 /**
  * @file nat.api
@@ -595,6 +595,7 @@ typeonly manual_endian define nat44_lb_addr_port {
   u8 addr[4];
   u16 port;
   u8 probability;
+  u32 vrf_id;
 };
 
 /** \brief Add/delete NAT44 load-balancing static mapping rule
@@ -604,7 +605,6 @@ typeonly manual_endian define nat44_lb_addr_port {
     @param external_addr - external IPv4 address of the service
     @param external_port - external L4 port number of the service
     @param protocol - IP protocol number of the service
-    @param vrf_id - internal network VRF ID
     @param twice_nat - if 1 translate external host address and port
     @param self_twice_nat - if 1 translate external host address and port
                             whenever external host address equals
@@ -621,7 +621,6 @@ autoreply manual_endian define nat44_add_del_lb_static_mapping {
   u8 external_addr[4];
   u16 external_port;
   u8 protocol;
-  u32 vrf_id;
   u8 twice_nat;
   u8 self_twice_nat;
   u8 out2in_only;
@@ -645,7 +644,6 @@ define nat44_lb_static_mapping_dump {
     @param external_addr - external IPv4 address of the service
     @param external_port - external L4 port number of the service
     @param protocol - IP protocol number of the service
-    @param vrf_id - internal network VRF ID
     @param twice_nat - if 1 translate external host address and port
     @param self_twice_nat - if 1 translate external host address and port
                             whenever external host address equals
@@ -660,7 +658,6 @@ manual_endian define nat44_lb_static_mapping_details {
   u8 external_addr[4];
   u16 external_port;
   u8 protocol;
-  u32 vrf_id;
   u8 twice_nat;
   u8 self_twice_nat;
   u8 out2in_only;
index f351206..cdf05fd 100755 (executable)
@@ -1235,7 +1235,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
 }
 
 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
-                                     snat_protocol_t proto, u32 vrf_id,
+                                     snat_protocol_t proto,
                                      nat44_lb_addr_port_t *locals, u8 is_add,
                                      twice_nat_type_t twice_nat, u8 out2in_only,
                                      u8 *tag)
@@ -1244,7 +1244,6 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
   snat_static_mapping_t *m;
   snat_session_key_t m_key;
   clib_bihash_kv_8_8_t kv, value;
-  u32 fib_index;
   snat_address_t *a = 0;
   int i;
   nat44_lb_addr_port_t *local;
@@ -1277,10 +1276,6 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       if (vec_len (locals) < 2)
         return VNET_API_ERROR_INVALID_VALUE;
 
-      fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
-                                                     vrf_id,
-                                                     FIB_SOURCE_PLUGIN_LOW);
-
       /* Find external address in allocated addresses and reserve port for
          address and port pair mapping when dynamic translations enabled */
       if (!(sm->static_mapping_only || out2in_only))
@@ -1323,8 +1318,6 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       m->tag = vec_dup (tag);
       m->external_addr = e_addr;
       m->addr_only = 0;
-      m->vrf_id = vrf_id;
-      m->fib_index = fib_index;
       m->external_port = e_port;
       m->proto = proto;
       m->twice_nat = twice_nat;
@@ -1345,7 +1338,10 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       m_key.fib_index = m->fib_index;
       for (i = 0; i < vec_len (locals); i++)
         {
+          locals[i].fib_index = fib_table_find_or_create_and_lock (
+            FIB_PROTOCOL_IP4, locals[i].vrf_id, FIB_SOURCE_PLUGIN_LOW);
           m_key.addr = locals[i].addr;
+          m_key.fib_index = locals[i].fib_index;
           if (!out2in_only)
             {
               m_key.port = locals[i].port;
@@ -1380,8 +1376,6 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       if (!m)
         return VNET_API_ERROR_NO_SUCH_ENTRY;
 
-      fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW);
-
       /* Free external address port */
       if (!(sm->static_mapping_only || out2in_only))
         {
@@ -1425,11 +1419,13 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
 
       vec_foreach (local, m->locals)
         {
+          fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
+                            FIB_SOURCE_PLUGIN_LOW);
           m_key.addr = local->addr;
           if (!out2in_only)
             {
               m_key.port = local->port;
-              m_key.fib_index = m->fib_index;
+              m_key.fib_index = local->fib_index;
               kv.key = m_key.as_u64;
               if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
                 {
@@ -2207,15 +2203,16 @@ get_local:
             }
           mapping->addr = m->locals[lo].addr;
           mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
+          mapping->fib_index = m->locals[lo].fib_index;
         }
       else
         {
+          mapping->fib_index = m->fib_index;
           mapping->addr = m->local_addr;
           /* Address only mapping doesn't change port */
           mapping->port = m->addr_only ? match.port
             : clib_host_to_net_u16 (m->local_port);
         }
-      mapping->fib_index = m->fib_index;
       mapping->protocol = m->proto;
     }
   else
@@ -3083,17 +3080,16 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args)
    {
       if (vec_len (m->locals))
         {
-          s = format (s, "%U vrf %d external %U:%d %s %s",
+          s = format (s, "%U external %U:%d %s %s",
                       format_snat_protocol, m->proto,
-                      m->vrf_id,
                       format_ip4_address, &m->external_addr, m->external_port,
                       m->twice_nat == TWICE_NAT ? "twice-nat" :
                       m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
                       m->out2in_only ? "out2in-only" : "");
           vec_foreach (local, m->locals)
-            s = format (s, "\n  local %U:%d probability %d\%",
+            s = format (s, "\n  local %U:%d vrf %d probability %d\%",
                         format_ip4_address, &local->addr, local->port,
-                        local->probability);
+                        local->vrf_id, local->probability);
         }
       else
         s = format (s, "%U local %U:%d external %U:%d vrf %d %s %s",
index 97bbec2..0d51109 100644 (file)
@@ -231,6 +231,8 @@ typedef struct {
   u16 port;
   u8 probability;
   u8 prefix;
+  u32 vrf_id;
+  u32 fib_index;
 } nat44_lb_addr_port_t;
 
 typedef enum {
@@ -610,7 +612,7 @@ int snat_add_interface_address(snat_main_t *sm, u32 sw_if_index, int is_del,
 uword unformat_snat_protocol(unformat_input_t * input, va_list * args);
 u8 * format_snat_protocol(u8 * s, va_list * args);
 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
-                                     snat_protocol_t proto, u32 vrf_id,
+                                     snat_protocol_t proto,
                                      nat44_lb_addr_port_t *locals, u8 is_add,
                                      twice_nat_type_t twice_nat, u8 out2in_only,
                                      u8 *tag);
index aa733a0..e4fd0ca 100644 (file)
@@ -767,11 +767,20 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
          local.probability = (u8) probability;
          vec_add1 (locals, local);
        }
+      else if (unformat (line_input, "local %U:%u vrf %u probability %u",
+                        unformat_ip4_address, &l_addr, &l_port, &vrf_id,
+                        &probability))
+       {
+         memset (&local, 0, sizeof (local));
+         local.addr = l_addr;
+         local.port = (u16) l_port;
+         local.probability = (u8) probability;
+         local.vrf_id = vrf_id;
+         vec_add1 (locals, local);
+       }
       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
                         &e_addr, &e_port))
        ;
-      else if (unformat (line_input, "vrf %u", &vrf_id))
-       ;
       else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
                         &proto))
        proto_set = 1;
@@ -803,9 +812,8 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
       goto done;
     }
 
-  rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
-                                       locals, is_add, twice_nat,
-                                       out2in_only, 0);
+  rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, locals,
+                                       is_add, twice_nat, out2in_only, 0);
 
   switch (rv)
     {
@@ -1716,8 +1724,8 @@ VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
   .function = add_lb_static_mapping_command_fn,
   .short_help =
     "nat44 add load-balancing static mapping protocol tcp|udp "
-    "external <addr>:<port> local <addr>:<port> probability <n> "
-    "[twice-nat|self-twice-nat] [vrf <table-id>] [out2in-only] [del]",
+    "external <addr>:<port> local <addr>:<port> [vrf <table-id>] "
+    "probability <n> [twice-nat|self-twice-nat] [out2in-only] [del]",
 };
 
 /*?
index 6d4d0d9..5887efe 100644 (file)
@@ -1341,6 +1341,7 @@ unformat_nat44_lb_addr_port (vl_api_nat44_lb_addr_port_t * addr_port_pairs,
       clib_memcpy (&lb_addr_port.addr, ap->addr, 4);
       lb_addr_port.port = clib_net_to_host_u16 (ap->port);
       lb_addr_port.probability = ap->probability;
+      lb_addr_port.vrf_id = clib_net_to_host_u32 (ap->vrf_id);
       vec_add1 (lb_addr_port_pairs, lb_addr_port);
     }
 
@@ -1360,7 +1361,7 @@ static void
   snat_protocol_t proto;
   u8 *tag = 0;
 
-  if (sm->deterministic)
+  if (!sm->endpoint_dependent)
     {
       rv = VNET_API_ERROR_UNSUPPORTED;
       goto send_reply;
@@ -1380,8 +1381,7 @@ static void
   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, twice_nat,
+                                    proto, locals, mp->is_add, twice_nat,
                                     mp->out2in_only, tag);
 
   vec_free (locals);
@@ -1423,7 +1423,6 @@ send_nat44_lb_static_mapping_details (snat_static_mapping_t * m,
   clib_memcpy (rmp->external_addr, &(m->external_addr), 4);
   rmp->external_port = ntohs (m->external_port);
   rmp->protocol = snat_proto_to_ip_proto (m->proto);
-  rmp->vrf_id = ntohl (m->vrf_id);
   rmp->context = context;
   if (m->twice_nat == TWICE_NAT)
     rmp->twice_nat = 1;
@@ -1439,6 +1438,7 @@ send_nat44_lb_static_mapping_details (snat_static_mapping_t * m,
     clib_memcpy (locals->addr, &(ap->addr), 4);
     locals->port = htons (ap->port);
     locals->probability = ap->probability;
+    locals->vrf_id = ntohl (ap->vrf_id);
     locals++;
     rmp->local_num++;
   }
@@ -1454,7 +1454,7 @@ static void
   snat_main_t *sm = &snat_main;
   snat_static_mapping_t *m;
 
-  if (sm->deterministic)
+  if (!sm->endpoint_dependent)
     return;
 
   reg = vl_api_client_index_to_registration (mp->client_index);
index 363df71..4bae701 100644 (file)
@@ -108,7 +108,6 @@ class MethodHolder(VppTestCase):
                 lb_sm.external_addr,
                 lb_sm.external_port,
                 lb_sm.protocol,
-                vrf_id=lb_sm.vrf_id,
                 twice_nat=lb_sm.twice_nat,
                 self_twice_nat=lb_sm.self_twice_nat,
                 out2in_only=lb_sm.out2in_only,
@@ -3433,10 +3432,12 @@ class TestNAT44EndpointDependent(MethodHolder):
 
         locals = [{'addr': server1.ip4n,
                    'port': local_port,
-                   'probability': 70},
+                   'probability': 70,
+                   'vrf_id': 0},
                   {'addr': server2.ip4n,
                    'port': local_port,
-                   'probability': 30}]
+                   'probability': 30,
+                   'vrf_id': 0}]
 
         self.nat44_add_address(self.nat_addr)
         self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
@@ -3515,10 +3516,12 @@ class TestNAT44EndpointDependent(MethodHolder):
 
         locals = [{'addr': server1.ip4n,
                    'port': local_port,
-                   'probability': 90},
+                   'probability': 90,
+                   'vrf_id': 0},
                   {'addr': server2.ip4n,
                    'port': local_port,
-                   'probability': 10}]
+                   'probability': 10,
+                   'vrf_id': 0}]
 
         self.nat44_add_address(self.nat_addr)
         self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
@@ -3560,10 +3563,12 @@ class TestNAT44EndpointDependent(MethodHolder):
 
         locals = [{'addr': server1.ip4n,
                    'port': local_port,
-                   'probability': 70},
+                   'probability': 70,
+                   'vrf_id': 0},
                   {'addr': server2.ip4n,
                    'port': local_port,
-                   'probability': 30}]
+                   'probability': 30,
+                   'vrf_id': 0}]
 
         self.vapi.nat44_forwarding_enable_disable(1)
         self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
@@ -3998,10 +4003,12 @@ class TestNAT44EndpointDependent(MethodHolder):
         else:
             locals = [{'addr': server1.ip4n,
                        'port': port_in1,
-                       'probability': 50},
+                       'probability': 50,
+                       'vrf_id': 0},
                       {'addr': server2.ip4n,
                        'port': port_in2,
-                       'probability': 50}]
+                       'probability': 50,
+                       'vrf_id': 0}]
             out_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
             self.vapi.nat44_add_del_lb_static_mapping(out_addr_n,
                                                       port_out,
index 6ea1d2f..50a94d7 100644 (file)
@@ -1585,7 +1585,6 @@ class VppPapiProvider(object):
             external_addr,
             external_port,
             protocol,
-            vrf_id=0,
             twice_nat=0,
             self_twice_nat=0,
             out2in_only=0,
@@ -1605,7 +1604,6 @@ class VppPapiProvider(object):
              'external_addr': external_addr,
              'external_port': external_port,
              'protocol': protocol,
-             'vrf_id': vrf_id,
              'twice_nat': twice_nat,
              'self_twice_nat': self_twice_nat,
              'out2in_only': out2in_only,