summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2018-09-13 02:36:25 -0700
committerMatus Fabian <matfabia@cisco.com>2018-09-13 02:36:25 -0700
commitbb4e022502dd7f76d4f1cd705a7bac628d8c098c (patch)
treee8b5f13cbea161f66aad347fc7175edabd337f72 /src
parentc2b4dbe48a01e746bfa89c4208d6e6b686270ac0 (diff)
NAT: TCP MSS clamping
NAT plugin changes the MSS value in TCP SYN packets to avoid fragmentation. If the negotiated MSS value is greater than the configured value it is changed to the configured value. If the negotiated MSS value is smaller than the configured value it remains unchanged. Change-Id: Ic3c4f94a2f1b76e2bf79f50f3ad36a4097f3f188 Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/nat/dslite_in2out.c1
-rwxr-xr-xsrc/plugins/nat/in2out.c11
-rw-r--r--src/plugins/nat/nat.api35
-rwxr-xr-xsrc/plugins/nat/nat.c1
-rw-r--r--src/plugins/nat/nat.h4
-rw-r--r--src/plugins/nat/nat44_cli.c76
-rw-r--r--src/plugins/nat/nat64_in2out.c1
-rw-r--r--src/plugins/nat/nat_api.c59
-rw-r--r--src/plugins/nat/nat_inlines.h48
9 files changed, 236 insertions, 0 deletions
diff --git a/src/plugins/nat/dslite_in2out.c b/src/plugins/nat/dslite_in2out.c
index bf51ca23051..8f5a0c0e248 100644
--- a/src/plugins/nat/dslite_in2out.c
+++ b/src/plugins/nat/dslite_in2out.c
@@ -377,6 +377,7 @@ dslite_in2out_node_fn_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
sum0 =
ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
length);
+ mss_clamping (&snat_main, tcp0, &sum0);
tcp0->checksum = ip_csum_fold (sum0);
}
else
diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c
index 22a346855c6..661d8c1bef9 100755
--- a/src/plugins/nat/in2out.c
+++ b/src/plugins/nat/in2out.c
@@ -1336,6 +1336,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
sum0 = ip_csum_update (sum0, old_port0, new_port0,
ip4_header_t /* cheat */,
length /* changed member */);
+ mss_clamping (sm, tcp0, &sum0);
tcp0->checksum = ip_csum_fold(sum0);
}
else
@@ -1496,6 +1497,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
sum1 = ip_csum_update (sum1, old_port1, new_port1,
ip4_header_t /* cheat */,
length /* changed member */);
+ mss_clamping (sm, tcp1, &sum1);
tcp1->checksum = ip_csum_fold(sum1);
}
else
@@ -1693,6 +1695,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
sum0 = ip_csum_update (sum0, old_port0, new_port0,
ip4_header_t /* cheat */,
length /* changed member */);
+ mss_clamping (sm, tcp0, &sum0);
tcp0->checksum = ip_csum_fold(sum0);
}
else
@@ -3354,6 +3357,7 @@ nat44_ed_in2out_node_fn_inline (vlib_main_t * vm,
tcp0->dst_port = s0->ext_host_port;
ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
}
+ mss_clamping (sm, tcp0, &sum0);
tcp0->checksum = ip_csum_fold(sum0);
if (nat44_set_tcp_session_state_i2o (sm, s0, tcp0, thread_index))
goto trace00;
@@ -3539,6 +3543,7 @@ nat44_ed_in2out_node_fn_inline (vlib_main_t * vm,
ip1->dst_address.as_u32 = s1->ext_host_addr.as_u32;
}
tcp1->checksum = ip_csum_fold(sum1);
+ mss_clamping (sm, tcp1, &sum1);
if (nat44_set_tcp_session_state_i2o (sm, s1, tcp1, thread_index))
goto trace01;
}
@@ -3751,6 +3756,7 @@ nat44_ed_in2out_node_fn_inline (vlib_main_t * vm,
tcp0->dst_port = s0->ext_host_port;
ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
}
+ mss_clamping (sm, tcp0, &sum0);
tcp0->checksum = ip_csum_fold(sum0);
if (nat44_set_tcp_session_state_i2o (sm, s0, tcp0, thread_index))
goto trace0;
@@ -4122,6 +4128,7 @@ snat_det_in2out_node_fn (vlib_main_t * vm,
sum0 = ip_csum_update (sum0, old_port0, new_port0,
ip4_header_t /* cheat */,
length /* changed member */);
+ mss_clamping (sm, tcp0, &sum0);
tcp0->checksum = ip_csum_fold(sum0);
}
else
@@ -4272,6 +4279,7 @@ snat_det_in2out_node_fn (vlib_main_t * vm,
sum1 = ip_csum_update (sum1, old_port1, new_port1,
ip4_header_t /* cheat */,
length /* changed member */);
+ mss_clamping (sm, tcp1, &sum1);
tcp1->checksum = ip_csum_fold(sum1);
}
else
@@ -4458,6 +4466,7 @@ snat_det_in2out_node_fn (vlib_main_t * vm,
sum0 = ip_csum_update (sum0, old_port0, new_port0,
ip4_header_t /* cheat */,
length /* changed member */);
+ mss_clamping (sm, tcp0, &sum0);
tcp0->checksum = ip_csum_fold(sum0);
}
else
@@ -5354,6 +5363,7 @@ snat_in2out_fast_static_map_fn (vlib_main_t * vm,
sum0 = ip_csum_update (sum0, old_port0, new_port0,
ip4_header_t /* cheat */,
length /* changed member */);
+ mss_clamping (sm, tcp0, &sum0);
tcp0->checksum = ip_csum_fold(sum0);
}
else
@@ -5371,6 +5381,7 @@ snat_in2out_fast_static_map_fn (vlib_main_t * vm,
sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
ip4_header_t,
dst_address /* changed member */);
+ mss_clamping (sm, tcp0, &sum0);
tcp0->checksum = ip_csum_fold(sum0);
}
}
diff --git a/src/plugins/nat/nat.api b/src/plugins/nat/nat.api
index 1ff288dba2a..6e2d8e57853 100644
--- a/src/plugins/nat/nat.api
+++ b/src/plugins/nat/nat.api
@@ -332,6 +332,41 @@ define nat_get_addr_and_port_alloc_alg_reply {
u16 end_port;
};
+/** \brief Set TCP MSS rewriting configuration
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param mss_value - MSS value to be used for MSS rewriting
+ @param enable - disable(0)/enable(1) MSS rewriting feature
+*/
+autoreply define nat_set_mss_clamping {
+ u32 client_index;
+ u32 context;
+ u16 mss_value;
+ u8 enable;
+};
+
+/** \brief Get TCP MSS rewriting configuration
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+define nat_get_mss_clamping {
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief Get TCP MSS rewriting configuration reply
+ @param context - sender context, to match reply w/ request
+ @param retval - return code
+ @param mss_value - MSS value to be used for MSS rewriting
+ @param enable - disable(0)/enable(1) MSS rewriting feature
+*/
+define nat_get_mss_clamping_reply {
+ u32 context;
+ i32 retval;
+ u16 mss_value;
+ u8 enable;
+};
+
/*
* NAT44 APIs
*/
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index ac81a9930dc..03e264eda3b 100755
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -2078,6 +2078,7 @@ static clib_error_t * snat_init (vlib_main_t * vm)
sm->log_class = vlib_log_register_class ("nat", 0);
error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
sm->error_node_index = error_drop_node->index;
+ sm->mss_clamping = 0;
p = hash_get_mem (tm->thread_registrations_by_name, "workers");
if (p)
diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h
index d8d0b2a9c4d..06a61626333 100644
--- a/src/plugins/nat/nat.h
+++ b/src/plugins/nat/nat.h
@@ -439,6 +439,10 @@ typedef struct snat_main_s {
u32 tcp_transitory_timeout;
u32 icmp_timeout;
+ /* TCP MSS clamping */
+ u16 mss_clamping;
+ u16 mss_value_net;
+
/* API message ID base */
u16 msg_id_base;
diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c
index 17a3827dee6..4f02896f4b9 100644
--- a/src/plugins/nat/nat44_cli.c
+++ b/src/plugins/nat/nat44_cli.c
@@ -292,6 +292,56 @@ nat44_show_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
}
static clib_error_t *
+nat_set_mss_clamping_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ snat_main_t *sm = &snat_main;
+ clib_error_t *error = 0;
+ u32 mss;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "disable"))
+ sm->mss_clamping = 0;
+ else if (unformat (line_input, "%d", &mss))
+ {
+ sm->mss_clamping = (u16) mss;
+ sm->mss_value_net = clib_host_to_net_u16 (sm->mss_clamping);
+ }
+ else
+ {
+ error = clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+
+done:
+ unformat_free (line_input);
+
+ return error;
+}
+
+static clib_error_t *
+nat_show_mss_clamping_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ snat_main_t *sm = &snat_main;
+
+ if (sm->mss_clamping)
+ vlib_cli_output (vm, "mss-clamping %d", sm->mss_clamping);
+ else
+ vlib_cli_output (vm, "mss-clamping disabled");
+
+ return 0;
+}
+
+static clib_error_t *
add_address_command_fn (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
{
@@ -1704,6 +1754,32 @@ VLIB_CLI_COMMAND (nat44_show_alloc_addr_and_port_alg_command, static) = {
/*?
* @cliexpar
+ * @cliexstart{nat mss-clamping}
+ * Set TCP MSS rewriting configuration
+ * To enable TCP MSS rewriting use:
+ * vpp# nat mss-clamping 1452
+ * To disbale TCP MSS rewriting use:
+ * vpp# nat mss-clamping disable
+?*/
+VLIB_CLI_COMMAND (nat_set_mss_clamping_command, static) = {
+ .path = "nat mss-clamping",
+ .short_help = "nat mss-clamping <mss-value>|disable",
+ .function = nat_set_mss_clamping_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat mss-clamping}
+ * Show TCP MSS rewriting configuration
+?*/
+VLIB_CLI_COMMAND (nat_show_mss_clamping_command, static) = {
+ .path = "show nat mss-clamping",
+ .short_help = "show nat mss-clamping",
+ .function = nat_show_mss_clamping_command_fn,
+};
+
+/*?
+ * @cliexpar
* @cliexstart{show nat44 hash tables}
* Show NAT44 hash tables
* @cliexend
diff --git a/src/plugins/nat/nat64_in2out.c b/src/plugins/nat/nat64_in2out.c
index ddbf5850c7c..e843fcf6730 100644
--- a/src/plugins/nat/nat64_in2out.c
+++ b/src/plugins/nat/nat64_in2out.c
@@ -239,6 +239,7 @@ nat64_in2out_tcp_udp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4,
checksum = &tcp->checksum;
csum = ip_csum_sub_even (*checksum, sport);
csum = ip_csum_add_even (csum, udp->src_port);
+ mss_clamping (nm->sm, tcp, &csum);
*checksum = ip_csum_fold (csum);
}
diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c
index 2994f8001f4..4c532ed7e2b 100644
--- a/src/plugins/nat/nat_api.c
+++ b/src/plugins/nat/nat_api.c
@@ -573,6 +573,63 @@ static void *vl_api_nat_get_addr_and_port_alloc_alg_t_print
FINISH;
}
+static void
+vl_api_nat_set_mss_clamping_t_handler (vl_api_nat_set_mss_clamping_t * mp)
+{
+ snat_main_t *sm = &snat_main;
+ vl_api_nat_set_mss_clamping_reply_t *rmp;
+ int rv = 0;
+
+ if (mp->enable)
+ {
+ sm->mss_clamping = ntohs (mp->mss_value);
+ sm->mss_value_net = mp->mss_value;
+ }
+ else
+ sm->mss_clamping = 0;
+
+ REPLY_MACRO (VL_API_NAT_SET_MSS_CLAMPING_REPLY);
+}
+
+static void *
+vl_api_nat_set_mss_clamping_t_print (vl_api_nat_set_mss_clamping_t * mp,
+ void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: nat_set_mss_clamping enable %d mss_value %d\n",
+ mp->enable, ntohs (mp->mss_value));
+
+ FINISH;
+}
+
+static void
+vl_api_nat_get_mss_clamping_t_handler (vl_api_nat_get_mss_clamping_t * mp)
+{
+ snat_main_t *sm = &snat_main;
+ vl_api_nat_get_mss_clamping_reply_t *rmp;
+ int rv = 0;
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2 (VL_API_NAT_GET_MSS_CLAMPING_REPLY,
+ ({
+ rmp->enable = sm->mss_clamping ? 1 : 0;
+ rmp->mss_value = htons (sm->mss_clamping);
+ }))
+ /* *INDENT-ON* */
+}
+
+static void *
+vl_api_nat_get_mss_clamping_t_print (vl_api_nat_get_mss_clamping_t * mp,
+ void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: nat_get_mss_clamping");
+
+ FINISH;
+}
+
/*************/
/*** NAT44 ***/
/*************/
@@ -3083,6 +3140,8 @@ _(NAT_SET_TIMEOUTS, nat_set_timeouts) \
_(NAT_GET_TIMEOUTS, nat_get_timeouts) \
_(NAT_SET_ADDR_AND_PORT_ALLOC_ALG, nat_set_addr_and_port_alloc_alg) \
_(NAT_GET_ADDR_AND_PORT_ALLOC_ALG, nat_get_addr_and_port_alloc_alg) \
+_(NAT_SET_MSS_CLAMPING, nat_set_mss_clamping) \
+_(NAT_GET_MSS_CLAMPING, nat_get_mss_clamping) \
_(NAT44_ADD_DEL_ADDRESS_RANGE, nat44_add_del_address_range) \
_(NAT44_INTERFACE_ADD_DEL_FEATURE, nat44_interface_add_del_feature) \
_(NAT44_ADD_DEL_STATIC_MAPPING, nat44_add_del_static_mapping) \
diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h
index adfb1d51954..8922c05c393 100644
--- a/src/plugins/nat/nat_inlines.h
+++ b/src/plugins/nat/nat_inlines.h
@@ -328,6 +328,54 @@ make_sm_kv (clib_bihash_kv_8_8_t * kv, ip4_address_t * addr, u8 proto,
kv->value = ~0ULL;
}
+always_inline void
+mss_clamping (snat_main_t * sm, tcp_header_t * tcp, ip_csum_t * sum)
+{
+ u8 *data;
+ u8 opt_len, opts_len, kind;
+ u16 mss;
+
+ if (!(sm->mss_clamping && tcp_syn (tcp)))
+ return;
+
+ opts_len = (tcp_doff (tcp) << 2) - sizeof (tcp_header_t);
+ data = (u8 *) (tcp + 1);
+ for (; opts_len > 0; opts_len -= opt_len, data += opt_len)
+ {
+ kind = data[0];
+
+ if (kind == TCP_OPTION_EOL)
+ break;
+ else if (kind == TCP_OPTION_NOOP)
+ {
+ opt_len = 1;
+ continue;
+ }
+ else
+ {
+ if (opts_len < 2)
+ return;
+ opt_len = data[1];
+
+ if (opt_len < 2 || opt_len > opts_len)
+ return;
+ }
+
+ if (kind == TCP_OPTION_MSS)
+ {
+ mss = *(u16 *) (data + 2);
+ if (clib_net_to_host_u16 (mss) > sm->mss_clamping)
+ {
+ *sum =
+ ip_csum_update (*sum, mss, sm->mss_value_net, ip4_header_t,
+ length);
+ clib_memcpy (data + 2, &sm->mss_value_net, 2);
+ }
+ return;
+ }
+ }
+}
+
#endif /* __included_nat_inlines_h__ */
/*