aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--test/test_nat.py52
-rw-r--r--test/vpp_papi_provider.py14
11 files changed, 302 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__ */
/*
diff --git a/test/test_nat.py b/test/test_nat.py
index 5baadd89863..a705bd98fc0 100644
--- a/test/test_nat.py
+++ b/test/test_nat.py
@@ -139,6 +139,7 @@ class MethodHolder(VppTestCase):
self.verify_no_nat44_user()
self.vapi.nat_set_timeouts()
self.vapi.nat_set_addr_and_port_alloc_alg()
+ self.vapi.nat_set_mss_clamping()
def nat44_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
local_port=0, external_port=0, vrf_id=0,
@@ -1002,6 +1003,21 @@ class MethodHolder(VppTestCase):
# sourceIPv4Address
self.assertEqual(src_addr, record[8])
+ def verify_mss_value(self, pkt, mss):
+ """
+ Verify TCP MSS value
+
+ :param pkt:
+ :param mss:
+ """
+ if not pkt.haslayer(IP) or not pkt.haslayer(TCP):
+ raise TypeError("Not a TCP/IP packet")
+
+ for option in pkt[TCP].options:
+ if option[0] == 'MSS':
+ self.assertEqual(option[1], mss)
+ self.assert_tcp_checksum_valid(pkt)
+
class TestNAT44(MethodHolder):
""" NAT44 Test Cases """
@@ -3295,6 +3311,42 @@ class TestNAT44(MethodHolder):
nsessions = nsessions + user.nsessions
self.assertLess(nsessions, 2 * max_sessions)
+ def test_mss_clamping(self):
+ """ TCP MSS clamping """
+ self.nat44_add_address(self.nat_addr)
+ self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
+ self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
+ is_inside=0)
+
+ p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
+ IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
+ TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
+ flags="S", options=[('MSS', 1400)]))
+
+ self.vapi.nat_set_mss_clamping(enable=1, mss_value=1000)
+ self.pg0.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ capture = self.pg1.get_capture(1)
+ # Negotiated MSS value greater than configured - changed
+ self.verify_mss_value(capture[0], 1000)
+
+ self.vapi.nat_set_mss_clamping(enable=0)
+ self.pg0.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ capture = self.pg1.get_capture(1)
+ # MSS clamping disabled - negotiated MSS unchanged
+ self.verify_mss_value(capture[0], 1400)
+
+ self.vapi.nat_set_mss_clamping(enable=1, mss_value=1500)
+ self.pg0.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ capture = self.pg1.get_capture(1)
+ # Negotiated MSS value smaller than configured - unchanged
+ self.verify_mss_value(capture[0], 1400)
+
def tearDown(self):
super(TestNAT44, self).tearDown()
if not self.vpp_dead:
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 13d0d933ea1..61d80b21fb5 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -1827,6 +1827,20 @@ class VppPapiProvider(object):
"""Get address and port assignment algorithm"""
return self.api(self.papi.nat_get_addr_and_port_alloc_alg, {})
+ def nat_set_mss_clamping(self, enable=0, mss_value=1500):
+ """Set TCP MSS rewriting configuration
+
+ :param enable: disable(0)/enable(1) MSS rewriting feature
+ :param mss_value: MSS value to be used for MSS rewriting
+ """
+ return self.api(
+ self.papi.nat_set_mss_clamping,
+ {'enable': enable, 'mss_value': mss_value})
+
+ def nat_get_mss_clamping(self):
+ """Get TCP MSS rewriting configuration"""
+ return self.api(self.papi.nat_get_mss_clamping, {})
+
def nat_det_close_session_out(
self,
out_addr,