ip: support flow-hash gtpv1teid
support with GTPv1 TEID added to the flow hash. This can able to ECMP to PGW and parallelization. Type: feature Change-Id: I6f758579027caf6123831ef2db7afe17e424a6eb Signed-off-by: Takeru Hayasaka <hayatake396@gmail.com>
This commit is contained in:

committed by
Neale Ranns

parent
55686e1c59
commit
b23c6f4f29
@ -366,6 +366,41 @@ autoreply define set_ip_flow_hash_v2
|
||||
vl_api_ip_flow_hash_config_t flow_hash_config;
|
||||
};
|
||||
|
||||
/**
|
||||
@brief flow hash settings for an IP table
|
||||
@param src - include src in flow hash
|
||||
@param dst - include dst in flow hash
|
||||
@param sport - include sport in flow hash
|
||||
@param dport - include dport in flow hash
|
||||
@param proto - include proto in flow hash
|
||||
@param reverse - include reverse in flow hash
|
||||
@param symmetric - include symmetry in flow hash
|
||||
@param flowlabel - include flowlabel in flow hash
|
||||
@param gtpv1teid - include gtpv1teid in flow hash
|
||||
*/
|
||||
enumflag ip_flow_hash_config_v2
|
||||
{
|
||||
IP_API_V2_FLOW_HASH_SRC_IP = 0x01,
|
||||
IP_API_V2_FLOW_HASH_DST_IP = 0x02,
|
||||
IP_API_V2_FLOW_HASH_SRC_PORT = 0x04,
|
||||
IP_API_V2_FLOW_HASH_DST_PORT = 0x08,
|
||||
IP_API_V2_FLOW_HASH_PROTO = 0x10,
|
||||
IP_API_V2_FLOW_HASH_REVERSE = 0x20,
|
||||
IP_API_V2_FLOW_HASH_SYMETRIC = 0x40,
|
||||
IP_API_V2_FLOW_HASH_FLOW_LABEL = 0x80,
|
||||
IP_API_V2_FLOW_HASH_GTPV1_TEID = 0x100,
|
||||
};
|
||||
|
||||
autoreply define set_ip_flow_hash_v3
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 table_id;
|
||||
vl_api_address_family_t af;
|
||||
vl_api_ip_flow_hash_config_v2_t flow_hash_config;
|
||||
option status="in_progress";
|
||||
};
|
||||
|
||||
/** \brief Set the ip flow hash router ID
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
|
@ -2834,11 +2834,10 @@ set_ip_flow_hash_command_fn (vlib_main_t * vm,
|
||||
* @cliexend
|
||||
?*/
|
||||
/* *INDENT-OFF* */
|
||||
VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
|
||||
{
|
||||
VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
|
||||
.path = "set ip flow-hash",
|
||||
.short_help =
|
||||
"set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
|
||||
.short_help = "set ip flow-hash table <table-id> [src] [dst] [sport] "
|
||||
"[dport] [proto] [reverse] [gtpv1teid]",
|
||||
.function = set_ip_flow_hash_command_fn,
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <vnet/ip/ip_flow_hash.h>
|
||||
#include <vnet/ip/ip4_packet.h>
|
||||
#include <vnet/tcp/tcp_packet.h>
|
||||
#include <vnet/udp/udp_packet.h>
|
||||
|
||||
#define IP_DF 0x4000 /* don't fragment */
|
||||
|
||||
@ -53,9 +54,11 @@ ip4_compute_flow_hash (const ip4_header_t * ip,
|
||||
flow_hash_config_t flow_hash_config)
|
||||
{
|
||||
tcp_header_t *tcp = (void *) (ip + 1);
|
||||
udp_header_t *udp = (void *) (ip + 1);
|
||||
gtpv1u_header_t *gtpu = (void *) (udp + 1);
|
||||
u32 a, b, c, t1, t2;
|
||||
uword is_tcp_udp = (ip->protocol == IP_PROTOCOL_TCP
|
||||
|| ip->protocol == IP_PROTOCOL_UDP);
|
||||
uword is_udp = ip->protocol == IP_PROTOCOL_UDP;
|
||||
uword is_tcp_udp = (ip->protocol == IP_PROTOCOL_TCP || is_udp);
|
||||
|
||||
t1 = (flow_hash_config & IP_FLOW_HASH_SRC_ADDR)
|
||||
? ip->src_address.data_u32 : 0;
|
||||
@ -90,6 +93,13 @@ ip4_compute_flow_hash (const ip4_header_t * ip,
|
||||
b ^= (flow_hash_config & IP_FLOW_HASH_PROTO) ? ip->protocol : 0;
|
||||
c = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ?
|
||||
(t1 << 16) | t2 : (t2 << 16) | t1;
|
||||
if (PREDICT_TRUE (is_udp) &&
|
||||
PREDICT_FALSE ((flow_hash_config & IP_FLOW_HASH_GTPV1_TEID) &&
|
||||
udp->dst_port == GTPV1_PORT_BE))
|
||||
{
|
||||
t1 = gtpu->teid;
|
||||
c ^= t1;
|
||||
}
|
||||
a ^= ip_flow_hash_router_id;
|
||||
|
||||
hash_v3_mix32 (a, b, c);
|
||||
|
@ -50,14 +50,16 @@ ip6_compute_flow_hash (const ip6_header_t * ip,
|
||||
flow_hash_config_t flow_hash_config)
|
||||
{
|
||||
tcp_header_t *tcp;
|
||||
udp_header_t *udp = (void *) (ip + 1);
|
||||
gtpv1u_header_t *gtpu = (void *) (udp + 1);
|
||||
u64 a, b, c;
|
||||
u64 t1, t2;
|
||||
u32 t3;
|
||||
uword is_tcp_udp = 0;
|
||||
uword is_udp = ip->protocol == IP_PROTOCOL_UDP;
|
||||
u8 protocol = ip->protocol;
|
||||
|
||||
if (PREDICT_TRUE
|
||||
((ip->protocol == IP_PROTOCOL_TCP)
|
||||
|| (ip->protocol == IP_PROTOCOL_UDP)))
|
||||
if (PREDICT_TRUE ((ip->protocol == IP_PROTOCOL_TCP) || is_udp))
|
||||
{
|
||||
is_tcp_udp = 1;
|
||||
tcp = (void *) (ip + 1);
|
||||
@ -113,7 +115,13 @@ ip6_compute_flow_hash (const ip6_header_t * ip,
|
||||
((flow_hash_config & IP_FLOW_HASH_FL) ? ip6_flow_label_network_order (ip) :
|
||||
0);
|
||||
c ^= t1;
|
||||
|
||||
if (PREDICT_TRUE (is_udp) &&
|
||||
PREDICT_FALSE ((flow_hash_config & IP_FLOW_HASH_GTPV1_TEID) &&
|
||||
udp->dst_port == GTPV1_PORT_BE))
|
||||
{
|
||||
t3 = gtpu->teid;
|
||||
a ^= t3;
|
||||
}
|
||||
hash_mix64 (a, b, c);
|
||||
return (u32) c;
|
||||
}
|
||||
|
@ -1297,6 +1297,22 @@ vl_api_set_ip_flow_hash_v2_t_handler (vl_api_set_ip_flow_hash_v2_t *mp)
|
||||
REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_V2_REPLY);
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_set_ip_flow_hash_v3_t_handler (vl_api_set_ip_flow_hash_v3_t *mp)
|
||||
{
|
||||
vl_api_set_ip_flow_hash_v3_reply_t *rmp;
|
||||
ip_address_family_t af;
|
||||
int rv;
|
||||
|
||||
rv = ip_address_family_decode (mp->af, &af);
|
||||
|
||||
if (!rv)
|
||||
rv = ip_flow_hash_set (af, htonl (mp->table_id),
|
||||
htonl (mp->flow_hash_config));
|
||||
|
||||
REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_V3_REPLY);
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_set_ip_flow_hash_router_id_t_handler (
|
||||
vl_api_set_ip_flow_hash_router_id_t *mp)
|
||||
|
@ -38,7 +38,17 @@
|
||||
_ (proto, 4, IP_FLOW_HASH_PROTO) \
|
||||
_ (reverse, 5, IP_FLOW_HASH_REVERSE_SRC_DST) \
|
||||
_ (symmetric, 6, IP_FLOW_HASH_SYMMETRIC) \
|
||||
_ (flowlabel, 7, IP_FLOW_HASH_FL)
|
||||
_ (flowlabel, 7, IP_FLOW_HASH_FL) \
|
||||
_ (gtpv1teid, 8, IP_FLOW_HASH_GTPV1_TEID)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 ver_flags;
|
||||
u8 type;
|
||||
u16 length;
|
||||
u32 teid;
|
||||
} __attribute__ ((packed)) gtpv1u_header_t;
|
||||
#define GTPV1_PORT_BE 0x6808
|
||||
|
||||
/**
|
||||
* A flow hash configuration is a mask of the flow hash options
|
||||
|
@ -1276,6 +1276,12 @@ api_set_ip_flow_hash_v2 (vat_main_t *vat)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
api_set_ip_flow_hash_v3 (vat_main_t *vat)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
api_ip_mroute_add_del (vat_main_t *vam)
|
||||
{
|
||||
|
@ -145,13 +145,13 @@ unformat_ip_flow_hash_config (unformat_input_t *input, va_list *args)
|
||||
{
|
||||
if (unformat (input, "%_,"))
|
||||
;
|
||||
#define _(a, b) \
|
||||
#define _(a, b, c) \
|
||||
else if (unformat (input, "%_" #a)) \
|
||||
{ \
|
||||
*flow_hash_config |= b; \
|
||||
*flow_hash_config |= c; \
|
||||
matched_once = 1; \
|
||||
}
|
||||
foreach_flow_hash_bit_v1
|
||||
foreach_flow_hash_bit
|
||||
#undef _
|
||||
else
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ import unittest
|
||||
|
||||
import scapy.compat
|
||||
from scapy.contrib.mpls import MPLS
|
||||
from scapy.contrib.gtp import GTP_U_Header
|
||||
from scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
|
||||
from scapy.layers.inet6 import IPv6
|
||||
from scapy.layers.l2 import Ether, Dot1Q, ARP
|
||||
@ -1210,6 +1211,7 @@ class TestIPLoadBalance(VppTestCase):
|
||||
"""IP Load-Balancing"""
|
||||
|
||||
fhc = VppEnum.vl_api_ip_flow_hash_config_t
|
||||
fhcv2 = VppEnum.vl_api_ip_flow_hash_config_v2_t
|
||||
af = VppEnum.vl_api_address_family_t
|
||||
|
||||
#
|
||||
@ -1217,16 +1219,20 @@ class TestIPLoadBalance(VppTestCase):
|
||||
#
|
||||
port_ip_pkts = []
|
||||
port_mpls_pkts = []
|
||||
port_gtp_pkts = []
|
||||
|
||||
#
|
||||
# An array of packets that differ only in the source address
|
||||
#
|
||||
src_ip_pkts = []
|
||||
src_mpls_pkts = []
|
||||
src_gtp_pkts = []
|
||||
|
||||
for ii in range(NUM_PKTS):
|
||||
internal_src_ip_hdr = IP(dst="10.0.0.1", src="20.0.0.1")
|
||||
|
||||
port_ip_hdr = (
|
||||
IP(dst="10.0.0.1", src="20.0.0.1")
|
||||
internal_src_ip_hdr
|
||||
/ UDP(sport=1234, dport=1234 + ii)
|
||||
/ Raw(b"\xa5" * 100)
|
||||
)
|
||||
@ -1240,6 +1246,15 @@ class TestIPLoadBalance(VppTestCase):
|
||||
/ port_ip_hdr
|
||||
)
|
||||
)
|
||||
port_gtp_pkts.append(
|
||||
(
|
||||
Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
|
||||
/ internal_src_ip_hdr
|
||||
/ UDP(sport=2152, dport=2152, chksum=0)
|
||||
/ GTP_U_Header(gtp_type="g_pdu", teid=200)
|
||||
/ Raw(b"\xa5" * 100)
|
||||
)
|
||||
)
|
||||
|
||||
src_ip_hdr = (
|
||||
IP(dst="10.0.0.1", src="20.0.0.%d" % ii)
|
||||
@ -1256,6 +1271,15 @@ class TestIPLoadBalance(VppTestCase):
|
||||
/ src_ip_hdr
|
||||
)
|
||||
)
|
||||
src_gtp_pkts.append(
|
||||
(
|
||||
Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
|
||||
/ IP(dst="10.0.0.1", src="20.0.0.1")
|
||||
/ UDP(sport=2152, dport=2152, chksum=0)
|
||||
/ GTP_U_Header(gtp_type="g_pdu", teid=ii)
|
||||
/ Raw(b"\xa5" * 100)
|
||||
)
|
||||
)
|
||||
|
||||
route_10_0_0_1 = VppIpRoute(
|
||||
self,
|
||||
@ -1330,6 +1354,26 @@ class TestIPLoadBalance(VppTestCase):
|
||||
|
||||
self.send_and_expect_only(self.pg0, port_ip_pkts, self.pg2)
|
||||
|
||||
#
|
||||
# this case gtp v1 teid key LB
|
||||
#
|
||||
self.vapi.set_ip_flow_hash_v3(
|
||||
af=af.ADDRESS_IP4,
|
||||
table_id=0,
|
||||
flow_hash_config=(
|
||||
fhcv2.IP_API_V2_FLOW_HASH_SRC_IP
|
||||
| fhcv2.IP_API_V2_FLOW_HASH_PROTO
|
||||
| fhcv2.IP_API_V2_FLOW_HASH_GTPV1_TEID
|
||||
),
|
||||
)
|
||||
self.logger.info(self.vapi.cli("show ip fib"))
|
||||
|
||||
self.send_and_expect_load_balancing(
|
||||
self.pg0, src_gtp_pkts, [self.pg1, self.pg2]
|
||||
)
|
||||
|
||||
self.send_and_expect_only(self.pg0, port_gtp_pkts, self.pg2)
|
||||
|
||||
#
|
||||
# change the flow hash config back to defaults
|
||||
#
|
||||
|
Reference in New Issue
Block a user