aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladislav Grishenko <themiron@yandex-team.ru>2022-06-23 00:45:16 +0500
committerNeale Ranns <neale@graphiant.com>2022-09-30 03:48:42 +0000
commit5c801b362a536fcae704c50bf1573362d372bb3c (patch)
treef8724d4f1d7d68a7fbf3d47523e08a478ee70aea
parenta30495ce0dd15240c5d03a5f3e17c3428e09dd5c (diff)
udp: add udp encap source port entropy support
Encode entropy value in UDP source port when requested per RFC 7510. CLI already has "src-port-is-entropy", use zero UDP source port in API to avoid breaking changes, since zero port is not something to be used in wild. Also, mark UDP encapsualtion API as mp-safe as already done for CLI. Type: feature Change-Id: Ieb61ee11e058179ed566ff1f251a3391eb169d52 Signed-off-by: Vladislav Grishenko <themiron@yandex-team.ru>
-rw-r--r--src/plugins/lisp/lisp-gpe/lisp_gpe_adjacency.c3
-rw-r--r--src/vnet/udp/udp.api2
-rw-r--r--src/vnet/udp/udp_api.c19
-rw-r--r--src/vnet/udp/udp_encap.c40
-rw-r--r--src/vnet/udp/udp_encap.h1
-rw-r--r--src/vnet/udp/udp_encap_node.c43
-rw-r--r--src/vnet/udp/udp_inlines.h79
-rw-r--r--src/vnet/vxlan-gpe/encap.c6
-rw-r--r--test/test_udp.py203
9 files changed, 355 insertions, 41 deletions
diff --git a/src/plugins/lisp/lisp-gpe/lisp_gpe_adjacency.c b/src/plugins/lisp/lisp-gpe/lisp_gpe_adjacency.c
index dd8a252f378..7c857b92575 100644
--- a/src/plugins/lisp/lisp-gpe/lisp_gpe_adjacency.c
+++ b/src/plugins/lisp/lisp-gpe/lisp_gpe_adjacency.c
@@ -285,7 +285,8 @@ lisp_gpe_fixup (vlib_main_t * vm,
/* Fixup the checksum and len fields in the LISP tunnel encap
* that was applied at the midchain node */
- ip_udp_fixup_one (vm, b, is_v4_packet (vlib_buffer_get_current (b)));
+ ip_udp_fixup_one (vm, b, is_v4_packet (vlib_buffer_get_current (b)),
+ UDP_ENCAP_FIXUP_NONE);
}
/**
diff --git a/src/vnet/udp/udp.api b/src/vnet/udp/udp.api
index 02176be7c2b..6b468be461a 100644
--- a/src/vnet/udp/udp.api
+++ b/src/vnet/udp/udp.api
@@ -32,7 +32,7 @@ import "vnet/ip/ip_types.api";
* @param dst_ip - Encap destination address
* @param src_ip - Encap source address
* @param dst_port - Encap destination port
- * @param src_port - Encap source port
+ * @param src_port - Encap source port, 0 for entopy per rfc7510
* @param id - VPP assigned id; ignored in add message, set in dump
*/
typedef udp_encap
diff --git a/src/vnet/udp/udp_api.c b/src/vnet/udp/udp_api.c
index 0f2d014946f..ae6b5bb5807 100644
--- a/src/vnet/udp/udp_api.c
+++ b/src/vnet/udp/udp_api.c
@@ -99,6 +99,7 @@ vl_api_udp_encap_add_t_handler (vl_api_udp_encap_add_t *mp)
{
vl_api_udp_encap_add_reply_t *rmp;
ip46_address_t src_ip, dst_ip;
+ udp_encap_fixup_flags_t flags;
u32 fib_index, table_id;
fib_protocol_t fproto;
ip46_type_t itype;
@@ -119,11 +120,13 @@ vl_api_udp_encap_add_t_handler (vl_api_udp_encap_add_t *mp)
goto done;
}
- uei = udp_encap_add_and_lock (fproto, fib_index,
- &src_ip, &dst_ip,
+ flags = UDP_ENCAP_FIXUP_NONE;
+ if (mp->udp_encap.src_port == 0)
+ flags |= UDP_ENCAP_FIXUP_UDP_SRC_PORT_ENTROPY;
+
+ uei = udp_encap_add_and_lock (fproto, fib_index, &src_ip, &dst_ip,
ntohs (mp->udp_encap.src_port),
- ntohs (mp->udp_encap.dst_port),
- UDP_ENCAP_FIXUP_NONE);
+ ntohs (mp->udp_encap.dst_port), flags);
done:
/* *INDENT-OFF* */
@@ -189,11 +192,19 @@ vl_api_udp_decap_add_del_t_handler (vl_api_udp_decap_add_del_t *mp)
static clib_error_t *
udp_api_hookup (vlib_main_t * vm)
{
+ api_main_t *am = vlibapi_get_main ();
+
/*
* Set up the (msg_name, crc, message-id) table
*/
REPLY_MSG_ID_BASE = setup_message_id_table ();
+ /* Mark these APIs as mp safe */
+ vl_api_set_msg_thread_safe (am, REPLY_MSG_ID_BASE + VL_API_UDP_ENCAP_ADD, 1);
+ vl_api_set_msg_thread_safe (am, REPLY_MSG_ID_BASE + VL_API_UDP_ENCAP_DEL, 1);
+ vl_api_set_msg_thread_safe (am, REPLY_MSG_ID_BASE + VL_API_UDP_ENCAP_DUMP,
+ 1);
+
return 0;
}
diff --git a/src/vnet/udp/udp_encap.c b/src/vnet/udp/udp_encap.c
index a0f5a50c223..ac1f855b4a0 100644
--- a/src/vnet/udp/udp_encap.c
+++ b/src/vnet/udp/udp_encap.c
@@ -195,6 +195,20 @@ udp_encap_dpo_unlock (dpo_id_t * dpo)
fib_node_unlock (&ue->ue_fib_node);
}
+u8 *
+format_udp_encap_fixup_flags (u8 *s, va_list *args)
+{
+ udp_encap_fixup_flags_t flags = va_arg (*args, udp_encap_fixup_flags_t);
+
+ if (flags == UDP_ENCAP_FIXUP_NONE)
+ return format (s, "none");
+
+ if (flags & UDP_ENCAP_FIXUP_UDP_SRC_PORT_ENTROPY)
+ s = format (s, "%s", "src-port-is-entropy");
+
+ return (s);
+}
+
static u8 *
format_udp_encap_i (u8 * s, va_list * args)
{
@@ -210,23 +224,21 @@ format_udp_encap_i (u8 * s, va_list * args)
s = format (s, "udp-encap:[%d]: ip-fib-index:%d ", uei, ue->ue_fib_index);
if (FIB_PROTOCOL_IP4 == ue->ue_ip_proto)
{
- s = format (s, "ip:[src:%U, dst:%U] udp:[src:%d, dst:%d]",
- format_ip4_address,
- &ue->ue_hdrs.ip4.ue_ip4.src_address,
- format_ip4_address,
- &ue->ue_hdrs.ip4.ue_ip4.dst_address,
+ s = format (s, "ip:[src:%U, dst:%U] udp:[src:%d, dst:%d] flags:%U",
+ format_ip4_address, &ue->ue_hdrs.ip4.ue_ip4.src_address,
+ format_ip4_address, &ue->ue_hdrs.ip4.ue_ip4.dst_address,
clib_net_to_host_u16 (ue->ue_hdrs.ip4.ue_udp.src_port),
- clib_net_to_host_u16 (ue->ue_hdrs.ip4.ue_udp.dst_port));
+ clib_net_to_host_u16 (ue->ue_hdrs.ip4.ue_udp.dst_port),
+ format_udp_encap_fixup_flags, ue->ue_flags);
}
else
{
- s = format (s, "ip:[src:%U, dst:%U] udp:[src:%d dst:%d]",
- format_ip6_address,
- &ue->ue_hdrs.ip6.ue_ip6.src_address,
- format_ip6_address,
- &ue->ue_hdrs.ip6.ue_ip6.dst_address,
+ s = format (s, "ip:[src:%U, dst:%U] udp:[src:%d dst:%d] flags:%U",
+ format_ip6_address, &ue->ue_hdrs.ip6.ue_ip6.src_address,
+ format_ip6_address, &ue->ue_hdrs.ip6.ue_ip6.dst_address,
clib_net_to_host_u16 (ue->ue_hdrs.ip6.ue_udp.src_port),
- clib_net_to_host_u16 (ue->ue_hdrs.ip6.ue_udp.dst_port));
+ clib_net_to_host_u16 (ue->ue_hdrs.ip6.ue_udp.dst_port),
+ format_udp_encap_fixup_flags, ue->ue_flags);
}
vlib_get_combined_counter (&(udp_encap_counters), uei, &to);
s = format (s, " to:[%Ld:%Ld]]", to.packets, to.bytes);
@@ -553,10 +565,12 @@ udp_encap_show (vlib_main_t * vm,
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (udp_encap_add_command, static) = {
.path = "udp encap",
- .short_help = "udp encap [add|del] <id ID> <src-ip> <dst-ip> [<src-port>] <dst-port> [src-port-is-entropy] [table-id <table>]",
+ .short_help = "udp encap [add|del] <id ID> <src-ip> <dst-ip> [<src-port>] "
+ "<dst-port> [src-port-is-entropy] [table-id <table>]",
.function = udp_encap_cli,
.is_mp_safe = 1,
};
+
VLIB_CLI_COMMAND (udp_encap_show_command, static) = {
.path = "show udp encap",
.short_help = "show udp encap [ID]",
diff --git a/src/vnet/udp/udp_encap.h b/src/vnet/udp/udp_encap.h
index 648e3b59e6d..c8b42ffa92c 100644
--- a/src/vnet/udp/udp_encap.h
+++ b/src/vnet/udp/udp_encap.h
@@ -115,6 +115,7 @@ extern index_t udp_encap_add_and_lock (fib_protocol_t proto,
extern void udp_encap_lock (index_t uei);
extern void udp_encap_unlock (index_t uei);
extern u8 *format_udp_encap (u8 * s, va_list * args);
+extern u8 *format_udp_encap_fixup_flags (u8 *s, va_list *args);
extern void udp_encap_contribute_forwarding (index_t uei,
dpo_proto_t proto,
dpo_id_t * dpo);
diff --git a/src/vnet/udp/udp_encap_node.c b/src/vnet/udp/udp_encap_node.c
index 1ebe79532f4..639ac23dfef 100644
--- a/src/vnet/udp/udp_encap_node.c
+++ b/src/vnet/udp/udp_encap_node.c
@@ -20,12 +20,16 @@ typedef struct udp4_encap_trace_t_
{
udp_header_t udp;
ip4_header_t ip;
+ u32 flow_hash;
+ udp_encap_fixup_flags_t flags;
} udp4_encap_trace_t;
typedef struct udp6_encap_trace_t_
{
udp_header_t udp;
ip6_header_t ip;
+ u32 flow_hash;
+ udp_encap_fixup_flags_t flags;
} udp6_encap_trace_t;
extern vlib_combined_counter_main_t udp_encap_counters;
@@ -35,13 +39,16 @@ format_udp4_encap_trace (u8 * s, va_list * args)
{
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ u32 indent = format_get_indent (s);
udp4_encap_trace_t *t;
t = va_arg (*args, udp4_encap_trace_t *);
- s = format (s, "%U\n %U",
- format_ip4_header, &t->ip, sizeof (t->ip),
- format_udp_header, &t->udp, sizeof (t->udp));
+ s = format (s, "flags: %U, flow hash: 0x%08x\n%U%U\n%U%U",
+ format_udp_encap_fixup_flags, t->flags, t->flow_hash,
+ format_white_space, indent, format_ip4_header, &t->ip,
+ sizeof (t->ip), format_white_space, indent, format_udp_header,
+ &t->udp, sizeof (t->udp));
return (s);
}
@@ -50,13 +57,16 @@ format_udp6_encap_trace (u8 * s, va_list * args)
{
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ u32 indent = format_get_indent (s);
udp6_encap_trace_t *t;
t = va_arg (*args, udp6_encap_trace_t *);
- s = format (s, "%U\n %U",
- format_ip6_header, &t->ip, sizeof (t->ip),
- format_udp_header, &t->udp, sizeof (t->udp));
+ s = format (s, "flags: %U, flow hash: 0x%08x\n%U%U\n%U%U",
+ format_udp_encap_fixup_flags, t->flags, t->flow_hash,
+ format_white_space, indent, format_ip6_header, &t->ip,
+ sizeof (t->ip), format_white_space, indent, format_udp_header,
+ &t->udp, sizeof (t->udp));
return (s);
}
@@ -127,13 +137,16 @@ udp_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
sizeof (udp_header_t) + sizeof (ip6_header_t);
ip_udp_encap_two (vm, b0, b1, (u8 *) &ue0->ue_hdrs,
(u8 *) &ue1->ue_hdrs, n_bytes, encap_family,
- payload_family);
+ payload_family, ue0->ue_flags, ue1->ue_flags);
+
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
udp6_encap_trace_t *tr =
vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->udp = ue0->ue_hdrs.ip6.ue_udp;
tr->ip = ue0->ue_hdrs.ip6.ue_ip6;
+ tr->flags = ue0->ue_flags;
+ tr->flow_hash = vnet_buffer (b0)->ip.flow_hash;
}
if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -141,6 +154,8 @@ udp_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_add_trace (vm, node, b1, sizeof (*tr));
tr->udp = ue1->ue_hdrs.ip6.ue_udp;
tr->ip = ue1->ue_hdrs.ip6.ue_ip6;
+ tr->flags = ue1->ue_flags;
+ tr->flow_hash = vnet_buffer (b1)->ip.flow_hash;
}
}
else
@@ -150,7 +165,7 @@ udp_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
ip_udp_encap_two (vm, b0, b1, (u8 *) &ue0->ue_hdrs,
(u8 *) &ue1->ue_hdrs, n_bytes, encap_family,
- payload_family);
+ payload_family, ue0->ue_flags, ue1->ue_flags);
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -158,6 +173,8 @@ udp_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->udp = ue0->ue_hdrs.ip4.ue_udp;
tr->ip = ue0->ue_hdrs.ip4.ue_ip4;
+ tr->flags = ue0->ue_flags;
+ tr->flow_hash = vnet_buffer (b0)->ip.flow_hash;
}
if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -165,6 +182,8 @@ udp_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_add_trace (vm, node, b1, sizeof (*tr));
tr->udp = ue1->ue_hdrs.ip4.ue_udp;
tr->ip = ue1->ue_hdrs.ip4.ue_ip4;
+ tr->flags = ue1->ue_flags;
+ tr->flow_hash = vnet_buffer (b1)->ip.flow_hash;
}
}
@@ -208,7 +227,7 @@ udp_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
const u8 n_bytes =
sizeof (udp_header_t) + sizeof (ip6_header_t);
ip_udp_encap_one (vm, b0, (u8 *) &ue0->ue_hdrs.ip6, n_bytes,
- encap_family, payload_family);
+ encap_family, payload_family, ue0->ue_flags);
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -216,6 +235,8 @@ udp_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->udp = ue0->ue_hdrs.ip6.ue_udp;
tr->ip = ue0->ue_hdrs.ip6.ue_ip6;
+ tr->flags = ue0->ue_flags;
+ tr->flow_hash = vnet_buffer (b0)->ip.flow_hash;
}
}
else
@@ -224,7 +245,7 @@ udp_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
sizeof (udp_header_t) + sizeof (ip4_header_t);
ip_udp_encap_one (vm, b0, (u8 *) &ue0->ue_hdrs.ip4, n_bytes,
- encap_family, payload_family);
+ encap_family, payload_family, ue0->ue_flags);
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -232,6 +253,8 @@ udp_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->udp = ue0->ue_hdrs.ip4.ue_udp;
tr->ip = ue0->ue_hdrs.ip4.ue_ip4;
+ tr->flags = ue0->ue_flags;
+ tr->flow_hash = vnet_buffer (b0)->ip.flow_hash;
}
}
diff --git a/src/vnet/udp/udp_inlines.h b/src/vnet/udp/udp_inlines.h
index 025809e1873..f0dd44f48b5 100644
--- a/src/vnet/udp/udp_inlines.h
+++ b/src/vnet/udp/udp_inlines.h
@@ -21,6 +21,9 @@
#include <vnet/ip/ip6.h>
#include <vnet/udp/udp_packet.h>
#include <vnet/interface_output.h>
+#include <vnet/ip/ip4_inlines.h>
+#include <vnet/ip/ip6_inlines.h>
+#include <vnet/udp/udp_encap.h>
always_inline void *
vlib_buffer_push_udp (vlib_buffer_t * b, u16 sp, u16 dp, u8 offload_csum)
@@ -42,8 +45,39 @@ vlib_buffer_push_udp (vlib_buffer_t * b, u16 sp, u16 dp, u8 offload_csum)
return uh;
}
+/*
+ * Encode udp source port entropy value per
+ * https://datatracker.ietf.org/doc/html/rfc7510#section-3
+ */
+always_inline u16
+ip_udp_sport_entropy (vlib_buffer_t *b0)
+{
+ u16 port = clib_host_to_net_u16 (0x03 << 14);
+ port |= vnet_buffer (b0)->ip.flow_hash & 0xffff;
+ return port;
+}
+
+always_inline u32
+ip_udp_compute_flow_hash (vlib_buffer_t *b0, u8 is_ip4)
+{
+ ip4_header_t *ip4;
+ ip6_header_t *ip6;
+
+ if (is_ip4)
+ {
+ ip4 = (ip4_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset);
+ return ip4_compute_flow_hash (ip4, IP_FLOW_HASH_DEFAULT);
+ }
+ else
+ {
+ ip6 = (ip6_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset);
+ return ip6_compute_flow_hash (ip6, IP_FLOW_HASH_DEFAULT);
+ }
+}
+
always_inline void
-ip_udp_fixup_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 is_ip4)
+ip_udp_fixup_one (vlib_main_t *vm, vlib_buffer_t *b0, u8 is_ip4,
+ u8 sport_entropy)
{
u16 new_l0;
udp_header_t *udp0;
@@ -71,6 +105,9 @@ ip_udp_fixup_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 is_ip4)
new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
- sizeof (*ip0));
udp0->length = new_l0;
+
+ if (sport_entropy)
+ udp0->src_port = ip_udp_sport_entropy (b0);
}
else
{
@@ -87,6 +124,9 @@ ip_udp_fixup_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 is_ip4)
udp0 = (udp_header_t *) (ip0 + 1);
udp0->length = new_l0;
+ if (sport_entropy)
+ udp0->src_port = ip_udp_sport_entropy (b0);
+
udp0->checksum =
ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
ASSERT (bogus0 == 0);
@@ -99,13 +139,20 @@ ip_udp_fixup_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 is_ip4)
always_inline void
ip_udp_encap_one (vlib_main_t *vm, vlib_buffer_t *b0, u8 *ec0, word ec_len,
ip_address_family_t encap_family,
- ip_address_family_t payload_family)
+ ip_address_family_t payload_family,
+ udp_encap_fixup_flags_t flags)
{
+ u8 sport_entropy = (flags & UDP_ENCAP_FIXUP_UDP_SRC_PORT_ENTROPY) != 0;
if (payload_family < N_AF)
{
vnet_calc_checksums_inline (vm, b0, payload_family == AF_IP4,
payload_family == AF_IP6);
+
+ /* Сalculate flow hash to be used for entropy */
+ if (sport_entropy && 0 == vnet_buffer (b0)->ip.flow_hash)
+ vnet_buffer (b0)->ip.flow_hash =
+ ip_udp_compute_flow_hash (b0, payload_family == AF_IP4);
}
vlib_buffer_advance (b0, -ec_len);
@@ -118,7 +165,7 @@ ip_udp_encap_one (vlib_main_t *vm, vlib_buffer_t *b0, u8 *ec0, word ec_len,
/* Apply the encap string. */
clib_memcpy_fast (ip0, ec0, ec_len);
- ip_udp_fixup_one (vm, b0, 1);
+ ip_udp_fixup_one (vm, b0, 1, sport_entropy);
}
else
{
@@ -128,7 +175,7 @@ ip_udp_encap_one (vlib_main_t *vm, vlib_buffer_t *b0, u8 *ec0, word ec_len,
/* Apply the encap string. */
clib_memcpy_fast (ip0, ec0, ec_len);
- ip_udp_fixup_one (vm, b0, 0);
+ ip_udp_fixup_one (vm, b0, 0, sport_entropy);
}
}
@@ -136,16 +183,28 @@ always_inline void
ip_udp_encap_two (vlib_main_t *vm, vlib_buffer_t *b0, vlib_buffer_t *b1,
u8 *ec0, u8 *ec1, word ec_len,
ip_address_family_t encap_family,
- ip_address_family_t payload_family)
+ ip_address_family_t payload_family,
+ udp_encap_fixup_flags_t flags0,
+ udp_encap_fixup_flags_t flags1)
{
u16 new_l0, new_l1;
udp_header_t *udp0, *udp1;
int payload_ip4 = (payload_family == AF_IP4);
+ int sport_entropy0 = (flags0 & UDP_ENCAP_FIXUP_UDP_SRC_PORT_ENTROPY) != 0;
+ int sport_entropy1 = (flags1 & UDP_ENCAP_FIXUP_UDP_SRC_PORT_ENTROPY) != 0;
if (payload_family < N_AF)
{
vnet_calc_checksums_inline (vm, b0, payload_ip4, !payload_ip4);
vnet_calc_checksums_inline (vm, b1, payload_ip4, !payload_ip4);
+
+ /* Сalculate flow hash to be used for entropy */
+ if (sport_entropy0 && 0 == vnet_buffer (b0)->ip.flow_hash)
+ vnet_buffer (b0)->ip.flow_hash =
+ ip_udp_compute_flow_hash (b0, payload_ip4);
+ if (sport_entropy1 && 0 == vnet_buffer (b1)->ip.flow_hash)
+ vnet_buffer (b1)->ip.flow_hash =
+ ip_udp_compute_flow_hash (b1, payload_ip4);
}
vlib_buffer_advance (b0, -ec_len);
@@ -195,6 +254,11 @@ ip_udp_encap_two (vlib_main_t *vm, vlib_buffer_t *b0, vlib_buffer_t *b1,
sizeof (*ip1));
udp0->length = new_l0;
udp1->length = new_l1;
+
+ if (sport_entropy0)
+ udp0->src_port = ip_udp_sport_entropy (b0);
+ if (sport_entropy1)
+ udp1->src_port = ip_udp_sport_entropy (b1);
}
else
{
@@ -222,6 +286,11 @@ ip_udp_encap_two (vlib_main_t *vm, vlib_buffer_t *b0, vlib_buffer_t *b1,
udp0->length = new_l0;
udp1->length = new_l1;
+ if (sport_entropy0)
+ udp0->src_port = ip_udp_sport_entropy (b0);
+ if (sport_entropy1)
+ udp1->src_port = ip_udp_sport_entropy (b1);
+
udp0->checksum =
ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
udp1->checksum =
diff --git a/src/vnet/vxlan-gpe/encap.c b/src/vnet/vxlan-gpe/encap.c
index 35a5529e80b..824f10f4fb7 100644
--- a/src/vnet/vxlan-gpe/encap.c
+++ b/src/vnet/vxlan-gpe/encap.c
@@ -96,7 +96,7 @@ vxlan_gpe_encap_one_inline (vxlan_gpe_main_t *ngm, vlib_buffer_t *b0,
ASSERT (sizeof (ip6_vxlan_gpe_header_t) == 56);
ip_udp_encap_one (ngm->vlib_main, b0, t0->rewrite, t0->rewrite_size, af,
- N_AF);
+ N_AF, UDP_ENCAP_FIXUP_NONE);
next0[0] = t0->encap_next_node;
}
@@ -123,9 +123,9 @@ vxlan_gpe_encap_two_inline (vxlan_gpe_main_t *ngm, vlib_buffer_t *b0,
ASSERT (sizeof (ip6_vxlan_gpe_header_t) == 56);
ip_udp_encap_one (ngm->vlib_main, b0, t0->rewrite, t0->rewrite_size, af,
- N_AF);
+ N_AF, UDP_ENCAP_FIXUP_NONE);
ip_udp_encap_one (ngm->vlib_main, b1, t1->rewrite, t1->rewrite_size, af,
- N_AF);
+ N_AF, UDP_ENCAP_FIXUP_NONE);
next0[0] = next1[0] = t0->encap_next_node;
}
diff --git a/test/test_udp.py b/test/test_udp.py
index c7e97c641b8..ebc99e85388 100644
--- a/test/test_udp.py
+++ b/test/test_udp.py
@@ -25,6 +25,8 @@ from scapy.layers.inet6 import IPv6
from scapy.contrib.mpls import MPLS
NUM_PKTS = 67
+ENTROPY_PORT_MIN = 0x3 << 14
+ENTROPY_PORT_MAX = 0xFFFF
@tag_fixme_vpp_workers
@@ -78,16 +80,22 @@ class TestUdpEncap(VppTestCase):
i.admin_down()
super(TestUdpEncap, self).tearDown()
- def validate_outer4(self, rx, encap_obj):
+ def validate_outer4(self, rx, encap_obj, sport_entropy=False):
self.assertEqual(rx[IP].src, encap_obj.src_ip_s)
self.assertEqual(rx[IP].dst, encap_obj.dst_ip_s)
- self.assertEqual(rx[UDP].sport, encap_obj.src_port)
+ if sport_entropy:
+ self.assert_in_range(rx[UDP].sport, ENTROPY_PORT_MIN, ENTROPY_PORT_MAX)
+ else:
+ self.assertEqual(rx[UDP].sport, encap_obj.src_port)
self.assertEqual(rx[UDP].dport, encap_obj.dst_port)
- def validate_outer6(self, rx, encap_obj):
+ def validate_outer6(self, rx, encap_obj, sport_entropy=False):
self.assertEqual(rx[IPv6].src, encap_obj.src_ip_s)
self.assertEqual(rx[IPv6].dst, encap_obj.dst_ip_s)
- self.assertEqual(rx[UDP].sport, encap_obj.src_port)
+ if sport_entropy:
+ self.assert_in_range(rx[UDP].sport, ENTROPY_PORT_MIN, ENTROPY_PORT_MAX)
+ else:
+ self.assertEqual(rx[UDP].sport, encap_obj.src_port)
self.assertEqual(rx[UDP].dport, encap_obj.dst_port)
def validate_inner4(self, rx, tx, ttl=None):
@@ -343,6 +351,193 @@ class TestUdpEncap(VppTestCase):
self.validate_inner4(p, p_4omo4, ttl=63)
self.assertEqual(udp_encap_1.get_stats()["packets"], 2 * NUM_PKTS)
+ def test_udp_encap_entropy(self):
+ """UDP Encap src port entropy test"""
+
+ #
+ # construct a UDP encap object through each of the peers
+ # v4 through the first two peers, v6 through the second.
+ # use zero source port to enable entropy per rfc7510.
+ #
+ udp_encap_0 = VppUdpEncap(self, self.pg0.local_ip4, self.pg0.remote_ip4, 0, 440)
+ udp_encap_1 = VppUdpEncap(
+ self, self.pg1.local_ip4, self.pg1.remote_ip4, 0, 441, table_id=1
+ )
+ udp_encap_2 = VppUdpEncap(
+ self, self.pg2.local_ip6, self.pg2.remote_ip6, 0, 442, table_id=2
+ )
+ udp_encap_3 = VppUdpEncap(
+ self, self.pg3.local_ip6, self.pg3.remote_ip6, 0, 443, table_id=3
+ )
+ udp_encap_0.add_vpp_config()
+ udp_encap_1.add_vpp_config()
+ udp_encap_2.add_vpp_config()
+ udp_encap_3.add_vpp_config()
+
+ self.logger.info(self.vapi.cli("sh udp encap"))
+
+ self.assertTrue(find_udp_encap(self, udp_encap_0))
+ self.assertTrue(find_udp_encap(self, udp_encap_1))
+ self.assertTrue(find_udp_encap(self, udp_encap_2))
+ self.assertTrue(find_udp_encap(self, udp_encap_3))
+
+ #
+ # Routes via each UDP encap object - all combinations of v4 and v6.
+ #
+ route_4o4 = VppIpRoute(
+ self,
+ "1.1.0.1",
+ 24,
+ [
+ VppRoutePath(
+ "0.0.0.0",
+ 0xFFFFFFFF,
+ type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
+ next_hop_id=udp_encap_0.id,
+ proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
+ )
+ ],
+ table_id=1,
+ )
+ route_4o6 = VppIpRoute(
+ self,
+ "1.1.2.1",
+ 32,
+ [
+ VppRoutePath(
+ "0.0.0.0",
+ 0xFFFFFFFF,
+ type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
+ next_hop_id=udp_encap_2.id,
+ proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
+ )
+ ],
+ )
+ route_6o4 = VppIpRoute(
+ self,
+ "2001::1",
+ 128,
+ [
+ VppRoutePath(
+ "0.0.0.0",
+ 0xFFFFFFFF,
+ type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
+ next_hop_id=udp_encap_1.id,
+ proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
+ )
+ ],
+ )
+ route_6o6 = VppIpRoute(
+ self,
+ "2001::3",
+ 128,
+ [
+ VppRoutePath(
+ "0.0.0.0",
+ 0xFFFFFFFF,
+ type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
+ next_hop_id=udp_encap_3.id,
+ proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
+ )
+ ],
+ )
+ route_4o4.add_vpp_config()
+ route_4o6.add_vpp_config()
+ route_6o6.add_vpp_config()
+ route_6o4.add_vpp_config()
+
+ #
+ # 4o4 encap
+ #
+ p_4o4 = []
+ for i in range(NUM_PKTS):
+ p_4o4.append(
+ Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
+ / IP(src="2.2.2.2", dst="1.1.0.1")
+ / UDP(sport=1234 + i, dport=1234)
+ / Raw(b"\xa5" * 100)
+ )
+ rx = self.send_and_expect(self.pg1, p_4o4, self.pg0)
+ sports = set()
+ for i, p in enumerate(rx):
+ self.validate_outer4(p, udp_encap_0, True)
+ sports.add(p["UDP"].sport)
+ p = IP(p["UDP"].payload.load)
+ self.validate_inner4(p, p_4o4[i])
+ self.assertEqual(udp_encap_0.get_stats()["packets"], NUM_PKTS)
+ self.assertGreater(
+ len(sports), 1, "source port {} is not an entropy value".format(sports)
+ )
+
+ #
+ # 4o6 encap
+ #
+ p_4o6 = []
+ for i in range(NUM_PKTS):
+ p_4o6.append(
+ Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+ / IP(src="2.2.2.2", dst="1.1.2.1")
+ / UDP(sport=1234 + i, dport=1234)
+ / Raw(b"\xa5" * 100)
+ )
+ rx = self.send_and_expect(self.pg0, p_4o6, self.pg2)
+ sports = set()
+ for p in rx:
+ self.validate_outer6(p, udp_encap_2, True)
+ sports.add(p["UDP"].sport)
+ p = IP(p["UDP"].payload.load)
+ self.validate_inner4(p, p_4o6[i])
+ self.assertEqual(udp_encap_2.get_stats()["packets"], NUM_PKTS)
+ self.assertGreater(
+ len(sports), 1, "source port {} is not an entropy value".format(sports)
+ )
+
+ #
+ # 6o4 encap
+ #
+ p_6o4 = []
+ for i in range(NUM_PKTS):
+ p_6o4.append(
+ Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+ / IPv6(src="2001::100", dst="2001::1")
+ / UDP(sport=1234 + i, dport=1234)
+ / Raw(b"\xa5" * 100)
+ )
+ rx = self.send_and_expect(self.pg0, p_6o4, self.pg1)
+ sports = set()
+ for p in rx:
+ self.validate_outer4(p, udp_encap_1, True)
+ sports.add(p["UDP"].sport)
+ p = IPv6(p["UDP"].payload.load)
+ self.validate_inner6(p, p_6o4[i])
+ self.assertEqual(udp_encap_1.get_stats()["packets"], NUM_PKTS)
+ self.assertGreater(
+ len(sports), 1, "source port {} is not an entropy value".format(sports)
+ )
+
+ #
+ # 6o6 encap
+ #
+ p_6o6 = []
+ for i in range(NUM_PKTS):
+ p_6o6.append(
+ Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+ / IPv6(src="2001::100", dst="2001::3")
+ / UDP(sport=1234 + i, dport=1234)
+ / Raw(b"\xa5" * 100)
+ )
+ rx = self.send_and_expect(self.pg0, p_6o6, self.pg3)
+ sports = set()
+ for p in rx:
+ self.validate_outer6(p, udp_encap_3, True)
+ sports.add(p["UDP"].sport)
+ p = IPv6(p["UDP"].payload.load)
+ self.validate_inner6(p, p_6o6[i])
+ self.assertEqual(udp_encap_3.get_stats()["packets"], NUM_PKTS)
+ self.assertGreater(
+ len(sports), 1, "source port {} is not an entropy value".format(sports)
+ )
+
def test_udp_decap(self):
"""UDP Decap test"""
#