On Sun, Dec 08, 2019 at 08:11:19AM +0000, Roni Bar Yanai wrote: > Hi Roni,
Thanks for your feedback! > GTP-U header size is not constant, you *must* take into account the flags, > mainly > the sequence. The use of sequence in GTP-U is optional but some devices do > use > it. see from 3GPP definition: > "For PGW, SGW and eNodeB the usage of sequence numbers in G-PDUs is optional, > but > if GTP-U protocol entities in these nodes are relaying G-PDUs to other > nodes, they > shall relay the sequence numbers as well. An RNC, SGSN or GGSN shall reorder > out > of sequence T-PDUs when in sequence delivery is required. This is optional" I see, thanks. I was reading slide 9 and 10 from https://www.slideshare.net/aliirfan04/gtp-overview and I thought sequence number is not needed. I will add sequence number support. > > The assumption that GTP-U is only data is not correct, you have some signaling > for example END MARKER (like you wrote). This message is sent when there is a > mobility > between cells, and the message contains a TEID and indicates that last > packet sent from > the origin cell, to prevent packet re-order as handover might have packets > on the fly. So I would expected that END MARKER will do the exact same > forwarding as the GTP-U data. OK, thanks. > > see inline > > >-----Original Message----- > >From: dev <ovs-dev-boun...@openvswitch.org> On Behalf Of William Tu > >Sent: Thursday, December 5, 2019 10:44 PM > >To: d...@openvswitch.org > >Subject: [ovs-dev] [PATCHv4] userspace: Add GTP-U support. > > > >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://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftools.ietf.o > >rg%2Fhtml%2Fdraft-hmm-dmm-5g-uplane-analysis- > >00&data=02%7C01%7Croniba%40mellanox.com%7Cb73529a0bea34637f9ed0 > >8d779c3f1e4%7Ca652971c7d2e4d9ba6a4d149256f461b%7C0%7C0%7C63711175479 > >1292921&sdata=tY0GruNTBV9NWZg9gO2Lo4PWQZ1swHkB1AwdEg3AJUE%3 > >D&reserved=0 > > > >Signed-off-by: Yi Yang <yangy...@inspur.com> > >Co-authored-by: Yi Yang <yangy...@inspur.com> > >Signed-off-by: William Tu <u9012...@gmail.com> > >--- > >v3 -> v4: > > - applied Ben's doc revise > > - increment FLOW_WC_SEQ to 42 > > - minor fixes > > - travis: > >https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftravis- > >ci.org%2Fwilliamtu%2Fovs- > >travis%2Fbuilds%2F621289678&data=02%7C01%7Croniba%40mellanox.com% > >7Cb73529a0bea34637f9ed08d779c3f1e4%7Ca652971c7d2e4d9ba6a4d149256f461b > >%7C0%7C0%7C637111754791292921&sdata=eYRkIjcPUQqJwBQndsjCgtcPGG1 > >l4QFUnAWW4vwPjpI%3D&reserved=0 > > > >v2 -> v3: > > - pick up the code from v2, rebase to master > > - many fixes in code, docs, and add more tests > > - travis: > >https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftravis- > >ci.org%2Fwilliamtu%2Fovs- > >travis%2Fbuilds%2F619799361&data=02%7C01%7Croniba%40mellanox.com% > >7Cb73529a0bea34637f9ed08d779c3f1e4%7Ca652971c7d2e4d9ba6a4d149256f461b > >%7C0%7C0%7C637111754791292921&sdata=cu5bdmJ4ydInKt4chxOcGy33K5E > >9BMDzxgk5%2F7Cq%2FtI%3D&reserved=0 > > > >v1 -> v2: > > - Add new packet_type PT_GTPU_MSG to handle GTP-U signaling message, > > GTP-U signaling message should be steered into a control plane handler > > by explicit openflow entry in flow table. > > - Fix gtpu_flags and gptu_msgtype set issue. > > - Verify communication with kernel GTP implementation from Jiannan > > Ouyang. > > - Fix unit test issue and make sure all the unit tests can pass. > > - This patch series add GTP-U tunnel support in DPDK userspace, > > GTP-U is used for carrying user data within the GPRS core network and > > between the radio access network and the core network. The user data > > transported can be packets in any of IPv4, IPv6, or PPP formats. > >--- > > Documentation/faq/configuration.rst | 13 +++ > > Documentation/faq/releases.rst | 1 + > > NEWS | 3 + > > datapath/linux/compat/include/linux/openvswitch.h | 2 + > > include/openvswitch/flow.h | 4 +- > > include/openvswitch/match.h | 6 ++ > > include/openvswitch/meta-flow.h | 28 ++++++ > > include/openvswitch/packets.h | 4 +- > > lib/dpif-netlink-rtnl.c | 5 + > > lib/dpif-netlink.c | 5 + > > lib/flow.c | 22 +++-- > > lib/flow.h | 2 +- > > lib/match.c | 30 +++++- > > lib/meta-flow.c | 38 ++++++++ > > lib/meta-flow.xml | 79 ++++++++++++++- > > lib/netdev-native-tnl.c | 85 ++++++++++++++++ > > lib/netdev-native-tnl.h | 8 ++ > > lib/netdev-vport.c | 25 ++++- > > lib/nx-match.c | 8 +- > > lib/odp-util.c | 114 > > +++++++++++++++++++++- > > lib/odp-util.h | 2 +- > > lib/ofp-match.c | 2 +- > > lib/packets.h | 59 +++++++++++ > > lib/tnl-ports.c | 3 + > > ofproto/ofproto-dpif-rid.h | 2 +- > > ofproto/ofproto-dpif-xlate.c | 6 +- > > ofproto/tunnel.c | 3 +- > > tests/ofproto.at | 4 +- > > tests/tunnel-push-pop.at | 22 +++++ > > tests/tunnel.at | 78 +++++++++++++++ > > vswitchd/vswitch.xml | 24 +++++ > > 31 files changed, 658 insertions(+), 29 deletions(-) > > > >diff --git a/Documentation/faq/configuration.rst > >b/Documentation/faq/configuration.rst > >index ff3b71a5d4ef..a9ac9354d0dc 100644 > >--- a/Documentation/faq/configuration.rst > >+++ b/Documentation/faq/configuration.rst > >@@ -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. GTP-U (GPRS Tunnelling Protocol User Plane (GTPv1-U)) > >+ is supported in userspace datapath. 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 > >diff --git a/Documentation/faq/releases.rst b/Documentation/faq/releases.rst > >index 6702c58a2b6f..4fa28a378603 100644 > >--- a/Documentation/faq/releases.rst > >+++ b/Documentation/faq/releases.rst > >@@ -130,6 +130,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 > >diff --git a/NEWS b/NEWS > >index e2254121f619..96d742f773a2 100644 > >--- a/NEWS > >+++ b/NEWS > >@@ -26,6 +26,9 @@ Post-v2.12.0 > > * DPDK ring ports (dpdkr) are deprecated and will be removed in next > > releases. > > * Add support for DPDK 19.11. > >+ - 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 > > --------------------- > >diff --git a/datapath/linux/compat/include/linux/openvswitch.h > >b/datapath/linux/compat/include/linux/openvswitch.h > >index 778827f8b5a2..6cc90b5b29ef 100644 > >--- a/datapath/linux/compat/include/linux/openvswitch.h > >+++ b/datapath/linux/compat/include/linux/openvswitch.h > >@@ -242,6 +242,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 > > }; > > > >@@ -401,6 +402,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 > > }; > > > >diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h > >index 57b6c925c7bc..3054015d93c7 100644 > >--- a/include/openvswitch/flow.h > >+++ b/include/openvswitch/flow.h > >@@ -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 > >@@ -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. > >diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h > >index 05ecee7fc7cd..45a368c274b8 100644 > >--- a/include/openvswitch/match.h > >+++ b/include/openvswitch/match.h > >@@ -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); > >diff --git a/include/openvswitch/meta-flow.h > >b/include/openvswitch/meta-flow.h > >index b7fd6cb3f0fb..d57a36468e19 100644 > >--- a/include/openvswitch/meta-flow.h > >+++ b/include/openvswitch/meta-flow.h > >@@ -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: decimal. > >+ * Prerequisites: none. > >+ * Access: read/write. > >+ * 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/write. > >+ * NXM: none. > >+ * OXM: NXOXM_ET_GTPU_MSGTYPE(16) since v2.13. > >+ */ > >+ MFF_TUN_GTPU_MSGTYPE, > >+ > > #if TUN_METADATA_NUM_OPTS == 64 > > /* "tun_metadata<N>". > > * > >diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h > >index 925844edae6a..a65cb0d04e77 100644 > >--- a/include/openvswitch/packets.h > >+++ b/include/openvswitch/packets.h > >@@ -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; > > }; > > > >diff --git a/lib/dpif-netlink-rtnl.c b/lib/dpif-netlink-rtnl.c > >index 582274c46774..fd157ce2d918 100644 > >--- a/lib/dpif-netlink-rtnl.c > >+++ b/lib/dpif-netlink-rtnl.c > >@@ -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: > >@@ -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: > >@@ -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: > >@@ -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: > >diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c > >index e9a6887f7af2..bc740250e677 100644 > >--- a/lib/dpif-netlink.c > >+++ b/lib/dpif-netlink.c > >@@ -703,6 +703,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; > >@@ -736,6 +739,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; > > } > >diff --git a/lib/flow.c b/lib/flow.c > >index 45bb96b543be..9ddb24c15185 100644 > >--- a/lib/flow.c > >+++ b/lib/flow.c > >@@ -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 " > >@@ -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); > >@@ -1188,7 +1188,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)) { > >@@ -1768,7 +1768,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) { > >@@ -1789,6 +1789,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) { > >@@ -1919,7 +1921,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); > > > >@@ -2022,7 +2024,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); > >@@ -2166,7 +2168,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) { > >@@ -2213,7 +2215,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) { > >@@ -2891,7 +2893,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; > >@@ -3189,7 +3191,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; > >diff --git a/lib/flow.h b/lib/flow.h > >index 75751763c81a..b32f0b27754a 100644 > >--- a/lib/flow.h > >+++ b/lib/flow.h > >@@ -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; > >diff --git a/lib/match.c b/lib/match.c > >index ae568280a2bb..875bd7f66cd2 100644 > >--- a/lib/match.c > >+++ b/lib/match.c > >@@ -375,6 +375,34 @@ match_set_tun_erspan_hwid(struct match *match, > >uint8_t hwid) > > } > > > > 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) > > { > > match->wc.masks.in_port.ofp_port = u16_to_ofp(UINT16_MAX); > >@@ -1390,7 +1418,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,", > >diff --git a/lib/meta-flow.c b/lib/meta-flow.c > >index e3274b97f335..d002344fc8c5 100644 > >--- a/lib/meta-flow.c > >+++ b/lib/meta-flow.c > >@@ -391,6 +391,10 @@ mf_is_all_wild(const struct mf_field *mf, const struct > >flow_wildcards *wc) > > case MFF_NSH_C3: > > case MFF_NSH_C4: > > return !wc->masks.nsh.context[mf->id - MFF_NSH_C1]; > >+ case MFF_TUN_GTPU_FLAGS: > >+ return !wc->masks.tunnel.gtpu_flags; > >+ case MFF_TUN_GTPU_MSGTYPE: > >+ return !wc->masks.tunnel.gtpu_msgtype; > > > > case MFF_N_IDS: > > default: > >@@ -530,6 +534,8 @@ mf_is_value_valid(const struct mf_field *mf, const union > >mf_value *value) > > case MFF_TUN_ERSPAN_VER: > > case MFF_TUN_ERSPAN_DIR: > > case MFF_TUN_ERSPAN_HWID: > >+ case MFF_TUN_GTPU_FLAGS: > >+ case MFF_TUN_GTPU_MSGTYPE: > > CASE_MFF_TUN_METADATA: > > case MFF_METADATA: > > case MFF_IN_PORT: > >@@ -711,6 +717,12 @@ mf_get_value(const struct mf_field *mf, const struct > >flow > >*flow, > > case MFF_TUN_ERSPAN_HWID: > > value->u8 = flow->tunnel.erspan_hwid; > > break; > >+ case MFF_TUN_GTPU_FLAGS: > >+ value->u8 = flow->tunnel.gtpu_flags; > >+ break; > >+ case MFF_TUN_GTPU_MSGTYPE: > >+ value->u8 = flow->tunnel.gtpu_msgtype; > >+ break; > > CASE_MFF_TUN_METADATA: > > tun_metadata_read(&flow->tunnel, mf, value); > > break; > >@@ -1042,6 +1054,12 @@ mf_set_value(const struct mf_field *mf, > > case MFF_TUN_ERSPAN_HWID: > > match_set_tun_erspan_hwid(match, value->u8); > > break; > >+ case MFF_TUN_GTPU_FLAGS: > >+ match_set_tun_gtpu_flags(match, value->u8); > >+ break; > >+ case MFF_TUN_GTPU_MSGTYPE: > >+ match_set_tun_gtpu_msgtype(match, value->u8); > >+ break; > > CASE_MFF_TUN_METADATA: > > tun_metadata_set_match(mf, value, NULL, match, err_str); > > break; > >@@ -1459,6 +1477,12 @@ mf_set_flow_value(const struct mf_field *mf, > > case MFF_TUN_ERSPAN_HWID: > > flow->tunnel.erspan_hwid = value->u8; > > break; > >+ case MFF_TUN_GTPU_FLAGS: > >+ flow->tunnel.gtpu_flags = value->u8; > >+ break; > >+ case MFF_TUN_GTPU_MSGTYPE: > >+ flow->tunnel.gtpu_msgtype = value->u8; > >+ break; > > CASE_MFF_TUN_METADATA: > > tun_metadata_write(&flow->tunnel, mf, value); > > break; > >@@ -1780,6 +1804,8 @@ mf_is_pipeline_field(const struct mf_field *mf) > > case MFF_TUN_ERSPAN_IDX: > > case MFF_TUN_ERSPAN_DIR: > > case MFF_TUN_ERSPAN_HWID: > >+ case MFF_TUN_GTPU_FLAGS: > >+ case MFF_TUN_GTPU_MSGTYPE: > > CASE_MFF_TUN_METADATA: > > case MFF_METADATA: > > case MFF_IN_PORT: > >@@ -1970,6 +1996,12 @@ mf_set_wild(const struct mf_field *mf, struct match > >*match, char **err_str) > > case MFF_TUN_ERSPAN_HWID: > > match_set_tun_erspan_hwid_masked(match, 0, 0); > > break; > >+ case MFF_TUN_GTPU_FLAGS: > >+ match_set_tun_gtpu_flags_masked(match, 0, 0); > >+ break; > >+ case MFF_TUN_GTPU_MSGTYPE: > >+ match_set_tun_gtpu_msgtype_masked(match, 0, 0); > >+ break; > > CASE_MFF_TUN_METADATA: > > tun_metadata_set_match(mf, NULL, NULL, match, err_str); > > break; > >@@ -2377,6 +2409,12 @@ mf_set(const struct mf_field *mf, > > case MFF_TUN_ERSPAN_HWID: > > match_set_tun_erspan_hwid_masked(match, value->u8, mask->u8); > > break; > >+ case MFF_TUN_GTPU_FLAGS: > >+ match_set_tun_gtpu_flags_masked(match, value->u8, mask->u8); > >+ break; > >+ case MFF_TUN_GTPU_MSGTYPE: > >+ match_set_tun_gtpu_msgtype_masked(match, value->u8, mask->u8); > >+ break; > > CASE_MFF_TUN_METADATA: > > tun_metadata_set_match(mf, value, mask, match, err_str); > > break; > >diff --git a/lib/meta-flow.xml b/lib/meta-flow.xml > >index 90b405c73750..ef62bf443679 100644 > >--- a/lib/meta-flow.xml > >+++ b/lib/meta-flow.xml > >@@ -1456,7 +1456,8 @@ ovs-ofctl add-flow br-int > >'in_port=3,tun_src=192.168.1.1,tun_id=5001 actions=1' > > <li>LISP has a 24-bit instance ID.</li> > > <li>GRE has an optional 32-bit key.</li> > > <li>STT has a 64-bit key.</li> > >- <li>ERSPAN has a 10-bit key (Session ID).</li> > >+ <li>ERSPAN has a 10-bit key (Session ID).</li> > >+ <li>GTPU has a 32-bit key (Tunnel Endpoint ID).</li> > > </ul> > > > > <p> > >@@ -1797,6 +1798,82 @@ ovs-ofctl add-flow br-int > >'in_port=3,tun_src=192.168.1.1,tun_id=5001 actions=1' > > A 6-bit unique identifier of an ERSPAN v2 engine within a system. > > </field> > > > >+ <h2>GTP-U Metadata Fields</h2> > >+ > >+ <p> > >+ These fields provide access to set-up GPRS Tunnelling Protocol > >+ for User Plane (GTPv1-U), based on 3GPP TS 29.281. A GTP-U > >+ header has the following format: > >+ </p> > >+ > >+ <diagram> > >+ <header> > >+ <bits name="flags" above="8" width="0.6"/> > >+ <bits name="msg type" above="8" width="0.6"/> > >+ <bits name="length" above="16" width="0.9"/> > >+ <bits name="TEID" above="32" width="1.3"/> > >+ </header> > >+ <dots/> > >+ </diagram> > >+ > >+ <p> > >+ The flags and message type have the Open vSwitch GTP-U specific fields > >+ described below. Open vSwitch makes the TEID (Tunnel Endpoint > >+ Identifier), which identifies a tunnel endpoint in the receiving GTP-U > >+ protocol entity, available via <ref field="tun_id"/>. > >+ </p> > >+ > >+ <field id="MFF_TUN_GTPU_FLAGS" title="GTP-U Flags"> > >+ <p> > >+ This field holds the 8-bit GTP-U flags, encoded as: > >+ </p> > >+ > >+ <diagram> > >+ <header name="GTP-U Tunnel Flags"> > >+ <bits name="version" above="3" below="1" width="0.5"/> > >+ <bits name="PT" above="1" width="0.3"/> > >+ <bits name="rsv" above="1" below="0" width="0.3"/> > >+ <bits name="E" above="1" width="0.3"/> > >+ <bits name="S" above="1" width="0.3"/> > >+ <bits name="PN" above="1" width="0.3"/> > >+ </header> > >+ </diagram> > >+ > >+ <p> > >+ The flags are: > >+ </p> > >+ <dl> > >+ <dt>version</dt> > >+ <dd>Used to determine the version of the GTP-U protocol, which > >should > >+ be set to 1.</dd> > >+ > >+ <dt>PT</dt> > >+ <dd>Protocol type, used as a protocol discriminator > >+ between GTP (1) and GTP' (0).</dd> > >+ > >+ <dt>rsv</dt> > >+ <dd>Reserved. Must be zero.</dd> > >+ > >+ <dt>E</dt> > >+ <dd>If 1, indicates the presence of a meaningful value of the Next > >+ Extension Header field.</dd> > >+ > >+ <dt>S</dt> > >+ <dd>If 1, indicates the presence of a meaningful value of the > >Sequence > >+ Number field.</dd> > >+ > >+ <dt>PN</dt> > >+ <dd>If 1, indicates the presence of a meaningful value of the N-PDU > >+ Number field.</dd> > >+ </dl> > >+ </field> > >+ > >+ <field id="MFF_TUN_GTPU_MSGTYPE" title="GTP-U Message Type"> > >+ This field indicates whether it's a signalling message used for path > >+ management, or a user plane message which carries the original packet. > >+ The complete range of message types can be referred to [3GPP TS > >29.281]. > >+ </field> > >+ > > <h2>Geneve Fields</h2> > > > > <p> > >diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c > >index a78972888e33..7ae554c87964 100644 > >--- a/lib/netdev-native-tnl.c > >+++ b/lib/netdev-native-tnl.c > >@@ -55,6 +55,9 @@ static struct vlog_rate_limit err_rl = > >VLOG_RATE_LIMIT_INIT(60, 5); > > #define GENEVE_BASE_HLEN (sizeof(struct udp_header) + \ > > sizeof(struct genevehdr)) > > > >+#define GTPU_HLEN (sizeof(struct udp_header) + \ > >+ sizeof(struct gtpuhdr)) > This is the base header length, if S or N-PDU is on you have > to add 4-bytes OK, will add sequence. > >+ > > uint16_t tnl_udp_port_min = 32768; > > uint16_t tnl_udp_port_max = 61000; > > > >@@ -708,6 +711,88 @@ netdev_erspan_build_header(const struct netdev > >*netdev, > > } > > > > struct dp_packet * > >+netdev_gtpu_pop_header(struct dp_packet *packet) > >+{ > >+ struct pkt_metadata *md = &packet->md; > >+ struct flow_tnl *tnl = &md->tunnel; > >+ struct gtpuhdr *gtph; > >+ unsigned int hlen; > >+ > >+ ovs_assert(packet->l3_ofs > 0); > >+ ovs_assert(packet->l4_ofs > 0); > >+ > >+ pkt_metadata_init_tnl(md); > >+ if (GTPU_HLEN > dp_packet_l4_size(packet)) { > >+ goto err; > >+ } > >+ > >+ gtph = udp_extract_tnl_md(packet, tnl, &hlen); > >+ if (!gtph) { > >+ goto err; > >+ } > >+ > >+ if (gtph->md.flags != GTPU_FLAGS_DEFAULT) { > >+ VLOG_WARN_RL(&err_rl, "GTP-U not supported"); > >+ goto err; > >+ } > >+ > >+ tnl->gtpu_flags = gtph->md.flags; > >+ tnl->gtpu_msgtype = gtph->md.msgtype; > >+ tnl->tun_id = htonll(ntohl(get_16aligned_be32(>ph->teid))); > >+ > >+ if (tnl->gtpu_msgtype == GTPU_MSGTYPE_GPDU) { > >+ struct ip_header *ip; > >+ > >+ ip = (struct ip_header *)(gtph + 1); > No always correct, should be additional 4 bytes on sequence, n-pdu > >+ if (IP_VER(ip->ip_ihl_ver) == 4) { > >+ packet->packet_type = htonl(PT_IPV4); > >+ } else if (IP_VER(ip->ip_ihl_ver) == 6) { > >+ packet->packet_type = htonl(PT_IPV6); > >+ } else { > >+ VLOG_WARN_RL(&err_rl, "GTP-U: Receive non-IP packet"); > >+ } > >+ } else { > >+ /* non GPDU GTP-U messages, ex: echo request, end marker. */ > >+ packet->packet_type = htonl(PT_GTPU_MSG); > >+ } > >+ > >+ dp_packet_reset_packet(packet, hlen + GTPU_HLEN); > Why do you want to reset on control such as end marker? > >+ > >+ return packet; > >+ > >+err: > >+ dp_packet_delete(packet); > >+ return NULL; > >+} > >+ > >+int > >+netdev_gtpu_build_header(const struct netdev *netdev, > >+ struct ovs_action_push_tnl *data, > >+ const struct netdev_tnl_build_header_params > >*params) > >+{ > >+ struct netdev_vport *dev = netdev_vport_cast(netdev); > >+ struct netdev_tunnel_config *tnl_cfg; > >+ struct gtpuhdr *gtph; > >+ > >+ ovs_mutex_lock(&dev->mutex); > >+ tnl_cfg = &dev->tnl_cfg; > >+ gtph = udp_build_header(tnl_cfg, data, params); > >+ ovs_mutex_unlock(&dev->mutex); > >+ > >+ /* Set to default if not set in flow. */ > >+ gtph->md.flags = params->flow->tunnel.gtpu_flags ? : GTPU_FLAGS_DEFAULT; > >+ gtph->md.msgtype = params->flow->tunnel.gtpu_msgtype ? : > >+ GTPU_MSGTYPE_GPDU; > >+ put_16aligned_be32(>ph->teid, > >+ htonl(ntohll(params->flow->tunnel.tun_id))); > >+ > >+ data->header_len += sizeof *gtph; > >+ data->tnl_type = OVS_VPORT_TYPE_GTPU; > Note that in some cases, application might need to replace TEID > , if you have tnl_push you need to preserve the origin sequence. OK, thanks. > > >+ > >+ return 0; > >+} > >+ > >+struct dp_packet * > > netdev_vxlan_pop_header(struct dp_packet *packet) > > { > > struct pkt_metadata *md = &packet->md; > >diff --git a/lib/netdev-native-tnl.h b/lib/netdev-native-tnl.h > >index 5dc00122d93e..7567abaebf95 100644 > >--- a/lib/netdev-native-tnl.h > >+++ b/lib/netdev-native-tnl.h > >@@ -52,6 +52,14 @@ netdev_erspan_push_header(const struct netdev *netdev, > > struct dp_packet * > > netdev_erspan_pop_header(struct dp_packet *packet); > > > >+int > >+netdev_gtpu_build_header(const struct netdev *netdev, > >+ struct ovs_action_push_tnl *data, > >+ const struct netdev_tnl_build_header_params *p); > >+ > >+struct dp_packet * > >+netdev_gtpu_pop_header(struct dp_packet *packet); > >+ > > void > > netdev_tnl_push_udp_header(const struct netdev *netdev, > > struct dp_packet *packet, > >diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c > >index b57d21ff8d41..8b8857017986 100644 > >--- a/lib/netdev-vport.c > >+++ b/lib/netdev-vport.c > >@@ -111,7 +111,8 @@ netdev_vport_needs_dst_port(const struct netdev *dev) > > > > return (class->get_config == get_tunnel_config && > > (!strcmp("geneve", type) || !strcmp("vxlan", type) || > >- !strcmp("lisp", type) || !strcmp("stt", type)) ); > >+ !strcmp("lisp", type) || !strcmp("stt", type) || > >+ !strcmp("gtpu", type))); > > } > > > > const char * > >@@ -216,6 +217,8 @@ netdev_vport_construct(struct netdev *netdev_) > > dev->tnl_cfg.dst_port = port ? htons(port) : htons(LISP_DST_PORT); > > } else if (!strcmp(type, "stt")) { > > dev->tnl_cfg.dst_port = port ? htons(port) : htons(STT_DST_PORT); > >+ } else if (!strcmp(type, "gtpu")) { > >+ dev->tnl_cfg.dst_port = port ? htons(port) : htons(GTPU_DST_PORT); > > } > > > > dev->tnl_cfg.dont_fragment = true; > >@@ -433,6 +436,8 @@ tunnel_supported_layers(const char *type, > > } else if (!strcmp(type, "vxlan") > > && tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GPE)) { > > return TNL_L2 | TNL_L3; > >+ } else if (!strcmp(type, "gtpu")) { > >+ return TNL_L3; > > } else { > > return TNL_L2; > > } > >@@ -589,6 +594,10 @@ set_tunnel_config(struct netdev *dev_, const struct > >smap *args, char **errp) > > tnl_cfg.dst_port = htons(STT_DST_PORT); > > } > > > >+ if (!strcmp(type, "gtpu")) { > >+ tnl_cfg.dst_port = htons(GTPU_DST_PORT); > >+ } > >+ > > needs_dst_port = netdev_vport_needs_dst_port(dev_); > > tnl_cfg.dont_fragment = true; > > > >@@ -907,7 +916,8 @@ get_tunnel_config(const struct netdev *dev, struct smap > >*args) > > if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) || > > (!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) || > > (!strcmp("lisp", type) && dst_port != LISP_DST_PORT) || > >- (!strcmp("stt", type) && dst_port != STT_DST_PORT)) { > >+ (!strcmp("stt", type) && dst_port != STT_DST_PORT) || > >+ (!strcmp("gtpu", type) && dst_port != GTPU_DST_PORT)) { > > smap_add_format(args, "dst_port", "%d", dst_port); > > } > > } > >@@ -1223,6 +1233,17 @@ netdev_vport_tunnel_register(void) > > }, > > {{NULL, NULL, 0, 0}} > > }, > >+ { "gtpu_sys", > >+ { > >+ TUNNEL_FUNCTIONS_COMMON, > >+ .type = "gtpu", > >+ .build_header = netdev_gtpu_build_header, > >+ .push_header = netdev_tnl_push_udp_header, > >+ .pop_header = netdev_gtpu_pop_header, > >+ }, > >+ {{NULL, NULL, 0, 0}} > >+ }, > >+ > > }; > > static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; > > > >diff --git a/lib/nx-match.c b/lib/nx-match.c _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev