pnat: add support to wildcard IP Protocol field if not specified 12/36112/5
authorFahad Naeem <fahadnaeemkhan@gmail.com>
Tue, 10 May 2022 06:03:52 +0000 (01:03 -0500)
committerOle Tr�an <otroan@employees.org>
Thu, 12 May 2022 07:30:33 +0000 (07:30 +0000)
- add pnat_binding_add_v2 which explicitly requires match mask to
  set to PNAT_PROTO if we want to match on IP Protocol
- fix pnat_binding_add backward compatibility i.e. no need to set
  match mast to PNAT_PROTO

Type: improvement

Signed-off-by: Fahad Naeem <fahadnaeemkhan@gmail.com>
Change-Id: I5a23244be55b7d4c10552c555881527a4b2f325f

src/plugins/nat/pnat/pnat.api
src/plugins/nat/pnat/pnat.c
src/plugins/nat/pnat/pnat_api.c
src/plugins/nat/pnat/pnat_cli.c
test/test_pnat.py

index b663215..de555c4 100644 (file)
@@ -26,6 +26,7 @@ enum pnat_mask
     PNAT_DPORT = 0x8,
     PNAT_COPY_BYTE = 0x10,
     PNAT_CLEAR_BYTE = 0x20,
+    PNAT_PROTO = 0x40,
 };
 
 enum pnat_attachment_point
@@ -65,6 +66,7 @@ autoendian define pnat_binding_add
     vl_api_pnat_rewrite_tuple_t rewrite;
 };
 
+
 autoendian define pnat_binding_add_reply
 {
     u32 context;
@@ -72,6 +74,22 @@ autoendian define pnat_binding_add_reply
     u32 binding_index;
 };
 
+autoendian define pnat_binding_add_v2
+{
+    u32 client_index;
+    u32 context;
+    vl_api_pnat_match_tuple_t match;
+    vl_api_pnat_rewrite_tuple_t rewrite;
+};
+
+
+autoendian define pnat_binding_add_v2_reply
+{
+    u32 context;
+    i32 retval;
+    u32 binding_index;
+};
+
 autoendian autoreply define pnat_binding_del
 {
     u32 client_index;
index 547b063..2b4a6b4 100644 (file)
@@ -56,7 +56,9 @@ static pnat_mask_fast_t pnat_mask2fast(pnat_mask_t lookup_mask) {
         m.as_u64[0] = 0xffffffff00000000;
     if (lookup_mask & PNAT_DA)
         m.as_u64[0] |= 0x00000000ffffffff;
-    m.as_u64[1] = 0xffffffff00000000;
+    m.as_u64[1] = 0x00ffffff00000000;
+    if (lookup_mask & PNAT_PROTO)
+        m.as_u64[1] |= 0xff00000000000000;
     if (lookup_mask & PNAT_SPORT)
         m.as_u64[1] |= 0x00000000ffff0000;
     if (lookup_mask & PNAT_DPORT)
index 35a7395..02e6121 100644 (file)
@@ -36,11 +36,26 @@ static void vl_api_pnat_binding_add_t_handler(vl_api_pnat_binding_add_t *mp) {
     pnat_main_t *pm = &pnat_main;
     vl_api_pnat_binding_add_reply_t *rmp;
     u32 binding_index;
+
+    // for backward compatibility
+    if (mp->match.proto == 0)
+        mp->match.mask |= PNAT_PROTO;
+
     int rv = pnat_binding_add(&mp->match, &mp->rewrite, &binding_index);
     REPLY_MACRO2_END(VL_API_PNAT_BINDING_ADD_REPLY,
                      ({ rmp->binding_index = binding_index; }));
 }
 
+static void
+vl_api_pnat_binding_add_v2_t_handler(vl_api_pnat_binding_add_t *mp) {
+    pnat_main_t *pm = &pnat_main;
+    vl_api_pnat_binding_add_reply_t *rmp;
+    u32 binding_index;
+    int rv = pnat_binding_add(&mp->match, &mp->rewrite, &binding_index);
+    REPLY_MACRO2_END(VL_API_PNAT_BINDING_ADD_V2_REPLY,
+                     ({ rmp->binding_index = binding_index; }));
+}
+
 static void
 vl_api_pnat_binding_attach_t_handler(vl_api_pnat_binding_attach_t *mp) {
     pnat_main_t *pm = &pnat_main;
index 082f077..ce9beee 100644 (file)
@@ -122,6 +122,8 @@ uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args) {
             t->mask |= PNAT_SA;
         else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst))
             t->mask |= PNAT_DA;
+        else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto))
+            t->mask |= PNAT_PROTO;
         else if (unformat(input, "sport %d", &sport)) {
             if (sport == 0 || sport > 65535)
                 return 0;
@@ -132,9 +134,7 @@ uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args) {
                 return 0;
             t->mask |= PNAT_DPORT;
             t->dport = dport;
-        } else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto))
-            ;
-        else
+        } else
             break;
     }
     return 1;
index faf66e6..2bf3405 100644 (file)
@@ -242,6 +242,105 @@ class TestPNAT(VppTestCase):
             )
             self.vapi.pnat_binding_del(binding_index=binding_index[i])
 
+    def test_pnat_wildcard_proto(self):
+        """
+        PNAT test wildcard IP protocol, PNAT_PROTO for mask should be set by
+        handler
+        """
+
+        PNAT_IP4_INPUT = VppEnum.vl_api_pnat_attachment_point_t.PNAT_IP4_INPUT
+        PNAT_IP4_OUTPUT = \
+            VppEnum.vl_api_pnat_attachment_point_t.PNAT_IP4_OUTPUT
+
+        tests = [
+            {
+                'input': PNAT_IP4_INPUT,
+                'sw_if_index': self.pg0.sw_if_index,
+                'match': {'mask': 0x2, 'dst': '10.10.10.10'},
+                'rewrite': {'mask': 0x2, 'dst': self.pg1.remote_ip4},
+                'send': (IP(src=self.pg0.remote_ip4, dst='10.10.10.10')),
+                'reply': (IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4))
+            },
+            {
+                'input': PNAT_IP4_OUTPUT,
+                'sw_if_index': self.pg1.sw_if_index,
+                'match': {'mask': 0x1, 'src': self.pg0.remote_ip4},
+                'rewrite': {'mask': 0x1, 'src': '11.11.11.11'},
+                'send': (IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)),
+                'reply': (IP(src='11.11.11.11', dst=self.pg1.remote_ip4))
+            },
+        ]
+
+        p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+        for t in tests:
+            rv = self.vapi.pnat_binding_add(match=t['match'],
+                                            rewrite=t['rewrite'])
+            self.vapi.pnat_binding_attach(sw_if_index=t['sw_if_index'],
+                                          attachment=t['input'],
+                                          binding_index=rv.binding_index)
+
+            reply = t['reply']
+            reply[IP].ttl -= 1
+            rx = self.send_and_expect(self.pg0, p_ether / t['send'] * 1,
+                                      self.pg1)
+            for p in rx:
+                self.validate(p[1], reply)
+
+            self.ping_check()
+
+            self.vapi.pnat_binding_detach(sw_if_index=t['sw_if_index'],
+                                          attachment=t['input'],
+                                          binding_index=rv.binding_index)
+            self.vapi.pnat_binding_del(binding_index=rv.binding_index)
+
+    def test_pnat_wildcard_proto_v2(self):
+        """ PNAT test wildcard IP protocol using pnat_binding_add_v2"""
+
+        PNAT_IP4_INPUT = VppEnum.vl_api_pnat_attachment_point_t.PNAT_IP4_INPUT
+        PNAT_IP4_OUTPUT = \
+            VppEnum.vl_api_pnat_attachment_point_t.PNAT_IP4_OUTPUT
+
+        tests = [
+            {
+                'input': PNAT_IP4_INPUT,
+                'sw_if_index': self.pg0.sw_if_index,
+                'match': {'mask': 0x42, 'dst': '10.10.10.10'},
+                'rewrite': {'mask': 0x42, 'dst': self.pg1.remote_ip4},
+                'send': (IP(src=self.pg0.remote_ip4, dst='10.10.10.10')),
+                'reply': (IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4))
+            },
+            {
+                'input': PNAT_IP4_OUTPUT,
+                'sw_if_index': self.pg1.sw_if_index,
+                'match': {'mask': 0x41, 'src': self.pg0.remote_ip4},
+                'rewrite': {'mask': 0x41, 'src': '11.11.11.11'},
+                'send': (IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)),
+                'reply': (IP(src='11.11.11.11', dst=self.pg1.remote_ip4))
+            },
+        ]
+
+        p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+        for t in tests:
+            rv = self.vapi.pnat_binding_add_v2(match=t['match'],
+                                               rewrite=t['rewrite'])
+            self.vapi.pnat_binding_attach(sw_if_index=t['sw_if_index'],
+                                          attachment=t['input'],
+                                          binding_index=rv.binding_index)
+
+            reply = t['reply']
+            reply[IP].ttl -= 1
+            rx = self.send_and_expect(self.pg0, p_ether / t['send'] * 1,
+                                      self.pg1)
+            for p in rx:
+                self.validate(p[1], reply)
+
+            self.ping_check()
+
+            self.vapi.pnat_binding_detach(sw_if_index=t['sw_if_index'],
+                                          attachment=t['input'],
+                                          binding_index=rv.binding_index)
+            self.vapi.pnat_binding_del(binding_index=rv.binding_index)
+
 
 if __name__ == "__main__":
     unittest.main(testRunner=VppTestRunner)