summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Smith <mgsmith@netgate.com>2019-04-22 17:30:13 -0500
committerOle Trøan <otroan@employees.org>2019-04-26 11:19:21 +0000
commitaaed170828dfdb3d62295b76fd617f794dc76b3f (patch)
treed23842dbe40026a9ea26c994eb24ef8316c9135f
parent6825bc11287fd48b9ff2a4236446db5426b78c93 (diff)
nat: fix ED mode unknown proto session management
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>
-rwxr-xr-xsrc/plugins/nat/nat.c15
-rw-r--r--src/plugins/nat/nat_format.c6
-rw-r--r--src/plugins/nat/out2in_ed.c11
3 files changed, 24 insertions, 8 deletions
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index 97e2df1568e..249df38a3b5 100755
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -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];
diff --git a/src/plugins/nat/nat_format.c b/src/plugins/nat/nat_format.c
index 8452940898d..7dcdff6c769 100644
--- a/src/plugins/nat/nat_format.c
+++ b/src/plugins/nat/nat_format.c
@@ -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
{
diff --git a/src/plugins/nat/out2in_ed.c b/src/plugins/nat/out2in_ed.c
index 41f9bfe262e..06e72f31a1b 100644
--- a/src/plugins/nat/out2in_ed.c
+++ b/src/plugins/nat/out2in_ed.c
@@ -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);