This is the part from the larger patch that deals with network namespace support only.
The debug instrumentation is there to better diagnose cross namespace device setup.
The netlink attribute IFLA_NET_NS_FD can be used to specifiy the namespace for the newly create gtp netdevice.
In the libgtnl API the netspace filedescriptor is optional.
Andreas
--
Andreas Schultz (3): gtp: add some debug instrumentation gtp: select netns based on NL attribute gtp-rtnl: and netns support
gtp.c | 41 ++++++++++++++++++++++++++++++++++++---- gtp_nl.h | 1 + libgtnl/include/libgtpnl/gtp.h | 2 ++ libgtnl/include/libgtpnl/gtpnl.h | 2 +- libgtnl/include/linux/gtp_nl.h | 1 + libgtnl/src/gtp-genl.c | 2 ++ libgtnl/src/gtp-rtnl.c | 4 +++- libgtnl/src/gtp.c | 12 ++++++++++++ libgtnl/src/internal.h | 1 + libgtnl/src/libgtpnl.map | 2 ++ 10 files changed, 62 insertions(+), 6 deletions(-)
Signed-off-by: Andreas Schultz aschultz@tpip.net --- gtp.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/gtp.c b/gtp.c index 8782fea..cbe2da1 100644 --- a/gtp.c +++ b/gtp.c @@ -330,6 +330,8 @@ static int gtp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) if (!gti) goto user;
+ netdev_dbg(gti->dev, "encap_recv %p\n", sk); + switch (udp_sk(sk)->encap_type) { case UDP_ENCAP_GTP0: netdev_dbg(gti->dev, "received GTP0 packet\n"); @@ -893,6 +895,8 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, struct socket *sock0, *sock1u; struct sock *sk;
+ netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1); + sock0 = sockfd_lookup(fd_gtp0, &err); if (sock0 == NULL) { netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0); @@ -918,6 +922,8 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, goto err2; }
+ netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u); + gti->sock0 = sock0; gti->sock1u = sock1u;
This permits a split namespace setup where the GTP transport sockets are in one namespace the gtp tunnel interface is in another namespace.
The target namespece is selected by the new GTPA_NET_NS_FD NL attributes. It fall back to the netns of the GTP-U sockets if the NL attr is not present.
Signed-off-by: Andreas Schultz aschultz@tpip.net --- gtp.c | 35 +++++++++++++++++++++++++++++++---- gtp_nl.h | 1 + 2 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/gtp.c b/gtp.c index cbe2da1..0a45f53 100644 --- a/gtp.c +++ b/gtp.c @@ -740,7 +740,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - struct gtp_net *gn = net_generic(src_net, gtp_net_id); + struct gtp_net *gn; struct net_device *real_dev; struct gtp_instance *gti; int hashsize, err, fd0, fd1; @@ -780,6 +780,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, if (err < 0) goto err1;
+ gn = net_generic(dev_net(dev), gtp_net_id); list_add_rcu(>i->list, &gn->gtp_instance_list);
netdev_dbg(dev, "registered new interface\n"); @@ -847,6 +848,19 @@ 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_instance *gti, int hsize) { int i; @@ -1065,7 +1079,7 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) { - struct net *net = sock_net(skb->sk); + struct net *net; struct net_device *dev;
if (!info->attrs[GTPA_VERSION] || @@ -1075,6 +1089,10 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) !info->attrs[GTPA_TID]) return -EINVAL;
+ net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); + if (IS_ERR(net)) + return -EINVAL; + /* 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) @@ -1085,7 +1103,7 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info)
static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) { - struct net *net = sock_net(skb->sk); + struct net *net; struct gtp_instance *gti; struct net_device *dev; struct pdp_ctx *pctx; @@ -1113,6 +1131,10 @@ static int gtp_genl_tunnel_delete(struct sk_buff *skb, struct genl_info *info) if (gtp_version == GTP_V1 && tid > UINT_MAX) return -EINVAL;
+ net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); + if (IS_ERR(net)) + return -EINVAL; + /* 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) @@ -1181,7 +1203,7 @@ nla_put_failure:
static int gtp_genl_tunnel_get(struct sk_buff *skb, struct genl_info *info) { - struct net *net = sock_net(skb->sk); + struct net *net; struct net_device *dev; struct gtp_instance *gti; struct pdp_ctx *pctx = NULL; @@ -1202,6 +1224,10 @@ static int gtp_genl_tunnel_get(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 -EINVAL; + /* 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) @@ -1310,6 +1336,7 @@ static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = { [GTPA_SGSN_ADDRESS] = { .type = NLA_NESTED, }, [GTPA_MS_ADDRESS] = { .type = NLA_NESTED, }, [GTPA_FLOW] = { .type = NLA_U16, }, + [GTPA_NET_NS_FD] = { .type = NLA_U32, }, };
static const struct genl_ops gtp_genl_ops[] = { diff --git a/gtp_nl.h b/gtp_nl.h index 7bdd2f5..c20666d 100644 --- a/gtp_nl.h +++ b/gtp_nl.h @@ -40,6 +40,7 @@ enum gtp_attrs { GTPA_SGSN_ADDRESS, GTPA_MS_ADDRESS, GTPA_FLOW, + GTPA_NET_NS_FD, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1)
On Tue, Nov 17, 2015 at 12:06:19PM +0100, Andreas Schultz wrote:
This permits a split namespace setup where the GTP transport sockets are in one namespace the gtp tunnel interface is in another namespace.
The target namespece is selected by the new GTPA_NET_NS_FD NL attributes. It fall back to the netns of the GTP-U sockets if the NL attr is not present.
Signed-off-by: Andreas Schultz aschultz@tpip.net
gtp.c | 35 +++++++++++++++++++++++++++++++---- gtp_nl.h | 1 + 2 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/gtp.c b/gtp.c index cbe2da1..0a45f53 100644 --- a/gtp.c +++ b/gtp.c @@ -740,7 +740,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti, static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) {
- struct gtp_net *gn = net_generic(src_net, gtp_net_id);
- struct gtp_net *gn; struct net_device *real_dev; struct gtp_instance *gti; int hashsize, err, fd0, fd1;
@@ -780,6 +780,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, if (err < 0) goto err1;
gn = net_generic(dev_net(dev), gtp_net_id); list_add_rcu(>i->list, &gn->gtp_instance_list);
netdev_dbg(dev, "registered new interface\n");
@@ -847,6 +848,19 @@ 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_instance *gti, int hsize) { int i; @@ -1065,7 +1079,7 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) {
- struct net *net = sock_net(skb->sk);
struct net *net; struct net_device *dev;
if (!info->attrs[GTPA_VERSION] ||
@@ -1075,6 +1089,10 @@ static int gtp_genl_tunnel_new(struct sk_buff *skb, struct genl_info *info) !info->attrs[GTPA_TID]) return -EINVAL;
- net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
- if (IS_ERR(net))
return -EINVAL;
You probably want to propagate the real error reason:
return PTR_ERR(net);
Signed-off-by: Andreas Schultz aschultz@tpip.net --- libgtnl/include/libgtpnl/gtp.h | 2 ++ libgtnl/include/libgtpnl/gtpnl.h | 2 +- libgtnl/include/linux/gtp_nl.h | 1 + libgtnl/src/gtp-genl.c | 2 ++ libgtnl/src/gtp-rtnl.c | 4 +++- libgtnl/src/gtp.c | 12 ++++++++++++ libgtnl/src/internal.h | 1 + libgtnl/src/libgtpnl.map | 2 ++ 8 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/libgtnl/include/libgtpnl/gtp.h b/libgtnl/include/libgtpnl/gtp.h index 10b34d5..fa09d2a 100644 --- a/libgtnl/include/libgtpnl/gtp.h +++ b/libgtnl/include/libgtpnl/gtp.h @@ -8,6 +8,7 @@ struct gtp_tunnel; struct gtp_tunnel *gtp_tunnel_alloc(void); void gtp_tunnel_free(struct gtp_tunnel *t);
+void gtp_tunnel_set_ifns(struct gtp_tunnel *t, int ifns); void gtp_tunnel_set_ifidx(struct gtp_tunnel *t, uint32_t ifidx); void gtp_tunnel_set_ms_ip4(struct gtp_tunnel *t, struct in_addr *ms_addr); void gtp_tunnel_set_sgsn_ip4(struct gtp_tunnel *t, struct in_addr *sgsn_addr); @@ -15,6 +16,7 @@ void gtp_tunnel_set_version(struct gtp_tunnel *t, uint32_t version); void gtp_tunnel_set_tid(struct gtp_tunnel *t, uint64_t tid); void gtp_tunnel_set_flowid(struct gtp_tunnel *t, uint16_t flowid);
+const int gtp_tunnel_get_ifns(struct gtp_tunnel *t); const uint32_t gtp_tunnel_get_ifidx(struct gtp_tunnel *t); const struct in_addr *gtp_tunnel_get_ms_ip4(struct gtp_tunnel *t); const struct in_addr *gtp_tunnel_get_sgsn_ip4(struct gtp_tunnel *t); diff --git a/libgtnl/include/libgtpnl/gtpnl.h b/libgtnl/include/libgtpnl/gtpnl.h index c4faf6c..3d3fd73 100644 --- a/libgtnl/include/libgtpnl/gtpnl.h +++ b/libgtnl/include/libgtpnl/gtpnl.h @@ -16,7 +16,7 @@ int genl_lookup_family(struct mnl_socket *nl, const char *family);
struct in_addr;
-int gtp_dev_create(const char *gtp_ifname, const char *real_ifname, +int gtp_dev_create(int dest_ns, const char *gtp_ifname, const char *real_ifname, int fd0, int fd1); int gtp_dev_config(const char *iface, struct in_addr *net, uint32_t prefix); int gtp_dev_destroy(const char *gtp_ifname); diff --git a/libgtnl/include/linux/gtp_nl.h b/libgtnl/include/linux/gtp_nl.h index 0a28046..a8fdf3a 100644 --- a/libgtnl/include/linux/gtp_nl.h +++ b/libgtnl/include/linux/gtp_nl.h @@ -40,6 +40,7 @@ enum gtp_attrs { GTPA_SGSN_ADDRESS, GTPA_MS_ADDRESS, GTPA_FLOWID, /* only for GTPv0 */ + GTPA_NET_NS_FD, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1) diff --git a/libgtnl/src/gtp-genl.c b/libgtnl/src/gtp-genl.c index c1f60ab..9e68a30 100644 --- a/libgtnl/src/gtp-genl.c +++ b/libgtnl/src/gtp-genl.c @@ -44,6 +44,8 @@ static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t) { mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version); + if (t->ifns > 0) + mnl_attr_put_u32(nlh, GTPA_NET_NS_FD, t->ifns); mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx); mnl_attr_put_u32(nlh, GTPA_SGSN_ADDRESS, t->sgsn_addr.s_addr); mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.s_addr); diff --git a/libgtnl/src/gtp-rtnl.c b/libgtnl/src/gtp-rtnl.c index 22b9430..2cd6da9 100644 --- a/libgtnl/src/gtp-rtnl.c +++ b/libgtnl/src/gtp-rtnl.c @@ -104,7 +104,7 @@ static int gtp_dev_talk(struct nlmsghdr *nlh, uint32_t seq) return ret; }
-int gtp_dev_create(const char *gtp_ifname, const char *real_ifname, +int gtp_dev_create(int dest_ns, const char *gtp_ifname, const char *real_ifname, int fd0, int fd1) { char buf[MNL_SOCKET_BUFFER_SIZE]; @@ -120,6 +120,8 @@ int gtp_dev_create(const char *gtp_ifname, const char *real_ifname, ifm->ifi_change |= IFF_UP; ifm->ifi_flags |= IFF_UP;
+ if (dest_ns > 0) + mnl_attr_put_u32(nlh, IFLA_NET_NS_FD, dest_ns); mnl_attr_put_u32(nlh, IFLA_LINK, if_nametoindex(real_ifname)); mnl_attr_put_str(nlh, IFLA_IFNAME, gtp_ifname); nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO); diff --git a/libgtnl/src/gtp.c b/libgtnl/src/gtp.c index 4534091..6e3d473 100644 --- a/libgtnl/src/gtp.c +++ b/libgtnl/src/gtp.c @@ -39,6 +39,12 @@ void gtp_tunnel_free(struct gtp_tunnel *t) } EXPORT_SYMBOL(gtp_tunnel_free);
+void gtp_tunnel_set_ifns(struct gtp_tunnel *t, int ifns) +{ + t->ifns = ifns; +} +EXPORT_SYMBOL(gtp_tunnel_set_ifns); + void gtp_tunnel_set_ifidx(struct gtp_tunnel *t, uint32_t ifidx) { t->ifidx = ifidx; @@ -75,6 +81,12 @@ void gtp_tunnel_set_flowid(struct gtp_tunnel *t, uint16_t flowid) } EXPORT_SYMBOL(gtp_tunnel_set_flowid);
+const int gtp_tunnel_get_ifns(struct gtp_tunnel *t) +{ + return t->ifns; +} +EXPORT_SYMBOL(gtp_tunnel_get_ifns); + const uint32_t gtp_tunnel_get_ifidx(struct gtp_tunnel *t) { return t->ifidx; diff --git a/libgtnl/src/internal.h b/libgtnl/src/internal.h index 75b3954..68f0135 100644 --- a/libgtnl/src/internal.h +++ b/libgtnl/src/internal.h @@ -13,6 +13,7 @@ #include <netinet/in.h>
struct gtp_tunnel { + int ifns; uint32_t ifidx; struct in_addr ms_addr; struct in_addr sgsn_addr; diff --git a/libgtnl/src/libgtpnl.map b/libgtnl/src/libgtpnl.map index 6e69ef8..2368467 100644 --- a/libgtnl/src/libgtpnl.map +++ b/libgtnl/src/libgtpnl.map @@ -15,12 +15,14 @@ global:
gtp_tunnel_alloc; gtp_tunnel_free; + gtp_tunnel_set_ifns; gtp_tunnel_set_ifidx; gtp_tunnel_set_ms_ip4; gtp_tunnel_set_sgsn_ip4; gtp_tunnel_set_version; gtp_tunnel_set_tid; gtp_tunnel_set_flowid; + gtp_tunnel_get_ifns; gtp_tunnel_get_ifidx; gtp_tunnel_get_ms_ip4; gtp_tunnel_get_sgsn_ip4;