Re: [PATCH net-next 09/14] gtp: Allow configuring GTP interface as standalone

2017-09-20 Thread Andreas Schultz



On 20/09/17 17:57, Tom Herbert wrote:

On Wed, Sep 20, 2017 at 8:27 AM, Andreas Schultz <aschu...@tpip.net> wrote:

On 19/09/17 02:38, Tom Herbert wrote:


Add new configuration of GTP interfaces that allow specifying a port to
listen on (as opposed to having to get sockets from a userspace control
plane). This allows GTP interfaces to be configured and the data path
tested without requiring a GTP-C daemon.



This would imply that you can have multiple independent GTP sockets on the
same IP address.That is not permitted by the GTP specifications. 3GPP TS
29.281, section 4.3 states clearly that there is "only" one GTP entity per
IP address.A PDP context is defined by the destination IP and the TEID. The
destination port is not part of the identity of a PDP context.


We are in no way trying change GTP, if someone runs this in a real GTP
network then they need to abide by the specification. However, there
is nothing inconsistent and it breaks nothing if someone wishes to use
different port numbers in their own private network for testing or
development purposes. Every other UDP application that has assigned
port number allows configurable ports, I don't see that GTP is so
special that it should be an exception.


GTP isn't special, I just don't like to have testing only features in 
there when the same goal can be reached without having to add extra 
stuff. Adding code that is not going to be useful in real production 
setups (or in this case would even break production setups when enabled 
accidentally) makes the implementation more complex than it needs to be.


You can always add multiple IP's to your test system and have the same 
effect without having to change the ports.


Regards
Andreas



Tom



Re: [PATCH net-next 03/14] gtp: Call common functions to get tunnel routes and add dst_cache

2017-09-20 Thread Andreas Schultz



On 19/09/17 14:09, Harald Welte wrote:

Hi Dave,

On Mon, Sep 18, 2017 at 09:17:51PM -0700, David Miller wrote:

This and the new dst caching code ignores any source address selection
done by ip_route_output_key() or the new tunnel route lookup helpers.

Either source address selection should be respected, or if saddr will
never be modified by a route lookup for some specific reason here,
that should be documented.


The IP source address is fixed by signaling on the GTP-C control plane
and nothing that the kernel can unilaterally decide to change.  Such a
change of address would have to be decided by and first be signaled on
GTP-C to the peer by the userspace daemon, which would then update the
PDP context in the kernel.


I think we had this discussion before. The sending IP and port are not 
part of the identity of the PDP context. So IMHO the sender is permitted

to change the source IP at random.

Regards
Andreas



So I guess you're asking us to document that rationale as form of a
source code comment ?



Re: [PATCH net-next 09/14] gtp: Allow configuring GTP interface as standalone

2017-09-20 Thread Andreas Schultz

On 19/09/17 02:38, Tom Herbert wrote:

Add new configuration of GTP interfaces that allow specifying a port to
listen on (as opposed to having to get sockets from a userspace control
plane). This allows GTP interfaces to be configured and the data path
tested without requiring a GTP-C daemon.


This would imply that you can have multiple independent GTP sockets on 
the same IP address.That is not permitted by the GTP specifications. 
3GPP TS 29.281, section 4.3 states clearly that there is "only" one GTP 
entity per IP address.A PDP context is defined by the destination IP and 
the TEID. The destination port is not part of the identity of a PDP context.


Even the source IP and source port are not part of the tunnel identity. 
This makes is possible to send traffic from a new SGSN/SGW during 
handover before the control protocol has announced the handover.


At this point the usual response is: THAT IS NOT SAFE. Yes, GTP has been 
designed for cooperative networks only and should not be used on 
hostile/unsecured networks.


On the sending side, using multiple ports is permitted as long as the 
default GTP port is always able to receive incoming messages.


Andreas

[...]


Re: [PATCH net-next 00/14] gtp: Additional feature support

2017-09-20 Thread Andreas Schultz

Hi Harald,

On 20/09/17 01:19, Harald Welte wrote:

Hi Tom,

On Tue, Sep 19, 2017 at 08:59:28AM -0700, Tom Herbert wrote:

On Tue, Sep 19, 2017 at 5:43 AM, Harald Welte 
wrote:

On Mon, Sep 18, 2017 at 05:38:50PM -0700, Tom Herbert wrote:

   - IPv6 support


see my detailed comments in other mails.  It's unfortunately only
support for the already "deprecated" IPv6-only PDP contexts, not the
more modern v4v6 type.  In order to interoperate with old and new
approach, all three cases (v4, v6 and v4v6) should be supported from
one code base.


It sounds like something that can be subsequently added.


Not entirely, at least on the netlink (and any other configuration
interface) you will have to reflect this from the very beginning.  You
have to have an explicit PDP type and cannot rely on the address type to
specify the type of PDP context.  Whatever interfaces are introduced
now will have to remain compatible to any future change.

My strategy to avoid any such possible 'road blocks' from being
introduced would be to simply add v4v6 and v6 support in one go.  The
differences are marginal (having both an IPv6 prefix and a v4 address in
parallel, rather than mutually exclusive only).


Do you have a reference to the spec?


See http://osmocom.org/issues/2418#note-7 which lists Section 11.2.1.3.2
of 3GPP TS 29.061 in combination with RFC3314, RFC7066, RFC6459 and
3GPP TS 23.060 9.2.1 as well as a summary of my understanding of it some
months ago.


   - Configurable networking interfaces so that GTP kernel can be
   used and tested without needing GSN network emulation (i.e. no
   user space daemon needed).


We have some pretty decent userspace utilities for configuring the
GTP interfaces and tunnels in the libgtpnl repository, but if it
helps people to have another way of configuration, I won't be
against it.


AFAIK those userspace utilities don't support IPv6.


Of course not [yet]. libgtpnl and the command line tools have been
implemented specifically for the in-kernel GTP driver, and you have to
make sure to add related support on both the kernel and the userspace
side (libgtpnl). So there's little point in adding features on either
side before the other side.  There would be no way to test...


Being able to configure GTP like any other encapsulation will
facilitate development of IPv6 and other features.


That may very well be the case, but adding "IPv6 support" to kernel GTP
in a way that is not in line with the existing userspace libraries and
control-plane implementations means that you're developing those
features in an artificial environment that doesn't resemble real 3GPP
interoperable networks out there.

As indicated, I'm not against adding additional interfaces, but we have
to make sure that we add IPv6 support (or any new feature support) to at
least libgtpnl, and to make sure we test interoperability with existing
3GPP network equipment such as real IPv6 capable phones and SGSNs.


I'm not sure if this is a useful feature.  GTP is used only in
operator-controlled networks and only on standard ports.  It's not
possible to negotiate any non-standard ports on the signaling plane
either.


Bear in mind that we're not required to do everything the GTP spec
says.


Yes, we are, at least as long as it affects interoperability with other
implemetations out there.

GTP uses well-known port numbers on *both* sides of the tunnel, and you
cannot deviate from that.


Actually, the well-known port is only mandatory for the receiving side.
The sending side can choose any port it wishes as long as it is prepared
to receive possible error indication on the well-known port.

Of course, it makes the implementation simple to use only one port, but 
for scalability it might be a good idea to support per PDP context 
sending ports.


Regards
Andreas


There's no point in having all kinds of feetures in the GTP user plane
which are not interoperable with other implementations, and which are
completely outside of the information model / architecture of GTP.

In the real world, GTP-U is only used in combination with GTP-C.  And in
GTP-C you can only negotiate the IP address of both sides of GTP-U, and
not the port number information.  As a result, the port numbers are
static on both sides.


My impression is GTP designers probably didn't think in terms of
getting best performance. But we can ;-)


I think it's wasted efforts if it's about "random udp ports" as no
standards-compliant implementation out there with which you will have to
interoperate will be able to support it.

GTP is used between home and roaming operator.  If you want to introduce
changes to how it works, you will have to have control over both sides
of the implementation of both the GTP-C and the GTP-u plane, which is
very unlikely and rather the exception in the hundreds of operators you
interoperate with.  Also keep in mind that there often are various
"middleboxes" that will suddenly have to reflect your changes.  That

Re: [PATCH net-next v1 1/3] gtp: refactor to support flow-based gtp encap and decap

2017-07-31 Thread Andreas Schultz
Hi Jiannan,

- On Jul 13, 2017, at 2:44 AM, Jiannan Ouyang ouya...@fb.com wrote:

[...]

> -static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb,
> - unsigned int hdrlen, unsigned int role)
> +static int gtp_rx(struct gtp_dev *gtp, struct sk_buff *skb,
> +   unsigned int hdrlen, struct sock *sk,
> +   struct metadata_dst *tun_dst)

Some time ago, there was an extensive discussion about the relation
of PDP context and network devices. You are basically reverting one
of the changes that was made in that context. I think it is wrong to
couple GTP devices and PDP context the way you do here (there are
people that disagree, though).

The GTP network device of one of two structures owning the PDP context,
the other is the GTP socket. GTP network devices and GTP sockets should
be strictly separated.

The GTP network device owns the IP given to the MS, handles mapping
IP's into GTP tunnels (peer GSN + TEIDs) and hands the resulting GTP 
packets of to the GTP socket for sending. The GTP socket decaps the GTP
packet, find the right context and based on information therein passes
it to the GTP network device.

By separating is that way, you can have MS with overlapping or colliding
IP's on the same GTP socket as long as they belong to different GTP network
devices.

We had a length discussion about whether the above scenario makes sense.
I'm not sure if we reached a final verdict, but the 3GPP specifications
clearly permit such a setup.


Regards
Andreas



Re: [PATCH net-next 0/4] gtp: support multiple APN's per GTP endpoint

2017-03-14 Thread Andreas Schultz


- On Mar 14, 2017, at 12:45 PM, pablo pa...@netfilter.org wrote:

> On Tue, Mar 14, 2017 at 12:25:44PM +0100, Andreas Schultz wrote:
> [...]
>> API impact:
>> ---
>> 
>> This is probably the most problematic part of this series...
>> 
>> The removeal of the TEID form the netdevice also means that the gtp genl API
>> for retriving tunnel information and removing tunnels needs to be adjusted.
>> 
>> Before this change it was possible to change a GTP tunnel using the gtp
>> netdevice id and the teid. The teid is no longer unique per gtp netdevice.
>> After this change it has to be either the netdevice and MS IP or the GTP
>> socket and teid.
> 
> Then we have to introduce some explicit VRF concept or such to sort
> out this.
> 
> It is definitely not acceptable to break the existing API.

The specific use case of the API that is no longer supported was never used by
anyone. The only supported and documented API for the GTP module is libgtpnl.
libgtpnl has always required the now mandatory fields. Therefor the externally
supported API does not change.

Regards
Andreas


Re: [PATCH net-next 1/4] gtp: move TEID hash to per socket structure

2017-03-14 Thread Andreas Schultz


- On Mar 14, 2017, at 12:33 PM, pablo pa...@netfilter.org wrote:

> On Tue, Mar 14, 2017 at 12:25:45PM +0100, Andreas Schultz wrote:
>> @@ -275,9 +280,9 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
>> struct
>> sk_buff *skb)
>>  
>>  gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
>>  
>> -pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
>> +pctx = gtp1_pdp_find(gsk, ntohl(gtp1->tid));
>>  if (!pctx) {
>> -netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
>> +pr_debug("No PDP ctx to decap skb=%p\n", skb);
>>  return 1;
> 
> Again the pr_debug() change has resurrected.

Yes, at that point in the code, there is now ways to resolve the network device.
Therefore the netdev_dbg has to go.

> I already told you: If we are going to have more than one gtp device,
> then this doesn't make sense. I have to repeat things over and over
> again, just because you don't want to rebase your patchset for some
> reason. I don't find any other explaination for this.

Without a PDP context, there is no network device, so netdev_dbg.
 
> So please remove this debugging rather than rendering this completely
> useful.

ACK
 
> Moreover this change has nothing to this patch, so this doesn't break
> the one logical change per patch.

This patch moves the incoming teid has from the network device to the
socket. This means that gtp1_pdp_find needs to change. So this related.
For the debug change, see above why it's related.

Andreas


Re: [PATCH net-next 2/4] gtp: add genl cmd to enable GTP encapsulation on UDP socket

2017-03-14 Thread Andreas Schultz
- On Mar 14, 2017, at 12:43 PM, pablo pa...@netfilter.org wrote:

> On Tue, Mar 14, 2017 at 12:25:46PM +0100, Andreas Schultz wrote:
> 
>> @@ -1254,6 +1293,8 @@ static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] 
>> = {
>>  [GTPA_NET_NS_FD]= { .type = NLA_U32, },
>>  [GTPA_I_TEI]= { .type = NLA_U32, },
>>  [GTPA_O_TEI]= { .type = NLA_U32, },
>> +[GTPA_PDP_HASHSIZE] = { .type = NLA_U32, },
> 
> This per PDP hashsize attribute clearly doesn't belong here.
> 
> Moreover, we now have a rhashtable implementation, so we hopefully we
> can get rid of this. It should be very easy to convert this to use
> rhashtable, and it is very much desiderable.

This would mean I have to mix the unrelated rhashtable change with moving the
hash into the socket. This certainly is not desirable either.

So, I'm going to have a look at the rhashtable thing and send a patch first
to convert the hashes to it.

>> +[GTPA_FD]   = { .type = NLA_U32, },
> 
> This new atttribute has nothing to do with the PDP context.
> And enum gtp_attrs *only* describe a PDP context. Adding more
> attributes there to mix semantics is not the way to go.

You seem to assume that the network device or the APN/VRF is the root entity
for the GTP tunnels. That is IMHO wrong. The 3GPP specification clearly defines
a GTP entity that is completely Independent from an APN or the local IP 
endpoint.

A GTP entity serves multiple local IP endpoints, It manages outgoing tunnels
by the local APN/VRF, source IP, destination IP and remote tunnel id, incoming
tunnels are managed by the local destination IP, local tunnel id and VRF/APN.

Therefor a PDP context needs the following attributes:

 * local source/destination IP (and port - but that's for different series)
 * remote destination IP
 * local and remote TEID
 * VRF/APN

The local source and destination IP is implicitly contained in the socket, 
therefor
the socket needs to part of the context. The VRF/APN is contained in the network
device reference. So this also needs to part of the PDP context.

Having either the socket or the network device as the sole root container for a
GTP entity is wrong since the PDP context always refer both.

> You likely have to inaugurate a new enum. This gtp_attrs enum only
> related to the PDP description.
> 
> Why not add some interface to attach more sockets to the gtp device
> globally? So still the gtp device is the top-level structure. 

That is IMHO the wrong model. In a real live setup it likely to have a
few GTP sockets and possibly hundreds if not thousands of network device
attached to them (we already had the discussion why this kind of sharing
makes sense). 
So from a resource perspective alone, having the network device as root makes
no sense.

> Then add
> a netlink attribute to specify to what VRF this tunnel belongs to,
> instead of implicitly using the socket to achieve this.

You got that the wrong way arround. The VRF is already in the PDP context
through the network device reference. The socket is added to the PDP context
to select the outgoing source IP of the GTP tunnel in order to support
multiple GTP source IP's per GTP entity.

> Another possibility is to explicitly have an interface to add
> new/delete VRFs, attach sockets to them.

We already have that interface. It's the create a GTP network interface
genl API. I explained a few lines above why I think that adding sockets to
GTP network devices is wrong.

> In general, I'm still not convinced this is the right design for this.

Following your "add VRF" idea, I would end up with a pseudo network device
that represents a GTP entity. This would be the root instance for all the
VRF's and GTP sockets. Although being a network device, it would not
behave in any way like a network device, it would not handle traffic or
have IP(v6) addresses attached to it.
I would then further have GTP VRF network devices. Those would be "real"
network device that handle traffic and have IP addresses/route attached
to them.

I'm not sure if this pseudo GTP entity root device fits well with
other networking concepts. And more over, I can't really see the need
for such an construct.

This need for an in-kernel root entity seem to come the concept that
the kernel *owns* the tunnels and that tunnel a static and independent
from the user space control instance.

I think that the user space control instance should own the tunnels and
only use the kernel facility to manage them. When the user space instance
goes away, so should the tunnels.
>From that perspective,  I want to keep the kernel facilities to the absolute
needed minimum.

Regards 
Andreas


[PATCH net-next 3/4] gtp: add support to select a GTP socket during PDP context creation

2017-03-14 Thread Andreas Schultz
For each new PDP a separate socket can be selected. The per netdevice
default sockets are no longer mandatory.

This means also that multiple gtp netdevices can share the same default
socket and that therefore the destruction of a gtp netdevice can no
longer automatically disable the gtp encapsulation on it's sockets.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 79 +++
 1 file changed, 68 insertions(+), 11 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index c4cf1b9..afa043d 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -381,9 +381,6 @@ static int gtp_dev_init(struct net_device *dev)
 
 static void gtp_dev_uninit(struct net_device *dev)
 {
-   struct gtp_dev *gtp = netdev_priv(dev);
-
-   gtp_encap_disable(gtp);
free_percpu(dev->tstats);
 }
 
@@ -647,9 +644,6 @@ static int gtp_newlink(struct net *src_net, struct 
net_device *dev,
struct gtp_net *gn;
int hashsize, err;
 
-   if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1])
-   return -EINVAL;
-
gtp = netdev_priv(dev);
 
if (!data[IFLA_GTP_PDP_HASHSIZE])
@@ -689,8 +683,11 @@ static void gtp_dellink(struct net_device *dev, struct 
list_head *head)
 {
struct gtp_dev *gtp = netdev_priv(dev);
 
-   gtp_encap_disable(gtp);
gtp_hashtable_free(gtp);
+   if (gtp->sk0)
+   sock_put(gtp->sk0);
+   if (gtp->sk1u)
+   sock_put(gtp->sk1u);
list_del_rcu(>list);
unregister_netdevice_queue(dev, head);
 }
@@ -1008,9 +1005,10 @@ static void pdp_context_delete(struct pdp_ctx *pctx)
 
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
+   struct socket *sock = NULL;
+   struct sock *sk = NULL;
unsigned int version;
struct gtp_dev *gtp;
-   struct sock *sk;
int err;
 
if (!info->attrs[GTPA_VERSION] ||
@@ -1045,12 +1043,14 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
goto out_unlock;
}
 
-   if (version == GTP_V0)
+   if (info->attrs[GTPA_FD]) {
+   sock = sockfd_lookup(nla_get_u32(info->attrs[GTPA_FD]), );
+   if (sock)
+   sk = sock->sk;
+   } else if (version == GTP_V0)
sk = gtp->sk0;
else if (version == GTP_V1)
sk = gtp->sk1u;
-   else
-   sk = NULL;
 
if (!sk) {
err = -ENODEV;
@@ -1059,6 +1059,9 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
 
err = ipv4_pdp_add(gtp, sk, info);
 
+   if (sock)
+   sockfd_put(sock);
+
 out_unlock:
rcu_read_unlock();
return err;
@@ -1079,12 +1082,66 @@ static struct pdp_ctx *gtp_find_pdp_by_link(struct net 
*net,
return ipv4_pdp_find(gtp, nla_get_be32(nla[GTPA_MS_ADDRESS]));
 }
 
+static struct pdp_ctx *gtp_genl_find_pdp_by_socket(struct net *net,
+  struct nlattr *nla[])
+{
+   struct socket *sock;
+   struct gtp_sock *gsk;
+   struct pdp_ctx *pctx;
+   int fd, err = 0;
+
+   if (!nla[GTPA_FD])
+   return ERR_PTR(-EINVAL);
+
+   fd = nla_get_u32(nla[GTPA_FD]);
+   sock = sockfd_lookup(fd, );
+   if (!sock) {
+   pr_debug("gtp socket fd=%d not found\n", fd);
+   return ERR_PTR(-EBADF);
+   }
+
+   gsk = rcu_dereference_sk_user_data(sock->sk);
+   if (!gsk) {
+   pctx = ERR_PTR(-EINVAL);
+   goto out_sock;
+   }
+
+   switch (nla_get_u32(nla[GTPA_VERSION])) {
+   case GTP_V0:
+   if (!nla[GTPA_TID]) {
+   pctx = ERR_PTR(-EINVAL);
+   break;
+   }
+   pctx = gtp0_pdp_find(gsk, nla_get_u64(nla[GTPA_TID]));
+   break;
+
+   case GTP_V1:
+   if (!nla[GTPA_I_TEI]) {
+   pctx = ERR_PTR(-EINVAL);
+   break;
+   }
+   pctx = gtp1_pdp_find(gsk, nla_get_u64(nla[GTPA_I_TEI]));
+   break;
+
+   default:
+   pctx = ERR_PTR(-EINVAL);
+   break;
+   }
+
+out_sock:
+   sockfd_put(sock);
+   return pctx;
+}
+
 static struct pdp_ctx *gtp_find_pdp(struct net *net, struct nlattr *nla[])
 {
struct pdp_ctx *pctx;
 
if (nla[GTPA_LINK])
pctx = gtp_find_pdp_by_link(net, nla);
+   else if (nla[GTPA_FD])
+   pctx = gtp_genl_find_pdp_by_socket(net, nla);
+
else
pctx = ERR_PTR(-EINVAL);
 
-- 
2.10.2



[PATCH net-next 1/4] gtp: move TEID hash to per socket structure

2017-03-14 Thread Andreas Schultz
Untangele the TEID information from the network device and move
it into a per socket structure.

The removeal of the TEID form the netdevice also means that the
gtp genl API for retriving tunnel information and removing tunnels
needs to be adjusted.
Before this change it was possible to change a GTP tunnel using
the gtp netdevice id and the teid. The teid is no longer unique
per gtp netdevice. So after this change it has to be either the
netdevice and MS IP or the GTP socket and teid.

Fortunatly, libgtpnl has always populated the Link Id, TEID,
GSN Peer IP and MS IP. So, the library interface has ensured that
all information that is mandatory after this change is guranteed
to be present. The only project that doesn't use libgtpnl (OpenAir-CN)
is also populating all of those values.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 145 +-
 1 file changed, 78 insertions(+), 67 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 3e1854f..66616f7 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -75,10 +75,15 @@ struct gtp_dev {
struct net_device   *dev;
 
unsigned inthash_size;
-   struct hlist_head   *tid_hash;
struct hlist_head   *addr_hash;
 };
 
+/* One instance of the GTP socket. */
+struct gtp_sock {
+   unsigned inthash_size;
+   struct hlist_head   tid_hash[];
+};
+
 static unsigned int gtp_net_id __read_mostly;
 
 struct gtp_net {
@@ -106,12 +111,12 @@ static inline u32 ipv4_hashfn(__be32 ip)
 }
 
 /* Resolve a PDP context structure based on the 64bit TID. */
-static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid)
+static struct pdp_ctx *gtp0_pdp_find(struct gtp_sock *gsk, u64 tid)
 {
struct hlist_head *head;
struct pdp_ctx *pdp;
 
-   head = >tid_hash[gtp0_hashfn(tid) % gtp->hash_size];
+   head = >tid_hash[gtp0_hashfn(tid) % gsk->hash_size];
 
hlist_for_each_entry_rcu(pdp, head, hlist_tid) {
if (pdp->gtp_version == GTP_V0 &&
@@ -122,12 +127,12 @@ static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, 
u64 tid)
 }
 
 /* Resolve a PDP context structure based on the 32bit TEI. */
-static struct pdp_ctx *gtp1_pdp_find(struct gtp_dev *gtp, u32 tid)
+static struct pdp_ctx *gtp1_pdp_find(struct gtp_sock *gsk, u32 tid)
 {
struct hlist_head *head;
struct pdp_ctx *pdp;
 
-   head = >tid_hash[gtp1u_hashfn(tid) % gtp->hash_size];
+   head = >tid_hash[gtp1u_hashfn(tid) % gsk->hash_size];
 
hlist_for_each_entry_rcu(pdp, head, hlist_tid) {
if (pdp->gtp_version == GTP_V1 &&
@@ -215,7 +220,7 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff 
*skb, unsigned int hdrlen
 }
 
 /* 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)
+static int gtp0_udp_encap_recv(struct gtp_sock *gsk, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp0_header);
@@ -233,16 +238,16 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb)
if (gtp0->type != GTP_TPDU)
return 1;
 
-   pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
+   pctx = gtp0_pdp_find(gsk, be64_to_cpu(gtp0->tid));
if (!pctx) {
-   netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
+   pr_debug("No PDP ctx to decap skb=%p\n", skb);
return 1;
}
 
return gtp_rx(pctx, skb, hdrlen);
 }
 
-static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
+static int gtp1u_udp_encap_recv(struct gtp_sock *gsk, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp1_header);
@@ -275,9 +280,9 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb)
 
gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
 
-   pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
+   pctx = gtp1_pdp_find(gsk, ntohl(gtp1->tid));
if (!pctx) {
-   netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
+   pr_debug("No PDP ctx to decap skb=%p\n", skb);
return 1;
}
 
@@ -286,13 +291,21 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb)
 
 static void gtp_encap_destroy(struct sock *sk)
 {
-   struct gtp_dev *gtp;
+   struct gtp_sock *gsk;
+   struct pdp_ctx *pctx;
+   int i;
 
-   gtp = rcu_dereference_sk_user_data(sk);
-   if (gtp) {
+   gsk = rcu_dereference_sk_user_data(sk);
+   if (gsk) {
udp_sk(sk)->encap_type = 0;
 

[PATCH net-next 2/4] gtp: add genl cmd to enable GTP encapsulation on UDP socket

2017-03-14 Thread Andreas Schultz
Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c| 47 +++
 include/uapi/linux/gtp.h |  4 
 2 files changed, 51 insertions(+)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 66616f7..c4cf1b9 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1244,6 +1244,45 @@ static int gtp_genl_dump_pdp(struct sk_buff *skb,
return skb->len;
 }
 
+static int gtp_genl_enable_socket(struct sk_buff *skb, struct genl_info *info)
+{
+   u32 version, fd, hashsize;
+   struct sock *sk;
+
+   if (!info->attrs[GTPA_VERSION] ||
+   !info->attrs[GTPA_FD])
+   return -EINVAL;
+
+   if (!info->attrs[GTPA_PDP_HASHSIZE])
+   hashsize = 1024;
+   else
+   hashsize = nla_get_u32(info->attrs[IFLA_GTP_PDP_HASHSIZE]);
+
+   version = nla_get_u32(info->attrs[GTPA_VERSION]);
+   fd = nla_get_u32(info->attrs[GTPA_FD]);
+
+   switch (version) {
+   case GTP_V0:
+   sk = gtp_encap_enable_socket(fd, UDP_ENCAP_GTP0, hashsize);
+   break;
+
+   case GTP_V1:
+   sk = gtp_encap_enable_socket(fd, UDP_ENCAP_GTP1U, hashsize);
+   break;
+
+   default:
+   return -EINVAL;
+   }
+
+   if (!sk)
+   return -EINVAL;
+
+   if (IS_ERR(sk))
+   return PTR_ERR(sk);
+
+   return 0;
+}
+
 static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = {
[GTPA_LINK] = { .type = NLA_U32, },
[GTPA_VERSION]  = { .type = NLA_U32, },
@@ -1254,6 +1293,8 @@ static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = {
[GTPA_NET_NS_FD]= { .type = NLA_U32, },
[GTPA_I_TEI]= { .type = NLA_U32, },
[GTPA_O_TEI]= { .type = NLA_U32, },
+   [GTPA_PDP_HASHSIZE] = { .type = NLA_U32, },
+   [GTPA_FD]   = { .type = NLA_U32, },
 };
 
 static const struct genl_ops gtp_genl_ops[] = {
@@ -1276,6 +1317,12 @@ static const struct genl_ops gtp_genl_ops[] = {
.policy = gtp_genl_policy,
.flags = GENL_ADMIN_PERM,
},
+   {
+   .cmd = GTP_CMD_ENABLE_SOCKET,
+   .doit = gtp_genl_enable_socket,
+   .policy = gtp_genl_policy,
+   .flags = GENL_ADMIN_PERM,
+   },
 };
 
 static struct genl_family gtp_genl_family __ro_after_init = {
diff --git a/include/uapi/linux/gtp.h b/include/uapi/linux/gtp.h
index 72a04a0..a9e9fe0 100644
--- a/include/uapi/linux/gtp.h
+++ b/include/uapi/linux/gtp.h
@@ -6,6 +6,8 @@ enum gtp_genl_cmds {
GTP_CMD_DELPDP,
GTP_CMD_GETPDP,
 
+   GTP_CMD_ENABLE_SOCKET,
+
GTP_CMD_MAX,
 };
 
@@ -26,6 +28,8 @@ enum gtp_attrs {
GTPA_I_TEI, /* for GTPv1 only */
GTPA_O_TEI, /* for GTPv1 only */
GTPA_PAD,
+   GTPA_PDP_HASHSIZE,
+   GTPA_FD,
__GTPA_MAX,
 };
 #define GTPA_MAX (__GTPA_MAX + 1)
-- 
2.10.2



[PATCH net-next 4/4] Extend Kernel GTP-U tunneling documentation

2017-03-14 Thread Andreas Schultz
* clarify specification references for v0/v1
* add section "APN vs. Network device"
* add section "Local GTP-U entity and tunnel identification"

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
Signed-off-by: Harald Welte <lafo...@gnumonks.org>
---
 Documentation/networking/gtp.txt | 103 +--
 1 file changed, 99 insertions(+), 4 deletions(-)

diff --git a/Documentation/networking/gtp.txt b/Documentation/networking/gtp.txt
index 93e9675..0d9c18f 100644
--- a/Documentation/networking/gtp.txt
+++ b/Documentation/networking/gtp.txt
@@ -1,6 +1,7 @@
 The Linux kernel GTP tunneling module
 ==
-Documentation by Harald Welte <lafo...@gnumonks.org>
+Documentation by Harald Welte <lafo...@gnumonks.org> and
+ Andreas Schultz <aschu...@tpip.net>
 
 In 'drivers/net/gtp.c' you are finding a kernel-level implementation
 of a GTP tunnel endpoint.
@@ -91,9 +92,13 @@ http://git.osmocom.org/libgtpnl/
 
 == Protocol Versions ==
 
-There are two different versions of GTP-U: v0 and v1.  Both are
-implemented in the Kernel GTP module.  Version 0 is a legacy version,
-and deprecated from recent 3GPP specifications.
+There are two different versions of GTP-U: v0 [GSM TS 09.60] and v1
+[3GPP TS 29.281].  Both are implemented in the Kernel GTP module.
+Version 0 is a legacy version, and deprecated from recent 3GPP
+specifications.
+
+GTP-U uses UDP for transporting PDUs.  The receiving UDP port is 2151
+for GTPv1-U and 3386 for GTPv0-U.
 
 There are three versions of GTP-C: v0, v1, and v2.  As the kernel
 doesn't implement GTP-C, we don't have to worry about this.  It's the
@@ -133,3 +138,93 @@ doe to a lack of user interest, it never got merged.
 In 2015, Andreas Schultz came to the rescue and fixed lots more bugs,
 extended it with new features and finally pushed all of us to get it
 mainline, where it was merged in 4.7.0.
+
+== Architectural Details ==
+
+=== Local GTP-U entity and tunnel identification ===
+
+GTP-U uses UDP for transporting PDU's. The receiving UDP port is 2152
+for GTPv1-U and 3386 for GTPv0-U.
+
+There is only one GTP-U entity (and therefor SGSN/GGSN/S-GW/PDN-GW
+instance) per IP address. Tunnel Endpoint Identifier (TEID) are unique
+per GTP-U entity.
+
+A specific tunnel is only defined by the destination entity. Since the
+destination port is constant, only the destination IP and TEID define
+a tunnel. The source IP and Port have no meaning for the tunnel.
+
+Therefore:
+
+  * when sending, the remote entity is defined by the remote IP and
+the tunnel endpoint id. The source IP and port have no meaning and
+can be changed at any time.
+
+  * when receiving the local entity is defined by the local
+destination IP and the tunnel endpoint id. The source IP and port
+have no meaning and can change at any time.
+
+[3GPP TS 29.281] Section 4.3.0 defines this so:
+
+> The TEID in the GTP-U header is used to de-multiplex traffic
+> incoming from remote tunnel endpoints so that it is delivered to the
+> User plane entities in a way that allows multiplexing of different
+> users, different packet protocols and different QoS levels.
+> Therefore no two remote GTP-U endpoints shall send traffic to a
+> GTP-U protocol entity using the same TEID value except
+> for data forwarding as part of mobility procedures.
+
+The definition above only defines that two remote GTP-U endpoints
+*should not* send to the same TEID, it *does not* forbid or exclude
+such a scenario. In fact, the mentioned mobility procedures make it
+necessary that the GTP-U entity accepts traffic for TEIDs from
+multiple or unknown peers.
+
+Therefore, the receiving side identifies tunnels exclusively based on
+TEIDs, not based on the source IP!
+
+== APN vs. Network Device ==
+
+The GTP-U driver creates a Linux network device for each Gi/SGi
+interface.
+
+[3GPP TS 29.281] calls the Gi/SGi reference point an interface. This
+may lead to the impression that the GGSN/P-GW can have only one such
+interface.
+
+Correct is that the Gi/SGi reference point defines the interworking
+between +the 3GPP packet domain (PDN) based on GTP-U tunnel and IP
+based networks.
+
+There is no provision in any of the 3GPP documents that limits the
+number of Gi/SGi interfaces implemented by a GGSN/P-GW.
+
+[3GPP TS 29.061] Section 11.3 makes it clear that the selection of a
+specific Gi/SGi interfaces is made through the Access Point Name
+(APN):
+
+> 2. each private network manages its own addressing. In general this
+>will result in different private networks having overlapping
+>address ranges. A logically separate connection (e.g. an IP in IP
+>tunnel or layer 2 virtual circuit) is used between the GGSN/P-GW
+>and each private network.
+>
+>In this case the IP address alone is not necessarily unique.  The
+>pair of valu

[PATCH net-next 0/4] gtp: support multiple APN's per GTP endpoint

2017-03-14 Thread Andreas Schultz
Support multiple APN's per GTP endpoint and as an additional benefit support
multiple GTP sockets per GTP entity.

Use case multiple APN's:


In 3GPP a APN is control path construct. When mappend into the data path,
it mean that UE IP's can be source from independended IP networks with
overlaping IP ranges.

3GPP, TS 29.061 version 13.6.0 Release 13, Section 11.3 describes this as:

> 2. each private network manages its own addressing. In general this will
>result in different private networks having overlapping address ranges.
>A logically separate connection (e.g. an IP in IP tunnel or layer 2
>virtual circuit) is used between the GGSN/P-GW and each private network.
>In this case the IP address alone is not necessarily unique. The pair
>of values, Access Point Name (APN) and IPv4 address and/or IPv6 prefixes,
>is unique.

To support such a setup, each APN is mapped to a Linux network device.
VRF-Lite, network namespaces or other mechanismns can the be used to realize
the full separation of the per APN IP networks.

Use case multiple GTP sockets per GTP entity:
-

A GTP entity like a PGW can use multiple GTP sockets for:

 * separate IPv4 and IPv6 transport endpoints
 * support multiple reference points in separated IP networks, e.g. have
   Gn/Gp/S5/S8 in a GRX attaches network and S2a/S2b in another private
   network

Especially the S2a/S2b separation is an important scenario. The networks
use for roaming and non roaming attachment (Gn/Gp/S5/S8 reference points)
are usually different from the connection for trusted and untrusted WiFi
access (S2a/S2b). Will the GTP transport networks are separated, it is
still desirable to terminated the tunnels in the same GTP entity to ensure
uninterrupted IP connectivity during 3G/LTE to/from WiFi handover.

Implementation:
---

APN's are a control path construct, the identification of the associated network
device need therefore to be bound to be tunnel endpoint identifier.

This series moves the hash for the incoming tunnel endpoint identifiers into
the socket to support multiple network devices per GTP socket. It the adds
a method of enabling the GTP encapsulation on a socket without having to
bound the socket to a network device and finally allows to specify a GTP
socket per PDP context.

API impact:
---

This is probably the most problematic part of this series...

The removeal of the TEID form the netdevice also means that the gtp genl API
for retriving tunnel information and removing tunnels needs to be adjusted.

Before this change it was possible to change a GTP tunnel using the gtp
netdevice id and the teid. The teid is no longer unique per gtp netdevice.
After this change it has to be either the netdevice and MS IP or the GTP
socket and teid.

Fortunatly, libgtpnl has always populated the Link Id, TEID, GSN Peer IP and
MS IP. The library interface has ensured that all information that is mandatory
after this change is guaranteed to be present.

The only project that doesn't use libgtpnl (OpenAir-CN) is also populating
all of those values.

The API change will therefore not break any existing userspace applications.

--
Andreas Schultz (4):
  gtp: move TEID hash to per socket structure
  gtp: add genl cmd to enable GTP encapsulation on UDP socket
  gtp: add support to select a GTP socket during PDP context creation
  Extend Kernel GTP-U tunneling documentation

 Documentation/networking/gtp.txt | 103 ++-
 drivers/net/gtp.c| 263 ---
 include/uapi/linux/gtp.h |   4 +
 3 files changed, 292 insertions(+), 78 deletions(-)

-- 
2.10.2



Re: [PATCH net-next v5 0/7] gtp: misc improvements

2017-03-13 Thread Andreas Schultz
Hi Pablo,

- On Mar 13, 2017, at 5:48 PM, pablo pa...@netfilter.org wrote:

> On Thu, Mar 09, 2017 at 05:42:55PM +0100, Andreas Schultz wrote:
>> Hi Pablo,
>> 
>> This is a resent of last series that missed the merge window. There
>> are no changes compared to v4.
>> 
>> v4: Compared to v3 it contains mostly smallish naming and spelling fixes.
>> It also drops the documentation patch, Harald did a better job with the
>> documentation and the some things I described do not yet match the
>> implementation.
>> I'll readd the relevant parts with a follow up series.
>> 
>> This series lays the groundwork for removing the socket references from
>> the GTP netdevice by removing duplicate code and simplifying the logic on
>> some code paths.
>> 
>> It slighly changes the GTP genl API by making the socket parameters optional
>> (though one of them is still required).
>> 
>> The removal of the socket references will break the 1:1 releation between
>> GTP netdevice and GTP socket that prevents us to support multiple VRFs with
>> overlapping IP addresse spaces attached to the same GTP-U entity (needed for
>> multi APN support, coming a follow up series).
>> 
>> Pablo found a socket hold problem in v2. In order to solve that I had to
>> switch the socket references from the struct socket to the internal
>> struct sock. This should have no functionl impact, but we can now hang
>> on to the reference without blocking user space from closing the GTP socket.
> 
> Acked-by: Pablo Neira Ayuso <pa...@netfilter.org>

Thanks, Pablo.
 
> I personally don't like this podge hodge unsorted submissions, I don't
> think they belong to the same series but you keep pushing with this
> patchset in this same way, which is annoying.

I don't think this a podge hodge series. There is a clear goal behind all
those changes and every patch is a step towards this. When I tried to
send the full series including the final change that ties everything
together, I got told that this was way too much. Now, that I split it into
a smaller series, I get told that there is no clear idea connecting those
changes.

Frankly, between the two options, I had no idea how else to submit this
work.

> In your follow up patchsets, please split them in smaller series that
> are related.

Now that the basic infrastructure changes are in place, the followup
changes are much more focused.

The IPv6 transport change might be challenge later one, but that will be
a separate series anyway.

> I would like you take the time to develop the VRF idea that you want
> to introduce, I just would like that we avoid bloating the GTP tunnel
> with features that we can just achieve via composite of different
> subsystems.

The VRF change is more about moving stuff around, it doesn't add much.
But you'll see that for yourself when I send the changes.

> Thank you.

Thank you,
Andreas


[PATCH net-next v5 4/7] gtp: consolidate gtp socket rx path

2017-03-09 Thread Andreas Schultz
Add network device to gtp context in preparation for splitting
the TEID from the network device.

Use this to rework the socker rx path. Move the common RX part
of v0 and v1 into a helper. Also move the final rx part into
that helper as well.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 80 ++-
 1 file changed, 44 insertions(+), 36 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 74018eb..0c6707a 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,8 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct net_device   *dev;
+
atomic_ttx_seq;
struct rcu_head rcu_head;
 };
@@ -175,6 +177,40 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct 
pdp_ctx *pctx,
return false;
 }
 
+static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int 
hdrlen,
+ bool xnet)
+{
+   struct pcpu_sw_netstats *stats;
+
+   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
+   netdev_dbg(pctx->dev, "No PDP ctx for this MS\n");
+   return 1;
+   }
+
+   /* Get rid of the GTP + UDP headers. */
+   if (iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet))
+   return -1;
+
+   netdev_dbg(pctx->dev, "forwarding packet from GGSN to uplink\n");
+
+   /* Now that the UDP and the GTP header have been removed, set up the
+* new network header. This is required by the upper layer to
+* calculate the transport header.
+*/
+   skb_reset_network_header(skb);
+
+   skb->dev = pctx->dev;
+
+   stats = this_cpu_ptr(pctx->dev->tstats);
+   u64_stats_update_begin(>syncp);
+   stats->rx_packets++;
+   stats->rx_bytes += skb->len;
+   u64_stats_update_end(>syncp);
+
+   netif_rx(skb);
+   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,
   bool xnet)
@@ -201,13 +237,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
return 1;
}
 
-   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
-   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return 1;
-   }
-
-   /* Get rid of the GTP + UDP headers. */
-   return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+   return gtp_rx(pctx, skb, hdrlen, xnet);
 }
 
 static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
@@ -250,13 +280,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return 1;
}
 
-   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
-   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return 1;
-   }
-
-   /* Get rid of the GTP + UDP headers. */
-   return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+   return gtp_rx(pctx, skb, hdrlen, xnet);
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -290,10 +314,9 @@ static void gtp_encap_disable(struct gtp_dev *gtp)
  */
 static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
-   struct pcpu_sw_netstats *stats;
struct gtp_dev *gtp;
+   int ret = 0;
bool xnet;
-   int ret;
 
gtp = rcu_dereference_sk_user_data(sk);
if (!gtp)
@@ -319,33 +342,17 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
switch (ret) {
case 1:
netdev_dbg(gtp->dev, "pass up to the process\n");
-   return 1;
+   break;
case 0:
-   netdev_dbg(gtp->dev, "forwarding packet from GGSN to uplink\n");
break;
case -1:
netdev_dbg(gtp->dev, "GTP packet has been dropped\n");
kfree_skb(skb);
-   return 0;
+   ret = 0;
+   break;
}
 
-   /* Now that the UDP and the GTP header have been removed, set up the
-* new network header. This is required by the upper layer to
-* calculate the transport header.
-*/
-   skb_reset_network_header(skb);
-
-   skb->dev = gtp->dev;
-
-   stats = this_cpu_ptr(gtp->dev->tstats);
-   u64_stats_update_begin(>syncp);
-   stats->rx_packets++;
-   stats->rx_bytes += skb->len;
-   u64_stats_update_end(>syncp);
-
-   netif_rx(skb);
-
-   return 0;
+   return ret;
 }
 
 static int gtp_dev_init(struct net_device *dev)
@@ -951,6 +958,7 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
if (pctx == NULL)
return -ENOMEM;
 
+   pctx->dev = gtp->dev;
ipv4_pdp_fill(pctx, info);
atomic_set(>tx_seq, 0);
 
-- 
2.10.2



[PATCH net-next v5 2/7] gtp: make GTP sockets in gtp_newlink optional

2017-03-09 Thread Andreas Schultz
Having both GTPv0-U and GTPv1-U is not always desirable.
Fallback from GTPv1-U to GTPv0-U was depreciated from 3GPP
Rel-8 onwards. Post Rel-8 implementation are discuraged
from listening on the v0 port (see 3GPP TS 29.281, Sect. 1).

A future change will completely decouple the sockets from the
network device. Till then, at least one of the sockets needs to
be specified (either v0 or v1), the other is optional.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 148 --
 1 file changed, 78 insertions(+), 70 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index e1b5af3..9aa2b35 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -259,30 +259,30 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
 }
 
-static void gtp_encap_disable(struct gtp_dev *gtp)
-{
-   if (gtp->sk0) {
-   udp_sk(gtp->sk0)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sk0, NULL);
-   sock_put(gtp->sk0);
-   }
-   if (gtp->sk1u) {
-   udp_sk(gtp->sk1u)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sk1u, NULL);
-   sock_put(gtp->sk1u);
-   }
-
-   gtp->sk0 = NULL;
-   gtp->sk1u = NULL;
-}
-
 static void gtp_encap_destroy(struct sock *sk)
 {
struct gtp_dev *gtp;
 
gtp = rcu_dereference_sk_user_data(sk);
-   if (gtp)
-   gtp_encap_disable(gtp);
+   if (gtp) {
+   udp_sk(sk)->encap_type = 0;
+   rcu_assign_sk_user_data(sk, NULL);
+   sock_put(sk);
+   }
+}
+
+static void gtp_encap_disable_sock(struct sock *sk)
+{
+   if (!sk)
+   return;
+
+   gtp_encap_destroy(sk);
+}
+
+static void gtp_encap_disable(struct gtp_dev *gtp)
+{
+   gtp_encap_disable_sock(gtp->sk0);
+   gtp_encap_disable_sock(gtp->sk1u);
 }
 
 /* UDP encapsulation receive handler. See net/ipv4/udp.c.
@@ -642,27 +642,23 @@ static void gtp_link_setup(struct net_device *dev)
 
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
 static void gtp_hashtable_free(struct gtp_dev *gtp);
-static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1);
+static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]);
 
 static int gtp_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
 {
-   int hashsize, err, fd0, fd1;
struct gtp_dev *gtp;
struct gtp_net *gn;
+   int hashsize, err;
 
-   if (!data[IFLA_GTP_FD0] || !data[IFLA_GTP_FD1])
+   if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1])
return -EINVAL;
 
gtp = netdev_priv(dev);
 
-   fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
-   fd1 = nla_get_u32(data[IFLA_GTP_FD1]);
-
-   err = gtp_encap_enable(dev, gtp, fd0, fd1);
+   err = gtp_encap_enable(gtp, data);
if (err < 0)
-   goto out_err;
+   return err;
 
if (!data[IFLA_GTP_PDP_HASHSIZE])
hashsize = 1024;
@@ -690,7 +686,6 @@ static int gtp_newlink(struct net *src_net, struct 
net_device *dev,
gtp_hashtable_free(gtp);
 out_encap:
gtp_encap_disable(gtp);
-out_err:
return err;
 }
 
@@ -805,63 +800,76 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
kfree(gtp->tid_hash);
 }
 
-static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1)
+static struct sock *gtp_encap_enable_socket(int fd, int type,
+   struct gtp_dev *gtp)
 {
struct udp_tunnel_sock_cfg tuncfg = {NULL};
-   struct socket *sock0, *sock1u;
+   struct socket *sock;
+   struct sock *sk;
int err;
 
-   netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1);
+   pr_debug("enable gtp on %d, %d\n", fd, type);
 
-   sock0 = sockfd_lookup(fd_gtp0, );
-   if (sock0 == NULL) {
-   netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0);
-   return -ENOENT;
+   sock = sockfd_lookup(fd, );
+   if (!sock) {
+   pr_debug("gtp socket fd=%d not found\n", fd);
+   return NULL;
}
 
-   if (sock0->sk->sk_protocol != IPPROTO_UDP) {
-   netdev_dbg(dev, "socket fd=%d not UDP\n", fd_gtp0);
-   err = -EINVAL;
-   goto err1;
+   if (sock->sk->sk_protocol != IPPROTO_UDP) {
+   pr_debug("socket fd=%d not UDP\n", fd);
+   sk = ERR_PTR(-EINVAL);
+   goto out_sock;
}
 
-   sock1u = sockfd_lookup(fd_gtp1, 

[PATCH net-next v5 5/7] gtp: unify genl_find_pdp and prepare for per socket lookup

2017-03-09 Thread Andreas Schultz
This unifies duplicate code into a helper. It also prepares the
groundwork to add a lookup version that uses the socket to find
attached pdp contexts.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 121 ++
 1 file changed, 50 insertions(+), 71 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 0c6707a..bf4b352 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1037,55 +1037,67 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
return err;
 }
 
+static struct pdp_ctx *gtp_find_pdp_by_link(struct net *net,
+   struct nlattr *nla[])
+{
+   struct gtp_dev *gtp;
+
+   gtp = gtp_find_dev(net, nla);
+   if (!gtp)
+   return ERR_PTR(-ENODEV);
+
+   if (nla[GTPA_MS_ADDRESS]) {
+   __be32 ip = nla_get_be32(nla[GTPA_MS_ADDRESS]);
+
+   return ipv4_pdp_find(gtp, ip);
+   } else if (nla[GTPA_VERSION]) {
+   u32 gtp_version = nla_get_u32(nla[GTPA_VERSION]);
+
+   if (gtp_version == GTP_V0 && nla[GTPA_TID])
+   return gtp0_pdp_find(gtp, nla_get_u64(nla[GTPA_TID]));
+   else if (gtp_version == GTP_V1 && nla[GTPA_I_TEI])
+   return gtp1_pdp_find(gtp, nla_get_u32(nla[GTPA_I_TEI]));
+   }
+
+   return ERR_PTR(-EINVAL);
+}
+
+static struct pdp_ctx *gtp_find_pdp(struct net *net, struct nlattr *nla[])
+{
+   struct pdp_ctx *pctx;
+
+   if (nla[GTPA_LINK])
+   pctx = gtp_find_pdp_by_link(net, nla);
+   else
+   pctx = ERR_PTR(-EINVAL);
+
+   if (!pctx)
+   pctx = ERR_PTR(-ENOENT);
+
+   return pctx;
+}
+
 static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
 {
struct pdp_ctx *pctx;
-   struct gtp_dev *gtp;
int err = 0;
 
-   if (!info->attrs[GTPA_VERSION] ||
-   !info->attrs[GTPA_LINK])
+   if (!info->attrs[GTPA_VERSION])
return -EINVAL;
 
rcu_read_lock();
 
-   gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
-   if (!gtp) {
-   err = -ENODEV;
-   goto out_unlock;
-   }
-
-   switch (nla_get_u32(info->attrs[GTPA_VERSION])) {
-   case GTP_V0:
-   if (!info->attrs[GTPA_TID]) {
-   err = -EINVAL;
-   goto out_unlock;
-   }
-   pctx = gtp0_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_TID]));
-   break;
-   case GTP_V1:
-   if (!info->attrs[GTPA_I_TEI]) {
-   err = -EINVAL;
-   goto out_unlock;
-   }
-   pctx = gtp1_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_I_TEI]));
-   break;
-
-   default:
-   err = -EINVAL;
-   goto out_unlock;
-   }
-
-   if (!pctx) {
-   err = -ENOENT;
+   pctx = gtp_find_pdp(sock_net(skb->sk), info->attrs);
+   if (IS_ERR(pctx)) {
+   err = PTR_ERR(pctx);
goto out_unlock;
}
 
if (pctx->gtp_version == GTP_V0)
-   netdev_dbg(gtp->dev, "GTPv0-U: deleting tunnel id = %llx (pdp 
%p)\n",
+   netdev_dbg(pctx->dev, "GTPv0-U: deleting tunnel id = %llx (pdp 
%p)\n",
   pctx->u.v0.tid, pctx);
else if (pctx->gtp_version == GTP_V1)
-   netdev_dbg(gtp->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp 
%p)\n",
+   netdev_dbg(pctx->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp 
%p)\n",
   pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
 
hlist_del_rcu(>hlist_tid);
@@ -1139,49 +1151,16 @@ static int gtp_genl_get_pdp(struct sk_buff *skb, struct 
genl_info *info)
 {
struct pdp_ctx *pctx = NULL;
struct sk_buff *skb2;
-   struct gtp_dev *gtp;
-   u32 gtp_version;
int err;
 
-   if (!info->attrs[GTPA_VERSION] ||
-   !info->attrs[GTPA_LINK])
+   if (!info->attrs[GTPA_VERSION])
return -EINVAL;
 
-   gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]);
-   switch (gtp_version) {
-   case GTP_V0:
-   case GTP_V1:
-   break;
-   default:
-   return -EINVAL;
-   }
-
rcu_read_lock();
 
-   gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
-   if (!gtp) {
-   err = -ENODEV;
-   goto err_unlock;
-   }
-
-   if (gtp_version == GTP_V0 &&
-   info->attrs[GTPA_TID]) {
-   u64 tid = nla_get_u64(info->attrs[GTPA_TID]);
-
-   pctx = gtp0_pdp_find(gtp, tid);
-   } else if (gtp_version == GTP_V1 &&
-

[PATCH net-next v5 7/7] gtp: add socket to pdp context

2017-03-09 Thread Andreas Schultz
Having the socket present in context simplifies the sending logic.
It also fixes the invalid assumption that we have to use the same
sending socket for all client IP's on a specific gtp interface.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 94 +++
 1 file changed, 47 insertions(+), 47 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index d58f46f..3e1854f 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,7 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct sock *sk;
struct net_device   *dev;
 
atomic_ttx_seq;
@@ -179,8 +180,7 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct 
pdp_ctx *pctx,
return false;
 }
 
-static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int 
hdrlen,
- bool xnet)
+static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int 
hdrlen)
 {
struct pcpu_sw_netstats *stats;
 
@@ -190,7 +190,8 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff 
*skb, unsigned int hdrlen
}
 
/* Get rid of the GTP + UDP headers. */
-   if (iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet))
+   if (iptunnel_pull_header(skb, hdrlen, skb->protocol,
+!net_eq(sock_net(pctx->sk), 
dev_net(pctx->dev
return -1;
 
netdev_dbg(pctx->dev, "forwarding packet from GGSN to uplink\n");
@@ -214,8 +215,7 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff 
*skb, unsigned int hdrlen
 }
 
 /* 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,
-  bool xnet)
+static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp0_header);
@@ -239,11 +239,10 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return 1;
}
 
-   return gtp_rx(pctx, skb, hdrlen, xnet);
+   return gtp_rx(pctx, skb, hdrlen);
 }
 
-static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
-   bool xnet)
+static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp1_header);
@@ -282,7 +281,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
return 1;
}
 
-   return gtp_rx(pctx, skb, hdrlen, xnet);
+   return gtp_rx(pctx, skb, hdrlen);
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -318,7 +317,6 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 {
struct gtp_dev *gtp;
int ret = 0;
-   bool xnet;
 
gtp = rcu_dereference_sk_user_data(sk);
if (!gtp)
@@ -326,16 +324,14 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
 
-   xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
-
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
netdev_dbg(gtp->dev, "received GTP0 packet\n");
-   ret = gtp0_udp_encap_recv(gtp, skb, xnet);
+   ret = gtp0_udp_encap_recv(gtp, skb);
break;
case UDP_ENCAP_GTP1U:
netdev_dbg(gtp->dev, "received GTP1U packet\n");
-   ret = gtp1u_udp_encap_recv(gtp, skb, xnet);
+   ret = gtp1u_udp_encap_recv(gtp, skb);
break;
default:
ret = -1; /* Shouldn't happen. */
@@ -378,8 +374,9 @@ static void gtp_dev_uninit(struct net_device *dev)
free_percpu(dev->tstats);
 }
 
-static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4,
-  const struct sock *sk, __be32 daddr)
+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;
@@ -388,7 +385,7 @@ static struct rtable *ip4_route_output_gtp(struct net *net, 
struct flowi4 *fl4,
fl4->flowi4_tos = RT_CONN_FLAGS(sk);
fl4->flowi4_proto   = sk->sk_protocol;
 
-   return ip_route_output_key(net, fl4);
+   return ip_route_output_key(sock_net(sk), fl4);
 }
 
 static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
@@ -477,7 +474,6 @@ static int gtp_build_skb_ip4(stru

[PATCH net-next v5 1/7] gtp: switch from struct socket to struct sock for the GTP sockets

2017-03-09 Thread Andreas Schultz
After enabling the UDP encapsulation, only the sk member is used.

Holding the socket would prevent user space from closing the socket,
but holding a reference to the sk member does not have the same
effect.

This change will make it simpler to later detach the sockets from
the netdevice.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 42 +++---
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 8969874..e1b5af3 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -66,8 +66,8 @@ struct pdp_ctx {
 struct gtp_dev {
struct list_headlist;
 
-   struct socket   *sock0;
-   struct socket   *sock1u;
+   struct sock *sk0;
+   struct sock *sk1u;
 
struct net_device   *dev;
 
@@ -261,17 +261,19 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
 
 static void gtp_encap_disable(struct gtp_dev *gtp)
 {
-   if (gtp->sock0 && gtp->sock0->sk) {
-   udp_sk(gtp->sock0->sk)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sock0->sk, NULL);
+   if (gtp->sk0) {
+   udp_sk(gtp->sk0)->encap_type = 0;
+   rcu_assign_sk_user_data(gtp->sk0, NULL);
+   sock_put(gtp->sk0);
}
-   if (gtp->sock1u && gtp->sock1u->sk) {
-   udp_sk(gtp->sock1u->sk)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sock1u->sk, NULL);
+   if (gtp->sk1u) {
+   udp_sk(gtp->sk1u)->encap_type = 0;
+   rcu_assign_sk_user_data(gtp->sk1u, NULL);
+   sock_put(gtp->sk1u);
}
 
-   gtp->sock0 = NULL;
-   gtp->sock1u = NULL;
+   gtp->sk0 = NULL;
+   gtp->sk1u = NULL;
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -484,14 +486,14 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
 
switch (pctx->gtp_version) {
case GTP_V0:
-   if (gtp->sock0)
-   sk = gtp->sock0->sk;
+   if (gtp->sk0)
+   sk = gtp->sk0;
else
sk = NULL;
break;
case GTP_V1:
-   if (gtp->sock1u)
-   sk = gtp->sock1u->sk;
+   if (gtp->sk1u)
+   sk = gtp->sk1u;
else
sk = NULL;
break;
@@ -504,7 +506,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
return -ENOENT;
}
 
-   rt = ip4_route_output_gtp(sock_net(sk), , gtp->sock0->sk,
+   rt = ip4_route_output_gtp(sock_net(sk), , gtp->sk0,
  pctx->sgsn_addr_ip4.s_addr);
if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to SSGN %pI4\n",
@@ -839,18 +841,20 @@ static int gtp_encap_enable(struct net_device *dev, 
struct gtp_dev *gtp,
 
netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u);
 
-   gtp->sock0 = sock0;
-   gtp->sock1u = sock1u;
+   sock_hold(sock0->sk);
+   gtp->sk0 = sock0->sk;
+   sock_hold(sock1u->sk);
+   gtp->sk1u = sock1u->sk;
 
tuncfg.sk_user_data = gtp;
tuncfg.encap_rcv = gtp_encap_recv;
tuncfg.encap_destroy = gtp_encap_destroy;
 
tuncfg.encap_type = UDP_ENCAP_GTP0;
-   setup_udp_tunnel_sock(sock_net(gtp->sock0->sk), gtp->sock0, );
+   setup_udp_tunnel_sock(sock_net(gtp->sk0), sock0, );
 
tuncfg.encap_type = UDP_ENCAP_GTP1U;
-   setup_udp_tunnel_sock(sock_net(gtp->sock1u->sk), gtp->sock1u, );
+   setup_udp_tunnel_sock(sock_net(gtp->sk1u), sock1u, );
 
err = 0;
 err2:
-- 
2.10.2



[PATCH net-next v5 6/7] gtp: consolidate pdp context destruction into helper

2017-03-09 Thread Andreas Schultz
Consolidate duplicate code into helper.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 24 ++--
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index bf4b352..d58f46f 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -86,6 +86,8 @@ struct gtp_net {
 
 static u32 gtp_h_initval;
 
+static void pdp_context_delete(struct pdp_ctx *pctx);
+
 static inline u32 gtp0_hashfn(u64 tid)
 {
u32 *tid32 = (u32 *) 
@@ -780,13 +782,10 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
struct pdp_ctx *pctx;
int i;
 
-   for (i = 0; i < gtp->hash_size; i++) {
-   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid) {
-   hlist_del_rcu(>hlist_tid);
-   hlist_del_rcu(>hlist_addr);
-   kfree_rcu(pctx, rcu_head);
-   }
-   }
+   for (i = 0; i < gtp->hash_size; i++)
+   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid)
+   pdp_context_delete(pctx);
+
synchronize_rcu();
kfree(gtp->addr_hash);
kfree(gtp->tid_hash);
@@ -995,6 +994,13 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
return 0;
 }
 
+static void pdp_context_delete(struct pdp_ctx *pctx)
+{
+   hlist_del_rcu(>hlist_tid);
+   hlist_del_rcu(>hlist_addr);
+   kfree_rcu(pctx, rcu_head);
+}
+
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
struct gtp_dev *gtp;
@@ -1100,9 +1106,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct 
genl_info *info)
netdev_dbg(pctx->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp 
%p)\n",
   pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
 
-   hlist_del_rcu(>hlist_tid);
-   hlist_del_rcu(>hlist_addr);
-   kfree_rcu(pctx, rcu_head);
+   pdp_context_delete(pctx);
 
 out_unlock:
rcu_read_unlock();
-- 
2.10.2



[PATCH net-next v5 0/7] gtp: misc improvements

2017-03-09 Thread Andreas Schultz
Hi Pablo,

This is a resent of last series that missed the merge window. There
are no changes compared to v4.

v4: Compared to v3 it contains mostly smallish naming and spelling fixes.
It also drops the documentation patch, Harald did a better job with the
documentation and the some things I described do not yet match the 
implementation.
I'll readd the relevant parts with a follow up series.

This series lays the groundwork for removing the socket references from
the GTP netdevice by removing duplicate code and simplifying the logic on
some code paths.

It slighly changes the GTP genl API by making the socket parameters optional
(though one of them is still required).

The removal of the socket references will break the 1:1 releation between
GTP netdevice and GTP socket that prevents us to support multiple VRFs with
overlapping IP addresse spaces attached to the same GTP-U entity (needed for
multi APN support, coming a follow up series).

Pablo found a socket hold problem in v2. In order to solve that I had to
switch the socket references from the struct socket to the internal
struct sock. This should have no functionl impact, but we can now hang
on to the reference without blocking user space from closing the GTP socket.

v4->v5:
 * resent for new merge window
v3->v4:
 * drop the documentation patch
 * spelling fixes
 * pass nlattr instead of genl_info into gtp_find_dev,
   makes the code slightly more compact and readable
v2->v3:
 * add documentation to explain the goal of all these changes
 * incorporate review comments
 * switch from struct socket to struct sock

Regards
Andreas

--
Andreas Schultz (7):
  gtp: switch from struct socket to struct sock for the GTP sockets
  gtp: make GTP sockets in gtp_newlink optional
  gtp: merge gtp_get_net and gtp_genl_find_dev
  gtp: consolidate gtp socket rx path
  gtp: unify genl_find_pdp and prepare for per socket lookup
  gtp: consolidate pdp context destruction into helper
  gtp: add socket to pdp context

 drivers/net/gtp.c | 543 +++---
 1 file changed, 269 insertions(+), 274 deletions(-)

-- 
2.10.2



[PATCH net-next v5 3/7] gtp: merge gtp_get_net and gtp_genl_find_dev

2017-03-09 Thread Andreas Schultz
Both function are always used together with the final goal to
get the gtp_dev. This simplifies the code by merging them together.

The netdevice lookup is changed to use the regular dev_get_by_index.
The gtp netdevice list is now only used to find the PDP contexts for
imcomming packets. It can be completely eliminated Once the TEID
hash is moved into the GTP socket.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 146 ++
 1 file changed, 69 insertions(+), 77 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 9aa2b35..74018eb 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -744,21 +744,6 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = {
.fill_info  = gtp_fill_info,
 };
 
-static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[])
-{
-   struct net *net;
-
-   /* Examine the link attributes and figure out which network namespace
-* we are talking about.
-*/
-   if (tb[GTPA_NET_NS_FD])
-   net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD]));
-   else
-   net = get_net(src_net);
-
-   return net;
-}
-
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize)
 {
int i;
@@ -872,16 +857,30 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct 
nlattr *data[])
return 0;
 }
 
-static struct net_device *gtp_find_dev(struct net *net, int ifindex)
+static struct gtp_dev *gtp_find_dev(struct net *src_net, struct nlattr *nla[])
 {
-   struct gtp_net *gn = net_generic(net, gtp_net_id);
-   struct gtp_dev *gtp;
-
-   list_for_each_entry_rcu(gtp, >gtp_dev_list, list) {
-   if (ifindex == gtp->dev->ifindex)
-   return gtp->dev;
-   }
-   return NULL;
+   struct gtp_dev *gtp = NULL;
+   struct net_device *dev;
+   struct net *net;
+
+   /* Examine the link attributes and figure out which network namespace
+* we are talking about.
+*/
+   if (nla[GTPA_NET_NS_FD])
+   net = get_net_ns_by_fd(nla_get_u32(nla[GTPA_NET_NS_FD]));
+   else
+   net = get_net(src_net);
+
+   if (IS_ERR(net))
+   return NULL;
+
+   /* Check if there's an existing gtpX device to configure */
+   dev = dev_get_by_index_rcu(net, nla_get_u32(nla[GTPA_LINK]));
+   if (dev->netdev_ops == _netdev_ops)
+   gtp = netdev_priv(dev);
+
+   put_net(net);
+   return gtp;
 }
 
 static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
@@ -911,9 +910,9 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct 
genl_info *info)
}
 }
 
-static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
+static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info)
 {
-   struct gtp_dev *gtp = netdev_priv(dev);
+   struct net_device *dev = gtp->dev;
u32 hash_ms, hash_tid = 0;
struct pdp_ctx *pctx;
bool found = false;
@@ -990,8 +989,8 @@ static int ipv4_pdp_add(struct net_device *dev, struct 
genl_info *info)
 
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
-   struct net_device *dev;
-   struct net *net;
+   struct gtp_dev *gtp;
+   int err;
 
if (!info->attrs[GTPA_VERSION] ||
!info->attrs[GTPA_LINK] ||
@@ -1015,77 +1014,79 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
return -EINVAL;
}
 
-   net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
-   if (IS_ERR(net))
-   return PTR_ERR(net);
+   rcu_read_lock();
 
-   /* Check if there's an existing gtpX device to configure */
-   dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
-   if (dev == NULL) {
-   put_net(net);
-   return -ENODEV;
+   gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
+   if (!gtp) {
+   err = -ENODEV;
+   goto out_unlock;
}
-   put_net(net);
 
-   return ipv4_pdp_add(dev, info);
+   err = ipv4_pdp_add(gtp, info);
+
+out_unlock:
+   rcu_read_unlock();
+   return err;
 }
 
 static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
 {
-   struct net_device *dev;
struct pdp_ctx *pctx;
struct gtp_dev *gtp;
-   struct net *net;
+   int err = 0;
 
if (!info->attrs[GTPA_VERSION] ||
!info->attrs[GTPA_LINK])
return -EINVAL;
 
-   net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
-   if (IS_ERR(net))
-   return PTR_ERR(net);
+   rcu_read_lock();
 
-   /* Check if there's an existing gtpX device to configure */
-   dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
-   if (dev == NULL) {
-

Re: [PATCH net-next] net/gtp: Add udp source port generation according to flow hash

2017-02-23 Thread Andreas Schultz


- On Feb 23, 2017, at 5:42 PM, pablo pa...@netfilter.org wrote:

> On Thu, Feb 23, 2017 at 03:21:13PM +0100, Andreas Schultz wrote:
>> - On Feb 23, 2017, at 2:49 PM, pablo pa...@netfilter.org wrote:
> [...]
>> > According to specs, section 4.4.2.3 Encapsulated T-PDU, TS 29.281.
>> > 
>> > "The UDP Source Port is a locally allocated port number at the sending
>> > GTP-U entity."
>> > 
>> > Older specs that refer to GTP-U such as TS 09.60 and TS 29.060 also
>> > state the same.
>> 
>> It is absolutely valid the choose any sending port you want. I only
>> think you should know which port you did send on.
>> 
>> TS 29.281, Sect. 5.2.2.1 defines the UDP port extension to be used
>> in error indications. It provides the UDP source port of a G-PDU
>> that triggered an error.
>> 
>> If the send side does not know which port it uses to send, how
>> can it use this indication to correlate an error? That's the reason
>> I thought it would be better to add the UDP source port to the
>> PDP context and allow the control path to assign the source port
>> on context creation.
>> 
>> Of course, this header is optional and the receiving side is not
>> required to use it.
>> 
>> About the RSS spreading in the receive side, I would think that
>> a receiver would prefer to process all packets that belong to a
>> give TEID with the same receive instance. So keeping the UDP
>> source port for a given TEID stable would be beneficial. As far
>> as I understand it, the hash used in the patch uses the source
>> and destination values from the original flow. This would mean
>> that GTP packets that belong to the same TEID would end up with
>> different UDP source ports.
> 
> The receiver needs to scale up, and that happens if packets are
> distributed between CPUs in a way that make sense. I don't think it
> makes sense to pass packets that belong to the same tunnel to the same
> CPU, this is exactly the scenario that makes DDOS easier to trigger.

When we are talking about the xmit path, then currently none of the
receivers we are talking to is going to be Linux and we have no
idea how they will behave nor do we have any influence on them. Do
we really need to make assumptions about other vendors implementations?

Traces on live GRX networks show that about 90% of the SGSN/S-GW
that would talk to us always use the default GTP-U port as source
port. Some multi chassis GSN's seem to assign source port ranges to
chassis, but that has nothing todo with DDOS protection.

So, even when do the randomization on TX, it won't help our receiver
scale up. We have to deal what the other (100% non Linux side is
going to throw at us).

>> So what about this as a compromise, we dd a UDP source port field
>> to the PDP context, it defaults to 0 (zero), the control instance
>> can optionally initialize this field, when we hit the xmit code
>> and the port is non zero, use that value, if it is zero use the hash?
> 
> You want to use this for your VRF concept? I would like that you take
> the time to explain us your usecases.

I only want the normal multi APN per GGSN/P-GW setup that every mobile
carrier on this world is running on the big commercial vendor boxes, nothing
more and nothing less.

I have tried to explain this multiple times already, but it seems I
failed every time to put it in intelligible form. The last attempt
was here: http://marc.info/?l=linux-netdev=148700022003294=2

> How are you going to use this mapping between tunnels and UDP source ports?

There is no mapping between tunnels and UDP source ports. UDP source
ports do not matter to the receiving side at all in GTP tunnels. There
is one error handling case that can benefit from knowing the source port
and I think that case shouldn't be discarded lightly.

A GTP-U tunnel is only defined by its destination IP, destination UDP port
(which is constant 2152) and it's TEID. This also means that a GTP tunnel
is a one-way construct. Only the GTP-C instance knows that a PDP context
is actually two GTP-U tunnels, one in each direction.

We had the discussion if the source IP does play a role in this. The
3GPP specifications do not make a 100% clear statement for GTP-U on that.
So the case can be made that the GTP-U tunnel pair should be symmetric
(the destination IP of one tunnel is the source of the other). There
are various other statements in the documents that imply that this is
not always the case.

I thought we had come to the conclusion (with Harald) to make the reverse
GSN peer filter an option. Then every control path implementation has
the choice to use it or not. The same should IMHO apply to the source port
randomization.

For GTP-C the situation is clear, the control instance has to

Re: [PATCH net-next] net/gtp: Add udp source port generation according to flow hash

2017-02-23 Thread Andreas Schultz
- On Feb 23, 2017, at 2:49 PM, pablo pa...@netfilter.org wrote:

> On Wed, Feb 22, 2017 at 01:47:17PM -0800, Tom Herbert wrote:
>> On Wed, Feb 22, 2017 at 1:29 PM, Or Gerlitz <gerlitz...@gmail.com> wrote:
>> > On Thu, Feb 16, 2017 at 11:58 PM, Andreas Schultz <aschu...@tpip.net> 
>> > wrote:
>> >> Hi Or,
>> >> - On Feb 16, 2017, at 3:59 PM, Or Gerlitz ogerl...@mellanox.com wrote:
>> >>
>> >>> Generate the source udp header according to the flow represented by
>> >>> the packet we are encapsulating, as done for other udp tunnels. This
>> >>> helps on the receiver side to apply RSS spreading.
>> >>
>> >> This might work for GTPv0-U, However, for GTPv1-U this could interfere
>> >> with error handling in the user space control process when the UDP port
>> >> extension  header is used in error indications.
>> >
>> >
>> > in the document you posted there's this quote "The source IP and port
>> > have no meaning and can change at any time" -- I assume it refers to
>> > v0? can we identify in the kernel code that we're on v0 and have the
>> > patch come into play?
>> >
>> >> 3GPP TS 29.281 Rel 13, section 5.2.2.1 defines the UDP port extension and
>> >> section 7.3.1 says that the UDP source port extension can be used to
>> >> mitigate DOS attacks. This would IMHO imply that the user space control
>> >> process needs to know the TEID to UDP source port mapping.
>> >
>> >> The other question is, on what is this actually hashing. When I understand
>> >> the code correctly, this will hash on the source/destination of the 
>> >> orignal
>> >> flow. I would expect that a SGSN/SGW/eNodeB would like the keep flow
>> >> processing on a per TEID base, so the port hashing should be base on the 
>> >> TEID.
>> >
>> > is it possible for packets belonging to the same TCP session or UDP
>> > "pseudo session" (given pair of src/dst ip/port) to be encapsulated
>> > using different TEID?
>> >
>> > hashing on the TEID imposes a harder requirement on the NIC HW vs.
>> > just UDP based RSS.
>> 
>> This shouldn't be taken as a HW requirement and it's unlikely we'd add
>> explicit GTP support in flow_dissector. If we can't get entropy in the
>> UDP source port then IPv6 flow label is a potential alternative (so
>> that should be supported in NICs for RSS).
> 
> According to specs, section 4.4.2.3 Encapsulated T-PDU, TS 29.281.
> 
> "The UDP Source Port is a locally allocated port number at the sending
> GTP-U entity."
> 
> Older specs that refer to GTP-U such as TS 09.60 and TS 29.060 also
> state the same.

It is absolutely valid the choose any sending port you want. I only
think you should know which port you did send on.

TS 29.281, Sect. 5.2.2.1 defines the UDP port extension to be used
in error indications. It provides the UDP source port of a G-PDU
that triggered an error.

If the send side does not know which port it uses to send, how
can it use this indication to correlate an error? That's the reason
I thought it would be better to add the UDP source port to the
PDP context and allow the control path to assign the source port
on context creation.

Of course, this header is optional and the receiving side is not
required to use it.

About the RSS spreading in the receive side, I would think that
a receiver would prefer to process all packets that belong to a
give TEID with the same receive instance. So keeping the UDP
source port for a given TEID stable would be beneficial. As far
as I understand it, the hash used in the patch uses the source
and destination values from the original flow. This would mean
that GTP packets that belong to the same TEID would end up with
different UDP source ports.

So what about this as a compromise, we dd a UDP source port field
to the PDP context, it defaults to 0 (zero), the control instance
can optionally initialize this field, when we hit the xmit code
and the port is non zero, use that value, if it is zero use the hash?

Regards
Andreas

> 
> So Or patch looks fine to me.


Re: [PATCH net-next] net/gtp: Add udp source port generation according to flow hash

2017-02-23 Thread Andreas Schultz
Hi Tom,

- On Feb 22, 2017, at 10:47 PM, Tom Herbert t...@herbertland.com wrote:

> On Wed, Feb 22, 2017 at 1:29 PM, Or Gerlitz <gerlitz...@gmail.com> wrote:
>> On Thu, Feb 16, 2017 at 11:58 PM, Andreas Schultz <aschu...@tpip.net> wrote:
>>> Hi Or,
>>> - On Feb 16, 2017, at 3:59 PM, Or Gerlitz ogerl...@mellanox.com wrote:
>>>
>>>> Generate the source udp header according to the flow represented by
>>>> the packet we are encapsulating, as done for other udp tunnels. This
>>>> helps on the receiver side to apply RSS spreading.
>>>
>>> This might work for GTPv0-U, However, for GTPv1-U this could interfere
>>> with error handling in the user space control process when the UDP port
>>> extension  header is used in error indications.
>>
>>
>> in the document you posted there's this quote "The source IP and port
>> have no meaning and can change at any time" -- I assume it refers to
>> v0? can we identify in the kernel code that we're on v0 and have the
>> patch come into play?
>>
>>> 3GPP TS 29.281 Rel 13, section 5.2.2.1 defines the UDP port extension and
>>> section 7.3.1 says that the UDP source port extension can be used to
>>> mitigate DOS attacks. This would IMHO imply that the user space control
>>> process needs to know the TEID to UDP source port mapping.
>>
>>> The other question is, on what is this actually hashing. When I understand
>>> the code correctly, this will hash on the source/destination of the orignal
>>> flow. I would expect that a SGSN/SGW/eNodeB would like the keep flow
>>> processing on a per TEID base, so the port hashing should be base on the 
>>> TEID.
>>
>> is it possible for packets belonging to the same TCP session or UDP
>> "pseudo session" (given pair of src/dst ip/port) to be encapsulated
>> using different TEID?
>>
>> hashing on the TEID imposes a harder requirement on the NIC HW vs.
>> just UDP based RSS.
> 
> This shouldn't be taken as a HW requirement and it's unlikely we'd add
> explicit GTP support in flow_dissector. If we can't get entropy in the
> UDP source port then IPv6 flow label is a potential alternative (so
> that should be supported in NICs for RSS).
> 
> I'll also reiterate my previous point about the need for GTP testing--
> in order for us to be able to evaluate the GTP datapath for things
> like performance or how they withstand against DDOS we really need an
> easy way to isolate the datapath.

GTP as specified is very unsecure by definition. It is meant to be run
only on *private* mobile carrier and intra mobile carrier EPC networks.
Running it openly on the public internet would be extremly foolish.

There are some mechanisms in GTPv1-C on how to handle overload and
more extensive mechanisms in GTPv2-C for overload handling. The basic
guiding principle is to simply drop any traffic that it can't handle.

Anyhow, I havn't seen anything in 3GPP or GSMA documents that deals
with DDOS.

There are guidelines like the GSMA's IR.88 that describe how the intra
carrier roaming should work and what security measures should be
implemented.

Traffic coming in at Gi/SGi or form the UE could create a DDOS on tunnel.
However, on the UE side you still have the RAN (eNODE, SGSN, S-GW) or
an ePDG that has to apply QoS and thereby limit traffic. On the Gi/SGi
side side you have the PCEF that does the same.

So in a complete 3GPP node (GGSN, P-GW) that uses the GTP tunnel
implementation, malicious traffic should be blocked before it can reach
the tunnel.

And as I stated before, the GTP tunnel module is not supposed to be
use without any of those components. So the DDOS concern should not
be handled at the tunnel level.

Andreas

> 
> Tom


Re: [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path

2017-02-23 Thread Andreas Schultz
Hi Tom,

- On Feb 22, 2017, at 6:41 PM, Tom Herbert t...@herbertland.com wrote:

> On Tue, Feb 21, 2017 at 2:18 AM, Andreas Schultz <aschu...@tpip.net> wrote:
>> Add network device to gtp context in preparation for splitting
>> the TEID from the network device.
>>
>> Use this to rework the socker rx path. Move the common RX part
>> of v0 and v1 into a helper. Also move the final rx part into
>> that helper as well.
>>
> Andeas,
> 
> How are these GTP kernel patches being tested?

We rn each version in a test setup with a ePDG and a SGW that
connects to a full GGSN/P-GW instance (based on erGW).
We also run performance test (less often) with a commercial
test software.

> Is it possible to > create some sort of GTP network device
> that separates out just the datapath for development in the
> same way that VXLAN did this?

We had this discussion about another patch:
(http://marc.info/?l=linux-netdev=148611438811696=2)

Currently the kernel module only supports the GGSN/P-GW side
of the GTP tunnel. This is because we check the UE IP address
in the GTP socket and use the destination IP in the network
interface to find the PDP context.

For a deployment in a real EPC, doing it the other way makes no
sense with the current code. However for a test setup it makes
perfect sense (either to use it as a driver to test other GTP
nodes or to test out own implementation).

So, I hope that we can integrate this soonish.

libgtpnl contains two tools that be used for testing. gtp-link
creates a network device and GTP sockets and keeps them alive.
gtp-tunnel can then be used add PDP context to that. The only
missing part for a bidirectional test setup is the above
mentioned patch with the direction flag and support for that
in the libgtpnl tools.

Adding static tunnel support into the kernel module in any form
makes IMHO no sense. GTP as defined by 3GPP always need a control
instance and there are much better options for static tunnel
encapsulations.

Andreas

> 
> Tom
> 
>> Signed-off-by: Andreas Schultz <aschu...@tpip.net>
>> ---
>>  drivers/net/gtp.c | 80 
>> ++-
>>  1 file changed, 44 insertions(+), 36 deletions(-)
>>
>> diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
>> index 961fb3c..fc0fff5 100644
>> --- a/drivers/net/gtp.c
>> +++ b/drivers/net/gtp.c
>> @@ -58,6 +58,8 @@ struct pdp_ctx {
>> struct in_addr  ms_addr_ip4;
>> struct in_addr  sgsn_addr_ip4;
>>
>> +   struct net_device   *dev;
>> +
>> atomic_ttx_seq;
>> struct rcu_head rcu_head;
>>  };
>> @@ -175,6 +177,40 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct
>> pdp_ctx *pctx,
>> return false;
>>  }
>>
>> +static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int
>> hdrlen,
>> + bool xnet)
>> +{
>> +   struct pcpu_sw_netstats *stats;
>> +
>> +   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
>> +   netdev_dbg(pctx->dev, "No PDP ctx for this MS\n");
>> +   return 1;
>> +   }
>> +
>> +   /* Get rid of the GTP + UDP headers. */
>> +   if (iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet))
>> +   return -1;
>> +
>> +   netdev_dbg(pctx->dev, "forwarding packet from GGSN to uplink\n");
>> +
>> +   /* Now that the UDP and the GTP header have been removed, set up the
>> +* new network header. This is required by the upper layer to
>> +* calculate the transport header.
>> +*/
>> +   skb_reset_network_header(skb);
>> +
>> +   skb->dev = pctx->dev;
>> +
>> +   stats = this_cpu_ptr(pctx->dev->tstats);
>> +   u64_stats_update_begin(>syncp);
>> +   stats->rx_packets++;
>> +   stats->rx_bytes += skb->len;
>> +   u64_stats_update_end(>syncp);
>> +
>> +   netif_rx(skb);
>> +   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,
>>bool xnet)
>> @@ -201,13 +237,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
>> struct
>> sk_buff *skb,
>> return 1;
>> }
>>
>> -   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
>> -   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
>> -   return 1;

Re: [PATCH net-next v3 1/8] gtp: add documentation

2017-02-22 Thread Andreas Schultz
Hi Harald,

- On Feb 22, 2017, at 9:36 AM, laforge lafo...@gnumonks.org wrote:

> Hi Andreas,
> 
> thanks for your feedback.
> 
> On Mon, Feb 20, 2017 at 06:28:07PM +0100, Andreas Schultz wrote:
>> > Are you absolutely sure about this?
>> 
>> Yes. It took me a while to realize this. The crux is this statement in TS
>> 29.060,
>> Section 7.3.1:
>> 
>> > The SGSN shall include an SGSN Address for control plane and an SGSN 
>> > address for
>> > user traffic, which may differ from that provided by the underlying network
>> > service
>> > (e.g. IP). The GGSN shall store these SGSN Addresses and use them when 
>> > sending
>> > control plane on this GTP tunnel or G-PDUs to the SGSN for the MS.
>> 
>> IMHO, this implies that the source IP of GTP-U and GTP-C frames does not 
>> have to
>> match the GSN address specified by a Create PDP Context Request.
> 
> Yes, I follow that reasoning for GTP-C (i.e. the transport-layer S-GW
> source IP of the CREATE PDP CTX REQ may differ from the one signalled
> inside GTP-C.
> 
> For GTP-U however, this just means that GTP-U in general can use
> different IP addresses from GTP-C.  This is well-known and I also have
> no doubts about this.
> 
> But what I still doubt is whether within an ongoing GTP-U tunnel, the
> source IP address can change at any time without any signaling
> announcing that change.
> 
>> TS 29.274, Section 4.2.2.1, Initial Messages:
>> 
>> > During the establishment of the GTP tunnel, the GTPv2 entity selects and
>> > communicates to the peer GTPv2 entity the IP Destination Address at which
>> > it expects to receive subsequent control plane Initial messages related
>> > to that GTP tunnel via .
>> 
>> TS 23.401, Annex D, Sect. D.3.3. makes is clear beyond doubt that we have to
>> accept packet for a valid TEID from virtually any IP. If you look at figure
>> D.3.3-1, step 16, you will see that only the new SGSN is contacting the P-GW.
>> There is no prior advertisement of the change from the old SGSN.
> 
> Yes, but that is again GTP-C, and not GTP-U.
> 
>> Step 16 would therefor not work if we limited the tunnel to a specific source
>> IP.
> 
> correct. But it is a GTP-C transaction.
> 
>> > I so far always assumed that you use GTP-C "MODIFY PDP CONTEXT" in case
>> > of such mobility situations, i.e. the control plane explicitly notifies
>> > the GTP-U entity of a change in the SGSN/S-GW address.
>> 
>> Yes, it does. But that notification only applies to the tunnel endpoint at
>> the SGSN/S-GW in the GGSN/P-GW to SGSN/S-GW direction.
>> 
>> > At least for 3G this seems to be the case, and my assumption appears to
>> > be confirmed with sources such as e.g. page 15 of
>> > http://www.nwadmin.de/presentation_mobility_manag ement_in_UMTS.pdf
>> > 
>> > Also, for LTE, it seems that there's a GTPv2-C "Modify Bearer
>> > Request/Response" involved in relocation from one S-GW to another S-GW:
>> > http://www.lteandbeyond.com/2012/03/x2-based-handover-with-sgw-relocation.html
>> 
>> I think this affirms my argument, Step 3a is sending GTP packets from a
>> source IP that is know to the P-GW before. The fact that this is only
>> used for GTP-C does IMHO not mean that the same should not apply to
>> GTP-U.
>> 
>> >> Step 3. The target Serving GW assigns addresses and TEIDs (one per
>> >> bearer) for downlink traffic from the PDN GW. The Serving GW allocates
>> >> DL TEIDs on S5/S8 even for non-accepted bearers. It sends a Modify
>> >> Bearer Request (Serving GW addresses for user plane and TEID(s))
>> >> message per PDN connection to the PDN GW(s). The SGW also includes
>> >> User Location Information IE and/or UE Time Zone IE if it is present
>> >> in step 2. The PDN GW updates its context field and returns a Modify
>> >> Bearer Response (Charging Id, MSISDN, etc.) message to the Serving GW.
>> >> The MSISDN is included if the PDN GW has it stored in its UE context.
>> >> The PDN GW starts sending downlink packets to the target GW using the
>> >> newly received address and TEIDs. These downlink packets will use the
>> >> new downlink path via the target Serving GW to the target eNodeB. The
>> >> Serving GW shall allocate TEIDs for the failed bearers and inform to
>> >> the MME.
>> > 
>> > Section 5.5.1.1.3 of TS 23.401 agrees with the GTPv2C signalling during
>> > relocation, AFAICT.
>> 
>> Again, 

Re: [PATCH net-next v4 0/7] gtp: misc improvements

2017-02-21 Thread Andreas Schultz
Hi,

In case anyone want's to have a look at the changes that I'm working
on for follow up series can find them at:

  https://github.com/RoadRunnr/net-next/tree/gtp

Regards
Andreas

- On Feb 21, 2017, at 11:18 AM, Andreas Schultz aschu...@tpip.net wrote:

> Hi Pablo,
> 
> This is v4 of the GTP improvements. Compared to v3 it contains mostly
> smallish naming and spelling fixes. It also drops the documentation
> patch, Harald did a better job with the documentation and the some things
> I described do not yet match the implementation. I'll readd the relevant
> parts with a follow up series.
> 
> This series lays the groundwork for removing the socket references from
> the GTP netdevice by removing duplicate code and simplifying the logic on
> some code paths.
> 
> It slighly changes the GTP genl API by making the socket parameters optional
> (though one of them is still required).
> 
> The removal of the socket references will break the 1:1 releation between
> GTP netdevice and GTP socket that prevents us to support multiple VRFs with
> overlaping IP addresse spaces attached to the same GTP-U entity (needed for
> multi APN support, comming a follow up series).
> 
> Pablo found a socket hold problem in v2. In order to solve that I had to
> switch the socket references from the struct socket to the internal
> struct sock. This should have no functionl impact, but we can now hang
> on to the reference without blocking user space from closing the GTP socket.
> 
> v3->v4:
> * drop the documentation patch
> * spelling fixes
> * pass nlattr instead of genl_info into gtp_find_dev,
>   makes the code slightly more compact and readable
> v2->v3:
> * add documentation to explain the goal of all these changes
> * incorporate review comments
> * switch from struct socket to struct sock
> 
> Regards
> Andreas
> 
> --
> Andreas Schultz (7):
>  gtp: switch from struct socket to struct sock for the GTP sockets
>  gtp: make GTP sockets in gtp_newlink optional
>  gtp: merge gtp_get_net and gtp_genl_find_dev
>  gtp: consolidate gtp socket rx path
>  gtp: unify genl_find_pdp and prepare for per socket lookup
>  gtp: consolidate pdp context destruction into helper
>  gtp: add socket to pdp context
> 
> drivers/net/gtp.c | 543 +++---
> 1 file changed, 269 insertions(+), 274 deletions(-)
> 
> --
> 2.10.2


[PATCH net-next v4 2/7] gtp: make GTP sockets in gtp_newlink optional

2017-02-21 Thread Andreas Schultz
Having both GTPv0-U and GTPv1-U is not always desirable.
Fallback from GTPv1-U to GTPv0-U was depreciated from 3GPP
Rel-8 onwards. Post Rel-8 implementation are discuraged
from listening on the v0 port (see 3GPP TS 29.281, Sect. 1).

A future change will completely decouple the sockets from the
network device. Till then, at least one of the sockets needs to
be specified (either v0 or v1), the other is optional.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 148 --
 1 file changed, 78 insertions(+), 70 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index a8ce8c7..96bb89b 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -259,30 +259,30 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
 }
 
-static void gtp_encap_disable(struct gtp_dev *gtp)
-{
-   if (gtp->sk0) {
-   udp_sk(gtp->sk0)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sk0, NULL);
-   sock_put(gtp->sk0);
-   }
-   if (gtp->sk1u) {
-   udp_sk(gtp->sk1u)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sk1u, NULL);
-   sock_put(gtp->sk1u);
-   }
-
-   gtp->sk0 = NULL;
-   gtp->sk1u = NULL;
-}
-
 static void gtp_encap_destroy(struct sock *sk)
 {
struct gtp_dev *gtp;
 
gtp = rcu_dereference_sk_user_data(sk);
-   if (gtp)
-   gtp_encap_disable(gtp);
+   if (gtp) {
+   udp_sk(sk)->encap_type = 0;
+   rcu_assign_sk_user_data(sk, NULL);
+   sock_put(sk);
+   }
+}
+
+static void gtp_encap_disable_sock(struct sock *sk)
+{
+   if (!sk)
+   return;
+
+   gtp_encap_destroy(sk);
+}
+
+static void gtp_encap_disable(struct gtp_dev *gtp)
+{
+   gtp_encap_disable_sock(gtp->sk0);
+   gtp_encap_disable_sock(gtp->sk1u);
 }
 
 /* UDP encapsulation receive handler. See net/ipv4/udp.c.
@@ -642,27 +642,23 @@ static void gtp_link_setup(struct net_device *dev)
 
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
 static void gtp_hashtable_free(struct gtp_dev *gtp);
-static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1);
+static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]);
 
 static int gtp_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
 {
-   int hashsize, err, fd0, fd1;
struct gtp_dev *gtp;
struct gtp_net *gn;
+   int hashsize, err;
 
-   if (!data[IFLA_GTP_FD0] || !data[IFLA_GTP_FD1])
+   if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1])
return -EINVAL;
 
gtp = netdev_priv(dev);
 
-   fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
-   fd1 = nla_get_u32(data[IFLA_GTP_FD1]);
-
-   err = gtp_encap_enable(dev, gtp, fd0, fd1);
+   err = gtp_encap_enable(gtp, data);
if (err < 0)
-   goto out_err;
+   return err;
 
if (!data[IFLA_GTP_PDP_HASHSIZE])
hashsize = 1024;
@@ -690,7 +686,6 @@ static int gtp_newlink(struct net *src_net, struct 
net_device *dev,
gtp_hashtable_free(gtp);
 out_encap:
gtp_encap_disable(gtp);
-out_err:
return err;
 }
 
@@ -805,63 +800,76 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
kfree(gtp->tid_hash);
 }
 
-static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1)
+static struct sock *gtp_encap_enable_socket(int fd, int type,
+   struct gtp_dev *gtp)
 {
struct udp_tunnel_sock_cfg tuncfg = {NULL};
-   struct socket *sock0, *sock1u;
+   struct socket *sock;
+   struct sock *sk;
int err;
 
-   netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1);
+   pr_debug("enable gtp on %d, %d\n", fd, type);
 
-   sock0 = sockfd_lookup(fd_gtp0, );
-   if (sock0 == NULL) {
-   netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0);
-   return -ENOENT;
+   sock = sockfd_lookup(fd, );
+   if (!sock) {
+   pr_debug("gtp socket fd=%d not found\n", fd);
+   return NULL;
}
 
-   if (sock0->sk->sk_protocol != IPPROTO_UDP) {
-   netdev_dbg(dev, "socket fd=%d not UDP\n", fd_gtp0);
-   err = -EINVAL;
-   goto err1;
+   if (sock->sk->sk_protocol != IPPROTO_UDP) {
+   pr_debug("socket fd=%d not UDP\n", fd);
+   sk = ERR_PTR(-EINVAL);
+   goto out_sock;
}
 
-   sock1u = sockfd_lookup(fd_gtp1, 

[PATCH net-next v4 3/7] gtp: merge gtp_get_net and gtp_genl_find_dev

2017-02-21 Thread Andreas Schultz
Both function are always used together with the final goal to
get the gtp_dev. This simplifies the code by merging them together.

The netdevice lookup is changed to use the regular dev_get_by_index.
The gtp netdevice list is now only used to find the PDP contexts for
imcomming packets. It can be completely eliminated Once the TEID
hash is moved into the GTP socket.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 146 ++
 1 file changed, 69 insertions(+), 77 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 96bb89b..961fb3c 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -744,21 +744,6 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = {
.fill_info  = gtp_fill_info,
 };
 
-static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[])
-{
-   struct net *net;
-
-   /* Examine the link attributes and figure out which network namespace
-* we are talking about.
-*/
-   if (tb[GTPA_NET_NS_FD])
-   net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD]));
-   else
-   net = get_net(src_net);
-
-   return net;
-}
-
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize)
 {
int i;
@@ -872,16 +857,30 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct 
nlattr *data[])
return 0;
 }
 
-static struct net_device *gtp_find_dev(struct net *net, int ifindex)
+static struct gtp_dev *gtp_find_dev(struct net *src_net, struct nlattr *nla[])
 {
-   struct gtp_net *gn = net_generic(net, gtp_net_id);
-   struct gtp_dev *gtp;
-
-   list_for_each_entry_rcu(gtp, >gtp_dev_list, list) {
-   if (ifindex == gtp->dev->ifindex)
-   return gtp->dev;
-   }
-   return NULL;
+   struct gtp_dev *gtp = NULL;
+   struct net_device *dev;
+   struct net *net;
+
+   /* Examine the link attributes and figure out which network namespace
+* we are talking about.
+*/
+   if (nla[GTPA_NET_NS_FD])
+   net = get_net_ns_by_fd(nla_get_u32(nla[GTPA_NET_NS_FD]));
+   else
+   net = get_net(src_net);
+
+   if (IS_ERR(net))
+   return NULL;
+
+   /* Check if there's an existing gtpX device to configure */
+   dev = dev_get_by_index_rcu(net, nla_get_u32(nla[GTPA_LINK]));
+   if (dev->netdev_ops == _netdev_ops)
+   gtp = netdev_priv(dev);
+
+   put_net(net);
+   return gtp;
 }
 
 static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
@@ -911,9 +910,9 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct 
genl_info *info)
}
 }
 
-static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
+static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info)
 {
-   struct gtp_dev *gtp = netdev_priv(dev);
+   struct net_device *dev = gtp->dev;
u32 hash_ms, hash_tid = 0;
struct pdp_ctx *pctx;
bool found = false;
@@ -990,8 +989,8 @@ static int ipv4_pdp_add(struct net_device *dev, struct 
genl_info *info)
 
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
-   struct net_device *dev;
-   struct net *net;
+   struct gtp_dev *gtp;
+   int err;
 
if (!info->attrs[GTPA_VERSION] ||
!info->attrs[GTPA_LINK] ||
@@ -1015,77 +1014,79 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
return -EINVAL;
}
 
-   net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
-   if (IS_ERR(net))
-   return PTR_ERR(net);
+   rcu_read_lock();
 
-   /* Check if there's an existing gtpX device to configure */
-   dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
-   if (dev == NULL) {
-   put_net(net);
-   return -ENODEV;
+   gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
+   if (!gtp) {
+   err = -ENODEV;
+   goto out_unlock;
}
-   put_net(net);
 
-   return ipv4_pdp_add(dev, info);
+   err = ipv4_pdp_add(gtp, info);
+
+out_unlock:
+   rcu_read_unlock();
+   return err;
 }
 
 static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
 {
-   struct net_device *dev;
struct pdp_ctx *pctx;
struct gtp_dev *gtp;
-   struct net *net;
+   int err = 0;
 
if (!info->attrs[GTPA_VERSION] ||
!info->attrs[GTPA_LINK])
return -EINVAL;
 
-   net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
-   if (IS_ERR(net))
-   return PTR_ERR(net);
+   rcu_read_lock();
 
-   /* Check if there's an existing gtpX device to configure */
-   dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
-   if (dev == NULL) {
-

[PATCH net-next v4 7/7] gtp: add socket to pdp context

2017-02-21 Thread Andreas Schultz
Having the socket present in context simplifies the sending logic.
It also fixes the invalid assumption that we have to use the same
sending socket for all client IP's on a specific gtp interface.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 94 +++
 1 file changed, 47 insertions(+), 47 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index b6aae68..ea868de 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,7 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct sock *sk;
struct net_device   *dev;
 
atomic_ttx_seq;
@@ -179,8 +180,7 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct 
pdp_ctx *pctx,
return false;
 }
 
-static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int 
hdrlen,
- bool xnet)
+static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int 
hdrlen)
 {
struct pcpu_sw_netstats *stats;
 
@@ -190,7 +190,8 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff 
*skb, unsigned int hdrlen
}
 
/* Get rid of the GTP + UDP headers. */
-   if (iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet))
+   if (iptunnel_pull_header(skb, hdrlen, skb->protocol,
+!net_eq(sock_net(pctx->sk), 
dev_net(pctx->dev
return -1;
 
netdev_dbg(pctx->dev, "forwarding packet from GGSN to uplink\n");
@@ -214,8 +215,7 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff 
*skb, unsigned int hdrlen
 }
 
 /* 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,
-  bool xnet)
+static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp0_header);
@@ -239,11 +239,10 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return 1;
}
 
-   return gtp_rx(pctx, skb, hdrlen, xnet);
+   return gtp_rx(pctx, skb, hdrlen);
 }
 
-static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
-   bool xnet)
+static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp1_header);
@@ -282,7 +281,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
return 1;
}
 
-   return gtp_rx(pctx, skb, hdrlen, xnet);
+   return gtp_rx(pctx, skb, hdrlen);
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -318,7 +317,6 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 {
struct gtp_dev *gtp;
int ret = 0;
-   bool xnet;
 
gtp = rcu_dereference_sk_user_data(sk);
if (!gtp)
@@ -326,16 +324,14 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
 
-   xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
-
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
netdev_dbg(gtp->dev, "received GTP0 packet\n");
-   ret = gtp0_udp_encap_recv(gtp, skb, xnet);
+   ret = gtp0_udp_encap_recv(gtp, skb);
break;
case UDP_ENCAP_GTP1U:
netdev_dbg(gtp->dev, "received GTP1U packet\n");
-   ret = gtp1u_udp_encap_recv(gtp, skb, xnet);
+   ret = gtp1u_udp_encap_recv(gtp, skb);
break;
default:
ret = -1; /* Shouldn't happen. */
@@ -378,8 +374,9 @@ static void gtp_dev_uninit(struct net_device *dev)
free_percpu(dev->tstats);
 }
 
-static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4,
-  const struct sock *sk, __be32 daddr)
+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;
@@ -388,7 +385,7 @@ static struct rtable *ip4_route_output_gtp(struct net *net, 
struct flowi4 *fl4,
fl4->flowi4_tos = RT_CONN_FLAGS(sk);
fl4->flowi4_proto   = sk->sk_protocol;
 
-   return ip_route_output_key(net, fl4);
+   return ip_route_output_key(sock_net(sk), fl4);
 }
 
 static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
@@ -477,7 +474,6 @@ static int gtp_build_skb_ip4(stru

[PATCH net-next v4 6/7] gtp: consolidate pdp context destruction into helper

2017-02-21 Thread Andreas Schultz
Consolidate duplicate code into helper.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 24 ++--
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index f529d1e..b6aae68 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -86,6 +86,8 @@ struct gtp_net {
 
 static u32 gtp_h_initval;
 
+static void pdp_context_delete(struct pdp_ctx *pctx);
+
 static inline u32 gtp0_hashfn(u64 tid)
 {
u32 *tid32 = (u32 *) 
@@ -780,13 +782,10 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
struct pdp_ctx *pctx;
int i;
 
-   for (i = 0; i < gtp->hash_size; i++) {
-   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid) {
-   hlist_del_rcu(>hlist_tid);
-   hlist_del_rcu(>hlist_addr);
-   kfree_rcu(pctx, rcu_head);
-   }
-   }
+   for (i = 0; i < gtp->hash_size; i++)
+   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid)
+   pdp_context_delete(pctx);
+
synchronize_rcu();
kfree(gtp->addr_hash);
kfree(gtp->tid_hash);
@@ -995,6 +994,13 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
return 0;
 }
 
+static void pdp_context_delete(struct pdp_ctx *pctx)
+{
+   hlist_del_rcu(>hlist_tid);
+   hlist_del_rcu(>hlist_addr);
+   kfree_rcu(pctx, rcu_head);
+}
+
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
struct gtp_dev *gtp;
@@ -1100,9 +1106,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct 
genl_info *info)
netdev_dbg(pctx->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp 
%p)\n",
   pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
 
-   hlist_del_rcu(>hlist_tid);
-   hlist_del_rcu(>hlist_addr);
-   kfree_rcu(pctx, rcu_head);
+   pdp_context_delete(pctx);
 
 out_unlock:
rcu_read_unlock();
-- 
2.10.2



[PATCH net-next v4 5/7] gtp: unify genl_find_pdp and prepare for per socket lookup

2017-02-21 Thread Andreas Schultz
This unifies duplicate code into a helper. It also prepares the
groundwork to add a lookup version that uses the socket to find
attached pdp contexts.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 121 ++
 1 file changed, 50 insertions(+), 71 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index fc0fff5..f529d1e 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1037,55 +1037,67 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
return err;
 }
 
+static struct pdp_ctx *gtp_find_pdp_by_link(struct net *net,
+   struct nlattr *nla[])
+{
+   struct gtp_dev *gtp;
+
+   gtp = gtp_find_dev(net, nla);
+   if (!gtp)
+   return ERR_PTR(-ENODEV);
+
+   if (nla[GTPA_MS_ADDRESS]) {
+   __be32 ip = nla_get_be32(nla[GTPA_MS_ADDRESS]);
+
+   return ipv4_pdp_find(gtp, ip);
+   } else if (nla[GTPA_VERSION]) {
+   u32 gtp_version = nla_get_u32(nla[GTPA_VERSION]);
+
+   if (gtp_version == GTP_V0 && nla[GTPA_TID])
+   return gtp0_pdp_find(gtp, nla_get_u64(nla[GTPA_TID]));
+   else if (gtp_version == GTP_V1 && nla[GTPA_I_TEI])
+   return gtp1_pdp_find(gtp, nla_get_u32(nla[GTPA_I_TEI]));
+   }
+
+   return ERR_PTR(-EINVAL);
+}
+
+static struct pdp_ctx *gtp_find_pdp(struct net *net, struct nlattr *nla[])
+{
+   struct pdp_ctx *pctx;
+
+   if (nla[GTPA_LINK])
+   pctx = gtp_find_pdp_by_link(net, nla);
+   else
+   pctx = ERR_PTR(-EINVAL);
+
+   if (!pctx)
+   pctx = ERR_PTR(-ENOENT);
+
+   return pctx;
+}
+
 static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
 {
struct pdp_ctx *pctx;
-   struct gtp_dev *gtp;
int err = 0;
 
-   if (!info->attrs[GTPA_VERSION] ||
-   !info->attrs[GTPA_LINK])
+   if (!info->attrs[GTPA_VERSION])
return -EINVAL;
 
rcu_read_lock();
 
-   gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
-   if (!gtp) {
-   err = -ENODEV;
-   goto out_unlock;
-   }
-
-   switch (nla_get_u32(info->attrs[GTPA_VERSION])) {
-   case GTP_V0:
-   if (!info->attrs[GTPA_TID]) {
-   err = -EINVAL;
-   goto out_unlock;
-   }
-   pctx = gtp0_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_TID]));
-   break;
-   case GTP_V1:
-   if (!info->attrs[GTPA_I_TEI]) {
-   err = -EINVAL;
-   goto out_unlock;
-   }
-   pctx = gtp1_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_I_TEI]));
-   break;
-
-   default:
-   err = -EINVAL;
-   goto out_unlock;
-   }
-
-   if (!pctx) {
-   err = -ENOENT;
+   pctx = gtp_find_pdp(sock_net(skb->sk), info->attrs);
+   if (IS_ERR(pctx)) {
+   err = PTR_ERR(pctx);
goto out_unlock;
}
 
if (pctx->gtp_version == GTP_V0)
-   netdev_dbg(gtp->dev, "GTPv0-U: deleting tunnel id = %llx (pdp 
%p)\n",
+   netdev_dbg(pctx->dev, "GTPv0-U: deleting tunnel id = %llx (pdp 
%p)\n",
   pctx->u.v0.tid, pctx);
else if (pctx->gtp_version == GTP_V1)
-   netdev_dbg(gtp->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp 
%p)\n",
+   netdev_dbg(pctx->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp 
%p)\n",
   pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
 
hlist_del_rcu(>hlist_tid);
@@ -1139,49 +1151,16 @@ static int gtp_genl_get_pdp(struct sk_buff *skb, struct 
genl_info *info)
 {
struct pdp_ctx *pctx = NULL;
struct sk_buff *skb2;
-   struct gtp_dev *gtp;
-   u32 gtp_version;
int err;
 
-   if (!info->attrs[GTPA_VERSION] ||
-   !info->attrs[GTPA_LINK])
+   if (!info->attrs[GTPA_VERSION])
return -EINVAL;
 
-   gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]);
-   switch (gtp_version) {
-   case GTP_V0:
-   case GTP_V1:
-   break;
-   default:
-   return -EINVAL;
-   }
-
rcu_read_lock();
 
-   gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
-   if (!gtp) {
-   err = -ENODEV;
-   goto err_unlock;
-   }
-
-   if (gtp_version == GTP_V0 &&
-   info->attrs[GTPA_TID]) {
-   u64 tid = nla_get_u64(info->attrs[GTPA_TID]);
-
-   pctx = gtp0_pdp_find(gtp, tid);
-   } else if (gtp_version == GTP_V1 &&
-

[PATCH net-next v4 0/7] gtp: misc improvements

2017-02-21 Thread Andreas Schultz
Hi Pablo,

This is v4 of the GTP improvements. Compared to v3 it contains mostly
smallish naming and spelling fixes. It also drops the documentation
patch, Harald did a better job with the documentation and the some things
I described do not yet match the implementation. I'll readd the relevant
parts with a follow up series.

This series lays the groundwork for removing the socket references from
the GTP netdevice by removing duplicate code and simplifying the logic on
some code paths.

It slighly changes the GTP genl API by making the socket parameters optional
(though one of them is still required).

The removal of the socket references will break the 1:1 releation between
GTP netdevice and GTP socket that prevents us to support multiple VRFs with
overlaping IP addresse spaces attached to the same GTP-U entity (needed for
multi APN support, comming a follow up series).

Pablo found a socket hold problem in v2. In order to solve that I had to
switch the socket references from the struct socket to the internal
struct sock. This should have no functionl impact, but we can now hang
on to the reference without blocking user space from closing the GTP socket.

v3->v4:
 * drop the documentation patch
 * spelling fixes
 * pass nlattr instead of genl_info into gtp_find_dev,
   makes the code slightly more compact and readable
v2->v3:
 * add documentation to explain the goal of all these changes
 * incorporate review comments
 * switch from struct socket to struct sock

Regards
Andreas

--
Andreas Schultz (7):
  gtp: switch from struct socket to struct sock for the GTP sockets
  gtp: make GTP sockets in gtp_newlink optional
  gtp: merge gtp_get_net and gtp_genl_find_dev
  gtp: consolidate gtp socket rx path
  gtp: unify genl_find_pdp and prepare for per socket lookup
  gtp: consolidate pdp context destruction into helper
  gtp: add socket to pdp context

 drivers/net/gtp.c | 543 +++---
 1 file changed, 269 insertions(+), 274 deletions(-)

-- 
2.10.2



[PATCH net-next v4 1/7] gtp: switch from struct socket to struct sock for the GTP sockets

2017-02-21 Thread Andreas Schultz
After enabling the UDP encapsulation, only the sk member is used.

Holding the socket would prevent user space from closing the socket,
but holding a reference to the sk member does not have the same
effect.

This change will make it simpler to later detach the sockets from
the netdevice.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 42 +++---
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index bda0c64..a8ce8c7 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -66,8 +66,8 @@ struct pdp_ctx {
 struct gtp_dev {
struct list_headlist;
 
-   struct socket   *sock0;
-   struct socket   *sock1u;
+   struct sock *sk0;
+   struct sock *sk1u;
 
struct net_device   *dev;
 
@@ -261,17 +261,19 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
 
 static void gtp_encap_disable(struct gtp_dev *gtp)
 {
-   if (gtp->sock0 && gtp->sock0->sk) {
-   udp_sk(gtp->sock0->sk)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sock0->sk, NULL);
+   if (gtp->sk0) {
+   udp_sk(gtp->sk0)->encap_type = 0;
+   rcu_assign_sk_user_data(gtp->sk0, NULL);
+   sock_put(gtp->sk0);
}
-   if (gtp->sock1u && gtp->sock1u->sk) {
-   udp_sk(gtp->sock1u->sk)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sock1u->sk, NULL);
+   if (gtp->sk1u) {
+   udp_sk(gtp->sk1u)->encap_type = 0;
+   rcu_assign_sk_user_data(gtp->sk1u, NULL);
+   sock_put(gtp->sk1u);
}
 
-   gtp->sock0 = NULL;
-   gtp->sock1u = NULL;
+   gtp->sk0 = NULL;
+   gtp->sk1u = NULL;
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -484,14 +486,14 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
 
switch (pctx->gtp_version) {
case GTP_V0:
-   if (gtp->sock0)
-   sk = gtp->sock0->sk;
+   if (gtp->sk0)
+   sk = gtp->sk0;
else
sk = NULL;
break;
case GTP_V1:
-   if (gtp->sock1u)
-   sk = gtp->sock1u->sk;
+   if (gtp->sk1u)
+   sk = gtp->sk1u;
else
sk = NULL;
break;
@@ -504,7 +506,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
return -ENOENT;
}
 
-   rt = ip4_route_output_gtp(sock_net(sk), , gtp->sock0->sk,
+   rt = ip4_route_output_gtp(sock_net(sk), , gtp->sk0,
  pctx->sgsn_addr_ip4.s_addr);
if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to SSGN %pI4\n",
@@ -839,18 +841,20 @@ static int gtp_encap_enable(struct net_device *dev, 
struct gtp_dev *gtp,
 
netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u);
 
-   gtp->sock0 = sock0;
-   gtp->sock1u = sock1u;
+   sock_hold(sock0->sk);
+   gtp->sk0 = sock0->sk;
+   sock_hold(sock1u->sk);
+   gtp->sk1u = sock1u->sk;
 
tuncfg.sk_user_data = gtp;
tuncfg.encap_rcv = gtp_encap_recv;
tuncfg.encap_destroy = gtp_encap_destroy;
 
tuncfg.encap_type = UDP_ENCAP_GTP0;
-   setup_udp_tunnel_sock(sock_net(gtp->sock0->sk), gtp->sock0, );
+   setup_udp_tunnel_sock(sock_net(gtp->sk0), sock0, );
 
tuncfg.encap_type = UDP_ENCAP_GTP1U;
-   setup_udp_tunnel_sock(sock_net(gtp->sock1u->sk), gtp->sock1u, );
+   setup_udp_tunnel_sock(sock_net(gtp->sk1u), sock1u, );
 
err = 0;
 err2:
-- 
2.10.2



[PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path

2017-02-21 Thread Andreas Schultz
Add network device to gtp context in preparation for splitting
the TEID from the network device.

Use this to rework the socker rx path. Move the common RX part
of v0 and v1 into a helper. Also move the final rx part into
that helper as well.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 80 ++-
 1 file changed, 44 insertions(+), 36 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 961fb3c..fc0fff5 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,8 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct net_device   *dev;
+
atomic_ttx_seq;
struct rcu_head rcu_head;
 };
@@ -175,6 +177,40 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct 
pdp_ctx *pctx,
return false;
 }
 
+static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int 
hdrlen,
+ bool xnet)
+{
+   struct pcpu_sw_netstats *stats;
+
+   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
+   netdev_dbg(pctx->dev, "No PDP ctx for this MS\n");
+   return 1;
+   }
+
+   /* Get rid of the GTP + UDP headers. */
+   if (iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet))
+   return -1;
+
+   netdev_dbg(pctx->dev, "forwarding packet from GGSN to uplink\n");
+
+   /* Now that the UDP and the GTP header have been removed, set up the
+* new network header. This is required by the upper layer to
+* calculate the transport header.
+*/
+   skb_reset_network_header(skb);
+
+   skb->dev = pctx->dev;
+
+   stats = this_cpu_ptr(pctx->dev->tstats);
+   u64_stats_update_begin(>syncp);
+   stats->rx_packets++;
+   stats->rx_bytes += skb->len;
+   u64_stats_update_end(>syncp);
+
+   netif_rx(skb);
+   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,
   bool xnet)
@@ -201,13 +237,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
return 1;
}
 
-   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
-   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return 1;
-   }
-
-   /* Get rid of the GTP + UDP headers. */
-   return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+   return gtp_rx(pctx, skb, hdrlen, xnet);
 }
 
 static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
@@ -250,13 +280,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return 1;
}
 
-   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
-   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return 1;
-   }
-
-   /* Get rid of the GTP + UDP headers. */
-   return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+   return gtp_rx(pctx, skb, hdrlen, xnet);
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -290,10 +314,9 @@ static void gtp_encap_disable(struct gtp_dev *gtp)
  */
 static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
-   struct pcpu_sw_netstats *stats;
struct gtp_dev *gtp;
+   int ret = 0;
bool xnet;
-   int ret;
 
gtp = rcu_dereference_sk_user_data(sk);
if (!gtp)
@@ -319,33 +342,17 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
switch (ret) {
case 1:
netdev_dbg(gtp->dev, "pass up to the process\n");
-   return 1;
+   break;
case 0:
-   netdev_dbg(gtp->dev, "forwarding packet from GGSN to uplink\n");
break;
case -1:
netdev_dbg(gtp->dev, "GTP packet has been dropped\n");
kfree_skb(skb);
-   return 0;
+   ret = 0;
+   break;
}
 
-   /* Now that the UDP and the GTP header have been removed, set up the
-* new network header. This is required by the upper layer to
-* calculate the transport header.
-*/
-   skb_reset_network_header(skb);
-
-   skb->dev = gtp->dev;
-
-   stats = this_cpu_ptr(gtp->dev->tstats);
-   u64_stats_update_begin(>syncp);
-   stats->rx_packets++;
-   stats->rx_bytes += skb->len;
-   u64_stats_update_end(>syncp);
-
-   netif_rx(skb);
-
-   return 0;
+   return ret;
 }
 
 static int gtp_dev_init(struct net_device *dev)
@@ -951,6 +958,7 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
if (pctx == NULL)
return -ENOMEM;
 
+   pctx->dev = gtp->dev;
ipv4_pdp_fill(pctx, info);
atomic_set(>tx_seq, 0);
 
-- 
2.10.2



Re: [PATCH net-next v3 1/8] gtp: add documentation

2017-02-20 Thread Andreas Schultz
Hi,

- On Feb 20, 2017, at 5:15 PM, laforge lafo...@gnumonks.org wrote:

> Hi Andreas,
> 
> this is not really about the documentation, but it still makes sense to
> discuss here as the issue is best described:
> 
> On Mon, Feb 13, 2017 at 04:36:17PM +0100, Andreas Schultz wrote:
>> +Local GTP-U entity and tunnel identification
>> +
>> +
>> +GTP-U uses UDP for transporting PDU's. The receiving UDP port is 2152 for
>> +GTPv1-U and 3386 for GTPv0-U.
>> +
>> +There is only one GTP-U entity (and therefor SGSN/GGSN/S-GW/PDN-GW instance)
>> +per IP address. Tunnel Endpoint Identifier (TEID) are unique per GTP-U 
>> entity.
>> +
>> +A specific tunnel is only defined by the destination entity. Since the
>> +destination port is constant, only the destination IP and TEID define
>> +a tunnel. The source IP and Port have no meaning for the tunnel.
> 
> Are you absolutely sure about this?

Yes. It took me a while to realize this. The crux is this statement in TS 
29.060,
Section 7.3.1:

> The SGSN shall include an SGSN Address for control plane and an SGSN address 
> for
> user traffic, which may differ from that provided by the underlying network 
> service
> (e.g. IP). The GGSN shall store these SGSN Addresses and use them when sending
> control plane on this GTP tunnel or G-PDUs to the SGSN for the MS.

IMHO, this implies that the source IP of GTP-U and GTP-C frames does not have to
match the GSN address specified by a Create PDP Context Request.

For GTPv2-C there is no such clear statement. However, GTPv2-C makes it clear
that a TEID describes the local tunnel ENDPOINT, there nothing that defines
the tunnel *source* (the same is true for GTPv1-C, except that is not so
explicit).

TS 29.274, Section 4.2.2.1, Initial Messages:

> During the establishment of the GTP tunnel, the GTPv2 entity selects and
> communicates to the peer GTPv2 entity the IP Destination Address at which
> it expects to receive subsequent control plane Initial messages related
> to that GTP tunnel via .

TS 23.401, Annex D, Sect. D.3.3. makes is clear beyond doubt that we have to
accept packet for a valid TEID from virtually any IP. If you look at figure
D.3.3-1, step 16, you will see that only the new SGSN is contacting the P-GW.
There is no prior advertisement of the change from the old SGSN.

Step 16 would therefor not work if we limited the tunnel to a specific source
IP.

The same applies to figure D.3.4-1, step 18.

>> +[3GPP TS 29.281] Section 4.3.0 defines this so:
>> +
>> +> The TEID in the GTP-U header is used to de-multiplex traffic incoming from
>> +> remote tunnel endpoints so that it is delivered to the User plane entities
>> +> in a way that allows multiplexing of different users, different packet
>> +> protocols and different QoS levels. Therefore no two remote GTP-U 
>> endpoints
>> +> shall send traffic to a GTP-U protocol entity using the same TEID value
>> except
>> +> for data forwarding as part of mobility procedures.
>> +
>> +The definition above only defines that two remote GTP-U endpoints *should 
>> not*
>> +send to the same TEID, it *does not* forbid or exclude such a scenario. In
>> +fact, the mentioned mobility procedures make it necessary that the GTP-U 
>> entity
>> +accepts traffic for TEID's from multiple or unknown peers.
> 
> I so far always assumed that you use GTP-C "MODIFY PDP CONTEXT" in case
> of such mobility situations, i.e. the control plane explicitly notifies
> the GTP-U entity of a change in the SGSN/S-GW address.

Yes, it does. But that notification only applies to the tunnel endpoint at
the SGSN/S-GW in the GGSN/P-GW to SGSN/S-GW direction.

> At least for 3G this seems to be the case, and my assumption appears to
> be confirmed with sources such as e.g. page 15 of
> http://www.nwadmin.de/presentation_mobility_manag ement_in_UMTS.pdf
> 
> Also, for LTE, it seems that there's a GTPv2-C "Modify Bearer
> Request/Response" involved in relocation from one S-GW to another S-GW:
> http://www.lteandbeyond.com/2012/03/x2-based-handover-with-sgw-relocation.html

I think this affirms my argument, Step 3a is sending GTP packets from a
source IP that is know to the P-GW before. The fact that this is only
used for GTP-C does IMHO not mean that the same should not apply to
GTP-U.

>> Step 3. The target Serving GW assigns addresses and TEIDs (one per
>> bearer) for downlink traffic from the PDN GW. The Serving GW allocates
>> DL TEIDs on S5/S8 even for non-accepted bearers. It sends a Modify
>> Bearer Request (Serving GW addresses for user plane and TEID(s))
>> message per PDN connection to the PDN GW(s). The SGW also includes
&

Re: [PATCH net-next] GTP: Add some basic documentation about drivers/net/gtp.c

2017-02-19 Thread Andreas Schultz
- On Feb 18, 2017, at 1:58 PM, laforge lafo...@gnumonks.org wrote:

> In order to clarify what the module actually does, and how to use it,
> let's add some basic documentation to the kernel tree, together with
> pointers to related specs and projects.
> 
> Signed-off-by: Harald Welte <lafo...@gnumonks.org>
Acked-by: Andreas Schultz <aschu...@tpip.net>

> ---
> Documentation/networking/gtp.txt | 135 +++
> 1 file changed, 135 insertions(+)
> create mode 100644 Documentation/networking/gtp.txt
> 
> diff --git a/Documentation/networking/gtp.txt 
> b/Documentation/networking/gtp.txt
> new file mode 100644
> index ..93e96750f103
> --- /dev/null
> +++ b/Documentation/networking/gtp.txt
> @@ -0,0 +1,135 @@
> +The Linux kernel GTP tunneling module
> +==
> +Documentation by Harald Welte <lafo...@gnumonks.org>
> +
> +In 'drivers/net/gtp.c' you are finding a kernel-level implementation
> +of a GTP tunnel endpoint.
> +
> +== What is GTP ==
> +
> +GTP is the Generic Tunnel Protocol, which is a 3GPP protocol used for
> +tunneling User-IP payload between a mobile station (phone, modem)
> +and the interconnection between an external packet data network (such
> +as the internet).
> +
> +So when you start a 'data connection' from your mobile phone, the
> +phone will use the control plane to signal for the establishment of
> +such a tunnel between that external data network and the phone.  The
> +tunnel endpoints thus reside on the phone and in the gateway.  All
> +intermediate nodes just transport the encapsulated packet.
> +
> +The phone itself does not implement GTP but uses some other
> +technology-dependent protocol stack for transmitting the user IP
> +payload, such as LLC/SNDCP/RLC/MAC.
> +
> +At some network element inside the cellular operator infrastructure
> +(SGSN in case of GPRS/EGPRS or classic UMTS, hNodeB in case of a 3G
> +femtocell, eNodeB in case of 4G/LTE), the cellular protocol stacking
> +is translated into GTP *without breaking the end-to-end tunnel*.  So
> +intermediate nodes just perform some specific relay function.
> +
> +At some point the GTP packet ends up on the so-called GGSN (GSM/UMTS)
> +or P-GW (LTE), which terminates the tunnel, decapsulates the packet
> +and forwards it onto an external packet data network.  This can be
> +public internet, but can also be any private IP network (or even
> +theoretically some non-IP network like X.25).
> +
> +You can find the protocol specification in 3GPP TS 29.060, available
> +publicly via the 3GPP website at http://www.3gpp.org/DynaReport/29060.htm
> +
> +A direct PDF link to v13.6.0 is provided for convenience below:
> +http://www.etsi.org/deliver/etsi_ts/129000_129099/129060/13.06.00_60/ts_129060v130600p.pdf
> +
> +== The Linux GTP tunnelling module ==
> +
> +The module implements the function of a tunnel endpoint, i.e. it is
> +able to decapsulate tunneled IP packets in the uplink originated by
> +the phone, and encapsulate raw IP packets received from the external
> +packet network in downlink towards the phone.
> +
> +It *only* implements the so-called 'user plane', carrying the User-IP
> +payload, called GTP-U.  It does not implement the 'control plane',
> +which is a signaling protocol used for establishment and teardown of
> +GTP tunnels (GTP-C).
> +
> +So in order to have a working GGSN/P-GW setup, you will need a
> +userspace program that implements the GTP-C protocol and which then
> +uses the netlink interface provided by the GTP-U module in the kernel
> +to configure the kernel module.
> +
> +This split architecture follows the tunneling modules of other
> +protocols, e.g. PPPoE or L2TP, where you also run a userspace daemon
> +to handle the tunnel establishment, authentication etc. and only the
> +data plane is accelerated inside the kernel.
> +
> +Don't be confused by terminology:  The GTP User Plane goes through
> +kernel accelerated path, while the GTP Control Plane goes to
> +Userspace :)
> +
> +The official homepge of the module is at
> +https://osmocom.org/projects/linux-kernel-gtp-u/wiki
> +
> +== Userspace Programs with Linux Kernel GTP-U support ==
> +
> +At the time of this writing, there are at least two Free Software
> +implementations that implement GTP-C and can use the netlink interface
> +to make use of the Linux kernel GTP-U support:
> +
> +* OpenGGSN (classic 2G/3G GGSN in C):
> +  https://osmocom.org/projects/openggsn/wiki/OpenGGSN
> +
> +* ergw (GGSN + P-GW in Erlang):
> +  https://github.com/travelping/ergw
> +

OpenAir5G also seems to have support:

https://gitlab.eurecom.fr/

Re: RFC: unit tests for kernel GTP module

2017-02-17 Thread Andreas Schultz
Hi,

- On Feb 16, 2017, at 11:08 PM, laforge lafo...@gnumonks.org wrote:

> Dear GTP-interested folks,
> 
> I would love to somehow get towards some degree of unit testing (or even
> "continuous integration") for teh kernel GTP code.
> 
> We currently have the original code in the kernel, we had some recent
> small fixes and now are getting more patches into place.  With
> relatively few active users out there (and probably none of them in
> production yet), it's particularly easy to introduce regressions while
> working on the code.  Also, having tested new code even against a
> test set with limited covrage could help to get more confidence in new
> patches and thus get them merged sooner.

We do run the current kernel code in production. The version I have
been push patches for will be deployed into prod soonish.

Automated testing is something we are also looking at. Currently, we
have cooperation going on with a vendor of a an RAN and EPC protocol
testing solution. The goal is to have a automated testing setup for
our GGSN/PDN-GW OpenSource project. That setup will also exercise the
kernel parts.
The test suite is proprietary, so we can only share the results but
not the test setup itself.

> Using tools like sgsnemu of OpenGGSN and the command line tools included
> in libgtpnl, it should be possibel to cook up some scripts for testing.
> Even the most basic set of tests would be an improvement over what we
> have now.  One could also think about pcap replay to test with
> hand-crafted or real-world packets from other GTP implementations.

We more or less removed static GTP tunnels. The tools in libgtpnl
only work when an application is keeping the GTP socket alive.

Andreas

> As much as I'd like to put something like this into place myself, I
> don't think I will be able to work much on this in the near future. The
> GTP module at this point is a pure hobby and contrary to some years ago
> while I started it, I don't have any contract work in the GTP area at
> this point, so other projects currently unfortunately get more
> attention.
> 
> So in case somebody among the GTP-interested parties (Travelping, OAI,
> ...) would want to do something in terms of testing, I'd be more than
> happy if somebody would step ahead.  Otherwise it's all just vapourware
> going to end up on my ever-growing TODO list :/
> 
> Also, if netdev folks have some ideas/pointers about possible
> frameworks/tools for this kind of testing [it must exist for at least
> some other kernel networking code?]: Please let me know.  I'd be
> interested to have a look if there's something that can be used as a
> basis (starting network namespaces, sending/transmitting packets, test
> case startup/teardown, ...)
> 
> My "old school" approach would have been to start one or multiple
> user-mode-linux kernels (those that are to be tested), and then have
> scripts that set up a gtp socket and gtp tunnels via the libgtp command
> line tools, and throw packets at that.   But I'm sure there must be
> quite powerful frameworks for that kind of testing in the 21st century?
> How do other tunneling implementations handle this?
> 
> Regards,
>   Harald
> --
> - Harald Welte    http://laforge.gnumonks.org/
> 
> "Privacy in residential applications is a desirable marketing option."
>   (ETSI EN 300 175-7 Ch. A6)


Re: [PATCH net-next] net/gtp: Add udp source port generation according to flow hash

2017-02-16 Thread Andreas Schultz
Hi Or,

- On Feb 16, 2017, at 3:59 PM, Or Gerlitz ogerl...@mellanox.com wrote:

> Generate the source udp header according to the flow represented by
> the packet we are encapsulating, as done for other udp tunnels. This
> helps on the receiver side to apply RSS spreading.

This might work for GTPv0-U, However, for GTPv1-U this could interfere
with error handling in the user space control process when the UDP port
extension  header is used in error indications.

3GPP TS 29.281 Rel 13, section 5.2.2.1 defines the UDP port extension and
section 7.3.1 says that the UDP source port extension can be used to 
mitigate DOS attacks. This would IMHO imply that the user space control
process needs to know the TEID to UDP source port mapping.

The other question is, on what is this actually hashing. When I understand
the code correctly, this will hash on the source/destination of the orignal
flow. I would expect that a SGSN/SGW/eNodeB would like the keep flow
processing on a per TEID base, so the port hashing should be base on the
TEID.

All together, I think adding an additional UDP source port argument to
the PDP context might be a better solution.

Andreas

> 
> Signed-off-by: Or Gerlitz 
> ---
> 
> found in code inspection.. compile tested only
> 
> 
> drivers/net/gtp.c | 5 -
> 1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
> index bda0c64..ff1244b 100644
> --- a/drivers/net/gtp.c
> +++ b/drivers/net/gtp.c
> @@ -564,6 +564,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, 
> struct
> net_device *dev)
> {
>   unsigned int proto = ntohs(skb->protocol);
>   struct gtp_pktinfo pktinfo;
> + __be16 src_port;
>   int err;
> 
>   /* Ensure there is sufficient headroom. */
> @@ -572,6 +573,8 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, 
> struct
> net_device *dev)
> 
>   skb_reset_inner_headers(skb);
> 
> + src_port = udp_flow_src_port(dev_net(dev), skb, 0, 0, true);
> +
>   /* PDP context lookups in gtp_build_skb_*() need rcu read-side lock. */
>   rcu_read_lock();
>   switch (proto) {
> @@ -596,7 +599,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, 
> struct
> net_device *dev)
>   pktinfo.iph->tos,
>   ip4_dst_hoplimit(>dst),
>   0,
> - pktinfo.gtph_port, pktinfo.gtph_port,
> + src_port, pktinfo.gtph_port,
>   true, false);
>   break;
>   }
> --
> 2.3.7


Re: [PATCH net-next v3 0/8] gtp: misc improvements

2017-02-16 Thread Andreas Schultz
Hi Pablo, Harald,

Do you have some time to look at the patches?

Andreas

- On Feb 13, 2017, at 4:36 PM, Andreas Schultz aschu...@tpip.net wrote:

> Hi Pablo,
> 
> This is v3 of the GTP improvements.
> 
> This series lays the groundwork for removing the socket references from
> the GTP netdevice by removing duplicate code and simplifying the logic on
> some code paths.
> 
> It slighly changes the GTP genl API by making the socket parameters optional
> (though one of them is still required).
> 
> The removal of the socket references will break the 1:1 releation between
> GTP netdevice and GTP socket that prevents us to support multiple VRFs with
> overlaping IP addresse spaces attached to the same GTP-U entity (needed for
> multi APN support).
> 
> Pablo found a socket hold problem in v2. In order to solve that I had to
> switch the socket references from the struct socket to the internal
> struct sock. This should have no functionl impact, but we can now hang
> on to the reference without blocking user space from closing the GTP socket.
> 
> There was also some length off-list conversation about why the netdevice to
> socket relation needs to be changed at all. Harald did already agree to this
> but Pablo had some questions. I've tried to address that with a bit of
> dokumentation for the GTP module. Hopefully this will explain the need for
> the change sufficiently.
> 
> This series does have conflicts with the SGSN side tunnel work done by
> Jonas Bonn. The unification of the tunnel Rx code touches the same places
> he changed.
> 
> v2->v3:
> * add documentation to explain the goal of all these changes
> * incorporate review comments
> * switch from struct socket to struct sock
> 
> Regards
> Andreas
> 
> --
> Andreas Schultz (8):
>  gtp: add documentation
>  gtp: switch from struct socket to struct sock for the GTP sockets
>  gtp: make GTP sockets in gtp_newlink optional
>  gtp: merge gtp_get_net and gtp_genl_find_dev
>  gtp: consolidate gtp socket rx path
>  gtp: unify genl_find_pdp and prepare for per socket lookup
>  gtp: consolidate pdp context destruction into helper
>  gtp: add socket to pdp context
> 
> Documentation/networking/gtp.txt | 112 
> drivers/net/gtp.c| 548 +++
> 2 files changed, 386 insertions(+), 274 deletions(-)
> create mode 100644 Documentation/networking/gtp.txt
> 
> --
> 2.10.2


Re: [PATCH net-next v3 2/8] gtp: switch from struct socket to struct sock for the GTP sockets

2017-02-14 Thread Andreas Schultz
- On Feb 14, 2017, at 6:48 PM, David S. Miller da...@davemloft.net wrote:

> From: Andreas Schultz <aschu...@tpip.net>
> Date: Mon, 13 Feb 2017 16:36:18 +0100
> 
>> +if (gtp->sk0) {
>> +udp_sk(gtp->sk0)->encap_type = 0;
>> +rcu_assign_sk_user_data(gtp->sk0, NULL);
>> +sock_put(gtp->sk0);
>>  }
> 
> This does "sock_put(NULL);" because you are assigning gtp->sk0 to
> NULL before the sock_put() call.  So you are leaking the socket,
> at best.

I don't understand how this should happen. If I where to use rcu_assign_pointer,
then yes, but rcu_assign_sk_user_data does assign to the sk_user_data member
of struct sock and not to the argument itself.

Andreas


[PATCH net-next v3 8/8] gtp: add socket to pdp context

2017-02-13 Thread Andreas Schultz
Having the socket present in context simplifies the sending logic.
It also fixes the invalid assumption that we have to use the same
sending socket for all client IP's on a specific gtp interface.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 94 +++
 1 file changed, 47 insertions(+), 47 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 62f598b..45d6f7e 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,7 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct sock *sk;
struct net_device   *dev;
 
atomic_ttx_seq;
@@ -179,8 +180,7 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct 
pdp_ctx *pctx,
return false;
 }
 
-static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int 
hdrlen,
- bool xnet)
+static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int 
hdrlen)
 {
struct pcpu_sw_netstats *stats;
 
@@ -190,7 +190,8 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff 
*skb, unsigned int hdrlen
}
 
/* Get rid of the GTP + UDP headers. */
-   if (iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet))
+   if (iptunnel_pull_header(skb, hdrlen, skb->protocol,
+!net_eq(sock_net(pctx->sk), 
dev_net(pctx->dev
return -1;
 
pr_debug("forwarding packet from GGSN to uplink\n");
@@ -214,8 +215,7 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff 
*skb, unsigned int hdrlen
 }
 
 /* 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,
-  bool xnet)
+static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp0_header);
@@ -239,11 +239,10 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return 1;
}
 
-   return gtp_rx(pctx, skb, hdrlen, xnet);
+   return gtp_rx(pctx, skb, hdrlen);
 }
 
-static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
-   bool xnet)
+static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp1_header);
@@ -282,7 +281,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
return 1;
}
 
-   return gtp_rx(pctx, skb, hdrlen, xnet);
+   return gtp_rx(pctx, skb, hdrlen);
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -318,7 +317,6 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 {
struct gtp_dev *gtp;
int ret = 0;
-   bool xnet;
 
gtp = rcu_dereference_sk_user_data(sk);
if (!gtp)
@@ -326,16 +324,14 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
 
-   xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
-
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
netdev_dbg(gtp->dev, "received GTP0 packet\n");
-   ret = gtp0_udp_encap_recv(gtp, skb, xnet);
+   ret = gtp0_udp_encap_recv(gtp, skb);
break;
case UDP_ENCAP_GTP1U:
netdev_dbg(gtp->dev, "received GTP1U packet\n");
-   ret = gtp1u_udp_encap_recv(gtp, skb, xnet);
+   ret = gtp1u_udp_encap_recv(gtp, skb);
break;
default:
ret = -1; /* Shouldn't happen. */
@@ -378,8 +374,9 @@ static void gtp_dev_uninit(struct net_device *dev)
free_percpu(dev->tstats);
 }
 
-static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4,
-  const struct sock *sk, __be32 daddr)
+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;
@@ -388,7 +385,7 @@ static struct rtable *ip4_route_output_gtp(struct net *net, 
struct flowi4 *fl4,
fl4->flowi4_tos = RT_CONN_FLAGS(sk);
fl4->flowi4_proto   = sk->sk_protocol;
 
-   return ip_route_output_key(net, fl4);
+   return ip_route_output_key(sock_net(sk), fl4);
 }
 
 static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
@@ -477,7 +474,6 @@ static int gtp_build_skb_ip4(struct 

[PATCH net-next v3 7/8] gtp: consolidate pdp context destruction into helper

2017-02-13 Thread Andreas Schultz
Consolidate duplicate code into helper.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 24 ++--
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index d3c384e..62f598b 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -86,6 +86,8 @@ struct gtp_net {
 
 static u32 gtp_h_initval;
 
+static void pdp_context_delete(struct pdp_ctx *pctx);
+
 static inline u32 gtp0_hashfn(u64 tid)
 {
u32 *tid32 = (u32 *) 
@@ -781,13 +783,10 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
struct pdp_ctx *pctx;
int i;
 
-   for (i = 0; i < gtp->hash_size; i++) {
-   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid) {
-   hlist_del_rcu(>hlist_tid);
-   hlist_del_rcu(>hlist_addr);
-   kfree_rcu(pctx, rcu_head);
-   }
-   }
+   for (i = 0; i < gtp->hash_size; i++)
+   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid)
+   pdp_context_delete(pctx);
+
synchronize_rcu();
kfree(gtp->addr_hash);
kfree(gtp->tid_hash);
@@ -997,6 +996,13 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
return 0;
 }
 
+static void pdp_context_delete(struct pdp_ctx *pctx)
+{
+   hlist_del_rcu(>hlist_tid);
+   hlist_del_rcu(>hlist_addr);
+   kfree_rcu(pctx, rcu_head);
+}
+
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
struct gtp_dev *gtp;
@@ -1105,9 +,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct 
genl_info *info)
netdev_dbg(pctx->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp 
%p)\n",
   pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
 
-   hlist_del_rcu(>hlist_tid);
-   hlist_del_rcu(>hlist_addr);
-   kfree_rcu(pctx, rcu_head);
+   pdp_context_delete(pctx);
 
 out_unlock:
rcu_read_unlock();
-- 
2.10.2



[PATCH net-next v3 5/8] gtp: consolidate gtp socket rx path

2017-02-13 Thread Andreas Schultz
Add network device to gtp context in preparation for splitting
the TEID from the network device.

Use this to rework the socker rx path. Move the common RX part
of v0 and v1 into a helper. Also move the final rx part into
that helper as well.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 80 ++-
 1 file changed, 44 insertions(+), 36 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index f340e20..e21b663 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,8 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct net_device   *dev;
+
atomic_ttx_seq;
struct rcu_head rcu_head;
 };
@@ -175,6 +177,40 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct 
pdp_ctx *pctx,
return false;
 }
 
+static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int 
hdrlen,
+ bool xnet)
+{
+   struct pcpu_sw_netstats *stats;
+
+   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
+   pr_debug("No PDP ctx for this MS\n");
+   return 1;
+   }
+
+   /* Get rid of the GTP + UDP headers. */
+   if (iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet))
+   return -1;
+
+   pr_debug("forwarding packet from GGSN to uplink\n");
+
+   /* Now that the UDP and the GTP header have been removed, set up the
+* new network header. This is required by the upper layer to
+* calculate the transport header.
+*/
+   skb_reset_network_header(skb);
+
+   skb->dev = pctx->dev;
+
+   stats = this_cpu_ptr(pctx->dev->tstats);
+   u64_stats_update_begin(>syncp);
+   stats->rx_packets++;
+   stats->rx_bytes += skb->len;
+   u64_stats_update_end(>syncp);
+
+   netif_rx(skb);
+   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,
   bool xnet)
@@ -201,13 +237,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
return 1;
}
 
-   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
-   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return 1;
-   }
-
-   /* Get rid of the GTP + UDP headers. */
-   return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+   return gtp_rx(pctx, skb, hdrlen, xnet);
 }
 
 static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
@@ -250,13 +280,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return 1;
}
 
-   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
-   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return 1;
-   }
-
-   /* Get rid of the GTP + UDP headers. */
-   return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+   return gtp_rx(pctx, skb, hdrlen, xnet);
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -290,10 +314,9 @@ static void gtp_encap_disable(struct gtp_dev *gtp)
  */
 static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
-   struct pcpu_sw_netstats *stats;
struct gtp_dev *gtp;
+   int ret = 0;
bool xnet;
-   int ret;
 
gtp = rcu_dereference_sk_user_data(sk);
if (!gtp)
@@ -319,33 +342,17 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
switch (ret) {
case 1:
netdev_dbg(gtp->dev, "pass up to the process\n");
-   return 1;
+   break;
case 0:
-   netdev_dbg(gtp->dev, "forwarding packet from GGSN to uplink\n");
break;
case -1:
netdev_dbg(gtp->dev, "GTP packet has been dropped\n");
kfree_skb(skb);
-   return 0;
+   ret = 0;
+   break;
}
 
-   /* Now that the UDP and the GTP header have been removed, set up the
-* new network header. This is required by the upper layer to
-* calculate the transport header.
-*/
-   skb_reset_network_header(skb);
-
-   skb->dev = gtp->dev;
-
-   stats = this_cpu_ptr(gtp->dev->tstats);
-   u64_stats_update_begin(>syncp);
-   stats->rx_packets++;
-   stats->rx_bytes += skb->len;
-   u64_stats_update_end(>syncp);
-
-   netif_rx(skb);
-
-   return 0;
+   return ret;
 }
 
 static int gtp_dev_init(struct net_device *dev)
@@ -953,6 +960,7 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
if (pctx == NULL)
return -ENOMEM;
 
+   pctx->dev = gtp->dev;
ipv4_pdp_fill(pctx, info);
atomic_set(>tx_seq, 0);
 
-- 
2.10.2



[PATCH net-next v3 0/8] gtp: misc improvements

2017-02-13 Thread Andreas Schultz
Hi Pablo,

This is v3 of the GTP improvements.

This series lays the groundwork for removing the socket references from
the GTP netdevice by removing duplicate code and simplifying the logic on
some code paths.

It slighly changes the GTP genl API by making the socket parameters optional
(though one of them is still required).

The removal of the socket references will break the 1:1 releation between
GTP netdevice and GTP socket that prevents us to support multiple VRFs with
overlaping IP addresse spaces attached to the same GTP-U entity (needed for
multi APN support).

Pablo found a socket hold problem in v2. In order to solve that I had to
switch the socket references from the struct socket to the internal
struct sock. This should have no functionl impact, but we can now hang
on to the reference without blocking user space from closing the GTP socket.

There was also some length off-list conversation about why the netdevice to
socket relation needs to be changed at all. Harald did already agree to this
but Pablo had some questions. I've tried to address that with a bit of
dokumentation for the GTP module. Hopefully this will explain the need for
the change sufficiently.

This series does have conflicts with the SGSN side tunnel work done by
Jonas Bonn. The unification of the tunnel Rx code touches the same places
he changed.

v2->v3:
 * add documentation to explain the goal of all these changes
 * incorporate review comments
 * switch from struct socket to struct sock

Regards
Andreas

--
Andreas Schultz (8):
  gtp: add documentation
  gtp: switch from struct socket to struct sock for the GTP sockets
  gtp: make GTP sockets in gtp_newlink optional
  gtp: merge gtp_get_net and gtp_genl_find_dev
  gtp: consolidate gtp socket rx path
  gtp: unify genl_find_pdp and prepare for per socket lookup
  gtp: consolidate pdp context destruction into helper
  gtp: add socket to pdp context

 Documentation/networking/gtp.txt | 112 
 drivers/net/gtp.c| 548 +++
 2 files changed, 386 insertions(+), 274 deletions(-)
 create mode 100644 Documentation/networking/gtp.txt

-- 
2.10.2



[PATCH net-next v3 2/8] gtp: switch from struct socket to struct sock for the GTP sockets

2017-02-13 Thread Andreas Schultz
After enabling the UDP encapsulation, only the sk member is used.

Holding the socket would prevent user space from closing the socket,
but holding a reference to the sk member does not have the same
effect.

This change will make it simpler to later detach the sockets from
the netdevice.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 42 +++---
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index bda0c64..a8ce8c7 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -66,8 +66,8 @@ struct pdp_ctx {
 struct gtp_dev {
struct list_headlist;
 
-   struct socket   *sock0;
-   struct socket   *sock1u;
+   struct sock *sk0;
+   struct sock *sk1u;
 
struct net_device   *dev;
 
@@ -261,17 +261,19 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
 
 static void gtp_encap_disable(struct gtp_dev *gtp)
 {
-   if (gtp->sock0 && gtp->sock0->sk) {
-   udp_sk(gtp->sock0->sk)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sock0->sk, NULL);
+   if (gtp->sk0) {
+   udp_sk(gtp->sk0)->encap_type = 0;
+   rcu_assign_sk_user_data(gtp->sk0, NULL);
+   sock_put(gtp->sk0);
}
-   if (gtp->sock1u && gtp->sock1u->sk) {
-   udp_sk(gtp->sock1u->sk)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sock1u->sk, NULL);
+   if (gtp->sk1u) {
+   udp_sk(gtp->sk1u)->encap_type = 0;
+   rcu_assign_sk_user_data(gtp->sk1u, NULL);
+   sock_put(gtp->sk1u);
}
 
-   gtp->sock0 = NULL;
-   gtp->sock1u = NULL;
+   gtp->sk0 = NULL;
+   gtp->sk1u = NULL;
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -484,14 +486,14 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
 
switch (pctx->gtp_version) {
case GTP_V0:
-   if (gtp->sock0)
-   sk = gtp->sock0->sk;
+   if (gtp->sk0)
+   sk = gtp->sk0;
else
sk = NULL;
break;
case GTP_V1:
-   if (gtp->sock1u)
-   sk = gtp->sock1u->sk;
+   if (gtp->sk1u)
+   sk = gtp->sk1u;
else
sk = NULL;
break;
@@ -504,7 +506,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
return -ENOENT;
}
 
-   rt = ip4_route_output_gtp(sock_net(sk), , gtp->sock0->sk,
+   rt = ip4_route_output_gtp(sock_net(sk), , gtp->sk0,
  pctx->sgsn_addr_ip4.s_addr);
if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to SSGN %pI4\n",
@@ -839,18 +841,20 @@ static int gtp_encap_enable(struct net_device *dev, 
struct gtp_dev *gtp,
 
netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u);
 
-   gtp->sock0 = sock0;
-   gtp->sock1u = sock1u;
+   sock_hold(sock0->sk);
+   gtp->sk0 = sock0->sk;
+   sock_hold(sock1u->sk);
+   gtp->sk1u = sock1u->sk;
 
tuncfg.sk_user_data = gtp;
tuncfg.encap_rcv = gtp_encap_recv;
tuncfg.encap_destroy = gtp_encap_destroy;
 
tuncfg.encap_type = UDP_ENCAP_GTP0;
-   setup_udp_tunnel_sock(sock_net(gtp->sock0->sk), gtp->sock0, );
+   setup_udp_tunnel_sock(sock_net(gtp->sk0), sock0, );
 
tuncfg.encap_type = UDP_ENCAP_GTP1U;
-   setup_udp_tunnel_sock(sock_net(gtp->sock1u->sk), gtp->sock1u, );
+   setup_udp_tunnel_sock(sock_net(gtp->sk1u), sock1u, );
 
err = 0;
 err2:
-- 
2.10.2



[PATCH net-next v3 6/8] gtp: unify genl_find_pdp and prepare for per socket lookup

2017-02-13 Thread Andreas Schultz
This unifies duplicate code into a helper. It also prepares the
groundwork to add a lookup version that uses the socket to find
attache pdp contexts.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 124 +++---
 1 file changed, 53 insertions(+), 71 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index e21b663..d3c384e 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1039,55 +1039,70 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
return err;
 }
 
+static struct pdp_ctx *gtp_genl_find_pdp_by_link(struct sk_buff *skb,
+struct genl_info *info)
+{
+   struct gtp_dev *gtp;
+
+   gtp = gtp_genl_find_dev(sock_net(skb->sk), info->attrs);
+   if (!gtp)
+   return ERR_PTR(-ENODEV);
+
+   if (info->attrs[GTPA_MS_ADDRESS]) {
+   __be32 ip = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
+
+   return ipv4_pdp_find(gtp, ip);
+   } else if (info->attrs[GTPA_VERSION]) {
+   u32 gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]);
+
+   if (gtp_version == GTP_V0 && info->attrs[GTPA_TID])
+   return gtp0_pdp_find(gtp, nla_get_u64(
+info->attrs[GTPA_TID]));
+   else if (gtp_version == GTP_V1 && info->attrs[GTPA_I_TEI])
+   return gtp1_pdp_find(gtp, nla_get_u32(
+info->attrs[GTPA_I_TEI]));
+   }
+
+   return ERR_PTR(-EINVAL);
+}
+
+static struct pdp_ctx *gtp_genl_find_pdp(struct sk_buff *skb,
+struct genl_info *info)
+{
+   struct pdp_ctx *pctx;
+
+   if (info->attrs[GTPA_LINK])
+   pctx = gtp_genl_find_pdp_by_link(skb, info);
+   else
+   pctx = ERR_PTR(-EINVAL);
+
+   if (!pctx)
+   pctx = ERR_PTR(-ENOENT);
+
+   return pctx;
+}
+
 static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
 {
struct pdp_ctx *pctx;
-   struct gtp_dev *gtp;
int err = 0;
 
-   if (!info->attrs[GTPA_VERSION] ||
-   !info->attrs[GTPA_LINK])
+   if (!info->attrs[GTPA_VERSION])
return -EINVAL;
 
rcu_read_lock();
 
-   gtp = gtp_genl_find_dev(sock_net(skb->sk), info->attrs);
-   if (!gtp) {
-   err = -ENODEV;
-   goto out_unlock;
-   }
-
-   switch (nla_get_u32(info->attrs[GTPA_VERSION])) {
-   case GTP_V0:
-   if (!info->attrs[GTPA_TID]) {
-   err = -EINVAL;
-   goto out_unlock;
-   }
-   pctx = gtp0_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_TID]));
-   break;
-   case GTP_V1:
-   if (!info->attrs[GTPA_I_TEI]) {
-   err = -EINVAL;
-   goto out_unlock;
-   }
-   pctx = gtp1_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_I_TEI]));
-   break;
-
-   default:
-   err = -EINVAL;
-   goto out_unlock;
-   }
-
-   if (!pctx) {
-   err = -ENOENT;
+   pctx = gtp_genl_find_pdp(skb, info);
+   if (IS_ERR(pctx)) {
+   err = PTR_ERR(pctx);
goto out_unlock;
}
 
if (pctx->gtp_version == GTP_V0)
-   netdev_dbg(gtp->dev, "GTPv0-U: deleting tunnel id = %llx (pdp 
%p)\n",
+   netdev_dbg(pctx->dev, "GTPv0-U: deleting tunnel id = %llx (pdp 
%p)\n",
   pctx->u.v0.tid, pctx);
else if (pctx->gtp_version == GTP_V1)
-   netdev_dbg(gtp->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp 
%p)\n",
+   netdev_dbg(pctx->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp 
%p)\n",
   pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
 
hlist_del_rcu(>hlist_tid);
@@ -1141,49 +1156,16 @@ static int gtp_genl_get_pdp(struct sk_buff *skb, struct 
genl_info *info)
 {
struct pdp_ctx *pctx = NULL;
struct sk_buff *skb2;
-   struct gtp_dev *gtp;
-   u32 gtp_version;
int err;
 
-   if (!info->attrs[GTPA_VERSION] ||
-   !info->attrs[GTPA_LINK])
+   if (!info->attrs[GTPA_VERSION])
return -EINVAL;
 
-   gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]);
-   switch (gtp_version) {
-   case GTP_V0:
-   case GTP_V1:
-   break;
-   default:
-   return -EINVAL;
-   }
-
rcu_read_lock();
 
-   gtp = gtp_genl_find_dev(sock_net(skb->sk), info->attrs);
-   if (!gtp) {
-   err = -ENODEV;
-   

[PATCH net-next v3 3/8] gtp: make GTP sockets in gtp_newlink optional

2017-02-13 Thread Andreas Schultz
Having both GTPv0-U and GTPv1-U is not always desirable.
Fallback from GTPv1-U to GTPv0-U was depreciated from 3GPP
Rel-8 onwards. Post Rel-8 implementation are discuraged
from listening on the v0 port (see 3GPP TS 29.281, Sect. 1).

A future change will completely decouple the sockets from the
network device. Till then, at least one of the sockets needs to
be specified (either v0 or v1), the other is optional.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 149 +-
 1 file changed, 79 insertions(+), 70 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index a8ce8c7..fe96d21 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -259,30 +259,30 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
 }
 
-static void gtp_encap_disable(struct gtp_dev *gtp)
-{
-   if (gtp->sk0) {
-   udp_sk(gtp->sk0)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sk0, NULL);
-   sock_put(gtp->sk0);
-   }
-   if (gtp->sk1u) {
-   udp_sk(gtp->sk1u)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sk1u, NULL);
-   sock_put(gtp->sk1u);
-   }
-
-   gtp->sk0 = NULL;
-   gtp->sk1u = NULL;
-}
-
 static void gtp_encap_destroy(struct sock *sk)
 {
struct gtp_dev *gtp;
 
gtp = rcu_dereference_sk_user_data(sk);
-   if (gtp)
-   gtp_encap_disable(gtp);
+   if (gtp) {
+   udp_sk(sk)->encap_type = 0;
+   rcu_assign_sk_user_data(sk, NULL);
+   sock_put(sk);
+   }
+}
+
+static void gtp_encap_disable_sock(struct sock *sk)
+{
+   if (!sk)
+   return;
+
+   gtp_encap_destroy(sk);
+}
+
+static void gtp_encap_disable(struct gtp_dev *gtp)
+{
+   gtp_encap_disable_sock(gtp->sk0);
+   gtp_encap_disable_sock(gtp->sk1u);
 }
 
 /* UDP encapsulation receive handler. See net/ipv4/udp.c.
@@ -642,27 +642,24 @@ static void gtp_link_setup(struct net_device *dev)
 
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
 static void gtp_hashtable_free(struct gtp_dev *gtp);
-static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1);
+static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]);
+static void gtp_encap_disable(struct gtp_dev *gtp);
 
 static int gtp_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
 {
-   int hashsize, err, fd0, fd1;
struct gtp_dev *gtp;
struct gtp_net *gn;
+   int hashsize, err;
 
-   if (!data[IFLA_GTP_FD0] || !data[IFLA_GTP_FD1])
+   if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1])
return -EINVAL;
 
gtp = netdev_priv(dev);
 
-   fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
-   fd1 = nla_get_u32(data[IFLA_GTP_FD1]);
-
-   err = gtp_encap_enable(dev, gtp, fd0, fd1);
+   err = gtp_encap_enable(gtp, data);
if (err < 0)
-   goto out_err;
+   return err;
 
if (!data[IFLA_GTP_PDP_HASHSIZE])
hashsize = 1024;
@@ -690,7 +687,6 @@ static int gtp_newlink(struct net *src_net, struct 
net_device *dev,
gtp_hashtable_free(gtp);
 out_encap:
gtp_encap_disable(gtp);
-out_err:
return err;
 }
 
@@ -805,63 +801,76 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
kfree(gtp->tid_hash);
 }
 
-static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1)
+static struct sock *gtp_encap_enable_socket(int fd, int type,
+   struct gtp_dev *gtp)
 {
struct udp_tunnel_sock_cfg tuncfg = {NULL};
-   struct socket *sock0, *sock1u;
+   struct socket *sock;
+   struct sock *sk;
int err;
 
-   netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1);
+   pr_debug("enable gtp on %d, %d\n", fd, type);
 
-   sock0 = sockfd_lookup(fd_gtp0, );
-   if (sock0 == NULL) {
-   netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0);
-   return -ENOENT;
+   sock = sockfd_lookup(fd, );
+   if (!sock) {
+   pr_debug("gtp socket fd=%d not found\n", fd);
+   return NULL;
}
 
-   if (sock0->sk->sk_protocol != IPPROTO_UDP) {
-   netdev_dbg(dev, "socket fd=%d not UDP\n", fd_gtp0);
-   err = -EINVAL;
-   goto err1;
+   if (sock->sk->sk_protocol != IPPROTO_UDP) {
+   pr_debug("socket fd=%d not UDP\n", fd);
+   sk = ERR_PTR(-EINVAL);
+   goto out_sock;

[PATCH net-next v3 4/8] gtp: merge gtp_get_net and gtp_genl_find_dev

2017-02-13 Thread Andreas Schultz
Both function are always used together with the final goal to
get the gtp_dev. This simplifies the code by merging them together.

The netdevice lookup is changed to use the regular dev_get_by_index.
The gtp netdevice list is now only used to find the PDP contexts for
imcomming packets. It can be completely eliminated Once the TEID
hash is moved into the GTP socket.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 147 ++
 1 file changed, 70 insertions(+), 77 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index fe96d21..f340e20 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -745,21 +745,6 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = {
.fill_info  = gtp_fill_info,
 };
 
-static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[])
-{
-   struct net *net;
-
-   /* Examine the link attributes and figure out which network namespace
-* we are talking about.
-*/
-   if (tb[GTPA_NET_NS_FD])
-   net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD]));
-   else
-   net = get_net(src_net);
-
-   return net;
-}
-
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize)
 {
int i;
@@ -873,16 +858,31 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct 
nlattr *data[])
return 0;
 }
 
-static struct net_device *gtp_find_dev(struct net *net, int ifindex)
+static struct gtp_dev *gtp_genl_find_dev(struct net *src_net,
+struct nlattr *tb[])
 {
-   struct gtp_net *gn = net_generic(net, gtp_net_id);
-   struct gtp_dev *gtp;
-
-   list_for_each_entry_rcu(gtp, >gtp_dev_list, list) {
-   if (ifindex == gtp->dev->ifindex)
-   return gtp->dev;
-   }
-   return NULL;
+   struct gtp_dev *gtp = NULL;
+   struct net_device *dev;
+   struct net *net;
+
+   /* Examine the link attributes and figure out which network namespace
+* we are talking about.
+*/
+   if (tb[GTPA_NET_NS_FD])
+   net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD]));
+   else
+   net = get_net(src_net);
+
+   if (IS_ERR(net))
+   return NULL;
+
+   /* Check if there's an existing gtpX device to configure */
+   dev = dev_get_by_index_rcu(net, nla_get_u32(tb[GTPA_LINK]));
+   if (dev->netdev_ops == _netdev_ops)
+   gtp = netdev_priv(dev);
+
+   put_net(net);
+   return gtp;
 }
 
 static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
@@ -912,9 +912,9 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct 
genl_info *info)
}
 }
 
-static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
+static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info)
 {
-   struct gtp_dev *gtp = netdev_priv(dev);
+   struct net_device *dev = gtp->dev;
u32 hash_ms, hash_tid = 0;
struct pdp_ctx *pctx;
bool found = false;
@@ -991,8 +991,8 @@ static int ipv4_pdp_add(struct net_device *dev, struct 
genl_info *info)
 
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
-   struct net_device *dev;
-   struct net *net;
+   struct gtp_dev *gtp;
+   int err;
 
if (!info->attrs[GTPA_VERSION] ||
!info->attrs[GTPA_LINK] ||
@@ -1016,77 +1016,79 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
return -EINVAL;
}
 
-   net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
-   if (IS_ERR(net))
-   return PTR_ERR(net);
+   rcu_read_lock();
 
-   /* Check if there's an existing gtpX device to configure */
-   dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
-   if (dev == NULL) {
-   put_net(net);
-   return -ENODEV;
+   gtp = gtp_genl_find_dev(sock_net(skb->sk), info->attrs);
+   if (!gtp) {
+   err = -ENODEV;
+   goto out_unlock;
}
-   put_net(net);
 
-   return ipv4_pdp_add(dev, info);
+   err = ipv4_pdp_add(gtp, info);
+
+out_unlock:
+   rcu_read_unlock();
+   return err;
 }
 
 static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
 {
-   struct net_device *dev;
struct pdp_ctx *pctx;
struct gtp_dev *gtp;
-   struct net *net;
+   int err = 0;
 
if (!info->attrs[GTPA_VERSION] ||
!info->attrs[GTPA_LINK])
return -EINVAL;
 
-   net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
-   if (IS_ERR(net))
-   return PTR_ERR(net);
+   rcu_read_lock();
 
-   /* Check if there's an existing gtpX device to configure */
-   dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LIN

[PATCH net-next v3 1/8] gtp: add documentation

2017-02-13 Thread Andreas Schultz
The GTP-U implementation in not only driven by 3GPP TS 29.281, but
also by the requirements of the 3GPP network entities that use it.

This document tries to explain and clarify some design decision and
their origins.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 Documentation/networking/gtp.txt | 112 +++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/networking/gtp.txt

diff --git a/Documentation/networking/gtp.txt b/Documentation/networking/gtp.txt
new file mode 100644
index 000..cefd983
--- /dev/null
+++ b/Documentation/networking/gtp.txt
@@ -0,0 +1,112 @@
+Note: this document contain some forward looking statements and does
+  not (yet) reflect the implementation. This is done to motivate
+  and explain some of the changes to come.
+
+  This note will be removed once the implementation matches this
+  document.
+
+General Packet Radio System (GPRS) Tunnelling Protocol User Plane (GTP-U)
+=
+
+The GTP-U protocol is a tunnelling protocol used in public land mobile networks
+[PLMN]. It is always use together with a user space control instance 
implementing
+a 3GPP network entity (e.g. GGSN, SGSN, PDN-GW, S-GW).
+
+The protocol is specified for version 0 in [GSM 09.60] and for version 1 in
+[3GPP TS 29.281]. However, the functionality defined in those documents has
+always to be taken in relation of the functional 3GPP entity that is using it.
+
+The rest of document is focusing on version 1 of the protocol. GTPv1 to GTPv0
+interworking and the use of GTPv0-U in general has be depreciated from 3GPP 
Rel8
+onward [3GPP TS 29.060].
+
+Local GTP-U entity and tunnel identification
+
+
+GTP-U uses UDP for transporting PDU's. The receiving UDP port is 2152 for
+GTPv1-U and 3386 for GTPv0-U.
+
+There is only one GTP-U entity (and therefor SGSN/GGSN/S-GW/PDN-GW instance)
+per IP address. Tunnel Endpoint Identifier (TEID) are unique per GTP-U entity.
+
+A specific tunnel is only defined by the destination entity. Since the
+destination port is constant, only the destination IP and TEID define
+a tunnel. The source IP and Port have no meaning for the tunnel.
+
+Therefore:
+
+  * when sending, the remote entity is defined by the remote IP and the tunnel
+endpoint id. The source IP and port have no meaning and can be changed
+at any time.
+
+  * when receiving the local entity is defined by the local destination IP
+ and the tunnel endpoint id. The source IP and port have no meaning and can
+ change at any time.
+
+[3GPP TS 29.281] Section 4.3.0 defines this so:
+
+> The TEID in the GTP-U header is used to de-multiplex traffic incoming from
+> remote tunnel endpoints so that it is delivered to the User plane entities
+> in a way that allows multiplexing of different users, different packet
+> protocols and different QoS levels. Therefore no two remote GTP-U endpoints
+> shall send traffic to a GTP-U protocol entity using the same TEID value 
except
+> for data forwarding as part of mobility procedures.
+
+The definition above only defines that two remote GTP-U endpoints *should not*
+send to the same TEID, it *does not* forbid or exclude such a scenario. In
+fact, the mentioned mobility procedures make it necessary that the GTP-U entity
+accepts traffic for TEID's from multiple or unknown peers.
+
+Therefor the receiving side only identifies tunnels based on TEID's, not based
+on the source IP.
+
+APN vs. Network Device
+--
+
+The GTP-U driver creates a Linux network device for each Gi/SGi interface.
+
+[3GPP TS 29.281] calls the Gi/SGi reference point an interface. This may lead
+to the impression that the GGSN/P-GW can have only one such interface.
+
+Correct is that the Gi/SGi reference point defines the interworking between
+the 3GPP packet domain (PDN) based on GTP-U tunnel and IP based networks.
+
+There is no provision in any of the 3GPP documents that limits the number of
+Gi/SGi interfaces implemented by a GGSN/P-GW.
+
+[3GPP TS 29.061] Section 11.3 makes it clear that the selection of a specific
+Gi/SGi interfaces is made through the Access Point Name (APN):
+
+>2. each private network manages its own addressing. In general this will
+>   result in different private networks having overlapping address ranges.
+>   A logically separate connection (e.g. an IP in IP tunnel or layer 2
+>   virtual circuit) is used between the GGSN/P-GW and each private 
network.
+>   In this case the IP address alone is not necessarily unique. The pair
+>   of values, Access Point Name (APN) and IPv4 address and/or IPv6
+>   prefixes, is unique.
+
+In order to support the overlapping address range use case, each APN is mapped
+to a separate Gi/SGi interface (network device).
+
+NOTE: The Access Point N

Re: [PATCH net-next v2 4/6] gtp: consolidate pdp context destruction into helper

2017-02-13 Thread Andreas Schultz


- On Feb 6, 2017, at 2:58 PM, laforge lafo...@gnumonks.org wrote:

> Hi Andreas,
> 
> On Mon, Jan 30, 2017 at 05:37:11PM +0100, Andreas Schultz wrote:
>> Consolidate duplicate code into helper.
> 
> Makes complete sense.
> 
> However:
> 
>> +static void pdp_context_delete(struct pdp_ctx *pctx);
>> +
> 
> why introduce the forward-declaration and then define the function
> further down in the file?  I think in general, it is preferred to put
> helper functions on top, before their first use, so forward declarations
> can be avoided?  Particularly if the helper function doesn't call any
> other functions that are not yet declared at this point.

I wanted to keep functions that work on the data structure close
together. I this case the function the initialized the pdp context
and the delete function for it.

Andreas

> 
> Please note the above might just be my personal taste, not sure if
> that's a general habit in the kernel networking code these days.
> 
> So with or without the re-ordering:
> 
> Acked-by: Harald Welte <lafo...@gnumonks.org>
> 
> --
> - Harald Welte <lafo...@gnumonks.org>   http://laforge.gnumonks.org/
> 
> "Privacy in residential applications is a desirable marketing option."
>   (ETSI EN 300 175-7 Ch. A6)


Re: [PATCH net-next v2 2/6] gtp: merge gtp_get_net and gtp_genl_find_dev

2017-02-13 Thread Andreas Schultz


- On Feb 6, 2017, at 2:55 PM, Harald Welte lafo...@netfilter.org wrote:

> Hi Andreas,
> 
> On Mon, Jan 30, 2017 at 05:37:09PM +0100, Andreas Schultz wrote:
>> Both function are always used together with the final goal to
>> get the gtp_dev. This simplifies the code by merging them together.
> 
> Ok, some code restructuring / unification, seems useful.
> 
> However:
> 
>> -netdev_dbg(dev, "GTPv0-U: update tunnel id = %llx (pdp 
>> %p)\n",
>> -   pctx->u.v0.tid, pctx);
>> +pr_debug("GTPv0-U: update tunnel id = %llx (pdp %p)\n",
>> + pctx->u.v0.tid, pctx);
> 
> (and other related changes) appear to be purely cosmetic and should thus
> be unrelated to the function merging described in the change log
> message.

The dev argument has been removed from the surrounding function.
However, for those debug message having the network device information
is use full. I've modified the code in v3 a bit to keep the debug message.

Andreas

> 
> --
> - Harald Welte <lafo...@netfilter.org> http://netfilter.org/
> 
>  "Fragmentation is like classful addressing -- an interesting early
>   architectural error that shows how much experimentation was going
>on while IP was being designed."-- Paul Vixie


Re: [PATCH 1/1] gtp: support SGSN-side tunnels

2017-02-13 Thread Andreas Schultz
Hi,

- On Feb 13, 2017, at 12:16 PM, pablo pa...@netfilter.org wrote:

> On Mon, Feb 13, 2017 at 10:25:19AM +0100, Andreas Schultz wrote:
>> Hi,
>> 
>> I'm a bit late to comment, but maybe you can consider an additional
>> change for v2...
>> 
>> - On Feb 3, 2017, at 10:12 AM, Jonas Bonn jo...@southpole.se wrote:
>> 
>> > The GTP-tunnel driver is explicitly GGSN-side as it searches for PDP
>> > contexts based on the incoming packets _destination_ address.  If we
>> > want to write an SGSN, then we want to be idenityfing PDP contexts
>> > based on _source_ address.
>> > 
>> > This patch adds a "flags" argument at GTP-link creation time to specify
>> > whether we are on the GGSN or SGSN side of the tunnel; this flag is then
>> > used to determine which part of the IP packet to use in determining
>> > the PDP context.
>> > 
>> > Signed-off-by: Jonas Bonn <jo...@southpole.se>
>> > ---
>> > 
>> > drivers/net/gtp.c| 43 
>> > ---
>> > include/uapi/linux/gtp.h |  2 +-
>> > include/uapi/linux/if_link.h |  5 +
>> > 3 files changed, 38 insertions(+), 12 deletions(-)
>> > 
>> > diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
>> > index 50349a9..1bbac69 100644
>> > --- a/drivers/net/gtp.c
>> > +++ b/drivers/net/gtp.c
>> > @@ -72,6 +72,7 @@ struct gtp_dev {
>> >struct net  *net;
>> >struct net_device   *dev;
>> > 
>> > +  unsigned intflags;
>> 
>> This should IMHO not go into the gtp_dev, the right place
>> is the PDP context.
> 
> So you want to allow mixed configurations where some PDP ctx may be in
> SGSN mode while others in GGSN.
> 
> This doesn't make any sense to me. On top of this, don't forget this
> is just for testing, so I don't see any valid usecase for such a fine
> grain thing.

You are right, running such a configuration does not make sense.
However, when I wrote this the PDP context looked like the most
sensible palace to me.

Anyhow, thinking about this again, I think that integrating that flag
in a rewrite of the validation logic in the Rx path make more sense.
Currently we validate the MS as soon as we have found the PDP context.
This should be delayed a bit and the validation should happen after
pulling the GTP header and right before injecting the payload into
the net device. The flag would then indeed go into the gtp_dev.

Andreas




Re: [PATCH 1/1] gtp: support SGSN-side tunnels

2017-02-13 Thread Andreas Schultz
Hi,

I'm a bit late to comment, but maybe you can consider an additional
change for v2...

- On Feb 3, 2017, at 10:12 AM, Jonas Bonn jo...@southpole.se wrote:

> The GTP-tunnel driver is explicitly GGSN-side as it searches for PDP
> contexts based on the incoming packets _destination_ address.  If we
> want to write an SGSN, then we want to be idenityfing PDP contexts
> based on _source_ address.
> 
> This patch adds a "flags" argument at GTP-link creation time to specify
> whether we are on the GGSN or SGSN side of the tunnel; this flag is then
> used to determine which part of the IP packet to use in determining
> the PDP context.
> 
> Signed-off-by: Jonas Bonn 
> ---
> 
> drivers/net/gtp.c| 43 ---
> include/uapi/linux/gtp.h |  2 +-
> include/uapi/linux/if_link.h |  5 +
> 3 files changed, 38 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
> index 50349a9..1bbac69 100644
> --- a/drivers/net/gtp.c
> +++ b/drivers/net/gtp.c
> @@ -72,6 +72,7 @@ struct gtp_dev {
>   struct net  *net;
>   struct net_device   *dev;
> 
> + unsigned intflags;

This should IMHO not go into the gtp_dev, the right place
is the PDP context.

In the current design the netdevice might seem like the logical
place, but the relation between tunnels and netdevices is actually
wrong. This leaves the PDP context the only correct place.

I currently have an ongoing discussion with Pablo about this. Harald
seems already convinced 
(http://marc.info/?l=linux-netdev=148638992010344=2).

>   unsigned inthash_size;
>   struct hlist_head   *tid_hash;
>   struct hlist_head   *addr_hash;
> @@ -150,8 +151,8 @@ static struct pdp_ctx *ipv4_pdp_find(struct gtp_dev *gtp,
> __be32 ms_addr)
>   return NULL;
> }
> 
> -static bool gtp_check_src_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx,
> -   unsigned int hdrlen)
> +static bool gtp_check_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx,
> +   unsigned int hdrlen, unsigned int flags)
> {
>   struct iphdr *iph;
> 
> @@ -160,18 +161,22 @@ static bool gtp_check_src_ms_ipv4(struct sk_buff *skb,
> struct pdp_ctx *pctx,
> 
>   iph = (struct iphdr *)(skb->data + hdrlen);
> 
> - return iph->saddr == pctx->ms_addr_ip4.s_addr;
> + if (flags & GTP_FLAGS_SGSN) {
> + return iph->daddr == pctx->ms_addr_ip4.s_addr;
> + } else {
> + return iph->saddr == pctx->ms_addr_ip4.s_addr;
> + }
> }
> 
> -/* Check if the inner IP source address in this packet is assigned to any
> +/* Check if the inner IP address in this packet is assigned to any
>  * existing mobile subscriber.
>  */
> -static bool gtp_check_src_ms(struct sk_buff *skb, struct pdp_ctx *pctx,
> -  unsigned int hdrlen)
> +static bool gtp_check_ms(struct sk_buff *skb, struct pdp_ctx *pctx,
> +  unsigned int hdrlen, unsigned int flags)
> {
>   switch (ntohs(skb->protocol)) {
>   case ETH_P_IP:
> - return gtp_check_src_ms_ipv4(skb, pctx, hdrlen);
> + return gtp_check_ms_ipv4(skb, pctx, hdrlen, flags);
>   }
>   return false;
> }
> @@ -205,7 +210,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct
> sk_buff *skb,
>   goto out_rcu;
>   }
> 
> - if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
> + if (!gtp_check_ms(skb, pctx, hdrlen, gtp->flags)) {
>   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
>   ret = -1;
>   goto out_rcu;
> @@ -248,7 +253,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
> struct
> sk_buff *skb,
>   if (gtp1->flags & GTP1_F_MASK)
>   hdrlen += 4;
> 
> - /* Make sure the header is larger enough, including extensions. */
> + /* Make sure the header is large enough, including extensions. */
>   if (!pskb_may_pull(skb, hdrlen))
>   return -1;
> 
> @@ -262,7 +267,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
> struct
> sk_buff *skb,
>   goto out_rcu;
>   }
> 
> - if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
> + if (!gtp_check_ms(skb, pctx, hdrlen, gtp->flags)) {
>   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
>   ret = -1;
>   goto out_rcu;
> @@ -491,7 +496,11 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct
> net_device *dev,
>* Prepend PDP header with TEI/TID from PDP ctx.
>*/
>   iph = ip_hdr(skb);
> - pctx = ipv4_pdp_find(gtp, iph->daddr);
> + if (gtp->flags & GTP_FLAGS_SGSN) {
> + pctx = ipv4_pdp_find(gtp, iph->saddr);
> + } else {
> + pctx = ipv4_pdp_find(gtp, iph->daddr);
> + }
>   if (!pctx) {
>   netdev_dbg(dev, "no PDP ctx found for %pI4, skip\n",
>  

Re: [PATCH 1/1] gtp: support SGSN-side tunnels

2017-02-06 Thread Andreas Schultz
Hi Jonas,

Sorry, for later reply, I'm currently on vacation with almost no
internet access.

- On Feb 6, 2017, at 2:33 PM, Jonas Bonn jo...@southpole.se wrote:

> Hi Pablo,
> 
> On 02/06/2017 12:08 PM, Pablo Neira Ayuso wrote:
>> Hi Jonas,
>>
>> On Fri, Feb 03, 2017 at 10:12:31AM +0100, Jonas Bonn wrote:
>>> The GTP-tunnel driver is explicitly GGSN-side as it searches for PDP
>>> contexts based on the incoming packets _destination_ address.  If we
>>> want to write an SGSN, then we want to be idenityfing PDP contexts
>>> based on _source_ address.
>>>
>>> This patch adds a "flags" argument at GTP-link creation time to specify
>>> whether we are on the GGSN or SGSN side of the tunnel; this flag is then
>>> used to determine which part of the IP packet to use in determining
>>> the PDP context.
>> So far the implementation that I saw in osmocom relies on userspace code
>> to tunnel data from ME to the SSGN/SGW running on the base station.
>>
>> The data we get from GGSN -> SGSN needs to be places into a SN-PDU (via
>> SNDCP) when sending it to the BTS, right? So I wonder how this can be
>> useful given that we would need to see real IP packets coming to the
>> SSGN that we tunnel into GTP.
> 
> Fair enough.  The use-case I am looking at involves PGW load-testing
> where the simulated load is generated locally on the SGSN so it _is_
> seeing IP packets and the SNDCP is left out altogether.  Perhaps this is
> too pathological to warrant messing with the upstream driver... I don't
> know: the symmetry does not cost much even if it's of limited use.

Sounds reasonable. I'll review change with that in mind next week.

Andreas

> Couldn't the SNDCP theoretically be a separate node and push IP packets
> to the SGSN, thus making this useful?  Perhaps it's a stretch...
> 
> /Jonas


Re: [PATCH 1/1] gtp: support SGSN-side tunnels

2017-02-06 Thread Andreas Schultz
- On Feb 6, 2017, at 12:08 PM, pablo pa...@netfilter.org wrote:

> Hi Jonas,
> 
> On Fri, Feb 03, 2017 at 10:12:31AM +0100, Jonas Bonn wrote:
>> The GTP-tunnel driver is explicitly GGSN-side as it searches for PDP
>> contexts based on the incoming packets _destination_ address.  If we
>> want to write an SGSN, then we want to be idenityfing PDP contexts
>> based on _source_ address.
>> 
>> This patch adds a "flags" argument at GTP-link creation time to specify
>> whether we are on the GGSN or SGSN side of the tunnel; this flag is then
>> used to determine which part of the IP packet to use in determining
>> the PDP context.
> 
> So far the implementation that I saw in osmocom relies on userspace code
> to tunnel data from ME to the SSGN/SGW running on the base station.
> 
> The data we get from GGSN -> SGSN needs to be places into a SN-PDU (via
> SNDCP) when sending it to the BTS, right? So I wonder how this can be
> useful given that we would need to see real IP packets coming to the
> SSGN that we tunnel into GTP.

Uhm, no, absolutely not. The SGSN is not seeing IP packets, it's seeing
stuff that is supposed to put into GTP tunnels. The only instance in an
EPC (apart from a UE), that knows about the payload content of a GTP tunnel
is the GGSN/PGW. Even with Rel 13 Non IP bearers and CIoT optimization,
the interpretation of the content of an bearer is only done at the PGW.

Andreas
> 
> Thanks!


Re: [PATCH net-next v2 5/6] gtp: add socket to pdp context

2017-02-02 Thread Andreas Schultz


- On Feb 2, 2017, at 3:46 PM, pablo pa...@netfilter.org wrote:

> On Thu, Feb 02, 2017 at 03:38:07PM +0100, Andreas Schultz wrote:
>> 
>> 
>> - On Feb 2, 2017, at 3:28 PM, pablo pa...@netfilter.org wrote:
>> 
>> > On Thu, Feb 02, 2017 at 03:12:55PM +0100, Andreas Schultz wrote:
>> >> Hi,
>> >> 
>> >> - On Feb 2, 2017, at 2:56 PM, pablo pa...@netfilter.org wrote:
>> >> 
>> >> > On Mon, Jan 30, 2017 at 05:37:12PM +0100, Andreas Schultz wrote:
>> >> >> Having the socket present in context simplifies the sending logic.
>> >> >> It also fixes the invalid assumption that we have to use the same
>> >> >> sending socket for all client IP's on a specific gtp interface.
>> >> >> 
>> >> >> Signed-off-by: Andreas Schultz <aschu...@tpip.net>
>> >> >> ---
>> >> >>  drivers/net/gtp.c | 72 
>> >> >> ++-
>> >> >>  1 file changed, 39 insertions(+), 33 deletions(-)
>> >> >> 
>> >> >> diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
>> >> >> index 68c6c9b..ff00597 100644
>> >> >> --- a/drivers/net/gtp.c
>> >> >> +++ b/drivers/net/gtp.c
>> >> > [...]
>> >> >> @@ -984,16 +966,26 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, 
>> >> >> struct
>> >> >> genl_info *info)
>> >> >>return 0;
>> >> >>  }
>> >> >>  
>> >> >> +static void pdp_context_free(struct rcu_head *head)
>> >> >> +{
>> >> >> +  struct pdp_ctx *pctx = container_of(head, struct pdp_ctx, 
>> >> >> rcu_head);
>> >> >> +
>> >> >> +  sock_put(pctx->sk);
>> >> >> +  kfree(pctx);
>> >> >> +}
>> >> >> +
>> >> >>  static void pdp_context_delete(struct pdp_ctx *pctx)
>> >> >>  {
>> >> >>hlist_del_rcu(>hlist_tid);
>> >> >>hlist_del_rcu(>hlist_addr);
>> >> >> -  kfree(pctx);
>> >> >> +  call_rcu(>rcu_head, pdp_context_free);
>> >> > 
>> >> > This is fixing incorrect rcu conversion in 4/6. Please, fix this there.
>> >> 
>> >> Ehm, right, but the kfree in 4/6 could have been a kfree_rcu instead 
>> >> without
>> >> the call_rcu.
>> >> 
>> >> Do you prefer to introduce the call_rcu in 4/6 and then just add the 
>> >> sock_put
>> >> in this patch or should I change 4/6 to kfree_rcu and do the call_rcu
>> >> conversion here?
>> > 
>> > I suggest you just call kfree_rcu() from 4/6.
>> > 
>> > Regarding holding socket reference, see my comment for patch 1/6.
>> 
>> This is going to be a problem at this stage of the changes.
>> 
>> The final goal is to have a reference from the socket to the pdp context.
> 
> Is this just a cleanup? Or you need this sk caching for some follow up
> work?

It's not caching, the plan is to completely remove the socket from the
GTP netdevice (as far as that is possible without breaking the existing API).

A GGSN or PGW can serve multiple APN's on the same GTP-U socket. Those APN's
can have overlapping IP address ranges. The only sensible way to handle
this, is to have a netdevice per APN. This breaks the current 1:1 relation
between sockets and netdevices.

Andreas

> 
>> Then, when the socket is closed, the pdp context can be destroyed.
>>
>> However, at this point, only the netdevice knows about the contexts. So
>> when the socket is closed, the pdp context would have a dangling reference
>> to the socket.
>>
>> I can integrate this change into the later one. But it will make that
>> change larger and more difficult to review.
>> 
>> I guess, I'm going to drop this change from this series and see if can
>> reorder the next part so that it still makes and I easy to review
> 
> Agreed. Thanks.


Re: [PATCH net-next v2 5/6] gtp: add socket to pdp context

2017-02-02 Thread Andreas Schultz


- On Feb 2, 2017, at 3:28 PM, pablo pa...@netfilter.org wrote:

> On Thu, Feb 02, 2017 at 03:12:55PM +0100, Andreas Schultz wrote:
>> Hi,
>> 
>> - On Feb 2, 2017, at 2:56 PM, pablo pa...@netfilter.org wrote:
>> 
>> > On Mon, Jan 30, 2017 at 05:37:12PM +0100, Andreas Schultz wrote:
>> >> Having the socket present in context simplifies the sending logic.
>> >> It also fixes the invalid assumption that we have to use the same
>> >> sending socket for all client IP's on a specific gtp interface.
>> >> 
>> >> Signed-off-by: Andreas Schultz <aschu...@tpip.net>
>> >> ---
>> >>  drivers/net/gtp.c | 72 
>> >> ++-
>> >>  1 file changed, 39 insertions(+), 33 deletions(-)
>> >> 
>> >> diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
>> >> index 68c6c9b..ff00597 100644
>> >> --- a/drivers/net/gtp.c
>> >> +++ b/drivers/net/gtp.c
>> > [...]
>> >> @@ -984,16 +966,26 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct
>> >> genl_info *info)
>> >>   return 0;
>> >>  }
>> >>  
>> >> +static void pdp_context_free(struct rcu_head *head)
>> >> +{
>> >> + struct pdp_ctx *pctx = container_of(head, struct pdp_ctx, rcu_head);
>> >> +
>> >> + sock_put(pctx->sk);
>> >> + kfree(pctx);
>> >> +}
>> >> +
>> >>  static void pdp_context_delete(struct pdp_ctx *pctx)
>> >>  {
>> >>   hlist_del_rcu(>hlist_tid);
>> >>   hlist_del_rcu(>hlist_addr);
>> >> - kfree(pctx);
>> >> + call_rcu(>rcu_head, pdp_context_free);
>> > 
>> > This is fixing incorrect rcu conversion in 4/6. Please, fix this there.
>> 
>> Ehm, right, but the kfree in 4/6 could have been a kfree_rcu instead without
>> the call_rcu.
>> 
>> Do you prefer to introduce the call_rcu in 4/6 and then just add the sock_put
>> in this patch or should I change 4/6 to kfree_rcu and do the call_rcu
>> conversion here?
> 
> I suggest you just call kfree_rcu() from 4/6.
> 
> Regarding holding socket reference, see my comment for patch 1/6.

This is going to be a problem at this stage of the changes.

The final goal is to have a reference from the socket to the pdp context.
Then, when the socket is closed, the pdp context can be destroyed.

However, at this point, only the netdevice knows about the contexts. So
when the socket is closed, the pdp context would have a dangling reference
to the socket.

I can integrate this change into the later one. But it will make that
change larger and more difficult to review.

I guess, I'm going to drop this change from this series and see if can
reorder the next part so that it still makes and I easy to review

Andreas



Re: [PATCH net-next v2 1/6] gtp: make GTP sockets in gtp_newlink optional

2017-02-02 Thread Andreas Schultz


- On Feb 2, 2017, at 3:10 PM, pablo pa...@netfilter.org wrote:

> On Mon, Jan 30, 2017 at 05:37:08PM +0100, Andreas Schultz wrote:
>> Having both GTPv0-U and GTPv1-U is not always desirable.
>> Fallback from GTPv1-U to GTPv0-U was depreciated from 3GPP
>> Rel-8 onwards. Post Rel-8 implementation are discuraged
>> from listening on the v0 port (see 3GPP TS 29.281, Sect. 1).
>> 
>> A future change will completely decouple the sockets from the
>> network device. Till then, at least one of the sockets needs to
>> be specified (either v0 or v1), the other is optional.
>> 
>> Signed-off-by: Andreas Schultz <aschu...@tpip.net>
>> ---
>>  drivers/net/gtp.c | 142 
>> +-
>>  1 file changed, 76 insertions(+), 66 deletions(-)
>> 
>> diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
>> index bda0c64..18944f4 100644
>> --- a/drivers/net/gtp.c
>> +++ b/drivers/net/gtp.c
>> @@ -259,28 +259,30 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp,
>> struct sk_buff *skb,
>>  return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
>>  }
>>  
>> -static void gtp_encap_disable(struct gtp_dev *gtp)
>> -{
>> -if (gtp->sock0 && gtp->sock0->sk) {
>> -udp_sk(gtp->sock0->sk)->encap_type = 0;
>> -rcu_assign_sk_user_data(gtp->sock0->sk, NULL);
>> -}
>> -if (gtp->sock1u && gtp->sock1u->sk) {
>> -udp_sk(gtp->sock1u->sk)->encap_type = 0;
>> -rcu_assign_sk_user_data(gtp->sock1u->sk, NULL);
>> -}
>> -
>> -gtp->sock0 = NULL;
>> -gtp->sock1u = NULL;
>> -}
>> -
>>  static void gtp_encap_destroy(struct sock *sk)
>>  {
>>  struct gtp_dev *gtp;
>>  
>>  gtp = rcu_dereference_sk_user_data(sk);
>> -if (gtp)
>> -gtp_encap_disable(gtp);
>> +if (gtp) {
>> +udp_sk(sk)->encap_type = 0;
>> +rcu_assign_sk_user_data(sk, NULL);
>> +}
>> +}
>> +
>> +static void gtp_encap_disable_sock(struct socket *sock)
> 
> Nitpick: Please, use sk for consistency:
> 
>static void gtp_encap_disable_sock(struct socket *sk)
> 

Throughout the net subsystem 'struct socket` is always using sock
for variable names and 'struct sock' is using sk. I have been
following that convention, but can change to sk if you really want.

Andreas


Re: [PATCH net-next v2 3/6] gtp: unify genl_find_pdp and prepare for per socket lookup

2017-02-02 Thread Andreas Schultz


- On Feb 2, 2017, at 3:19 PM, pablo pa...@netfilter.org wrote:

> On Mon, Jan 30, 2017 at 05:37:10PM +0100, Andreas Schultz wrote:
>> This unifies duplicate code into a helper. It also prepares the
>> groundwork to add a lookup version that uses the socket to find
>> attache pdp contexts.
>> 
>> Signed-off-by: Andreas Schultz <aschu...@tpip.net>
>> ---
>>  drivers/net/gtp.c | 120 
>> +++---
>>  1 file changed, 51 insertions(+), 69 deletions(-)
>> 
>> diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
>> index c96c71f..6b7a3c2 100644
>> --- a/drivers/net/gtp.c
>> +++ b/drivers/net/gtp.c
> [...]
>> +static struct pdp_ctx *gtp_genl_find_pdp(struct sk_buff *skb,
>> + struct genl_info *info)
>> +{
>> +struct pdp_ctx *pctx;
>> +
>> +if (info->attrs[GTPA_LINK])
>> +pctx = gtp_genl_find_pdp_by_link(skb, info);
>> +else
>> +pctx = ERR_PTR(-EINVAL);
>> +if (!pctx)
>> +pctx = ERR_PTR(-ENOENT);
>> +
>> +return pctx;
>> +}
> 
> For gtp_genl_find_pdp(),  I think this is easier to read:
> 
>if (!info->attrs[GTPA_LINK])
>return ERR_PTR(-EINVAL);
> 
>pctx = gtp_genl_find_pdp_by_link(skb, info);
>   if (!pctx)
>   return ERR_PTR(-ENOENT);
> 
> return pctx;

Yes, but a later patch (will be submitted after this series is
accepted) will change that to:

if (info->attrs[GTPA_LINK])
pctx = gtp_genl_find_pdp_by_link(skb, info);
else if (info->attrs[GTPA_FD])
pctx = gtp_genl_find_pdp_by_socket(skb, info);
else
pctx = ERR_PTR(-EINVAL);

if (!pctx)
pctx = ERR_PTR(-ENOENT);

return pctx;

I can use your form for this change, but have a larger change
later. Which way do you prefer it?

Andreas



Re: [PATCH net-next v2 5/6] gtp: add socket to pdp context

2017-02-02 Thread Andreas Schultz
Hi,

- On Feb 2, 2017, at 2:56 PM, pablo pa...@netfilter.org wrote:

> On Mon, Jan 30, 2017 at 05:37:12PM +0100, Andreas Schultz wrote:
>> Having the socket present in context simplifies the sending logic.
>> It also fixes the invalid assumption that we have to use the same
>> sending socket for all client IP's on a specific gtp interface.
>> 
>> Signed-off-by: Andreas Schultz <aschu...@tpip.net>
>> ---
>>  drivers/net/gtp.c | 72 
>> ++-
>>  1 file changed, 39 insertions(+), 33 deletions(-)
>> 
>> diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
>> index 68c6c9b..ff00597 100644
>> --- a/drivers/net/gtp.c
>> +++ b/drivers/net/gtp.c
> [...]
>> @@ -984,16 +966,26 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct
>> genl_info *info)
>>  return 0;
>>  }
>>  
>> +static void pdp_context_free(struct rcu_head *head)
>> +{
>> +struct pdp_ctx *pctx = container_of(head, struct pdp_ctx, rcu_head);
>> +
>> +sock_put(pctx->sk);
>> +kfree(pctx);
>> +}
>> +
>>  static void pdp_context_delete(struct pdp_ctx *pctx)
>>  {
>>  hlist_del_rcu(>hlist_tid);
>>  hlist_del_rcu(>hlist_addr);
>> -kfree(pctx);
>> +call_rcu(>rcu_head, pdp_context_free);
> 
> This is fixing incorrect rcu conversion in 4/6. Please, fix this there.

Ehm, right, but the kfree in 4/6 could have been a kfree_rcu instead without
the call_rcu.

Do you prefer to introduce the call_rcu in 4/6 and then just add the sock_put
in this patch or should I change 4/6 to kfree_rcu and do the call_rcu
conversion here?

Andreas


[PATCH 3/6] gtp: unify genl_find_pdp and prepare for per socket lookup

2017-01-30 Thread Andreas Schultz
This unifies duplicate code into a helper. It also prepares the
groundwork to add a lookup version that uses the socket to find
attache pdp contexts.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 120 +++---
 1 file changed, 51 insertions(+), 69 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index c96c71f..6b7a3c2 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1027,47 +1027,62 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
return err;
 }
 
+static struct pdp_ctx *gtp_genl_find_pdp_by_link(struct sk_buff *skb,
+struct genl_info *info)
+{
+   struct gtp_dev *gtp;
+
+   gtp = gtp_genl_find_dev(sock_net(skb->sk), info->attrs);
+   if (!gtp)
+   return ERR_PTR(-ENODEV);
+
+   if (info->attrs[GTPA_MS_ADDRESS]) {
+   __be32 ip = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
+
+   return ipv4_pdp_find(gtp, ip);
+   } else if (info->attrs[GTPA_VERSION]) {
+   u32 gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]);
+
+   if (gtp_version == GTP_V0 && info->attrs[GTPA_TID])
+   return gtp0_pdp_find(gtp, nla_get_u64(
+info->attrs[GTPA_TID]));
+   else if (gtp_version == GTP_V1 && info->attrs[GTPA_I_TEI])
+   return gtp1_pdp_find(gtp, nla_get_u32(
+info->attrs[GTPA_I_TEI]));
+   }
+
+   return ERR_PTR(-EINVAL);
+}
+
+static struct pdp_ctx *gtp_genl_find_pdp(struct sk_buff *skb,
+struct genl_info *info)
+{
+   struct pdp_ctx *pctx;
+
+   if (info->attrs[GTPA_LINK])
+   pctx = gtp_genl_find_pdp_by_link(skb, info);
+   else
+   pctx = ERR_PTR(-EINVAL);
+
+   if (!pctx)
+   pctx = ERR_PTR(-ENOENT);
+
+   return pctx;
+}
+
 static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
 {
struct pdp_ctx *pctx;
-   struct gtp_dev *gtp;
int err = 0;
 
-   if (!info->attrs[GTPA_VERSION] ||
-   !info->attrs[GTPA_LINK])
+   if (!info->attrs[GTPA_VERSION])
return -EINVAL;
 
rcu_read_lock();
 
-   gtp = gtp_genl_find_dev(sock_net(skb->sk), info->attrs);
-   if (!gtp) {
-   err = -ENODEV;
-   goto out_unlock;
-   }
-
-   switch (nla_get_u32(info->attrs[GTPA_VERSION])) {
-   case GTP_V0:
-   if (!info->attrs[GTPA_TID]) {
-   err = -EINVAL;
-   goto out_unlock;
-   }
-   pctx = gtp0_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_TID]));
-   break;
-   case GTP_V1:
-   if (!info->attrs[GTPA_I_TEI]) {
-   err = -EINVAL;
-   goto out_unlock;
-   }
-   pctx = gtp1_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_I_TEI]));
-   break;
-
-   default:
-   err = -EINVAL;
-   goto out_unlock;
-   }
-
-   if (!pctx) {
-   err = -ENOENT;
+   pctx = gtp_genl_find_pdp(skb, info);
+   if (IS_ERR(pctx)) {
+   err = PTR_ERR(pctx);
goto out_unlock;
}
 
@@ -1129,49 +1144,16 @@ static int gtp_genl_get_pdp(struct sk_buff *skb, struct 
genl_info *info)
 {
struct pdp_ctx *pctx = NULL;
struct sk_buff *skb2;
-   struct gtp_dev *gtp;
-   u32 gtp_version;
int err;
 
-   if (!info->attrs[GTPA_VERSION] ||
-   !info->attrs[GTPA_LINK])
+   if (!info->attrs[GTPA_VERSION])
return -EINVAL;
 
-   gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]);
-   switch (gtp_version) {
-   case GTP_V0:
-   case GTP_V1:
-   break;
-   default:
-   return -EINVAL;
-   }
-
rcu_read_lock();
 
-   gtp = gtp_genl_find_dev(sock_net(skb->sk), info->attrs);
-   if (!gtp) {
-   err = -ENODEV;
-   goto err_unlock;
-   }
-
-   if (gtp_version == GTP_V0 &&
-   info->attrs[GTPA_TID]) {
-   u64 tid = nla_get_u64(info->attrs[GTPA_TID]);
-
-   pctx = gtp0_pdp_find(gtp, tid);
-   } else if (gtp_version == GTP_V1 &&
-info->attrs[GTPA_I_TEI]) {
-   u32 tid = nla_get_u32(info->attrs[GTPA_I_TEI]);
-
-   pctx = gtp1_pdp_find(gtp, tid);
-   } else if (info->attrs[GTPA_MS_ADDRESS]) {
-   __be32 ip = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
-
-   pctx = ipv4_pdp_find(gtp, ip);
-   }
-
-   if (pctx == NULL

[PATCH 0/6] gtp: misc improvements

2017-01-30 Thread Andreas Schultz
Hi Pablo,

This series lays the groundwork for removing the socket references from
the GTP netdevice by removing duplicate code and simplifying the logic on
some code paths.

It slighly changes the GTP genl API by making the socket parameters optional
(though one of them is still required).

The removal of the socket references will break the 1:1 releation between
GTP netdevice and GTP socket that prevents us to support multiple VRFs with
overlaping IP addresse spaces attached to the same GTP socket (needed for
multi APN support).

Regards
Andreas

--
Andreas Schultz (6):
  gtp: make GTP sockets in gtp_newlink optional
  gtp: merge gtp_get_net and gtp_genl_find_dev
  gtp: unify genl_find_pdp and prepare for per socket lookup
  gtp: consolidate pdp context destruction into helper
  gtp: add socket to pdp context
  gtp: consolidate gtp socket rx path

 drivers/net/gtp.c | 564 +++---
 1 file changed, 280 insertions(+), 284 deletions(-)

-- 
2.10.2



[PATCH 2/6] gtp: merge gtp_get_net and gtp_genl_find_dev

2017-01-30 Thread Andreas Schultz
Both function are always used together with the final goal to
get the gtp_dev. This simplifies the code by merging them together.

The netdevice lookup is changed to use the regular dev_get_by_index.
The gtp netdevice list is now only used to find the PDP contexts for
imcomming packets. It can be completely eliminated Once the TEID
hash is moved into the GTP socket.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 170 ++
 1 file changed, 81 insertions(+), 89 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 18944f4..c96c71f 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -745,21 +745,6 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = {
.fill_info  = gtp_fill_info,
 };
 
-static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[])
-{
-   struct net *net;
-
-   /* Examine the link attributes and figure out which network namespace
-* we are talking about.
-*/
-   if (tb[GTPA_NET_NS_FD])
-   net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD]));
-   else
-   net = get_net(src_net);
-
-   return net;
-}
-
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize)
 {
int i;
@@ -870,16 +855,31 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct 
nlattr *data[])
return 0;
 }
 
-static struct net_device *gtp_find_dev(struct net *net, int ifindex)
+static struct gtp_dev *gtp_genl_find_dev(struct net *src_net,
+struct nlattr *tb[])
 {
-   struct gtp_net *gn = net_generic(net, gtp_net_id);
-   struct gtp_dev *gtp;
-
-   list_for_each_entry_rcu(gtp, >gtp_dev_list, list) {
-   if (ifindex == gtp->dev->ifindex)
-   return gtp->dev;
-   }
-   return NULL;
+   struct net *net;
+   struct net_device *dev;
+   struct gtp_dev *gtp = NULL;
+
+   /* Examine the link attributes and figure out which network namespace
+* we are talking about.
+*/
+   if (tb[GTPA_NET_NS_FD])
+   net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD]));
+   else
+   net = get_net(src_net);
+
+   if (IS_ERR(net))
+   return NULL;
+
+   /* Check if there's an existing gtpX device to configure */
+   dev = dev_get_by_index_rcu(net, nla_get_u32(tb[GTPA_LINK]));
+   if (dev->netdev_ops == _netdev_ops)
+   gtp = netdev_priv(dev);
+
+   put_net(net);
+   return gtp;
 }
 
 static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
@@ -909,9 +909,8 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct 
genl_info *info)
}
 }
 
-static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
+static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info)
 {
-   struct gtp_dev *gtp = netdev_priv(dev);
u32 hash_ms, hash_tid = 0;
struct pdp_ctx *pctx;
bool found = false;
@@ -936,11 +935,11 @@ static int ipv4_pdp_add(struct net_device *dev, struct 
genl_info *info)
ipv4_pdp_fill(pctx, info);
 
if (pctx->gtp_version == GTP_V0)
-   netdev_dbg(dev, "GTPv0-U: update tunnel id = %llx (pdp 
%p)\n",
-  pctx->u.v0.tid, pctx);
+   pr_debug("GTPv0-U: update tunnel id = %llx (pdp %p)\n",
+pctx->u.v0.tid, pctx);
else if (pctx->gtp_version == GTP_V1)
-   netdev_dbg(dev, "GTPv1-U: update tunnel id = %x/%x (pdp 
%p)\n",
-  pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
+   pr_debug("GTPv1-U: update tunnel id = %x/%x (pdp %p)\n",
+pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
 
return 0;
 
@@ -972,14 +971,14 @@ static int ipv4_pdp_add(struct net_device *dev, struct 
genl_info *info)
 
switch (pctx->gtp_version) {
case GTP_V0:
-   netdev_dbg(dev, "GTPv0-U: new PDP ctx id=%llx ssgn=%pI4 ms=%pI4 
(pdp=%p)\n",
-  pctx->u.v0.tid, >sgsn_addr_ip4,
-  >ms_addr_ip4, pctx);
+   pr_debug("GTPv0-U: new PDP ctx id=%llx ssgn=%pI4 ms=%pI4 
(pdp=%p)\n",
+pctx->u.v0.tid, >sgsn_addr_ip4,
+>ms_addr_ip4, pctx);
break;
case GTP_V1:
-   netdev_dbg(dev, "GTPv1-U: new PDP ctx id=%x/%x ssgn=%pI4 
ms=%pI4 (pdp=%p)\n",
-  pctx->u.v1.i_tei, pctx->u.v1.o_tei,
-  >sgsn_addr_ip4, >ms_addr_ip4, pctx);
+   pr_debug("GTPv1-U: new PDP ctx id=%x/%x ssgn=%pI4 ms=%pI4 
(pdp

[PATCH 1/6] gtp: make GTP sockets in gtp_newlink optional

2017-01-30 Thread Andreas Schultz
Having both GTPv0-U and GTPv1-U is not always desirable.
Fallback from GTPv1-U to GTPv0-U was depreciated from 3GPP
Rel-8 onwards. Post Rel-8 implementation are discuraged
from listening on the v0 port (see 3GPP TS 29.281, Sect. 1).

A future change will completely decouple the sockets from the
network device. Till then, at least one of the sockets needs to
be specified (either v0 or v1), the other is optional.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 142 +-
 1 file changed, 76 insertions(+), 66 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index bda0c64..18944f4 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -259,28 +259,30 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
 }
 
-static void gtp_encap_disable(struct gtp_dev *gtp)
-{
-   if (gtp->sock0 && gtp->sock0->sk) {
-   udp_sk(gtp->sock0->sk)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sock0->sk, NULL);
-   }
-   if (gtp->sock1u && gtp->sock1u->sk) {
-   udp_sk(gtp->sock1u->sk)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sock1u->sk, NULL);
-   }
-
-   gtp->sock0 = NULL;
-   gtp->sock1u = NULL;
-}
-
 static void gtp_encap_destroy(struct sock *sk)
 {
struct gtp_dev *gtp;
 
gtp = rcu_dereference_sk_user_data(sk);
-   if (gtp)
-   gtp_encap_disable(gtp);
+   if (gtp) {
+   udp_sk(sk)->encap_type = 0;
+   rcu_assign_sk_user_data(sk, NULL);
+   }
+}
+
+static void gtp_encap_disable_sock(struct socket *sock)
+{
+   if (!sock || !sock->sk)
+   return;
+
+   gtp_encap_destroy(sock->sk);
+   sockfd_put(sock);
+}
+
+static void gtp_encap_disable(struct gtp_dev *gtp)
+{
+   gtp_encap_disable_sock(gtp->sock0);
+   gtp_encap_disable_sock(gtp->sock1u);
 }
 
 /* UDP encapsulation receive handler. See net/ipv4/udp.c.
@@ -640,27 +642,24 @@ static void gtp_link_setup(struct net_device *dev)
 
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
 static void gtp_hashtable_free(struct gtp_dev *gtp);
-static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1);
+static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]);
+static void gtp_encap_disable(struct gtp_dev *gtp);
 
 static int gtp_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
 {
-   int hashsize, err, fd0, fd1;
+   int hashsize, err;
struct gtp_dev *gtp;
struct gtp_net *gn;
 
-   if (!data[IFLA_GTP_FD0] || !data[IFLA_GTP_FD1])
+   if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1])
return -EINVAL;
 
gtp = netdev_priv(dev);
 
-   fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
-   fd1 = nla_get_u32(data[IFLA_GTP_FD1]);
-
-   err = gtp_encap_enable(dev, gtp, fd0, fd1);
+   err = gtp_encap_enable(gtp, data);
if (err < 0)
-   goto out_err;
+   return err;
 
if (!data[IFLA_GTP_PDP_HASHSIZE])
hashsize = 1024;
@@ -688,7 +687,6 @@ static int gtp_newlink(struct net *src_net, struct 
net_device *dev,
gtp_hashtable_free(gtp);
 out_encap:
gtp_encap_disable(gtp);
-out_err:
return err;
 }
 
@@ -803,61 +801,73 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
kfree(gtp->tid_hash);
 }
 
-static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1)
+static struct socket *gtp_encap_enable_socket(int fd, int type,
+ struct gtp_dev *gtp)
 {
struct udp_tunnel_sock_cfg tuncfg = {NULL};
-   struct socket *sock0, *sock1u;
+   struct socket *sock;
int err;
 
-   netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1);
+   pr_debug("enable gtp on %d, %d\n", fd, type);
 
-   sock0 = sockfd_lookup(fd_gtp0, );
-   if (sock0 == NULL) {
-   netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0);
-   return -ENOENT;
+   sock = sockfd_lookup(fd, );
+   if (!sock) {
+   pr_debug("gtp socket fd=%d not found\n", fd);
+   return NULL;
}
 
-   if (sock0->sk->sk_protocol != IPPROTO_UDP) {
-   netdev_dbg(dev, "socket fd=%d not UDP\n", fd_gtp0);
+   if (sock->sk->sk_protocol != IPPROTO_UDP) {
+   pr_debug("socket fd=%d not UDP\n", fd);
err = -EINVAL;
-   goto err1;
+  

[PATCH 4/6] gtp: consolidate pdp context destruction into helper

2017-01-30 Thread Andreas Schultz
Consolidate duplicate code into helper.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 24 ++--
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 6b7a3c2..68c6c9b 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -84,6 +84,8 @@ struct gtp_net {
 
 static u32 gtp_h_initval;
 
+static void pdp_context_delete(struct pdp_ctx *pctx);
+
 static inline u32 gtp0_hashfn(u64 tid)
 {
u32 *tid32 = (u32 *) 
@@ -774,13 +776,10 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
struct pdp_ctx *pctx;
int i;
 
-   for (i = 0; i < gtp->hash_size; i++) {
-   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid) {
-   hlist_del_rcu(>hlist_tid);
-   hlist_del_rcu(>hlist_addr);
-   kfree_rcu(pctx, rcu_head);
-   }
-   }
+   for (i = 0; i < gtp->hash_size; i++)
+   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid)
+   pdp_context_delete(pctx);
+
synchronize_rcu();
kfree(gtp->addr_hash);
kfree(gtp->tid_hash);
@@ -985,6 +984,13 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
return 0;
 }
 
+static void pdp_context_delete(struct pdp_ctx *pctx)
+{
+   hlist_del_rcu(>hlist_tid);
+   hlist_del_rcu(>hlist_addr);
+   kfree(pctx);
+}
+
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
struct gtp_dev *gtp;
@@ -1093,9 +1099,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct 
genl_info *info)
pr_debug("GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n",
 pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
 
-   hlist_del_rcu(>hlist_tid);
-   hlist_del_rcu(>hlist_addr);
-   kfree_rcu(pctx, rcu_head);
+   pdp_context_delete(pctx);
 
 out_unlock:
rcu_read_unlock();
-- 
2.10.2



[PATCH net-next v2 1/6] gtp: make GTP sockets in gtp_newlink optional

2017-01-30 Thread Andreas Schultz
Having both GTPv0-U and GTPv1-U is not always desirable.
Fallback from GTPv1-U to GTPv0-U was depreciated from 3GPP
Rel-8 onwards. Post Rel-8 implementation are discuraged
from listening on the v0 port (see 3GPP TS 29.281, Sect. 1).

A future change will completely decouple the sockets from the
network device. Till then, at least one of the sockets needs to
be specified (either v0 or v1), the other is optional.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 142 +-
 1 file changed, 76 insertions(+), 66 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index bda0c64..18944f4 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -259,28 +259,30 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
 }
 
-static void gtp_encap_disable(struct gtp_dev *gtp)
-{
-   if (gtp->sock0 && gtp->sock0->sk) {
-   udp_sk(gtp->sock0->sk)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sock0->sk, NULL);
-   }
-   if (gtp->sock1u && gtp->sock1u->sk) {
-   udp_sk(gtp->sock1u->sk)->encap_type = 0;
-   rcu_assign_sk_user_data(gtp->sock1u->sk, NULL);
-   }
-
-   gtp->sock0 = NULL;
-   gtp->sock1u = NULL;
-}
-
 static void gtp_encap_destroy(struct sock *sk)
 {
struct gtp_dev *gtp;
 
gtp = rcu_dereference_sk_user_data(sk);
-   if (gtp)
-   gtp_encap_disable(gtp);
+   if (gtp) {
+   udp_sk(sk)->encap_type = 0;
+   rcu_assign_sk_user_data(sk, NULL);
+   }
+}
+
+static void gtp_encap_disable_sock(struct socket *sock)
+{
+   if (!sock || !sock->sk)
+   return;
+
+   gtp_encap_destroy(sock->sk);
+   sockfd_put(sock);
+}
+
+static void gtp_encap_disable(struct gtp_dev *gtp)
+{
+   gtp_encap_disable_sock(gtp->sock0);
+   gtp_encap_disable_sock(gtp->sock1u);
 }
 
 /* UDP encapsulation receive handler. See net/ipv4/udp.c.
@@ -640,27 +642,24 @@ static void gtp_link_setup(struct net_device *dev)
 
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
 static void gtp_hashtable_free(struct gtp_dev *gtp);
-static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1);
+static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]);
+static void gtp_encap_disable(struct gtp_dev *gtp);
 
 static int gtp_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
 {
-   int hashsize, err, fd0, fd1;
+   int hashsize, err;
struct gtp_dev *gtp;
struct gtp_net *gn;
 
-   if (!data[IFLA_GTP_FD0] || !data[IFLA_GTP_FD1])
+   if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1])
return -EINVAL;
 
gtp = netdev_priv(dev);
 
-   fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
-   fd1 = nla_get_u32(data[IFLA_GTP_FD1]);
-
-   err = gtp_encap_enable(dev, gtp, fd0, fd1);
+   err = gtp_encap_enable(gtp, data);
if (err < 0)
-   goto out_err;
+   return err;
 
if (!data[IFLA_GTP_PDP_HASHSIZE])
hashsize = 1024;
@@ -688,7 +687,6 @@ static int gtp_newlink(struct net *src_net, struct 
net_device *dev,
gtp_hashtable_free(gtp);
 out_encap:
gtp_encap_disable(gtp);
-out_err:
return err;
 }
 
@@ -803,61 +801,73 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
kfree(gtp->tid_hash);
 }
 
-static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1)
+static struct socket *gtp_encap_enable_socket(int fd, int type,
+ struct gtp_dev *gtp)
 {
struct udp_tunnel_sock_cfg tuncfg = {NULL};
-   struct socket *sock0, *sock1u;
+   struct socket *sock;
int err;
 
-   netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1);
+   pr_debug("enable gtp on %d, %d\n", fd, type);
 
-   sock0 = sockfd_lookup(fd_gtp0, );
-   if (sock0 == NULL) {
-   netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0);
-   return -ENOENT;
+   sock = sockfd_lookup(fd, );
+   if (!sock) {
+   pr_debug("gtp socket fd=%d not found\n", fd);
+   return NULL;
}
 
-   if (sock0->sk->sk_protocol != IPPROTO_UDP) {
-   netdev_dbg(dev, "socket fd=%d not UDP\n", fd_gtp0);
+   if (sock->sk->sk_protocol != IPPROTO_UDP) {
+   pr_debug("socket fd=%d not UDP\n", fd);
err = -EINVAL;
-   goto err1;
+  

[PATCH net-next v2 4/6] gtp: consolidate pdp context destruction into helper

2017-01-30 Thread Andreas Schultz
Consolidate duplicate code into helper.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 24 ++--
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 6b7a3c2..68c6c9b 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -84,6 +84,8 @@ struct gtp_net {
 
 static u32 gtp_h_initval;
 
+static void pdp_context_delete(struct pdp_ctx *pctx);
+
 static inline u32 gtp0_hashfn(u64 tid)
 {
u32 *tid32 = (u32 *) 
@@ -774,13 +776,10 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
struct pdp_ctx *pctx;
int i;
 
-   for (i = 0; i < gtp->hash_size; i++) {
-   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid) {
-   hlist_del_rcu(>hlist_tid);
-   hlist_del_rcu(>hlist_addr);
-   kfree_rcu(pctx, rcu_head);
-   }
-   }
+   for (i = 0; i < gtp->hash_size; i++)
+   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid)
+   pdp_context_delete(pctx);
+
synchronize_rcu();
kfree(gtp->addr_hash);
kfree(gtp->tid_hash);
@@ -985,6 +984,13 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
return 0;
 }
 
+static void pdp_context_delete(struct pdp_ctx *pctx)
+{
+   hlist_del_rcu(>hlist_tid);
+   hlist_del_rcu(>hlist_addr);
+   kfree(pctx);
+}
+
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
struct gtp_dev *gtp;
@@ -1093,9 +1099,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct 
genl_info *info)
pr_debug("GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n",
 pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
 
-   hlist_del_rcu(>hlist_tid);
-   hlist_del_rcu(>hlist_addr);
-   kfree_rcu(pctx, rcu_head);
+   pdp_context_delete(pctx);
 
 out_unlock:
rcu_read_unlock();
-- 
2.10.2



[PATCH net-next v2 6/6] gtp: consolidate gtp socket rx path

2017-01-30 Thread Andreas Schultz
Add network device to gtp context in preparation for splitting
the TEID from the network device.

Use this to rework the socker rx path. Move the common RX part
of v0 and v1 into a helper. Also move the final rx part into
that helper as well.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 92 ---
 1 file changed, 47 insertions(+), 45 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index ff00597..9c31e83 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,7 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct net_device   *dev;
struct sock *sk;
 
atomic_ttx_seq;
@@ -179,9 +180,42 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct 
pdp_ctx *pctx,
return false;
 }
 
+static int gtp_rx(struct sk_buff *skb, struct pdp_ctx *pctx, unsigned int 
hdrlen)
+{
+   struct pcpu_sw_netstats *stats;
+
+   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
+   pr_debug("No PDP ctx for this MS\n");
+   return 1;
+   }
+
+   /* Get rid of the GTP + UDP headers. */
+   if (iptunnel_pull_header(skb, hdrlen, skb->protocol,
+!net_eq(sock_net(pctx->sk), 
dev_net(pctx->dev
+   return -1;
+
+   pr_debug("forwarding packet from GGSN to uplink\n");
+
+   /* Now that the UDP and the GTP header have been removed, set up the
+* new network header. This is required by the upper layer to
+* calculate the transport header.
+*/
+   skb_reset_network_header(skb);
+
+   skb->dev = pctx->dev;
+
+   stats = this_cpu_ptr(pctx->dev->tstats);
+   u64_stats_update_begin(>syncp);
+   stats->rx_packets++;
+   stats->rx_bytes += skb->len;
+   u64_stats_update_end(>syncp);
+
+   netif_rx(skb);
+   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,
-  bool xnet)
+static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp0_header);
@@ -205,17 +239,10 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return 1;
}
 
-   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
-   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return 1;
-   }
-
-   /* Get rid of the GTP + UDP headers. */
-   return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+   return gtp_rx(skb, pctx, hdrlen);
 }
 
-static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
-   bool xnet)
+static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp1_header);
@@ -254,13 +281,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return 1;
}
 
-   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
-   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return 1;
-   }
-
-   /* Get rid of the GTP + UDP headers. */
-   return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+   return gtp_rx(skb, pctx, hdrlen);
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -294,10 +315,8 @@ static void gtp_encap_disable(struct gtp_dev *gtp)
  */
 static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
-   struct pcpu_sw_netstats *stats;
struct gtp_dev *gtp;
-   bool xnet;
-   int ret;
+   int ret = 0;
 
gtp = rcu_dereference_sk_user_data(sk);
if (!gtp)
@@ -305,16 +324,14 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
 
-   xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
-
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
netdev_dbg(gtp->dev, "received GTP0 packet\n");
-   ret = gtp0_udp_encap_recv(gtp, skb, xnet);
+   ret = gtp0_udp_encap_recv(gtp, skb);
break;
case UDP_ENCAP_GTP1U:
netdev_dbg(gtp->dev, "received GTP1U packet\n");
-   ret = gtp1u_udp_encap_recv(gtp, skb, xnet);
+   ret = gtp1u_udp_encap_recv(gtp, skb);
break;
default:
ret = -1; /* Shouldn't happen. */
@@ -323,33 +340,17 @@ static int gtp_encap_recv(struct sock *sk, struct sk_bu

[PATCH net-next v2 3/6] gtp: unify genl_find_pdp and prepare for per socket lookup

2017-01-30 Thread Andreas Schultz
This unifies duplicate code into a helper. It also prepares the
groundwork to add a lookup version that uses the socket to find
attache pdp contexts.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 120 +++---
 1 file changed, 51 insertions(+), 69 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index c96c71f..6b7a3c2 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1027,47 +1027,62 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
return err;
 }
 
+static struct pdp_ctx *gtp_genl_find_pdp_by_link(struct sk_buff *skb,
+struct genl_info *info)
+{
+   struct gtp_dev *gtp;
+
+   gtp = gtp_genl_find_dev(sock_net(skb->sk), info->attrs);
+   if (!gtp)
+   return ERR_PTR(-ENODEV);
+
+   if (info->attrs[GTPA_MS_ADDRESS]) {
+   __be32 ip = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
+
+   return ipv4_pdp_find(gtp, ip);
+   } else if (info->attrs[GTPA_VERSION]) {
+   u32 gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]);
+
+   if (gtp_version == GTP_V0 && info->attrs[GTPA_TID])
+   return gtp0_pdp_find(gtp, nla_get_u64(
+info->attrs[GTPA_TID]));
+   else if (gtp_version == GTP_V1 && info->attrs[GTPA_I_TEI])
+   return gtp1_pdp_find(gtp, nla_get_u32(
+info->attrs[GTPA_I_TEI]));
+   }
+
+   return ERR_PTR(-EINVAL);
+}
+
+static struct pdp_ctx *gtp_genl_find_pdp(struct sk_buff *skb,
+struct genl_info *info)
+{
+   struct pdp_ctx *pctx;
+
+   if (info->attrs[GTPA_LINK])
+   pctx = gtp_genl_find_pdp_by_link(skb, info);
+   else
+   pctx = ERR_PTR(-EINVAL);
+
+   if (!pctx)
+   pctx = ERR_PTR(-ENOENT);
+
+   return pctx;
+}
+
 static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
 {
struct pdp_ctx *pctx;
-   struct gtp_dev *gtp;
int err = 0;
 
-   if (!info->attrs[GTPA_VERSION] ||
-   !info->attrs[GTPA_LINK])
+   if (!info->attrs[GTPA_VERSION])
return -EINVAL;
 
rcu_read_lock();
 
-   gtp = gtp_genl_find_dev(sock_net(skb->sk), info->attrs);
-   if (!gtp) {
-   err = -ENODEV;
-   goto out_unlock;
-   }
-
-   switch (nla_get_u32(info->attrs[GTPA_VERSION])) {
-   case GTP_V0:
-   if (!info->attrs[GTPA_TID]) {
-   err = -EINVAL;
-   goto out_unlock;
-   }
-   pctx = gtp0_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_TID]));
-   break;
-   case GTP_V1:
-   if (!info->attrs[GTPA_I_TEI]) {
-   err = -EINVAL;
-   goto out_unlock;
-   }
-   pctx = gtp1_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_I_TEI]));
-   break;
-
-   default:
-   err = -EINVAL;
-   goto out_unlock;
-   }
-
-   if (!pctx) {
-   err = -ENOENT;
+   pctx = gtp_genl_find_pdp(skb, info);
+   if (IS_ERR(pctx)) {
+   err = PTR_ERR(pctx);
goto out_unlock;
}
 
@@ -1129,49 +1144,16 @@ static int gtp_genl_get_pdp(struct sk_buff *skb, struct 
genl_info *info)
 {
struct pdp_ctx *pctx = NULL;
struct sk_buff *skb2;
-   struct gtp_dev *gtp;
-   u32 gtp_version;
int err;
 
-   if (!info->attrs[GTPA_VERSION] ||
-   !info->attrs[GTPA_LINK])
+   if (!info->attrs[GTPA_VERSION])
return -EINVAL;
 
-   gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]);
-   switch (gtp_version) {
-   case GTP_V0:
-   case GTP_V1:
-   break;
-   default:
-   return -EINVAL;
-   }
-
rcu_read_lock();
 
-   gtp = gtp_genl_find_dev(sock_net(skb->sk), info->attrs);
-   if (!gtp) {
-   err = -ENODEV;
-   goto err_unlock;
-   }
-
-   if (gtp_version == GTP_V0 &&
-   info->attrs[GTPA_TID]) {
-   u64 tid = nla_get_u64(info->attrs[GTPA_TID]);
-
-   pctx = gtp0_pdp_find(gtp, tid);
-   } else if (gtp_version == GTP_V1 &&
-info->attrs[GTPA_I_TEI]) {
-   u32 tid = nla_get_u32(info->attrs[GTPA_I_TEI]);
-
-   pctx = gtp1_pdp_find(gtp, tid);
-   } else if (info->attrs[GTPA_MS_ADDRESS]) {
-   __be32 ip = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
-
-   pctx = ipv4_pdp_find(gtp, ip);
-   }
-
-   if (pctx == NULL

[PATCH net-next v2 5/6] gtp: add socket to pdp context

2017-01-30 Thread Andreas Schultz
Having the socket present in context simplifies the sending logic.
It also fixes the invalid assumption that we have to use the same
sending socket for all client IP's on a specific gtp interface.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 72 ++-
 1 file changed, 39 insertions(+), 33 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 68c6c9b..ff00597 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,8 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct sock *sk;
+
atomic_ttx_seq;
struct rcu_head rcu_head;
 };
@@ -371,8 +373,9 @@ static void gtp_dev_uninit(struct net_device *dev)
free_percpu(dev->tstats);
 }
 
-static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4,
-  const struct sock *sk, __be32 daddr)
+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;
@@ -381,7 +384,7 @@ static struct rtable *ip4_route_output_gtp(struct net *net, 
struct flowi4 *fl4,
fl4->flowi4_tos = RT_CONN_FLAGS(sk);
fl4->flowi4_proto   = sk->sk_protocol;
 
-   return ip_route_output_key(net, fl4);
+   return ip_route_output_key(sock_net(sk), fl4);
 }
 
 static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
@@ -470,7 +473,6 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
struct rtable *rt;
struct flowi4 fl4;
struct iphdr *iph;
-   struct sock *sk;
__be16 df;
int mtu;
 
@@ -486,30 +488,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
}
netdev_dbg(dev, "found PDP context %p\n", pctx);
 
-   switch (pctx->gtp_version) {
-   case GTP_V0:
-   if (gtp->sock0)
-   sk = gtp->sock0->sk;
-   else
-   sk = NULL;
-   break;
-   case GTP_V1:
-   if (gtp->sock1u)
-   sk = gtp->sock1u->sk;
-   else
-   sk = NULL;
-   break;
-   default:
-   return -ENOENT;
-   }
-
-   if (!sk) {
-   netdev_dbg(dev, "no userspace socket is available, skip\n");
-   return -ENOENT;
-   }
-
-   rt = ip4_route_output_gtp(sock_net(sk), , gtp->sock0->sk,
- pctx->sgsn_addr_ip4.s_addr);
+   rt = ip4_route_output_gtp(, pctx->sk, pctx->sgsn_addr_ip4.s_addr);
if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to SSGN %pI4\n",
   >sgsn_addr_ip4.s_addr);
@@ -554,7 +533,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
goto err_rt;
}
 
-   gtp_set_pktinfo_ipv4(pktinfo, sk, iph, pctx, rt, , dev);
+   gtp_set_pktinfo_ipv4(pktinfo, pctx->sk, iph, pctx, rt, , dev);
gtp_push_header(skb, pktinfo);
 
return 0;
@@ -908,7 +887,8 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct 
genl_info *info)
}
 }
 
-static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info)
+static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk,
+   struct genl_info *info)
 {
u32 hash_ms, hash_tid = 0;
struct pdp_ctx *pctx;
@@ -948,6 +928,8 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
if (pctx == NULL)
return -ENOMEM;
 
+   sock_hold(sk);
+   pctx->sk = sk;
ipv4_pdp_fill(pctx, info);
atomic_set(>tx_seq, 0);
 
@@ -984,16 +966,26 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
return 0;
 }
 
+static void pdp_context_free(struct rcu_head *head)
+{
+   struct pdp_ctx *pctx = container_of(head, struct pdp_ctx, rcu_head);
+
+   sock_put(pctx->sk);
+   kfree(pctx);
+}
+
 static void pdp_context_delete(struct pdp_ctx *pctx)
 {
hlist_del_rcu(>hlist_tid);
hlist_del_rcu(>hlist_addr);
-   kfree(pctx);
+   call_rcu(>rcu_head, pdp_context_free);
 }
 
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
+   unsigned int version;
struct gtp_dev *gtp;
+   struct socket *sock;
int err;
 
if (!info->attrs[GTPA_VERSION] ||
@@ -1002,7 +994,9 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
!info->attrs[GTPA_MS_ADDRESS])
 

[PATCH net-next v2 0/6] gtp: misc improvements

2017-01-30 Thread Andreas Schultz
Hi Pablo,

Resent as v2, because I forgot the net-next target. Sorry for noise,
I promise I won't forget it again.

This series lays the groundwork for removing the socket references from
the GTP netdevice by removing duplicate code and simplifying the logic on
some code paths.

It slighly changes the GTP genl API by making the socket parameters optional
(though one of them is still required).

The removal of the socket references will break the 1:1 releation between
GTP netdevice and GTP socket that prevents us to support multiple VRFs with
overlaping IP addresse spaces attached to the same GTP socket (needed for
multi APN support).

Regards
Andreas


Andreas Schultz (6):
  gtp: make GTP sockets in gtp_newlink optional
  gtp: merge gtp_get_net and gtp_genl_find_dev
  gtp: unify genl_find_pdp and prepare for per socket lookup
  gtp: consolidate pdp context destruction into helper
  gtp: add socket to pdp context
  gtp: consolidate gtp socket rx path

 drivers/net/gtp.c | 564 +++---
 1 file changed, 280 insertions(+), 284 deletions(-)

-- 
2.10.2



[PATCH net-next v2 2/6] gtp: merge gtp_get_net and gtp_genl_find_dev

2017-01-30 Thread Andreas Schultz
Both function are always used together with the final goal to
get the gtp_dev. This simplifies the code by merging them together.

The netdevice lookup is changed to use the regular dev_get_by_index.
The gtp netdevice list is now only used to find the PDP contexts for
imcomming packets. It can be completely eliminated Once the TEID
hash is moved into the GTP socket.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 170 ++
 1 file changed, 81 insertions(+), 89 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 18944f4..c96c71f 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -745,21 +745,6 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = {
.fill_info  = gtp_fill_info,
 };
 
-static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[])
-{
-   struct net *net;
-
-   /* Examine the link attributes and figure out which network namespace
-* we are talking about.
-*/
-   if (tb[GTPA_NET_NS_FD])
-   net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD]));
-   else
-   net = get_net(src_net);
-
-   return net;
-}
-
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize)
 {
int i;
@@ -870,16 +855,31 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct 
nlattr *data[])
return 0;
 }
 
-static struct net_device *gtp_find_dev(struct net *net, int ifindex)
+static struct gtp_dev *gtp_genl_find_dev(struct net *src_net,
+struct nlattr *tb[])
 {
-   struct gtp_net *gn = net_generic(net, gtp_net_id);
-   struct gtp_dev *gtp;
-
-   list_for_each_entry_rcu(gtp, >gtp_dev_list, list) {
-   if (ifindex == gtp->dev->ifindex)
-   return gtp->dev;
-   }
-   return NULL;
+   struct net *net;
+   struct net_device *dev;
+   struct gtp_dev *gtp = NULL;
+
+   /* Examine the link attributes and figure out which network namespace
+* we are talking about.
+*/
+   if (tb[GTPA_NET_NS_FD])
+   net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD]));
+   else
+   net = get_net(src_net);
+
+   if (IS_ERR(net))
+   return NULL;
+
+   /* Check if there's an existing gtpX device to configure */
+   dev = dev_get_by_index_rcu(net, nla_get_u32(tb[GTPA_LINK]));
+   if (dev->netdev_ops == _netdev_ops)
+   gtp = netdev_priv(dev);
+
+   put_net(net);
+   return gtp;
 }
 
 static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
@@ -909,9 +909,8 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct 
genl_info *info)
}
 }
 
-static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
+static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info)
 {
-   struct gtp_dev *gtp = netdev_priv(dev);
u32 hash_ms, hash_tid = 0;
struct pdp_ctx *pctx;
bool found = false;
@@ -936,11 +935,11 @@ static int ipv4_pdp_add(struct net_device *dev, struct 
genl_info *info)
ipv4_pdp_fill(pctx, info);
 
if (pctx->gtp_version == GTP_V0)
-   netdev_dbg(dev, "GTPv0-U: update tunnel id = %llx (pdp 
%p)\n",
-  pctx->u.v0.tid, pctx);
+   pr_debug("GTPv0-U: update tunnel id = %llx (pdp %p)\n",
+pctx->u.v0.tid, pctx);
else if (pctx->gtp_version == GTP_V1)
-   netdev_dbg(dev, "GTPv1-U: update tunnel id = %x/%x (pdp 
%p)\n",
-  pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
+   pr_debug("GTPv1-U: update tunnel id = %x/%x (pdp %p)\n",
+pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
 
return 0;
 
@@ -972,14 +971,14 @@ static int ipv4_pdp_add(struct net_device *dev, struct 
genl_info *info)
 
switch (pctx->gtp_version) {
case GTP_V0:
-   netdev_dbg(dev, "GTPv0-U: new PDP ctx id=%llx ssgn=%pI4 ms=%pI4 
(pdp=%p)\n",
-  pctx->u.v0.tid, >sgsn_addr_ip4,
-  >ms_addr_ip4, pctx);
+   pr_debug("GTPv0-U: new PDP ctx id=%llx ssgn=%pI4 ms=%pI4 
(pdp=%p)\n",
+pctx->u.v0.tid, >sgsn_addr_ip4,
+>ms_addr_ip4, pctx);
break;
case GTP_V1:
-   netdev_dbg(dev, "GTPv1-U: new PDP ctx id=%x/%x ssgn=%pI4 
ms=%pI4 (pdp=%p)\n",
-  pctx->u.v1.i_tei, pctx->u.v1.o_tei,
-  >sgsn_addr_ip4, >ms_addr_ip4, pctx);
+   pr_debug("GTPv1-U: new PDP ctx id=%x/%x ssgn=%pI4 ms=%pI4 
(pdp

[PATCH 6/6] gtp: consolidate gtp socket rx path

2017-01-30 Thread Andreas Schultz
Add network device to gtp context in preparation for splitting
the TEID from the network device.

Use this to rework the socker rx path. Move the common RX part
of v0 and v1 into a helper. Also move the final rx part into
that helper as well.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 92 ---
 1 file changed, 47 insertions(+), 45 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index ff00597..9c31e83 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,7 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct net_device   *dev;
struct sock *sk;
 
atomic_ttx_seq;
@@ -179,9 +180,42 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct 
pdp_ctx *pctx,
return false;
 }
 
+static int gtp_rx(struct sk_buff *skb, struct pdp_ctx *pctx, unsigned int 
hdrlen)
+{
+   struct pcpu_sw_netstats *stats;
+
+   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
+   pr_debug("No PDP ctx for this MS\n");
+   return 1;
+   }
+
+   /* Get rid of the GTP + UDP headers. */
+   if (iptunnel_pull_header(skb, hdrlen, skb->protocol,
+!net_eq(sock_net(pctx->sk), 
dev_net(pctx->dev
+   return -1;
+
+   pr_debug("forwarding packet from GGSN to uplink\n");
+
+   /* Now that the UDP and the GTP header have been removed, set up the
+* new network header. This is required by the upper layer to
+* calculate the transport header.
+*/
+   skb_reset_network_header(skb);
+
+   skb->dev = pctx->dev;
+
+   stats = this_cpu_ptr(pctx->dev->tstats);
+   u64_stats_update_begin(>syncp);
+   stats->rx_packets++;
+   stats->rx_bytes += skb->len;
+   u64_stats_update_end(>syncp);
+
+   netif_rx(skb);
+   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,
-  bool xnet)
+static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp0_header);
@@ -205,17 +239,10 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return 1;
}
 
-   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
-   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return 1;
-   }
-
-   /* Get rid of the GTP + UDP headers. */
-   return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+   return gtp_rx(skb, pctx, hdrlen);
 }
 
-static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
-   bool xnet)
+static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp1_header);
@@ -254,13 +281,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
return 1;
}
 
-   if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
-   netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return 1;
-   }
-
-   /* Get rid of the GTP + UDP headers. */
-   return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+   return gtp_rx(skb, pctx, hdrlen);
 }
 
 static void gtp_encap_destroy(struct sock *sk)
@@ -294,10 +315,8 @@ static void gtp_encap_disable(struct gtp_dev *gtp)
  */
 static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
-   struct pcpu_sw_netstats *stats;
struct gtp_dev *gtp;
-   bool xnet;
-   int ret;
+   int ret = 0;
 
gtp = rcu_dereference_sk_user_data(sk);
if (!gtp)
@@ -305,16 +324,14 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
 
-   xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
-
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
netdev_dbg(gtp->dev, "received GTP0 packet\n");
-   ret = gtp0_udp_encap_recv(gtp, skb, xnet);
+   ret = gtp0_udp_encap_recv(gtp, skb);
break;
case UDP_ENCAP_GTP1U:
netdev_dbg(gtp->dev, "received GTP1U packet\n");
-   ret = gtp1u_udp_encap_recv(gtp, skb, xnet);
+   ret = gtp1u_udp_encap_recv(gtp, skb);
break;
default:
ret = -1; /* Shouldn't happen. */
@@ -323,33 +340,17 @@ static int gtp_encap_recv(struct sock *sk, struct sk_bu

[PATCH 5/6] gtp: add socket to pdp context

2017-01-30 Thread Andreas Schultz
Having the socket present in context simplifies the sending logic.
It also fixes the invalid assumption that we have to use the same
sending socket for all client IP's on a specific gtp interface.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 72 ++-
 1 file changed, 39 insertions(+), 33 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 68c6c9b..ff00597 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,8 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct sock *sk;
+
atomic_ttx_seq;
struct rcu_head rcu_head;
 };
@@ -371,8 +373,9 @@ static void gtp_dev_uninit(struct net_device *dev)
free_percpu(dev->tstats);
 }
 
-static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4,
-  const struct sock *sk, __be32 daddr)
+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;
@@ -381,7 +384,7 @@ static struct rtable *ip4_route_output_gtp(struct net *net, 
struct flowi4 *fl4,
fl4->flowi4_tos = RT_CONN_FLAGS(sk);
fl4->flowi4_proto   = sk->sk_protocol;
 
-   return ip_route_output_key(net, fl4);
+   return ip_route_output_key(sock_net(sk), fl4);
 }
 
 static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
@@ -470,7 +473,6 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
struct rtable *rt;
struct flowi4 fl4;
struct iphdr *iph;
-   struct sock *sk;
__be16 df;
int mtu;
 
@@ -486,30 +488,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
}
netdev_dbg(dev, "found PDP context %p\n", pctx);
 
-   switch (pctx->gtp_version) {
-   case GTP_V0:
-   if (gtp->sock0)
-   sk = gtp->sock0->sk;
-   else
-   sk = NULL;
-   break;
-   case GTP_V1:
-   if (gtp->sock1u)
-   sk = gtp->sock1u->sk;
-   else
-   sk = NULL;
-   break;
-   default:
-   return -ENOENT;
-   }
-
-   if (!sk) {
-   netdev_dbg(dev, "no userspace socket is available, skip\n");
-   return -ENOENT;
-   }
-
-   rt = ip4_route_output_gtp(sock_net(sk), , gtp->sock0->sk,
- pctx->sgsn_addr_ip4.s_addr);
+   rt = ip4_route_output_gtp(, pctx->sk, pctx->sgsn_addr_ip4.s_addr);
if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to SSGN %pI4\n",
   >sgsn_addr_ip4.s_addr);
@@ -554,7 +533,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
goto err_rt;
}
 
-   gtp_set_pktinfo_ipv4(pktinfo, sk, iph, pctx, rt, , dev);
+   gtp_set_pktinfo_ipv4(pktinfo, pctx->sk, iph, pctx, rt, , dev);
gtp_push_header(skb, pktinfo);
 
return 0;
@@ -908,7 +887,8 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct 
genl_info *info)
}
 }
 
-static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info)
+static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk,
+   struct genl_info *info)
 {
u32 hash_ms, hash_tid = 0;
struct pdp_ctx *pctx;
@@ -948,6 +928,8 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
if (pctx == NULL)
return -ENOMEM;
 
+   sock_hold(sk);
+   pctx->sk = sk;
ipv4_pdp_fill(pctx, info);
atomic_set(>tx_seq, 0);
 
@@ -984,16 +966,26 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct 
genl_info *info)
return 0;
 }
 
+static void pdp_context_free(struct rcu_head *head)
+{
+   struct pdp_ctx *pctx = container_of(head, struct pdp_ctx, rcu_head);
+
+   sock_put(pctx->sk);
+   kfree(pctx);
+}
+
 static void pdp_context_delete(struct pdp_ctx *pctx)
 {
hlist_del_rcu(>hlist_tid);
hlist_del_rcu(>hlist_addr);
-   kfree(pctx);
+   call_rcu(>rcu_head, pdp_context_free);
 }
 
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
+   unsigned int version;
struct gtp_dev *gtp;
+   struct socket *sock;
int err;
 
if (!info->attrs[GTPA_VERSION] ||
@@ -1002,7 +994,9 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct 
genl_info *info)
!info->attrs[GTPA_MS_ADDRESS])
 

[PATCH net v3 3/3] gtp: fix cross netns recv on gtp socket

2017-01-27 Thread Andreas Schultz
The use of the passed through netlink src_net to check for a
cross netns operation was wrong. Using the GTP socket and the
GTP netdevice is always correct (even if the netdev has been
moved to new netns after link creation).

Remove the now obsolete net field from gtp_dev.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
Acked-by: Pablo Neira Ayuso <pa...@netfilter.org>
---
 drivers/net/gtp.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 1df54d6..99d3df7 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -69,7 +69,6 @@ struct gtp_dev {
struct socket   *sock0;
struct socket   *sock1u;
 
-   struct net  *net;
struct net_device   *dev;
 
unsigned inthash_size;
@@ -316,7 +315,7 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
 
-   xnet = !net_eq(gtp->net, dev_net(gtp->dev));
+   xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
 
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
@@ -658,7 +657,7 @@ static void gtp_link_setup(struct net_device *dev)
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
 static void gtp_hashtable_free(struct gtp_dev *gtp);
 static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1, struct net *src_net);
+   int fd_gtp0, int fd_gtp1);
 
 static int gtp_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
@@ -675,7 +674,7 @@ static int gtp_newlink(struct net *src_net, struct 
net_device *dev,
fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
fd1 = nla_get_u32(data[IFLA_GTP_FD1]);
 
-   err = gtp_encap_enable(dev, gtp, fd0, fd1, src_net);
+   err = gtp_encap_enable(dev, gtp, fd0, fd1);
if (err < 0)
goto out_err;
 
@@ -821,7 +820,7 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
 }
 
 static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1, struct net *src_net)
+   int fd_gtp0, int fd_gtp1)
 {
struct udp_tunnel_sock_cfg tuncfg = {NULL};
struct socket *sock0, *sock1u;
@@ -858,7 +857,6 @@ static int gtp_encap_enable(struct net_device *dev, struct 
gtp_dev *gtp,
 
gtp->sock0 = sock0;
gtp->sock1u = sock1u;
-   gtp->net = src_net;
 
tuncfg.sk_user_data = gtp;
tuncfg.encap_rcv = gtp_encap_recv;
-- 
2.10.2



[PATCH net v3 0/3] various gtp fixes

2017-01-27 Thread Andreas Schultz
I'm sorry for the compile error mess up in the last version.
It's no excuse for not test compiling, but the hunks got lost in
a rebase.

This is the part of the previous "simple gtp improvements" series
that Pablo indicated should go into net.

The addition of the module alias fixes genl family autoloading,
clearing the DF bit fixes a protocol violation in regard to the
specification and the netns comparison fixes a corner case of
cross netns recv.

Andreas

v2->v3: fix compiler error introduced in rebase

--
Andreas Schultz (3):
  gtp: add genl family modules alias
  gtp: clear DF bit on GTP packet tx
  gtp: fix cross netns recv on gtp socket

 drivers/net/gtp.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

-- 
2.10.2



[PATCH net v3 2/3] gtp: clear DF bit on GTP packet tx

2017-01-27 Thread Andreas Schultz
3GPP TS 29.281 and 3GPP TS 29.060 imply that GTP-U packets should be
sent with the DF bit cleared. For example 3GPP TS 29.060, Release 8,
Section 13.2.2:

> Backbone router: Any router in the backbone may fragment the GTP
> packet if needed, according to IPv4.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
Acked-by: Harald Welte <lafo...@netfilter.org>
Acked-by: Pablo Neira Ayuso <pa...@netfilter.org>
---
 drivers/net/gtp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 7580ccc..1df54d6 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -612,7 +612,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct 
net_device *dev)
pktinfo.fl4.saddr, pktinfo.fl4.daddr,
pktinfo.iph->tos,
ip4_dst_hoplimit(>dst),
-   htons(IP_DF),
+   0,
pktinfo.gtph_port, pktinfo.gtph_port,
true, false);
break;
-- 
2.10.2



[PATCH net v3 1/3] gtp: add genl family modules alias

2017-01-27 Thread Andreas Schultz
Auto-load the module when userspace asks for the gtp netlink
family.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
Acked-by: Harald Welte <lafo...@netfilter.org>
Acked-by: Pablo Neira Ayuso <pa...@netfilter.org>
---
 drivers/net/gtp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 8b6810b..7580ccc 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1376,3 +1376,4 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <hwe...@sysmocom.de>");
 MODULE_DESCRIPTION("Interface driver for GTP encapsulated traffic");
 MODULE_ALIAS_RTNL_LINK("gtp");
+MODULE_ALIAS_GENL_FAMILY("gtp");
-- 
2.10.2



[PATCH net-next v2 1/2] gtp: remove unnecessary rcu_read_lock

2017-01-26 Thread Andreas Schultz
The rcu read lock is hold by default in the ip input path. There
is no need to hold it twice in the socket recv decapsulate code path.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 24 
 1 file changed, 4 insertions(+), 20 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 8b6810b..5c63a37 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -184,7 +184,6 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
  sizeof(struct gtp0_header);
struct gtp0_header *gtp0;
struct pdp_ctx *pctx;
-   int ret = 0;
 
if (!pskb_may_pull(skb, hdrlen))
return -1;
@@ -197,26 +196,19 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
if (gtp0->type != GTP_TPDU)
return 1;
 
-   rcu_read_lock();
pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
if (!pctx) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
-   ret = -1;
-   goto out_rcu;
+   return -1;
}
 
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   ret = -1;
-   goto out_rcu;
+   return -1;
}
-   rcu_read_unlock();
 
/* Get rid of the GTP + UDP headers. */
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
-out_rcu:
-   rcu_read_unlock();
-   return ret;
 }
 
 static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
@@ -226,7 +218,6 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
  sizeof(struct gtp1_header);
struct gtp1_header *gtp1;
struct pdp_ctx *pctx;
-   int ret = 0;
 
if (!pskb_may_pull(skb, hdrlen))
return -1;
@@ -254,26 +245,19 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
 
gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
 
-   rcu_read_lock();
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
if (!pctx) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
-   ret = -1;
-   goto out_rcu;
+   return -1;
}
 
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   ret = -1;
-   goto out_rcu;
+   return -1;
}
-   rcu_read_unlock();
 
/* Get rid of the GTP + UDP headers. */
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
-out_rcu:
-   rcu_read_unlock();
-   return ret;
 }
 
 static void gtp_encap_disable(struct gtp_dev *gtp)
-- 
2.10.2



[PATCH net-next v2 2/2] gtp: let userspace handle packets for invalid tunnels

2017-01-26 Thread Andreas Schultz
enable userspace to send error replies for invalid tunnels

Acked-by: Harald Welte <lafo...@netfilter.org>
Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 5c63a37..5dd7de6 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -199,12 +199,12 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
if (!pctx) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
-   return -1;
+   return 1;
}
 
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return -1;
+   return 1;
}
 
/* Get rid of the GTP + UDP headers. */
@@ -248,12 +248,12 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
if (!pctx) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
-   return -1;
+   return 1;
}
 
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return -1;
+   return 1;
}
 
/* Get rid of the GTP + UDP headers. */
-- 
2.10.2



[PATCH net-next v2 0/2] gtp: simple gtp improvements

2017-01-26 Thread Andreas Schultz
This is the part of the previous "simple gtp improvements" series
that Pablo indicated should go into net-next.

The rcu_lock removal is small correctness changes. Passing invalid
to user space allows for more standards compliant handling of invalid
tunnels.

--
Andreas Schultz (2):
  gtp: remove unnecessary rcu_read_lock
  gtp: let userspace handle packets for invalid tunnels

 drivers/net/gtp.c | 24 
 1 file changed, 4 insertions(+), 20 deletions(-)

-- 
2.10.2



[PATCH net v2 1/3] gtp: add genl family modules alias

2017-01-26 Thread Andreas Schultz
Auto-load the module when userspace asks for the gtp netlink
family.

Acked-by: Harald Welte <lafo...@netfilter.org>
Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 8b6810b..7580ccc 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1376,3 +1376,4 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <hwe...@sysmocom.de>");
 MODULE_DESCRIPTION("Interface driver for GTP encapsulated traffic");
 MODULE_ALIAS_RTNL_LINK("gtp");
+MODULE_ALIAS_GENL_FAMILY("gtp");
-- 
2.10.2



[PATCH net v2 2/3] gtp: clear DF bit on GTP packet tx

2017-01-26 Thread Andreas Schultz
3GPP TS 29.281 and 3GPP TS 29.060 imply that GTP-U packets should be
sent with the DF bit cleared. For example 3GPP TS 29.060, Release 8,
Section 13.2.2:

> Backbone router: Any router in the backbone may fragment the GTP
> packet if needed, according to IPv4.

Acked-by: Harald Welte <lafo...@netfilter.org>
Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 7580ccc..1df54d6 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -612,7 +612,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct 
net_device *dev)
pktinfo.fl4.saddr, pktinfo.fl4.daddr,
pktinfo.iph->tos,
ip4_dst_hoplimit(>dst),
-   htons(IP_DF),
+   0,
pktinfo.gtph_port, pktinfo.gtph_port,
true, false);
break;
-- 
2.10.2



[PATCH net v2 0/3] various gtp fixes

2017-01-26 Thread Andreas Schultz
This is the part of the previous "simple gtp improvements" series
that Pablo indicated should go into net.

The addition of the module alias fixes genl family autoloading,
clearing the DF bit fixes a protocol violation in regard to the
specification and the netns comparison fixes a corner case of
cross netns recv.

I'm not sure if Pablos comments on the previous version qualify
as ACK, so I left that out.

--
Andreas Schultz (3):
  gtp: add genl family modules alias
  gtp: clear DF bit on GTP packet tx
  gtp: fix cross netns recv on gtp socket

 drivers/net/gtp.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

-- 
2.10.2



[PATCH net v2 3/3] gtp: fix cross netns recv on gtp socket

2017-01-26 Thread Andreas Schultz
The use of the passed through netlink src_net to check for a
cross netns operation was wrong. Using the GTP socket and the
GTP netdevice is always correct (even if the netdev has been
moved to new netns after link creation).

Remove the now obsolete net field from gtp_dev.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 1df54d6..72dd1ba 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -69,7 +69,6 @@ struct gtp_dev {
struct socket   *sock0;
struct socket   *sock1u;
 
-   struct net  *net;
struct net_device   *dev;
 
unsigned inthash_size;
@@ -316,7 +315,7 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
 
-   xnet = !net_eq(gtp->net, dev_net(gtp->dev));
+   xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
 
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
@@ -658,7 +657,7 @@ static void gtp_link_setup(struct net_device *dev)
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
 static void gtp_hashtable_free(struct gtp_dev *gtp);
 static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1, struct net *src_net);
+   int fd_gtp0, int fd_gtp1);
 
 static int gtp_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
@@ -858,7 +857,6 @@ static int gtp_encap_enable(struct net_device *dev, struct 
gtp_dev *gtp,
 
gtp->sock0 = sock0;
gtp->sock1u = sock1u;
-   gtp->net = src_net;
 
tuncfg.sk_user_data = gtp;
tuncfg.encap_rcv = gtp_encap_recv;
-- 
2.10.2



Re: [PATCH 0/5] GTP: Fine-tuning for some function implementations

2017-01-26 Thread Andreas Schultz
Hi Markus,

- On Jan 26, 2017, at 11:15 AM, SF Markus Elfring 
elfr...@users.sourceforge.net wrote:

> From: Markus Elfring <elfr...@users.sourceforge.net>
> Date: Thu, 26 Jan 2017 11:10:01 +0100
> 
> A few update suggestions were taken into account
> from static source code analysis.
> 
> Markus Elfring (5):
>  Use kmalloc_array() in gtp_hashtable_new()
>  Improve another size determination in ipv4_pdp_add()
>  Adjust 12 checks for null pointers
>  Rename jump labels in gtp_encap_enable()
>  Rename jump labels in gtp_hashtable_new()

Looks good to me, for all the above:

Reviewed-by: Andreas Schultz <aschu...@tpip.net>

Andreas

> 
> drivers/net/gtp.c | 46 --
> 1 file changed, 24 insertions(+), 22 deletions(-)
> 
> --
> 2.11.0


Re: [PATCH 5/5] gtp: let userspace handle packets for invalid tunnels

2017-01-24 Thread Andreas Schultz
Hi Pablo,

- On Jan 24, 2017, at 8:03 PM, pablo pa...@netfilter.org wrote:

> Hi Andreas,
> 
> On Tue, Jan 24, 2017 at 06:24:02PM +0100, Andreas Schultz wrote:
>> enable userspace to send error replies for invalid tunnels
>> 
>> Signed-off-by: Andreas Schultz <aschu...@tpip.net>
>> ---
>>  drivers/net/gtp.c | 8 
>>  1 file changed, 4 insertions(+), 4 deletions(-)
>> 
>> diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
>> index 912721e..c607333 100644
>> --- a/drivers/net/gtp.c
>> +++ b/drivers/net/gtp.c
>> @@ -198,12 +198,12 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
>> struct
>> sk_buff *skb,
>>  pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
>>  if (!pctx) {
>>  netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
>> -return -1;
>> +return 1;
>>  }
>>  
>>  if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
>>  netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
>> -return -1;
>> +return 1;
> 
> So userspace gets the packet that we cannot forward. I guess your
> userspace codebase performs this sanity checks again so you can send
> the appropriate error reply?

For TEID /= 0, the only reply is a T-PDU of type error indication. There
is no cause specified. So I don't actually have to repeat the check.
TEID == 0 is more interesting, this tells userspace that it tried to
send on an invalid tunnel and should tear it down.

If you like, you can have a look at the userspace code. The relevant piece
is at 
https://github.com/travelping/gtp_u_kmod/blob/master/src/gtp_u_kmod_port.erl#L231

But be warned, it's written in Erlang ;-)

Andreas

> 
>>  }
>>  
>>  /* Get rid of the GTP + UDP headers. */
>> @@ -247,12 +247,12 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp,
>> struct sk_buff *skb,
>>  pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
>>  if (!pctx) {
>>  netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
>> -return -1;
>> +return 1;
>>  }
>>  
>>  if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
>>  netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
>> -return -1;
>> +return 1;
>>  }
>>  
>>  /* Get rid of the GTP + UDP headers. */
>> --
>> 2.10.2


[PATCH 2/5] gtp: clear DF bit on GTP packet tx

2017-01-24 Thread Andreas Schultz
3GPP TS 29.281 and 3GPP TS 29.060 imply that GTP-U packets should be
sent with the DF bit cleared. For example 3GPP TS 29.060, Release 8,
Section 13.2.2:

> Backbone router: Any router in the backbone may fragment the GTP
> packet if needed, according to IPv4.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 7580ccc..1df54d6 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -612,7 +612,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct 
net_device *dev)
pktinfo.fl4.saddr, pktinfo.fl4.daddr,
pktinfo.iph->tos,
ip4_dst_hoplimit(>dst),
-   htons(IP_DF),
+   0,
pktinfo.gtph_port, pktinfo.gtph_port,
true, false);
break;
-- 
2.10.2



[PATCH 4/5] gtp: remove unnecessary rcu_read_lock

2017-01-24 Thread Andreas Schultz
The rcu read lock is hold by default in the ip input path. There
is no need to hold it twice in the socket recv decapsulate code path.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 24 
 1 file changed, 4 insertions(+), 20 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 72dd1ba..912721e 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -183,7 +183,6 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
  sizeof(struct gtp0_header);
struct gtp0_header *gtp0;
struct pdp_ctx *pctx;
-   int ret = 0;
 
if (!pskb_may_pull(skb, hdrlen))
return -1;
@@ -196,26 +195,19 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
if (gtp0->type != GTP_TPDU)
return 1;
 
-   rcu_read_lock();
pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
if (!pctx) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
-   ret = -1;
-   goto out_rcu;
+   return -1;
}
 
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   ret = -1;
-   goto out_rcu;
+   return -1;
}
-   rcu_read_unlock();
 
/* Get rid of the GTP + UDP headers. */
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
-out_rcu:
-   rcu_read_unlock();
-   return ret;
 }
 
 static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
@@ -225,7 +217,6 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
  sizeof(struct gtp1_header);
struct gtp1_header *gtp1;
struct pdp_ctx *pctx;
-   int ret = 0;
 
if (!pskb_may_pull(skb, hdrlen))
return -1;
@@ -253,26 +244,19 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
 
gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
 
-   rcu_read_lock();
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
if (!pctx) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
-   ret = -1;
-   goto out_rcu;
+   return -1;
}
 
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   ret = -1;
-   goto out_rcu;
+   return -1;
}
-   rcu_read_unlock();
 
/* Get rid of the GTP + UDP headers. */
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
-out_rcu:
-   rcu_read_unlock();
-   return ret;
 }
 
 static void gtp_encap_disable(struct gtp_dev *gtp)
-- 
2.10.2



[PATCH 5/5] gtp: let userspace handle packets for invalid tunnels

2017-01-24 Thread Andreas Schultz
enable userspace to send error replies for invalid tunnels

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 912721e..c607333 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -198,12 +198,12 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
if (!pctx) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
-   return -1;
+   return 1;
}
 
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return -1;
+   return 1;
}
 
/* Get rid of the GTP + UDP headers. */
@@ -247,12 +247,12 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb,
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
if (!pctx) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
-   return -1;
+   return 1;
}
 
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
-   return -1;
+   return 1;
}
 
/* Get rid of the GTP + UDP headers. */
-- 
2.10.2



[PATCH 0/5] simple gtp improvements

2017-01-24 Thread Andreas Schultz
As requested are here the simple and most obvious changes from
the larger GTP changeset. I'll break down the rest and send them
out separately.

The module alias addition and the rcu_lock removal are just small
convenience changes.

The other changes are needed to correctly implement one of the
3GPP GW functions, userspace needs to see invalid T-PDU's in
order to generate the proper error messages, GTP fragmentation
rules need the cleared DF bit.

Andreas

--
Andreas Schultz (5):
  gtp: add genl family modules alias
  gtp: clear DF bit on GTP packet tx
  gtp: fix cross netns recv on gtp socket
  gtp: remove unnecessary rcu_read_lock
  gtp: let userspace handle packets for invalid tunnels

 drivers/net/gtp.c | 33 -
 1 file changed, 8 insertions(+), 25 deletions(-)

-- 
2.10.2



[PATCH 1/5] gtp: add genl family modules alias

2017-01-24 Thread Andreas Schultz
Auto-load the module when userspace asks for the gtp netlink
family.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 8b6810b..7580ccc 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1376,3 +1376,4 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <hwe...@sysmocom.de>");
 MODULE_DESCRIPTION("Interface driver for GTP encapsulated traffic");
 MODULE_ALIAS_RTNL_LINK("gtp");
+MODULE_ALIAS_GENL_FAMILY("gtp");
-- 
2.10.2



[PATCH 3/5] gtp: fix cross netns recv on gtp socket

2017-01-24 Thread Andreas Schultz
The use of the passed through netlink src_net to check for a
cross netns operation was wrong. Using the GTP socket and the
GTP netdevice is always correct (even if the netdev has been
moved to new netns after link creation).

Remove the now obsolete net field from gtp_dev.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 1df54d6..72dd1ba 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -69,7 +69,6 @@ struct gtp_dev {
struct socket   *sock0;
struct socket   *sock1u;
 
-   struct net  *net;
struct net_device   *dev;
 
unsigned inthash_size;
@@ -316,7 +315,7 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
 
-   xnet = !net_eq(gtp->net, dev_net(gtp->dev));
+   xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
 
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
@@ -658,7 +657,7 @@ static void gtp_link_setup(struct net_device *dev)
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
 static void gtp_hashtable_free(struct gtp_dev *gtp);
 static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
-   int fd_gtp0, int fd_gtp1, struct net *src_net);
+   int fd_gtp0, int fd_gtp1);
 
 static int gtp_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
@@ -858,7 +857,6 @@ static int gtp_encap_enable(struct net_device *dev, struct 
gtp_dev *gtp,
 
gtp->sock0 = sock0;
gtp->sock1u = sock1u;
-   gtp->net = src_net;
 
tuncfg.sk_user_data = gtp;
tuncfg.encap_rcv = gtp_encap_recv;
-- 
2.10.2



[PATCH v2 14/18] gtp: move TEID hash to per socket structure

2017-01-24 Thread Andreas Schultz
Untangele the TEID information from the network device and move
it into a per socket structure.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 100 --
 1 file changed, 60 insertions(+), 40 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 7d82252..d2ba943 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -75,10 +75,15 @@ struct gtp_dev {
struct net_device   *dev;
 
unsigned inthash_size;
-   struct hlist_head   *tid_hash;
struct hlist_head   *addr_hash;
 };
 
+/* One instance of the GTP socket. */
+struct gtp_sock {
+   unsigned inthash_size;
+   struct hlist_head   tid_hash[];
+};
+
 static unsigned int gtp_net_id __read_mostly;
 
 struct gtp_net {
@@ -106,12 +111,12 @@ static inline u32 ipv4_hashfn(__be32 ip)
 }
 
 /* Resolve a PDP context structure based on the 64bit TID. */
-static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid)
+static struct pdp_ctx *gtp0_pdp_find(struct gtp_sock *gsk, u64 tid)
 {
struct hlist_head *head;
struct pdp_ctx *pdp;
 
-   head = >tid_hash[gtp0_hashfn(tid) % gtp->hash_size];
+   head = >tid_hash[gtp0_hashfn(tid) % gsk->hash_size];
 
hlist_for_each_entry_rcu(pdp, head, hlist_tid) {
if (pdp->gtp_version == GTP_V0 &&
@@ -122,12 +127,12 @@ static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, 
u64 tid)
 }
 
 /* Resolve a PDP context structure based on the 32bit TEI. */
-static struct pdp_ctx *gtp1_pdp_find(struct gtp_dev *gtp, u32 tid)
+static struct pdp_ctx *gtp1_pdp_find(struct gtp_sock *gsk, u32 tid)
 {
struct hlist_head *head;
struct pdp_ctx *pdp;
 
-   head = >tid_hash[gtp1u_hashfn(tid) % gtp->hash_size];
+   head = >tid_hash[gtp1u_hashfn(tid) % gsk->hash_size];
 
hlist_for_each_entry_rcu(pdp, head, hlist_tid) {
if (pdp->gtp_version == GTP_V1 &&
@@ -215,7 +220,7 @@ static int gtp_rx(struct sk_buff *skb, struct pdp_ctx 
*pctx, unsigned int hdrlen
 }
 
 /* 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)
+static int gtp0_udp_encap_recv(struct gtp_sock *gsk, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp0_header);
@@ -233,7 +238,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb)
if (gtp0->type != GTP_TPDU)
return 1;
 
-   pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
+   pctx = gtp0_pdp_find(gsk, be64_to_cpu(gtp0->tid));
if (IS_ERR(pctx)) {
pr_debug("No PDP ctx to decap skb=%p\n", skb);
return 1;
@@ -242,7 +247,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb)
return gtp_rx(skb, pctx, hdrlen);
 }
 
-static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
+static int gtp1u_udp_encap_recv(struct gtp_sock *gsk, struct sk_buff *skb)
 {
unsigned int hdrlen = sizeof(struct udphdr) +
  sizeof(struct gtp1_header);
@@ -275,7 +280,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb)
 
gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
 
-   pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
+   pctx = gtp1_pdp_find(gsk, ntohl(gtp1->tid));
if (IS_ERR(pctx)) {
pr_debug("No PDP ctx to decap skb=%p\n", skb);
return 1;
@@ -289,11 +294,11 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, 
struct sk_buff *skb)
  */
 static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
-   struct gtp_dev *gtp;
+   struct gtp_sock *gsk;
int ret = 0;
 
-   gtp = rcu_dereference_sk_user_data(sk);
-   if (!gtp)
+   gsk = rcu_dereference_sk_user_data(sk);
+   if (!gsk)
return 1;
 
pr_debug("encap_recv sk=%p\n", sk);
@@ -301,11 +306,11 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
pr_debug("received GTP0 packet\n");
-   ret = gtp0_udp_encap_recv(gtp, skb);
+   ret = gtp0_udp_encap_recv(gsk, skb);
break;
case UDP_ENCAP_GTP1U:
pr_debug("received GTP1U packet\n");
-   ret = gtp1u_udp_encap_recv(gtp, skb);
+   ret = gtp1u_udp_encap_recv(gsk, skb);
break;
default:
ret = -1; /* Shouldn't happen. */
@@ -329,12 +334,21 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 
 static void gtp_encap_destroy(struct sock *s

[PATCH v2 04/18] gtp: return error ptr in find pdp helpers

2017-01-24 Thread Andreas Schultz
Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 22 +++---
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 60946b7..e95c856 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -114,7 +114,7 @@ static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, 
u64 tid)
pdp->u.v0.tid == tid)
return pdp;
}
-   return NULL;
+   return ERR_PTR(-ENOENT);
 }
 
 /* Resolve a PDP context structure based on the 32bit TEI. */
@@ -130,7 +130,7 @@ static struct pdp_ctx *gtp1_pdp_find(struct gtp_dev *gtp, 
u32 tid)
pdp->u.v1.i_tei == tid)
return pdp;
}
-   return NULL;
+   return ERR_PTR(-ENOENT);
 }
 
 /* Resolve a PDP context based on IPv4 address of MS. */
@@ -147,7 +147,7 @@ static struct pdp_ctx *ipv4_pdp_find(struct gtp_dev *gtp, 
__be32 ms_addr)
return pdp;
}
 
-   return NULL;
+   return ERR_PTR(-ENOENT);
 }
 
 static bool gtp_check_src_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx,
@@ -199,7 +199,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
 
rcu_read_lock();
pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
-   if (!pctx) {
+   if (IS_ERR(pctx)) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
ret = -1;
goto out_rcu;
@@ -256,7 +256,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb,
 
rcu_read_lock();
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
-   if (!pctx) {
+   if (IS_ERR(pctx)) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
ret = -1;
goto out_rcu;
@@ -476,10 +476,10 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
 */
iph = ip_hdr(skb);
pctx = ipv4_pdp_find(gtp, iph->daddr);
-   if (!pctx) {
+   if (IS_ERR(pctx)) {
netdev_dbg(dev, "no PDP ctx found for %pI4, skip\n",
   >daddr);
-   return -ENOENT;
+   return PTR_ERR(pctx);
}
netdev_dbg(dev, "found PDP context %p\n", pctx);
 
@@ -1085,8 +1085,8 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct 
genl_info *info)
return -EINVAL;
}
 
-   if (pctx == NULL)
-   return -ENOENT;
+   if (IS_ERR(pctx))
+   return PTR_ERR(pctx);
 
if (pctx->gtp_version == GTP_V0)
netdev_dbg(dev, "GTPv0-U: deleting tunnel id = %llx (pdp %p)\n",
@@ -1194,8 +1194,8 @@ static int gtp_genl_get_pdp(struct sk_buff *skb, struct 
genl_info *info)
pctx = ipv4_pdp_find(gtp, ip);
}
 
-   if (pctx == NULL) {
-   err = -ENOENT;
+   if (IS_ERR(pctx)) {
+   err = PTR_ERR(pctx);
goto err_unlock;
}
 
-- 
2.10.2



[PATCH v2 10/18] gtp: add socket to pdp context

2017-01-24 Thread Andreas Schultz
Having the socket present in context simplifies the sending logic.
It also fixes the invalid assumtion that we have to use the same
sending socket for all client IP's on a specific gtp interface.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 70 ++-
 1 file changed, 38 insertions(+), 32 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index c7e32a6..fb93468 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,8 @@ struct pdp_ctx {
struct in_addr  ms_addr_ip4;
struct in_addr  sgsn_addr_ip4;
 
+   struct sock *sk;
+
atomic_ttx_seq;
struct rcu_head rcu_head;
 };
@@ -353,8 +355,9 @@ static void gtp_dev_uninit(struct net_device *dev)
free_percpu(dev->tstats);
 }
 
-static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4,
-  const struct sock *sk, __be32 daddr)
+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;
@@ -363,7 +366,7 @@ static struct rtable *ip4_route_output_gtp(struct net *net, 
struct flowi4 *fl4,
fl4->flowi4_tos = RT_CONN_FLAGS(sk);
fl4->flowi4_proto   = sk->sk_protocol;
 
-   return ip_route_output_key(net, fl4);
+   return ip_route_output_key(sock_net(sk), fl4);
 }
 
 static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
@@ -452,7 +455,6 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
struct rtable *rt;
struct flowi4 fl4;
struct iphdr *iph;
-   struct sock *sk;
__be16 df;
int mtu;
 
@@ -468,30 +470,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
}
netdev_dbg(dev, "found PDP context %p\n", pctx);
 
-   switch (pctx->gtp_version) {
-   case GTP_V0:
-   if (gtp->sock0)
-   sk = gtp->sock0->sk;
-   else
-   sk = NULL;
-   break;
-   case GTP_V1:
-   if (gtp->sock1u)
-   sk = gtp->sock1u->sk;
-   else
-   sk = NULL;
-   break;
-   default:
-   return -ENOENT;
-   }
-
-   if (!sk) {
-   netdev_dbg(dev, "no userspace socket is available, skip\n");
-   return -ENOENT;
-   }
-
-   rt = ip4_route_output_gtp(sock_net(sk), , gtp->sock0->sk,
- pctx->sgsn_addr_ip4.s_addr);
+   rt = ip4_route_output_gtp(, pctx->sk, pctx->sgsn_addr_ip4.s_addr);
if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to SSGN %pI4\n",
   >sgsn_addr_ip4.s_addr);
@@ -536,7 +515,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct 
net_device *dev,
goto err_rt;
}
 
-   gtp_set_pktinfo_ipv4(pktinfo, sk, iph, pctx, rt, , dev);
+   gtp_set_pktinfo_ipv4(pktinfo, pctx->sk, iph, pctx, rt, , dev);
gtp_push_header(skb, pktinfo);
 
return 0;
@@ -906,7 +885,8 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct 
genl_info *info)
}
 }
 
-static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
+static int ipv4_pdp_add(struct net_device *dev, struct sock *sk,
+   struct genl_info *info)
 {
struct gtp_dev *gtp = netdev_priv(dev);
u32 hash_ms, hash_tid = 0;
@@ -947,6 +927,8 @@ static int ipv4_pdp_add(struct net_device *dev, struct 
genl_info *info)
if (pctx == NULL)
return -ENOMEM;
 
+   sock_hold(sk);
+   pctx->sk = sk;
ipv4_pdp_fill(pctx, info);
atomic_set(>tx_seq, 0);
 
@@ -987,6 +969,7 @@ static void pdp_context_free(struct rcu_head *head)
 {
struct pdp_ctx *pctx = container_of(head, struct pdp_ctx, rcu_head);
 
+   sock_put(pctx->sk);
kfree(pctx);
 }
 
@@ -997,10 +980,27 @@ static void pdp_context_delete(struct pdp_ctx *pctx)
call_rcu(>rcu_head, pdp_context_free);
 }
 
+static struct socket *gtp_genl_new_pdp_select_socket(int version,
+struct net_device *dev)
+{
+   struct gtp_dev *gtp = netdev_priv(dev);
+
+   switch (version) {
+   case GTP_V0:
+   return gtp->sock0;
+   case GTP_V1:
+   return gtp->sock1u;
+   default:
+   return NULL;
+   }
+}
+
 static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 {
+   unsigned int version;
str

[PATCH v2 09/18] gtp: use addr_hash when traversing pdp contexts

2017-01-24 Thread Andreas Schultz
This prepares for the removal of the tid_hash from the device.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index c117f63..c7e32a6 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -778,7 +778,7 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
int i;
 
for (i = 0; i < gtp->hash_size; i++)
-   hlist_for_each_entry_rcu(pctx, >tid_hash[i], hlist_tid)
+   hlist_for_each_entry_rcu(pctx, >addr_hash[i], hlist_addr)
pdp_context_delete(pctx);
 
synchronize_rcu();
@@ -1195,7 +1195,7 @@ static int gtp_genl_dump_pdp(struct sk_buff *skb,
last_gtp = NULL;
 
for (i = k; i < gtp->hash_size; i++) {
-   hlist_for_each_entry_rcu(pctx, >tid_hash[i], 
hlist_tid) {
+   hlist_for_each_entry_rcu(pctx, >addr_hash[i], 
hlist_addr) {
if (tid && tid != pctx->u.tid)
continue;
else
-- 
2.10.2



[PATCH v2 13/18] gtp: replace netdev_dbg and KERN_DEBUG printk with pr_debug

2017-01-24 Thread Andreas Schultz
pr_debug is more versatile for normal debugging.
Also replace netdev_dbg in in places where the network device
will be remove soon.

Signed-off-by: Andreas Schultz <aschu...@tpip.net>
---
 drivers/net/gtp.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 8d74b7d..7d82252 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -235,7 +235,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb)
 
pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
if (IS_ERR(pctx)) {
-   netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
+   pr_debug("No PDP ctx to decap skb=%p\n", skb);
return 1;
}
 
@@ -277,7 +277,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct 
sk_buff *skb)
 
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
if (IS_ERR(pctx)) {
-   netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
+   pr_debug("No PDP ctx to decap skb=%p\n", skb);
return 1;
}
 
@@ -296,15 +296,15 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
if (!gtp)
return 1;
 
-   netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
+   pr_debug("encap_recv sk=%p\n", sk);
 
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
-   netdev_dbg(gtp->dev, "received GTP0 packet\n");
+   pr_debug("received GTP0 packet\n");
ret = gtp0_udp_encap_recv(gtp, skb);
break;
case UDP_ENCAP_GTP1U:
-   netdev_dbg(gtp->dev, "received GTP1U packet\n");
+   pr_debug("received GTP1U packet\n");
ret = gtp1u_udp_encap_recv(gtp, skb);
break;
default:
@@ -313,12 +313,12 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff 
*skb)
 
switch (ret) {
case 1:
-   netdev_dbg(gtp->dev, "pass up to the process\n");
+   pr_debug("pass up to the process\n");
break;
case 0:
break;
case -1:
-   netdev_dbg(gtp->dev, "GTP packet has been dropped\n");
+   pr_debug("GTP packet has been dropped\n");
kfree_skb(skb);
ret = 0;
break;
-- 
2.10.2



  1   2   >