nat: test all intf addrs in is_interface_addr() 53/32453/4
authorAlexander Chernavin <achernavin@netgate.com>
Wed, 26 May 2021 13:55:42 +0000 (09:55 -0400)
committerOle Tr�an <otroan@employees.org>
Wed, 16 Jun 2021 07:58:39 +0000 (07:58 +0000)
Type: fix

Currently, is_interface_addr() tests if a given IPv4 address belongs to
an interface by a given sw_if_index. However, there are several issues:
 * only the first found address on the interface is actually tested,
 * sw_if_index is always cached even if the interface hasn't been
   assigned any addresses yet.

With this change, is_interface_addr() tests all IPv4 addresses on an
interface by a given sw_if_index and caches sw_if_index only if there
are addresses present.

Signed-off-by: Alexander Chernavin <achernavin@netgate.com>
Change-Id: If1acc4a534647a5f0ce8e9b565b867c92a016dc3

src/plugins/nat/nat44-ed/nat44_ed.h
src/plugins/nat/nat44-ed/nat44_ed_inlines.h
src/plugins/nat/nat44-ei/nat44_ei.h
src/plugins/nat/nat44-ei/nat44_ei_inlines.h

index bbd5a14..2710d29 100644 (file)
@@ -28,6 +28,7 @@
 #include <vppinfra/elog.h>
 #include <vppinfra/bihash_8_8.h>
 #include <vppinfra/bihash_16_8.h>
+#include <vppinfra/hash.h>
 #include <vppinfra/dlist.h>
 #include <vppinfra/error.h>
 #include <vlibapi/api.h>
@@ -683,7 +684,7 @@ typedef struct
 typedef struct
 {
   u32 cached_sw_if_index;
-  u32 cached_ip4_address;
+  uword *cached_presence_by_ip4_address;
 } snat_runtime_t;
 
 extern snat_main_t snat_main;
index b2b578a..680bdef 100644 (file)
@@ -724,20 +724,30 @@ is_interface_addr (snat_main_t *sm, vlib_node_runtime_t *node,
                   u32 sw_if_index0, u32 ip4_addr)
 {
   snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data;
-  ip4_address_t *first_int_addr;
+  u8 ip4_addr_exists;
 
   if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
     {
-      first_int_addr = ip4_interface_first_address (
-       sm->ip4_main, sw_if_index0, 0 /* just want the address */);
-      rt->cached_sw_if_index = sw_if_index0;
-      if (first_int_addr)
-       rt->cached_ip4_address = first_int_addr->as_u32;
-      else
-       rt->cached_ip4_address = 0;
+      ip_lookup_main_t *lm = &sm->ip4_main->lookup_main;
+      ip_interface_address_t *ia;
+      ip4_address_t *a;
+
+      rt->cached_sw_if_index = ~0;
+      hash_free (rt->cached_presence_by_ip4_address);
+
+      foreach_ip_interface_address (
+       lm, ia, sw_if_index0, 1 /* honor unnumbered */, ({
+         a = ip_interface_address_get_address (lm, ia);
+         hash_set (rt->cached_presence_by_ip4_address, a->as_u32, 1);
+         rt->cached_sw_if_index = sw_if_index0;
+       }));
+
+      if (rt->cached_sw_if_index == ~0)
+       return 0;
     }
 
-  if (PREDICT_FALSE (ip4_addr == rt->cached_ip4_address))
+  ip4_addr_exists = !!hash_get (rt->cached_presence_by_ip4_address, ip4_addr);
+  if (PREDICT_FALSE (ip4_addr_exists))
     return 1;
   else
     return 0;
index ae63d9d..055f81c 100644 (file)
@@ -32,6 +32,7 @@
 #include <vppinfra/dlist.h>
 #include <vppinfra/error.h>
 #include <vppinfra/bihash_8_8.h>
+#include <vppinfra/hash.h>
 
 #include <nat/lib/lib.h>
 #include <nat/lib/inlines.h>
@@ -304,7 +305,7 @@ typedef struct
 typedef struct
 {
   u32 cached_sw_if_index;
-  u32 cached_ip4_address;
+  uword *cached_presence_by_ip4_address;
 } nat44_ei_runtime_t;
 
 typedef struct
index 3093588..6729272 100644 (file)
@@ -118,20 +118,30 @@ nat44_ei_is_interface_addr (ip4_main_t *im, vlib_node_runtime_t *node,
                            u32 sw_if_index0, u32 ip4_addr)
 {
   nat44_ei_runtime_t *rt = (nat44_ei_runtime_t *) node->runtime_data;
-  ip4_address_t *first_int_addr;
+  u8 ip4_addr_exists;
 
   if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
     {
-      first_int_addr = ip4_interface_first_address (
-       im, sw_if_index0, 0 /* just want the address */);
-      rt->cached_sw_if_index = sw_if_index0;
-      if (first_int_addr)
-       rt->cached_ip4_address = first_int_addr->as_u32;
-      else
-       rt->cached_ip4_address = 0;
+      ip_lookup_main_t *lm = &im->lookup_main;
+      ip_interface_address_t *ia;
+      ip4_address_t *a;
+
+      rt->cached_sw_if_index = ~0;
+      hash_free (rt->cached_presence_by_ip4_address);
+
+      foreach_ip_interface_address (
+       lm, ia, sw_if_index0, 1 /* honor unnumbered */, ({
+         a = ip_interface_address_get_address (lm, ia);
+         hash_set (rt->cached_presence_by_ip4_address, a->as_u32, 1);
+         rt->cached_sw_if_index = sw_if_index0;
+       }));
+
+      if (rt->cached_sw_if_index == ~0)
+       return 0;
     }
 
-  if (PREDICT_FALSE (ip4_addr == rt->cached_ip4_address))
+  ip4_addr_exists = !!hash_get (rt->cached_presence_by_ip4_address, ip4_addr);
+  if (PREDICT_FALSE (ip4_addr_exists))
     return 1;
   else
     return 0;