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&amp;data=02%7C01%7Croniba%40mellanox.com%7Cb73529a0bea34637f9ed0
> >8d779c3f1e4%7Ca652971c7d2e4d9ba6a4d149256f461b%7C0%7C0%7C63711175479
> >1292921&amp;sdata=tY0GruNTBV9NWZg9gO2Lo4PWQZ1swHkB1AwdEg3AJUE%3
> >D&amp;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&amp;data=02%7C01%7Croniba%40mellanox.com%
> >7Cb73529a0bea34637f9ed08d779c3f1e4%7Ca652971c7d2e4d9ba6a4d149256f461b
> >%7C0%7C0%7C637111754791292921&amp;sdata=eYRkIjcPUQqJwBQndsjCgtcPGG1
> >l4QFUnAWW4vwPjpI%3D&amp;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&amp;data=02%7C01%7Croniba%40mellanox.com%
> >7Cb73529a0bea34637f9ed08d779c3f1e4%7Ca652971c7d2e4d9ba6a4d149256f461b
> >%7C0%7C0%7C637111754791292921&amp;sdata=cu5bdmJ4ydInKt4chxOcGy33K5E
> >9BMDzxgk5%2F7Cq%2FtI%3D&amp;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(&gtph->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(&gtph->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

Reply via email to