Skip to content

Commit

Permalink
userspace: Add GTP-U support.
Browse files Browse the repository at this point in the history
GTP, GPRS Tunneling Protocol, is a group of IP-based communications
protocols used to carry general packet radio service (GPRS) within
GSM, UMTS and LTE networks.  GTP protocol has two parts: Signalling
(GTP-Control, GTP-C) and User data (GTP-User, GTP-U). GTP-C is used
for setting up GTP-U protocol, which is an IP-in-UDP tunneling
protocol. Usually GTP is used in connecting between base station for
radio, Serving Gateway (S-GW), and PDN Gateway (P-GW).

This patch implements GTP-U protocol for userspace datapath,
supporting only required header fields and G-PDU message type.
See spec in:
https://tools.ietf.org/html/draft-hmm-dmm-5g-uplane-analysis-00

Tested-at: https://travis-ci.org/github/williamtu/ovs-travis/builds/666518784
Signed-off-by: Feng Yang <[email protected]>
Co-authored-by: Feng Yang <[email protected]>
Signed-off-by: Yi Yang <[email protected]>
Co-authored-by: Yi Yang <[email protected]>
Signed-off-by: William Tu <[email protected]>
Acked-by: Ben Pfaff <[email protected]>
  • Loading branch information
3 people committed Mar 26, 2020
1 parent f598f46 commit 3c6d05a
Show file tree
Hide file tree
Showing 30 changed files with 752 additions and 40 deletions.
13 changes: 13 additions & 0 deletions Documentation/faq/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,19 @@ Q: Does Open vSwitch support IPv6 GRE?
options:remote_ip=fc00:100::1 \
options:packet_type=legacy_l2

Q: Does Open vSwitch support GTP-U?

A: Yes. Starting with version 2.13, the Open vSwitch userspace
datapath supports GTP-U (GPRS Tunnelling Protocol User Plane
(GTPv1-U)). TEID is set by using tunnel key field.

::

$ ovs-vsctl add-br br0
$ ovs-vsctl add-port br0 gtpu0 -- \
set int gtpu0 type=gtpu options:key=<teid> \
options:remote_ip=172.31.1.1

Q: How do I connect two bridges?

A: First, why do you want to do this? Two connected bridges are not much
Expand Down
1 change: 1 addition & 0 deletions Documentation/faq/releases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ Q: Are all features available with all datapaths?
Tunnel - Geneve-IPv6 4.4 2.6 2.6 NO
Tunnel - ERSPAN 4.18 2.10 2.10 NO
Tunnel - ERSPAN-IPv6 4.18 2.10 2.10 NO
Tunnel - GTP-U NO NO 2.13 NO
QoS - Policing YES 1.1 2.6 NO
QoS - Shaping YES 1.1 NO NO
sFlow YES 1.0 1.0 NO
Expand Down
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ v2.13.0 - 14 Feb 2020
- 'ovs-appctl dpctl/dump-flows' can now show offloaded=partial for
partially offloaded flows, dp:dpdk for fully offloaded by dpdk, and
type filter supports new filters: "dpdk" and "partially-offloaded".
- GTP-U Tunnel Protocol
* Add two new fields: tun_gtpu_flags, tun_gtpu_msgtype.
* Only support for userspace datapath.

v2.12.0 - 03 Sep 2019
---------------------
Expand Down
2 changes: 2 additions & 0 deletions datapath/linux/compat/include/linux/openvswitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ enum ovs_vport_type {
OVS_VPORT_TYPE_ERSPAN = 107, /* ERSPAN tunnel. */
OVS_VPORT_TYPE_IP6ERSPAN = 108, /* ERSPAN tunnel. */
OVS_VPORT_TYPE_IP6GRE = 109,
OVS_VPORT_TYPE_GTPU = 110,
__OVS_VPORT_TYPE_MAX
};

Expand Down Expand Up @@ -404,6 +405,7 @@ enum ovs_tunnel_key_attr {
OVS_TUNNEL_KEY_ATTR_IPV6_DST, /* struct in6_addr dst IPv6 address. */
OVS_TUNNEL_KEY_ATTR_PAD,
OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS, /* struct erspan_metadata */
OVS_TUNNEL_KEY_ATTR_GTPU_OPTS, /* struct gtpu_metadata */
__OVS_TUNNEL_KEY_ATTR_MAX
};

Expand Down
4 changes: 2 additions & 2 deletions include/openvswitch/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extern "C" {
/* This sequence number should be incremented whenever anything involving flows
* or the wildcarding of flows changes. This will cause build assertion
* failures in places which likely need to be updated. */
#define FLOW_WC_SEQ 41
#define FLOW_WC_SEQ 42

/* Number of Open vSwitch extension 32-bit registers. */
#define FLOW_N_REGS 16
Expand Down Expand Up @@ -168,7 +168,7 @@ BUILD_ASSERT_DECL(sizeof(struct ovs_key_nsh) % sizeof(uint64_t) == 0);
/* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t)
== sizeof(struct flow_tnl) + sizeof(struct ovs_key_nsh) + 300
&& FLOW_WC_SEQ == 41);
&& FLOW_WC_SEQ == 42);

/* Incremental points at which flow classification may be performed in
* segments.
Expand Down
6 changes: 6 additions & 0 deletions include/openvswitch/match.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ void match_set_tun_erspan_dir_masked(struct match *match, uint8_t dir,
void match_set_tun_erspan_hwid(struct match *match, uint8_t hwid);
void match_set_tun_erspan_hwid_masked(struct match *match, uint8_t hwid,
uint8_t mask);
void match_set_tun_gtpu_flags(struct match *match, uint8_t flags);
void match_set_tun_gtpu_flags_masked(struct match *match, uint8_t flags,
uint8_t mask);
void match_set_tun_gtpu_msgtype(struct match *match, uint8_t msgtype);
void match_set_tun_gtpu_msgtype_masked(struct match *match, uint8_t msgtype,
uint8_t mask);
void match_set_in_port(struct match *, ofp_port_t ofp_port);
void match_set_pkt_mark(struct match *, uint32_t pkt_mark);
void match_set_pkt_mark_masked(struct match *, uint32_t pkt_mark, uint32_t mask);
Expand Down
28 changes: 28 additions & 0 deletions include/openvswitch/meta-flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,34 @@ enum OVS_PACKED_ENUM mf_field_id {
*/
MFF_TUN_ERSPAN_HWID,

/* "tun_gtpu_flags".
*
* GTP-U tunnel flags.
*
* Type: u8.
* Maskable: bitwise.
* Formatting: hexadecimal.
* Prerequisites: none.
* Access: read-only.
* NXM: none.
* OXM: NXOXM_ET_GTPU_FLAGS(15) since v2.13.
*/
MFF_TUN_GTPU_FLAGS,

/* "tun_gtpu_msgtype".
*
* GTP-U tunnel message type.
*
* Type: u8.
* Maskable: bitwise.
* Formatting: decimal.
* Prerequisites: none.
* Access: read-only.
* NXM: none.
* OXM: NXOXM_ET_GTPU_MSGTYPE(16) since v2.13.
*/
MFF_TUN_GTPU_MSGTYPE,

#if TUN_METADATA_NUM_OPTS == 64
/* "tun_metadata<N>".
*
Expand Down
4 changes: 3 additions & 1 deletion include/openvswitch/packets.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ struct flow_tnl {
uint32_t erspan_idx;
uint8_t erspan_dir;
uint8_t erspan_hwid;
uint8_t pad1[6]; /* Pad to 64 bits. */
uint8_t gtpu_flags;
uint8_t gtpu_msgtype;
uint8_t pad1[4]; /* Pad to 64 bits. */
struct tun_metadata metadata;
};

Expand Down
5 changes: 5 additions & 0 deletions lib/dpif-netlink-rtnl.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ vport_type_to_kind(enum ovs_vport_type type,
} else {
return NULL;
}
case OVS_VPORT_TYPE_GTPU:
return NULL;
case OVS_VPORT_TYPE_NETDEV:
case OVS_VPORT_TYPE_INTERNAL:
case OVS_VPORT_TYPE_LISP:
Expand Down Expand Up @@ -277,6 +279,7 @@ dpif_netlink_rtnl_verify(const struct netdev_tunnel_config *tnl_cfg,
case OVS_VPORT_TYPE_INTERNAL:
case OVS_VPORT_TYPE_LISP:
case OVS_VPORT_TYPE_STT:
case OVS_VPORT_TYPE_GTPU:
case OVS_VPORT_TYPE_UNSPEC:
case __OVS_VPORT_TYPE_MAX:
default:
Expand Down Expand Up @@ -358,6 +361,7 @@ dpif_netlink_rtnl_create(const struct netdev_tunnel_config *tnl_cfg,
case OVS_VPORT_TYPE_INTERNAL:
case OVS_VPORT_TYPE_LISP:
case OVS_VPORT_TYPE_STT:
case OVS_VPORT_TYPE_GTPU:
case OVS_VPORT_TYPE_UNSPEC:
case __OVS_VPORT_TYPE_MAX:
default:
Expand Down Expand Up @@ -471,6 +475,7 @@ dpif_netlink_rtnl_port_destroy(const char *name, const char *type)
case OVS_VPORT_TYPE_INTERNAL:
case OVS_VPORT_TYPE_LISP:
case OVS_VPORT_TYPE_STT:
case OVS_VPORT_TYPE_GTPU:
case OVS_VPORT_TYPE_UNSPEC:
case __OVS_VPORT_TYPE_MAX:
default:
Expand Down
5 changes: 5 additions & 0 deletions lib/dpif-netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,9 @@ get_vport_type(const struct dpif_netlink_vport *vport)
case OVS_VPORT_TYPE_IP6GRE:
return "ip6gre";

case OVS_VPORT_TYPE_GTPU:
return "gtpu";

case OVS_VPORT_TYPE_UNSPEC:
case __OVS_VPORT_TYPE_MAX:
break;
Expand Down Expand Up @@ -778,6 +781,8 @@ netdev_to_ovs_vport_type(const char *type)
return OVS_VPORT_TYPE_IP6GRE;
} else if (!strcmp(type, "gre")) {
return OVS_VPORT_TYPE_GRE;
} else if (!strcmp(type, "gtpu")) {
return OVS_VPORT_TYPE_GTPU;
} else {
return OVS_VPORT_TYPE_UNSPEC;
}
Expand Down
28 changes: 18 additions & 10 deletions lib/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ struct mf_ctx {
* away. Some GCC versions gave warnings on ALWAYS_INLINE, so these are
* defined as macros. */

#if (FLOW_WC_SEQ != 41)
#if (FLOW_WC_SEQ != 42)
#define MINIFLOW_ASSERT(X) ovs_assert(X)
BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime "
"assertions enabled. Consider updating FLOW_WC_SEQ after "
Expand Down Expand Up @@ -731,7 +731,7 @@ void
miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
{
/* Add code to this function (or its callees) to extract new fields. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42);

const struct pkt_metadata *md = &packet->md;
const void *data = dp_packet_data(packet);
Expand Down Expand Up @@ -1187,7 +1187,7 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
{
int i;

BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42);

match_init_catchall(flow_metadata);
if (flow->tunnel.tun_id != htonll(0)) {
Expand Down Expand Up @@ -1227,6 +1227,12 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
if (flow->tunnel.erspan_hwid) {
match_set_tun_erspan_hwid(flow_metadata, flow->tunnel.erspan_hwid);
}
if (flow->tunnel.gtpu_flags) {
match_set_tun_gtpu_flags(flow_metadata, flow->tunnel.gtpu_flags);
}
if (flow->tunnel.gtpu_msgtype) {
match_set_tun_gtpu_msgtype(flow_metadata, flow->tunnel.gtpu_msgtype);
}
tun_metadata_get_fmd(&flow->tunnel, flow_metadata);
if (flow->metadata != htonll(0)) {
match_set_metadata(flow_metadata, flow->metadata);
Expand Down Expand Up @@ -1767,7 +1773,7 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc,
memset(&wc->masks, 0x0, sizeof wc->masks);

/* Update this function whenever struct flow changes. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42);

if (flow_tnl_dst_is_set(&flow->tunnel)) {
if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
Expand All @@ -1788,6 +1794,8 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc,
WC_MASK_FIELD(wc, tunnel.erspan_idx);
WC_MASK_FIELD(wc, tunnel.erspan_dir);
WC_MASK_FIELD(wc, tunnel.erspan_hwid);
WC_MASK_FIELD(wc, tunnel.gtpu_flags);
WC_MASK_FIELD(wc, tunnel.gtpu_msgtype);

if (!(flow->tunnel.flags & FLOW_TNL_F_UDPIF)) {
if (flow->tunnel.metadata.present.map) {
Expand Down Expand Up @@ -1918,7 +1926,7 @@ void
flow_wc_map(const struct flow *flow, struct flowmap *map)
{
/* Update this function whenever struct flow changes. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42);

flowmap_init(map);

Expand Down Expand Up @@ -2021,7 +2029,7 @@ void
flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc)
{
/* Update this function whenever struct flow changes. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42);

memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata);
memset(&wc->masks.regs, 0, sizeof wc->masks.regs);
Expand Down Expand Up @@ -2165,7 +2173,7 @@ flow_wildcards_set_xxreg_mask(struct flow_wildcards *wc, int idx,
uint32_t
miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis)
{
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42);
uint32_t hash = basis;

if (flow) {
Expand Down Expand Up @@ -2212,7 +2220,7 @@ ASSERT_SEQUENTIAL(ipv6_src, ipv6_dst);
uint32_t
flow_hash_5tuple(const struct flow *flow, uint32_t basis)
{
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42);
uint32_t hash = basis;

if (flow) {
Expand Down Expand Up @@ -2890,7 +2898,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type,

if (clear_flow_L3) {
/* Clear all L3 and L4 fields and dp_hash. */
BUILD_ASSERT(FLOW_WC_SEQ == 41);
BUILD_ASSERT(FLOW_WC_SEQ == 42);
memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0,
sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT);
flow->dp_hash = 0;
Expand Down Expand Up @@ -3188,7 +3196,7 @@ flow_compose(struct dp_packet *p, const struct flow *flow,
/* Add code to this function (or its callees) for emitting new fields or
* protocols. (This isn't essential, so it can be skipped for initial
* testing.) */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42);

uint32_t pseudo_hdr_csum;
size_t l4_len;
Expand Down
2 changes: 1 addition & 1 deletion lib/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ static inline void
pkt_metadata_from_flow(struct pkt_metadata *md, const struct flow *flow)
{
/* Update this function whenever struct flow changes. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42);

md->recirc_id = flow->recirc_id;
md->dp_hash = flow->dp_hash;
Expand Down
36 changes: 35 additions & 1 deletion lib/match.c
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,34 @@ match_set_tun_erspan_hwid(struct match *match, uint8_t hwid)
match_set_tun_erspan_hwid_masked(match, hwid, UINT8_MAX);
}

void
match_set_tun_gtpu_flags_masked(struct match *match, uint8_t flags,
uint8_t mask)
{
match->wc.masks.tunnel.gtpu_flags = flags;
match->flow.tunnel.gtpu_flags = flags & mask;
}

void
match_set_tun_gtpu_flags(struct match *match, uint8_t flags)
{
match_set_tun_gtpu_flags_masked(match, flags, UINT8_MAX);
}

void
match_set_tun_gtpu_msgtype_masked(struct match *match, uint8_t msgtype,
uint8_t mask)
{
match->wc.masks.tunnel.gtpu_msgtype = msgtype;
match->flow.tunnel.gtpu_msgtype = msgtype & mask;
}

void
match_set_tun_gtpu_msgtype(struct match *match, uint8_t msgtype)
{
match_set_tun_gtpu_msgtype_masked(match, msgtype, UINT8_MAX);
}

void
match_set_in_port(struct match *match, ofp_port_t ofp_port)
{
Expand Down Expand Up @@ -1325,6 +1353,12 @@ format_flow_tunnel(struct ds *s, const struct match *match)
if (wc->masks.tunnel.erspan_hwid && tnl->erspan_ver == 2) {
ds_put_format(s, "tun_erspan_hwid=%#"PRIx8",", tnl->erspan_hwid);
}
if (wc->masks.tunnel.gtpu_flags) {
ds_put_format(s, "gtpu_flags=%#"PRIx8",", tnl->gtpu_flags);
}
if (wc->masks.tunnel.gtpu_msgtype) {
ds_put_format(s, "gtpu_msgtype=%"PRIu8",", tnl->gtpu_msgtype);
}
if (wc->masks.tunnel.flags & FLOW_TNL_F_MASK) {
format_flags_masked(s, "tun_flags", flow_tun_flag_to_string,
tnl->flags & FLOW_TNL_F_MASK,
Expand Down Expand Up @@ -1396,7 +1430,7 @@ match_format(const struct match *match,
bool is_megaflow = false;
int i;

BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42);

if (priority != OFP_DEFAULT_PRIORITY) {
ds_put_format(s, "%spriority=%s%d,",
Expand Down
Loading

0 comments on commit 3c6d05a

Please sign in to comment.