nat: fix ED mode unknown proto session management 46/19146/3
authorMatthew Smith <mgsmith@netgate.com>
Mon, 22 Apr 2019 22:30:13 +0000 (17:30 -0500)
committerOle Trøan <otroan@employees.org>
Fri, 26 Apr 2019 11:19:21 +0000 (11:19 +0000)
In endpoint dependent mode, when a session at the head of a user
LRU is reused, if the IP protocol for that session was unknown (any
other than tcp, udp, or icmp), the attempt to delete the session
mapping from the in2out bihash was not using the same key that was
used when the mapping was added. This would cause the deletion of
the mapping to fail. If packets arrive later which match the original
session, the search for the session key would succeed when it should
have failed and the session, which is now associated with a different
pair of endpoints, may end up being updated when it should not be.

Update the key generation when reallocating an existing session to
do the right thing if the session is for an unknown protocol.

Also update format_nat_session() for unknown protocols so that
'vppctl show nat44 session detail' will display the protocol
correctly. In endpoint dependent mode, the IP protocol is stored in
the port field on a session if the protocol is unknown. The value
is stored in host byte order, but the format function was swapping
the bytes before writing the protocol.

Change-Id: I9e8daadd4569cb2610532dab4e4f41d1567cf3d1
Signed-off-by: Matthew Smith <mgsmith@netgate.com>
src/plugins/nat/nat.c
src/plugins/nat/nat_format.c
src/plugins/nat/out2in_ed.c

index 97e2df1..249df38 100755 (executable)
@@ -188,11 +188,20 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
 
   if (is_fwd_bypass_session (s))
     {
+      if (snat_is_unk_proto_session (s))
+       {
+         ed_key.proto = s->in2out.port;
+         ed_key.r_port = 0;
+         ed_key.l_port = 0;
+       }
+      else
+       {
+         ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
+         ed_key.l_port = s->in2out.port;
+         ed_key.r_port = s->ext_host_port;
+       }
       ed_key.l_addr = s->in2out.addr;
       ed_key.r_addr = s->ext_host_addr;
-      ed_key.l_port = s->in2out.port;
-      ed_key.r_port = s->ext_host_port;
-      ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
       ed_key.fib_index = 0;
       ed_kv.key[0] = ed_key.as_u64[0];
       ed_kv.key[1] = ed_key.as_u64[1];
index 8452940..7dcdff6 100644 (file)
@@ -124,12 +124,10 @@ format_snat_session (u8 * s, va_list * args)
     {
       s = format (s, "  i2o %U proto %u fib %u\n",
                  format_ip4_address, &sess->in2out.addr,
-                 clib_net_to_host_u16 (sess->in2out.port),
-                 sess->in2out.fib_index);
+                 sess->in2out.port, sess->in2out.fib_index);
       s = format (s, "    o2i %U proto %u fib %u\n",
                  format_ip4_address, &sess->out2in.addr,
-                 clib_net_to_host_u16 (sess->out2in.port),
-                 sess->out2in.fib_index);
+                 sess->out2in.port, sess->out2in.fib_index);
     }
   else
     {
index 41f9bfe..06e72f3 100644 (file)
@@ -452,6 +452,8 @@ create_bypass_for_fwd (snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index,
     }
   else
     {
+      u32 proto;
+
       if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
        return;
 
@@ -471,12 +473,19 @@ create_bypass_for_fwd (snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index,
          return;
        }
 
+      proto = ip_proto_to_snat_proto (key.proto);
+
       s->ext_host_addr = key.r_addr;
       s->ext_host_port = key.r_port;
       s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS;
       s->out2in.addr = key.l_addr;
       s->out2in.port = key.l_port;
-      s->out2in.protocol = ip_proto_to_snat_proto (key.proto);
+      s->out2in.protocol = proto;
+      if (proto == ~0)
+       {
+         s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
+         s->out2in.port = ip->protocol;
+       }
       s->out2in.fib_index = 0;
       s->in2out = s->out2in;
       user_session_increment (sm, u, 0);