diff options
author | Nathan Skrzypczak <nathan.skrzypczak@gmail.com> | 2022-02-02 19:31:43 +0100 |
---|---|---|
committer | Beno�t Ganne <bganne@cisco.com> | 2022-03-18 11:33:51 +0000 |
commit | 762cfd408b16b6ab43ade3ab491292b93bdeb9b3 (patch) | |
tree | 3b303cb9db68a8003aca57820174b03902f3c714 /src/plugins/cnat/cnat_node.h | |
parent | 6798e9ec34a49df008ecb7f84559e531f6c0d651 (diff) |
cnat: Fix conflicting rsession
When dNAT-ing to a VIP, it can happen
that the return session conflicts with
another forward session than the one
we own.
This patchs adds a rsession_flags
CNAT_SESSION_RETRY_SNAT that makes cnat_session_create
search for a free src port to use for the
resulting return session.
It also makes forward & return session
share their fate in the session scanner.
Type: fix
Change-Id: Id0edf59abf8e5bc0c0d8941ba289c4563c77dee0
Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com>
Diffstat (limited to 'src/plugins/cnat/cnat_node.h')
-rw-r--r-- | src/plugins/cnat/cnat_node.h | 83 |
1 files changed, 47 insertions, 36 deletions
diff --git a/src/plugins/cnat/cnat_node.h b/src/plugins/cnat/cnat_node.h index 246fdb8ba57..80d803c4b61 100644 --- a/src/plugins/cnat/cnat_node.h +++ b/src/plugins/cnat/cnat_node.h @@ -846,11 +846,55 @@ cnat_session_create (cnat_session_t *session, cnat_node_ctx_t *ctx, cnat_bihash_kv_t rkey; cnat_session_t *rsession = (cnat_session_t *) & rkey; cnat_bihash_kv_t *bkey = (cnat_bihash_kv_t *) session; - cnat_bihash_kv_t rvalue; - int rv; + int rv, n_retries = 0; + static u32 sport_seed = 0; session->value.cs_ts_index = cnat_timestamp_new (ctx->now); - cnat_bihash_add_del (&cnat_session_db, bkey, 1); + + /* First create the return session */ + ip46_address_copy (&rsession->key.cs_ip[VLIB_RX], + &session->value.cs_ip[VLIB_TX]); + ip46_address_copy (&rsession->key.cs_ip[VLIB_TX], + &session->value.cs_ip[VLIB_RX]); + rsession->key.cs_proto = session->key.cs_proto; + rsession->key.cs_loc = rsession_location; + rsession->key.__cs_pad = 0; + rsession->key.cs_af = ctx->af; + rsession->key.cs_port[VLIB_RX] = session->value.cs_port[VLIB_TX]; + rsession->key.cs_port[VLIB_TX] = session->value.cs_port[VLIB_RX]; + + ip46_address_copy (&rsession->value.cs_ip[VLIB_RX], + &session->key.cs_ip[VLIB_TX]); + ip46_address_copy (&rsession->value.cs_ip[VLIB_TX], + &session->key.cs_ip[VLIB_RX]); + rsession->value.cs_ts_index = session->value.cs_ts_index; + rsession->value.cs_lbi = INDEX_INVALID; + rsession->value.flags = rsession_flags | CNAT_SESSION_IS_RETURN; + rsession->value.cs_port[VLIB_TX] = session->key.cs_port[VLIB_RX]; + rsession->value.cs_port[VLIB_RX] = session->key.cs_port[VLIB_TX]; + +retry_add_ression: + rv = cnat_bihash_add_del (&cnat_session_db, &rkey, + 2 /* add but don't overwrite */); + if (rv) + { + if (!(rsession_flags & CNAT_SESSION_RETRY_SNAT)) + return; + + /* return session add failed pick an new random src port */ + rsession->value.cs_port[VLIB_TX] = session->key.cs_port[VLIB_RX] = + random_u32 (&sport_seed); + if (n_retries++ < 100) + goto retry_add_ression; + else + { + clib_warning ("Could not find a free port after 100 tries"); + /* translate this packet, but don't create state */ + return; + } + } + + cnat_bihash_add_del (&cnat_session_db, bkey, 1 /* add */); if (!(rsession_flags & CNAT_SESSION_FLAG_NO_CLIENT)) { @@ -894,39 +938,6 @@ cnat_session_create (cnat_session_t *session, cnat_node_ctx_t *ctx, } } - /* create the reverse flow key */ - ip46_address_copy (&rsession->key.cs_ip[VLIB_RX], - &session->value.cs_ip[VLIB_TX]); - ip46_address_copy (&rsession->key.cs_ip[VLIB_TX], - &session->value.cs_ip[VLIB_RX]); - rsession->key.cs_proto = session->key.cs_proto; - rsession->key.cs_loc = rsession_location; - rsession->key.__cs_pad = 0; - rsession->key.cs_af = ctx->af; - rsession->key.cs_port[VLIB_RX] = session->value.cs_port[VLIB_TX]; - rsession->key.cs_port[VLIB_TX] = session->value.cs_port[VLIB_RX]; - - /* First search for existing reverse session */ - rv = cnat_bihash_search_i2 (&cnat_session_db, &rkey, &rvalue); - if (!rv) - { - /* Reverse session already exists - cleanup before creating for refcnts */ - cnat_session_t *found_rsession = (cnat_session_t *) & rvalue; - cnat_session_free (found_rsession); - } - /* add the reverse flow */ - ip46_address_copy (&rsession->value.cs_ip[VLIB_RX], - &session->key.cs_ip[VLIB_TX]); - ip46_address_copy (&rsession->value.cs_ip[VLIB_TX], - &session->key.cs_ip[VLIB_RX]); - rsession->value.cs_ts_index = session->value.cs_ts_index; - rsession->value.cs_lbi = INDEX_INVALID; - rsession->value.flags = rsession_flags | CNAT_SESSION_IS_RETURN; - rsession->value.cs_port[VLIB_TX] = session->key.cs_port[VLIB_RX]; - rsession->value.cs_port[VLIB_RX] = session->key.cs_port[VLIB_TX]; - - cnat_bihash_add_del (&cnat_session_db, &rkey, 1); } always_inline uword |