From 99413ec2610fb8b4192fa4e7f2db08486ec1e69f Mon Sep 17 00:00:00 2001 From: Paolo Valerio Date: Fri, 16 Feb 2024 18:19:13 +0100 Subject: [PATCH] conntrack: Handle random selection for port ranges. The userspace conntrack only supported hash for port selection. With the patch, both userspace and kernel datapath support the random flag. The default behavior remains the same, that is, if no flags are specified, hash is selected. Signed-off-by: Paolo Valerio Acked-by: Aaron Conole Signed-off-by: Simon Horman --- Documentation/ref/ovs-actions.7.rst | 3 +-- NEWS | 3 +++ lib/conntrack.c | 15 ++++++++------- lib/conntrack.h | 5 +++++ lib/dpif-netdev.c | 4 +++- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Documentation/ref/ovs-actions.7.rst b/Documentation/ref/ovs-actions.7.rst index 36adcc5db..80acd9070 100644 --- a/Documentation/ref/ovs-actions.7.rst +++ b/Documentation/ref/ovs-actions.7.rst @@ -1551,8 +1551,7 @@ following arguments: should be selected. When a port range is specified, fallback to ephemeral ports does not happen, else, it will. The port number selection can be informed by the optional ``random`` and ``hash`` flags - described below. The userspace datapath only supports the ``hash`` - behavior. + described below. The optional *flags* are: diff --git a/NEWS b/NEWS index 0789dc0c6..5a5caffbf 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ Post-v3.3.0 -------------------- + - Userspace datapath: + * Conntrack now supports 'random' flag for selecting ports in a range + while natting. v3.3.0 - 16 Feb 2024 diff --git a/lib/conntrack.c b/lib/conntrack.c index 013709bd6..e09ecdf33 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -2222,7 +2222,7 @@ nat_range_hash(const struct conn_key *key, uint32_t basis, /* Ports are stored in host byte order for convenience. */ static void set_sport_range(const struct nat_action_info_t *ni, const struct conn_key *k, - uint32_t hash, uint16_t *curr, uint16_t *min, + uint32_t off, uint16_t *curr, uint16_t *min, uint16_t *max) { if (((ni->nat_action & NAT_ACTION_SNAT_ALL) == NAT_ACTION_SRC) || @@ -2241,19 +2241,19 @@ set_sport_range(const struct nat_action_info_t *ni, const struct conn_key *k, } else { *min = ni->min_port; *max = ni->max_port; - *curr = *min + (hash % ((*max - *min) + 1)); + *curr = *min + (off % ((*max - *min) + 1)); } } static void set_dport_range(const struct nat_action_info_t *ni, const struct conn_key *k, - uint32_t hash, uint16_t *curr, uint16_t *min, + uint32_t off, uint16_t *curr, uint16_t *min, uint16_t *max) { if (ni->nat_action & NAT_ACTION_DST_PORT) { *min = ni->min_port; *max = ni->max_port; - *curr = *min + (hash % ((*max - *min) + 1)); + *curr = *min + (off % ((*max - *min) + 1)); } else { *curr = ntohs(k->dst.port); *min = *max = *curr; @@ -2388,18 +2388,19 @@ nat_get_unique_tuple(struct conntrack *ct, struct conn *conn, fwd_key->nw_proto == IPPROTO_SCTP; uint16_t min_dport, max_dport, curr_dport; uint16_t min_sport, max_sport, curr_sport; - uint32_t hash; + uint32_t hash, port_off; hash = nat_range_hash(fwd_key, ct->hash_basis, nat_info); + port_off = nat_info->nat_flags & NAT_RANGE_RANDOM ? random_uint32() : hash; min_addr = nat_info->min_addr; max_addr = nat_info->max_addr; find_addr(fwd_key, &min_addr, &max_addr, &addr, hash, (fwd_key->dl_type == htons(ETH_TYPE_IP)), nat_info); - set_sport_range(nat_info, fwd_key, hash, &curr_sport, + set_sport_range(nat_info, fwd_key, port_off, &curr_sport, &min_sport, &max_sport); - set_dport_range(nat_info, fwd_key, hash, &curr_dport, + set_dport_range(nat_info, fwd_key, port_off, &curr_dport, &min_dport, &max_dport); if (pat_proto) { diff --git a/lib/conntrack.h b/lib/conntrack.h index 0a888be45..9b0c6aa88 100644 --- a/lib/conntrack.h +++ b/lib/conntrack.h @@ -77,12 +77,17 @@ enum nat_action_e { NAT_ACTION_DST_PORT = 1 << 3, }; +enum nat_flags_e { + NAT_RANGE_RANDOM = 1 << 0, +}; + struct nat_action_info_t { union ct_addr min_addr; union ct_addr max_addr; uint16_t min_port; uint16_t max_port; uint16_t nat_action; + uint16_t nat_flags; }; struct conntrack *conntrack_init(void); diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 46e24d204..0f08fa92b 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -9409,9 +9409,11 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, nl_attr_get_u16(b_nest); proto_num_max_specified = true; break; + case OVS_NAT_ATTR_PROTO_RANDOM: + nat_action_info.nat_flags |= NAT_RANGE_RANDOM; + break; case OVS_NAT_ATTR_PERSISTENT: case OVS_NAT_ATTR_PROTO_HASH: - case OVS_NAT_ATTR_PROTO_RANDOM: break; case OVS_NAT_ATTR_UNSPEC: case __OVS_NAT_ATTR_MAX: