diff mbox series

[RFC,net-next,v4,4/6] gtp: Implement GTP echo response

Message ID 20220204165101.10673-1-marcin.szycik@linux.intel.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series ice: GTP support in switchdev | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 4836 this patch: 4836
netdev/cc_maintainers success CCed 6 of 6 maintainers
netdev/build_clang success Errors and warnings before: 823 this patch: 823
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 4991 this patch: 4991
netdev/checkpatch warning WARNING: line length of 84 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Marcin Szycik Feb. 4, 2022, 4:51 p.m. UTC
From: Wojciech Drewek <wojciech.drewek@intel.com>

Adding GTP device through ip link creates the situation where
there is no userspace daemon which would handle GTP messages
(Echo Request for example). GTP-U instance which would not respond
to echo requests would violate GTP specification.

When GTP packet arrives with GTP_ECHO_REQ message type,
GTP_ECHO_RSP is send to the sender. GTP_ECHO_RSP message
should contain information element with GTPIE_RECOVERY tag and
restart counter value. For GTPv1 restart counter is not used
and should be equal to 0, for GTPv0 restart counter contains
information provided from userspace(IFLA_GTP_RESTART_COUNT).

Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com>
---
 drivers/net/gtp.c            | 212 ++++++++++++++++++++++++++++++++---
 include/net/gtp.h            |  31 +++++
 include/uapi/linux/if_link.h |   1 +
 3 files changed, 228 insertions(+), 16 deletions(-)

Comments

Harald Welte Feb. 5, 2022, 4:51 p.m. UTC | #1
Hi Marcin, Wojciech,

I would prefer to move this patch to right after introducing the
kernel-socket mode, as the former makes no sense without this patch.

Now that this patch implements responding to the GTP ECHO procedure,
one interesting question that comes to mind is how you would foresee
outbound GTP echo procedures to be used in this new use pattern.

With the existing (userspace creates the socket) pattern, the userspace
instance can at any point send GTP ECHO request packets to any of the
peers, while I don't really see how this would work if the socket is in
the kernel.

The use of the outbound ECHO procedure is not required for GTP-U by TS
29.060, so spec-wise it is fine to not support it.  It just means
that any higher-layer applications using this 'socketless' use pattern
will be deprived of being able to check for GTP-U path failure.

IMHO, this is non-negligable, as there are no other rqeust-response
message pairs on the GTP-U plane,  so transmitting and receiving ECHO
is the only way a control plane / management instance has to detect
GTP-U path failure.

So without being able to trigger GTP-ECHO, things could look prefectly
fine on the GPT-C side of things, but GTP-U may not be working at all.

Remember, GTP-U uses different IP addresses and also typically completely
different hosts/systems, so having GTP-C connectivity between two GSN
doesn't say anything about the GTP-U path.

Regards,
	Harald
Wojciech Drewek Feb. 8, 2022, 2:12 p.m. UTC | #2
Hi Harald

> -----Original Message-----
> From: Harald Welte <laforge@osmocom.org>
> Sent: sobota, 5 lutego 2022 17:52
> To: Marcin Szycik <marcin.szycik@linux.intel.com>
> Cc: netdev@vger.kernel.org; michal.swiatkowski@linux.intel.com; Drewek, Wojciech <wojciech.drewek@intel.com>;
> davem@davemloft.net; kuba@kernel.org; pablo@netfilter.org; osmocom-net-gprs@lists.osmocom.org
> Subject: Re: [RFC PATCH net-next v4 4/6] gtp: Implement GTP echo response
> 
> Hi Marcin, Wojciech,
> 
> I would prefer to move this patch to right after introducing the
> kernel-socket mode, as the former makes no sense without this patch.
Sure thing

> 
> Now that this patch implements responding to the GTP ECHO procedure,
> one interesting question that comes to mind is how you would foresee
> outbound GTP echo procedures to be used in this new use pattern.
> 
> With the existing (userspace creates the socket) pattern, the userspace
> instance can at any point send GTP ECHO request packets to any of the
> peers, while I don't really see how this would work if the socket is in
> the kernel.
> 
> The use of the outbound ECHO procedure is not required for GTP-U by TS
> 29.060, so spec-wise it is fine to not support it.  It just means
> that any higher-layer applications using this 'socketless' use pattern
> will be deprived of being able to check for GTP-U path failure.
> 
> IMHO, this is non-negligable, as there are no other rqeust-response
> message pairs on the GTP-U plane,  so transmitting and receiving ECHO
> is the only way a control plane / management instance has to detect
> GTP-U path failure.
> 
> So without being able to trigger GTP-ECHO, things could look prefectly
> fine on the GPT-C side of things, but GTP-U may not be working at all.
> 
> Remember, GTP-U uses different IP addresses and also typically completely
> different hosts/systems, so having GTP-C connectivity between two GSN
> doesn't say anything about the GTP-U path.
Two  approaches come to mind.
The first one assumes that peers are stored in kernel as PDP contexts in
gtp_dev (tid_hash and addr_hash). Then we could enable a watchdog
that could in regular intervals (defined by the user) send echo requests
to all peers.
In the second one user could trigger echo request from userspace
(using new genl cmd) at any time. However this approach would require that
some userspace daemon would implement triggering this command.
What do you think?

Regards,
Wojtek

> 
> Regards,
> 	Harald
> 
> --
> - Harald Welte <laforge@osmocom.org>            http://laforge.gnumonks.org/
> ============================================================================
> "Privacy in residential applications is a desirable marketing option."
>                                                   (ETSI EN 300 175-7 Ch. A6)
Harald Welte Feb. 11, 2022, 9:16 a.m. UTC | #3
Hi Wojciech,

On Tue, Feb 08, 2022 at 02:12:33PM +0000, Drewek, Wojciech wrote:
> > Remember, GTP-U uses different IP addresses and also typically completely
> > different hosts/systems, so having GTP-C connectivity between two GSN
> > doesn't say anything about the GTP-U path.
>
> Two  approaches come to mind.
> The first one assumes that peers are stored in kernel as PDP contexts in
> gtp_dev (tid_hash and addr_hash). Then we could enable a watchdog
> that could in regular intervals (defined by the user) send echo requests
> to all peers.

Interesting proposal.  However, it raises the next question of what to do if
the path is deemed to be lost (N out of M recent echo requests unanswered)? It
would have to notify the userspace daemon (control plane) via a netlink event
or the like.  So at that point you need to implement some special processing in
that userspace daemon...

> In the second one user could trigger echo request from userspace
> (using new genl cmd) at any time. However this approach would require that
> some userspace daemon would implement triggering this command.

I think this is the better approach.  It keeps a lot of logic like timeouts,
frequency of transmission, determining when a path is considered dead, ... out
of the kernel, where it doesn't need to be.

> What do you think?

As both approaches require some support from the userspace control plane instance,
I would argue that the second proposal is superior.

Regards,
	Harald
Wojciech Drewek Feb. 11, 2022, 10:27 a.m. UTC | #4
Hi Harald,

> -----Original Message-----
> From: Harald Welte <laforge@osmocom.org>
> Sent: piątek, 11 lutego 2022 10:16
> To: Drewek, Wojciech <wojciech.drewek@intel.com>
> Cc: Marcin Szycik <marcin.szycik@linux.intel.com>; netdev@vger.kernel.org; michal.swiatkowski@linux.intel.com;
> davem@davemloft.net; kuba@kernel.org; pablo@netfilter.org; osmocom-net-gprs@lists.osmocom.org
> Subject: Re: [RFC PATCH net-next v4 4/6] gtp: Implement GTP echo response
> 
> Hi Wojciech,
> 
> On Tue, Feb 08, 2022 at 02:12:33PM +0000, Drewek, Wojciech wrote:
> > > Remember, GTP-U uses different IP addresses and also typically completely
> > > different hosts/systems, so having GTP-C connectivity between two GSN
> > > doesn't say anything about the GTP-U path.
> >
> > Two  approaches come to mind.
> > The first one assumes that peers are stored in kernel as PDP contexts in
> > gtp_dev (tid_hash and addr_hash). Then we could enable a watchdog
> > that could in regular intervals (defined by the user) send echo requests
> > to all peers.
> 
> Interesting proposal.  However, it raises the next question of what to do if
> the path is deemed to be lost (N out of M recent echo requests unanswered)? It
> would have to notify the userspace daemon (control plane) via a netlink event
> or the like.  So at that point you need to implement some special processing in
> that userspace daemon...
> 
> > In the second one user could trigger echo request from userspace
> > (using new genl cmd) at any time. However this approach would require that
> > some userspace daemon would implement triggering this command.
> 
> I think this is the better approach.  It keeps a lot of logic like timeouts,
> frequency of transmission, determining when a path is considered dead, ... out
> of the kernel, where it doesn't need to be.
> 
> > What do you think?
> 
> As both approaches require some support from the userspace control plane instance,
> I would argue that the second proposal is superior.
> 
> Regards,
> 	Harald
I agree that second option is better so I'll start to implementing it.

Regards,
Wojtek
> 
> --
> - Harald Welte <laforge@osmocom.org>            http://laforge.gnumonks.org/
> ============================================================================
> "Privacy in residential applications is a desirable marketing option."
>                                                   (ETSI EN 300 175-7 Ch. A6)
Wojciech Drewek Feb. 11, 2022, 12:48 p.m. UTC | #5
Hi Harald

> -----Original Message-----
> From: Drewek, Wojciech
> Sent: piątek, 11 lutego 2022 11:27
> To: Harald Welte <laforge@osmocom.org>
> Cc: Marcin Szycik <marcin.szycik@linux.intel.com>; netdev@vger.kernel.org; michal.swiatkowski@linux.intel.com;
> davem@davemloft.net; kuba@kernel.org; pablo@netfilter.org; osmocom-net-gprs@lists.osmocom.org
> Subject: RE: [RFC PATCH net-next v4 4/6] gtp: Implement GTP echo response
> 
> Hi Harald,
> 
> > -----Original Message-----
> > From: Harald Welte <laforge@osmocom.org>
> > Sent: piątek, 11 lutego 2022 10:16
> > To: Drewek, Wojciech <wojciech.drewek@intel.com>
> > Cc: Marcin Szycik <marcin.szycik@linux.intel.com>; netdev@vger.kernel.org; michal.swiatkowski@linux.intel.com;
> > davem@davemloft.net; kuba@kernel.org; pablo@netfilter.org; osmocom-net-gprs@lists.osmocom.org
> > Subject: Re: [RFC PATCH net-next v4 4/6] gtp: Implement GTP echo response
> >
> > Hi Wojciech,
> >
> > On Tue, Feb 08, 2022 at 02:12:33PM +0000, Drewek, Wojciech wrote:
> > > > Remember, GTP-U uses different IP addresses and also typically completely
> > > > different hosts/systems, so having GTP-C connectivity between two GSN
> > > > doesn't say anything about the GTP-U path.
> > >
> > > Two  approaches come to mind.
> > > The first one assumes that peers are stored in kernel as PDP contexts in
> > > gtp_dev (tid_hash and addr_hash). Then we could enable a watchdog
> > > that could in regular intervals (defined by the user) send echo requests
> > > to all peers.
> >
> > Interesting proposal.  However, it raises the next question of what to do if
> > the path is deemed to be lost (N out of M recent echo requests unanswered)? It
> > would have to notify the userspace daemon (control plane) via a netlink event
> > or the like.  So at that point you need to implement some special processing in
> > that userspace daemon...
> >
> > > In the second one user could trigger echo request from userspace
> > > (using new genl cmd) at any time. However this approach would require that
> > > some userspace daemon would implement triggering this command.
> >
> > I think this is the better approach.  It keeps a lot of logic like timeouts,
> > frequency of transmission, determining when a path is considered dead, ... out
> > of the kernel, where it doesn't need to be.
> >
> > > What do you think?
> >
> > As both approaches require some support from the userspace control plane instance,
> > I would argue that the second proposal is superior.
> >
> > Regards,
> > 	Harald
> I agree that second option is better so I'll start to implementing it.
I have one question. The new cmd should be allowed to send echo request
only to the peers stored in the kernel space (PDP contexts) or the userspace
daemon has its own list of peers and any request should be allowed to be send?

Regards,
Wojtek 

> 
> Regards,
> Wojtek
> >
> > --
> > - Harald Welte <laforge@osmocom.org>            http://laforge.gnumonks.org/
> > ============================================================================
> > "Privacy in residential applications is a desirable marketing option."
> >                                                   (ETSI EN 300 175-7 Ch. A6)
Harald Welte Feb. 12, 2022, 11:05 a.m. UTC | #6
Hi Wojciech,

On Fri, Feb 11, 2022 at 12:48:35PM +0000, Drewek, Wojciech wrote:
> I have one question. The new cmd should be allowed to send echo request
> only to the peers stored in the kernel space (PDP contexts) or the userspace
> daemon has its own list of peers and any request should be allowed to be send?

I think we can expect userspace to know the peers (after all, it has created those
sessions and knows about the peer IP addresses), so we don't have to verify
in the kernel if it is a "valid" peer or not.

So a pure "send GTP ECHO req to given IP" and a corresponding "received GTP ECHO resp
from given IP" (with relevant parameters) without tracking any state in the kernel should
be sufficient.
diff mbox series

Patch

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 6fa1cfe023ef..d20bc272ff6c 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -75,6 +75,8 @@  struct gtp_dev {
 	unsigned int		hash_size;
 	struct hlist_head	*tid_hash;
 	struct hlist_head	*addr_hash;
+
+	u8			restart_count;
 };
 
 static unsigned int gtp_net_id __read_mostly;
@@ -217,6 +219,106 @@  static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb,
 	return -1;
 }
 
+static struct rtable *ip4_route_output_gtp(struct flowi4 *fl4,
+					   const struct sock *sk,
+					   __be32 daddr, __be32 saddr)
+{
+	memset(fl4, 0, sizeof(*fl4));
+	fl4->flowi4_oif		= sk->sk_bound_dev_if;
+	fl4->daddr		= daddr;
+	fl4->saddr		= saddr;
+	fl4->flowi4_tos		= RT_CONN_FLAGS(sk);
+	fl4->flowi4_proto	= sk->sk_protocol;
+
+	return ip_route_output_key(sock_net(sk), fl4);
+}
+
+/* GSM TS 09.60. 7.3
+ * In all Path Management messages:
+ * - TID: is not used and shall be set to 0.
+ * - Flow Label is not used and shall be set to 0
+ * In signalling messages:
+ * - number: this field is not yet used in signalling messages.
+ *   It shall be set to 255 by the sender and shall be ignored
+ *   by the receiver
+ * Returns true if the echo req was correct, false otherwise.
+ */
+static bool gtp0_validate_echo_req(struct gtp0_header *gtp0)
+{
+	return !(gtp0->tid || (gtp0->flags ^ 0x1e) ||
+		gtp0->number != 0xff || gtp0->flow);
+}
+
+static int gtp0_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)
+{
+	struct gtp0_packet *gtp_pkt;
+	struct gtp0_header *gtp0;
+	struct rtable *rt;
+	struct flowi4 fl4;
+	struct iphdr *iph;
+	__be16 seq;
+
+	gtp0 = (struct gtp0_header *)(skb->data + sizeof(struct udphdr));
+
+	if (!gtp0_validate_echo_req(gtp0))
+		return -1;
+
+	seq = gtp0->seq;
+
+	/* pull GTP and UDP headers */
+	skb_pull_data(skb, sizeof(struct gtp0_header) + sizeof(struct udphdr));
+
+	gtp_pkt = skb_push(skb, sizeof(struct gtp0_packet));
+	memset(gtp_pkt, 0, sizeof(struct gtp0_packet));
+
+	gtp_pkt->gtp0_h.flags = 0x1e; /* v0, GTP-non-prime. */
+	gtp_pkt->gtp0_h.type = GTP_ECHO_RSP;
+	gtp_pkt->gtp0_h.length =
+		htons(sizeof(struct gtp0_packet) - sizeof(struct gtp0_header));
+
+	/* GSM TS 09.60. 7.3 The Sequence Number in a signalling response
+	 * message shall be copied from the signalling request message
+	 * that the GSN is replying to.
+	 */
+	gtp_pkt->gtp0_h.seq = seq;
+
+	/* GSM TS 09.60. 7.3 In all Path Management Flow Label and TID
+	 * are not used and shall be set to 0.
+	 */
+	gtp_pkt->gtp0_h.flow = 0;
+	gtp_pkt->gtp0_h.tid = 0;
+	gtp_pkt->gtp0_h.number = 0xff;
+	gtp_pkt->gtp0_h.spare[0] = 0xff;
+	gtp_pkt->gtp0_h.spare[1] = 0xff;
+	gtp_pkt->gtp0_h.spare[2] = 0xff;
+
+	gtp_pkt->ie.tag = GTPIE_RECOVERY;
+	gtp_pkt->ie.val = gtp->restart_count;
+
+	iph = ip_hdr(skb);
+
+	/* find route to the sender,
+	 * src address becomes dst address and vice versa.
+	 */
+	rt = ip4_route_output_gtp(&fl4, gtp->sk0, iph->saddr, iph->daddr);
+	if (IS_ERR(rt)) {
+		netdev_dbg(gtp->dev, "no route for echo response from %pI4\n",
+			   &iph->saddr);
+		return -1;
+	}
+
+	udp_tunnel_xmit_skb(rt, gtp->sk0, skb,
+			    fl4.saddr, fl4.daddr,
+			    iph->tos,
+			    ip4_dst_hoplimit(&rt->dst),
+			    0,
+			    htons(GTP0_PORT), htons(GTP0_PORT),
+			    !net_eq(sock_net(gtp->sk1u),
+				    dev_net(gtp->dev)),
+			    false);
+	return 0;
+}
+
 /* 1 means pass up to the stack, -1 means drop and 0 means decapsulated. */
 static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
@@ -233,6 +335,13 @@  static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 	if ((gtp0->flags >> 5) != GTP_V0)
 		return 1;
 
+	/* If the sockets were created in kernel, it means that
+	 * there is no daemon running in userspace which would
+	 * handle echo request.
+	 */
+	if (gtp0->type == GTP_ECHO_REQ && gtp->sk_created)
+		return gtp0_echo_resp(gtp, skb);
+
 	if (gtp0->type != GTP_TPDU)
 		return 1;
 
@@ -245,6 +354,74 @@  static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 	return gtp_rx(pctx, skb, hdrlen, gtp->role);
 }
 
+static int gtp1u_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)
+{
+	struct gtp1_header_long *gtp1u;
+	struct gtp1u_packet *gtp_pkt;
+	struct rtable *rt;
+	struct flowi4 fl4;
+	struct iphdr *iph;
+
+	gtp1u = (struct gtp1_header_long *)(skb->data + sizeof(struct udphdr));
+
+	/* 3GPP TS 29.281 5.1 - For the Echo Request, Echo Response,
+	 * Error Indication and Supported Extension Headers Notification
+	 * messages, the S flag shall be set to 1 and TEID shall be set to 0.
+	 */
+	if (!(gtp1u->flags & GTP1_F_SEQ) || gtp1u->tid)
+		return -1;
+
+	/* pull GTP and UDP headers */
+	skb_pull_data(skb, sizeof(struct gtp1_header_long) + sizeof(struct udphdr));
+
+	gtp_pkt = skb_push(skb, sizeof(struct gtp1u_packet));
+	memset(gtp_pkt, 0, sizeof(struct gtp1u_packet));
+
+	/* S flag must be set to 1 */
+	gtp_pkt->gtp1u_h.flags = 0x32;
+	gtp_pkt->gtp1u_h.type = GTP_ECHO_RSP;
+	/* seq, npdu and next should be counted to the length of the GTP packet
+	 * that's why szie of gtp1_header should be subtracted,
+	 * not why szie of gtp1_header_long.
+	 */
+	gtp_pkt->gtp1u_h.length =
+		htons(sizeof(struct gtp1u_packet) - sizeof(struct gtp1_header));
+	/* 3GPP TS 29.281 5.1 - TEID has to be set to 0 */
+	gtp_pkt->gtp1u_h.tid = 0;
+
+	/* 3GPP TS 29.281 7.7.2 - The Restart Counter value in the
+	 * Recovery information element shall not be used, i.e. it shall
+	 * be set to zero by the sender and shall be ignored by the receiver.
+	 * The Recovery information element is mandatory due to backwards
+	 * compatibility reasons.
+	 */
+	gtp_pkt->ie.tag = GTPIE_RECOVERY;
+	gtp_pkt->ie.val = 0;
+
+	iph = ip_hdr(skb);
+
+	/* find route to the sender,
+	 * src address becomes dst address and vice versa.
+	 */
+	rt = ip4_route_output_gtp(&fl4, gtp->sk1u, iph->saddr, iph->daddr);
+	if (IS_ERR(rt)) {
+		netdev_dbg(gtp->dev, "no route for echo response from %pI4\n",
+			   &iph->saddr);
+		return -1;
+	}
+
+	udp_tunnel_xmit_skb(rt, gtp->sk1u, skb,
+			    fl4.saddr, fl4.daddr,
+			    iph->tos,
+			    ip4_dst_hoplimit(&rt->dst),
+			    0,
+			    htons(GTP1U_PORT), htons(GTP1U_PORT),
+			    !net_eq(sock_net(gtp->sk1u),
+				    dev_net(gtp->dev)),
+			    false);
+	return 0;
+}
+
 static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
 	unsigned int hdrlen = sizeof(struct udphdr) +
@@ -260,6 +437,13 @@  static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 	if ((gtp1->flags >> 5) != GTP_V1)
 		return 1;
 
+	/* If the sockets were created in kernel, it means that
+	 * there is no daemon running in userspace which would
+	 * handle echo request.
+	 */
+	if (gtp1->type == GTP_ECHO_REQ && gtp->sk_created)
+		return gtp1u_echo_resp(gtp, skb);
+
 	if (gtp1->type != GTP_TPDU)
 		return 1;
 
@@ -398,20 +582,6 @@  static void gtp_dev_uninit(struct net_device *dev)
 	free_percpu(dev->tstats);
 }
 
-static struct rtable *ip4_route_output_gtp(struct flowi4 *fl4,
-					   const struct sock *sk,
-					   __be32 daddr)
-{
-	memset(fl4, 0, sizeof(*fl4));
-	fl4->flowi4_oif		= sk->sk_bound_dev_if;
-	fl4->daddr		= daddr;
-	fl4->saddr		= inet_sk(sk)->inet_saddr;
-	fl4->flowi4_tos		= RT_CONN_FLAGS(sk);
-	fl4->flowi4_proto	= sk->sk_protocol;
-
-	return ip_route_output_key(sock_net(sk), fl4);
-}
-
 static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
 {
 	int payload_len = skb->len;
@@ -517,7 +687,8 @@  static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
 	}
 	netdev_dbg(dev, "found PDP context %p\n", pctx);
 
-	rt = ip4_route_output_gtp(&fl4, pctx->sk, pctx->peer_addr_ip4.s_addr);
+	rt = ip4_route_output_gtp(&fl4, pctx->sk, pctx->peer_addr_ip4.s_addr,
+				  inet_sk(pctx->sk)->inet_saddr);
 	if (IS_ERR(rt)) {
 		netdev_dbg(dev, "no route to SSGN %pI4\n",
 			   &pctx->peer_addr_ip4.s_addr);
@@ -684,6 +855,11 @@  static int gtp_newlink(struct net *src_net, struct net_device *dev,
 			hashsize = 1024;
 	}
 
+	if (!data[IFLA_GTP_RESTART_COUNT])
+		gtp->restart_count = 0;
+	else
+		gtp->restart_count = nla_get_u8(data[IFLA_GTP_RESTART_COUNT]);
+
 	gtp->net = src_net;
 
 	err = gtp_hashtable_new(gtp, hashsize);
@@ -735,6 +911,7 @@  static const struct nla_policy gtp_policy[IFLA_GTP_MAX + 1] = {
 	[IFLA_GTP_FD1]			= { .type = NLA_U32 },
 	[IFLA_GTP_PDP_HASHSIZE]		= { .type = NLA_U32 },
 	[IFLA_GTP_ROLE]			= { .type = NLA_U32 },
+	[IFLA_GTP_RESTART_COUNT]	= { .type = NLA_U8 },
 };
 
 static int gtp_validate(struct nlattr *tb[], struct nlattr *data[],
@@ -749,7 +926,8 @@  static int gtp_validate(struct nlattr *tb[], struct nlattr *data[],
 static size_t gtp_get_size(const struct net_device *dev)
 {
 	return nla_total_size(sizeof(__u32)) + /* IFLA_GTP_PDP_HASHSIZE */
-		nla_total_size(sizeof(__u32)); /* IFLA_GTP_ROLE */
+		nla_total_size(sizeof(__u32)) + /* IFLA_GTP_ROLE */
+		nla_total_size(sizeof(__u8)); /* IFLA_GTP_RESTART_COUNT */
 }
 
 static int gtp_fill_info(struct sk_buff *skb, const struct net_device *dev)
@@ -760,6 +938,8 @@  static int gtp_fill_info(struct sk_buff *skb, const struct net_device *dev)
 		goto nla_put_failure;
 	if (nla_put_u32(skb, IFLA_GTP_ROLE, gtp->role))
 		goto nla_put_failure;
+	if (nla_put_u8(skb, IFLA_GTP_RESTART_COUNT, gtp->restart_count))
+		goto nla_put_failure;
 
 	return 0;
 
diff --git a/include/net/gtp.h b/include/net/gtp.h
index c78702e3d663..53a712f73b13 100644
--- a/include/net/gtp.h
+++ b/include/net/gtp.h
@@ -7,8 +7,13 @@ 
 #define GTP0_PORT	3386
 #define GTP1U_PORT	2152
 
+/* GTP messages types */
+#define GTP_ECHO_REQ	1	/* Echo Request */
+#define GTP_ECHO_RSP	2	/* Echo Response */
 #define GTP_TPDU	255
 
+#define GTPIE_RECOVERY	14
+
 struct gtp0_header {	/* According to GSM TS 09.60. */
 	__u8	flags;
 	__u8	type;
@@ -27,11 +32,37 @@  struct gtp1_header {	/* According to 3GPP TS 29.060. */
 	__be32	tid;
 } __attribute__ ((packed));
 
+struct gtp1_header_long {	/* According to 3GPP TS 29.060. */
+	__u8	flags;
+	__u8	type;
+	__be16	length;
+	__be32	tid;
+	__be16	seq;
+	__u8	npdu;
+	__u8	next;
+} __packed;
+
 struct gtp_pdu_session_info {	/* According to 3GPP TS 38.415. */
 	u8	pdu_type;
 	u8	qfi;
 };
 
+/* GTP Information Element */
+struct gtp_ie {
+	__u8	tag;
+	__u8	val;
+} __packed;
+
+struct gtp0_packet {
+	struct gtp0_header gtp0_h;
+	struct gtp_ie ie;
+} __packed;
+
+struct gtp1u_packet {
+	struct gtp1_header_long gtp1u_h;
+	struct gtp_ie ie;
+} __packed;
+
 static inline bool netif_is_gtp(const struct net_device *dev)
 {
 	return dev->rtnl_link_ops &&
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 6218f93f5c1a..2fc5a0371283 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -822,6 +822,7 @@  enum {
 	IFLA_GTP_FD1,
 	IFLA_GTP_PDP_HASHSIZE,
 	IFLA_GTP_ROLE,
+	IFLA_GTP_RESTART_COUNT,
 	__IFLA_GTP_MAX,
 };
 #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)