提交 101cfbc1 编写于 作者: A Andreas Schultz 提交者: David S. Miller

gtp: add socket to pdp context

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: NAndreas Schultz <aschultz@tpip.net>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 6b5e2e74
...@@ -58,6 +58,7 @@ struct pdp_ctx { ...@@ -58,6 +58,7 @@ struct pdp_ctx {
struct in_addr ms_addr_ip4; struct in_addr ms_addr_ip4;
struct in_addr sgsn_addr_ip4; struct in_addr sgsn_addr_ip4;
struct sock *sk;
struct net_device *dev; struct net_device *dev;
atomic_t tx_seq; atomic_t tx_seq;
...@@ -179,8 +180,7 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct pdp_ctx *pctx, ...@@ -179,8 +180,7 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct pdp_ctx *pctx,
return false; return false;
} }
static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen, static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen)
bool xnet)
{ {
struct pcpu_sw_netstats *stats; struct pcpu_sw_netstats *stats;
...@@ -190,7 +190,8 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen ...@@ -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. */ /* 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; return -1;
netdev_dbg(pctx->dev, "forwarding packet from GGSN to uplink\n"); 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 ...@@ -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. */ /* 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_dev *gtp, struct sk_buff *skb)
bool xnet)
{ {
unsigned int hdrlen = sizeof(struct udphdr) + unsigned int hdrlen = sizeof(struct udphdr) +
sizeof(struct gtp0_header); sizeof(struct gtp0_header);
...@@ -239,11 +239,10 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, ...@@ -239,11 +239,10 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
return 1; 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, static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
bool xnet)
{ {
unsigned int hdrlen = sizeof(struct udphdr) + unsigned int hdrlen = sizeof(struct udphdr) +
sizeof(struct gtp1_header); sizeof(struct gtp1_header);
...@@ -282,7 +281,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, ...@@ -282,7 +281,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
return 1; return 1;
} }
return gtp_rx(pctx, skb, hdrlen, xnet); return gtp_rx(pctx, skb, hdrlen);
} }
static void gtp_encap_destroy(struct sock *sk) static void gtp_encap_destroy(struct sock *sk)
...@@ -318,7 +317,6 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) ...@@ -318,7 +317,6 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
{ {
struct gtp_dev *gtp; struct gtp_dev *gtp;
int ret = 0; int ret = 0;
bool xnet;
gtp = rcu_dereference_sk_user_data(sk); gtp = rcu_dereference_sk_user_data(sk);
if (!gtp) if (!gtp)
...@@ -326,16 +324,14 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) ...@@ -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); 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) { switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0: case UDP_ENCAP_GTP0:
netdev_dbg(gtp->dev, "received GTP0 packet\n"); netdev_dbg(gtp->dev, "received GTP0 packet\n");
ret = gtp0_udp_encap_recv(gtp, skb, xnet); ret = gtp0_udp_encap_recv(gtp, skb);
break; break;
case UDP_ENCAP_GTP1U: case UDP_ENCAP_GTP1U:
netdev_dbg(gtp->dev, "received GTP1U packet\n"); netdev_dbg(gtp->dev, "received GTP1U packet\n");
ret = gtp1u_udp_encap_recv(gtp, skb, xnet); ret = gtp1u_udp_encap_recv(gtp, skb);
break; break;
default: default:
ret = -1; /* Shouldn't happen. */ ret = -1; /* Shouldn't happen. */
...@@ -378,8 +374,9 @@ static void gtp_dev_uninit(struct net_device *dev) ...@@ -378,8 +374,9 @@ static void gtp_dev_uninit(struct net_device *dev)
free_percpu(dev->tstats); free_percpu(dev->tstats);
} }
static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4, static struct rtable *ip4_route_output_gtp(struct flowi4 *fl4,
const struct sock *sk, __be32 daddr) const struct sock *sk,
__be32 daddr)
{ {
memset(fl4, 0, sizeof(*fl4)); memset(fl4, 0, sizeof(*fl4));
fl4->flowi4_oif = sk->sk_bound_dev_if; 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, ...@@ -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_tos = RT_CONN_FLAGS(sk);
fl4->flowi4_proto = sk->sk_protocol; 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) 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 sk_buff *skb, struct net_device *dev, ...@@ -477,7 +474,6 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
struct rtable *rt; struct rtable *rt;
struct flowi4 fl4; struct flowi4 fl4;
struct iphdr *iph; struct iphdr *iph;
struct sock *sk;
__be16 df; __be16 df;
int mtu; int mtu;
...@@ -493,30 +489,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, ...@@ -493,30 +489,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
} }
netdev_dbg(dev, "found PDP context %p\n", pctx); netdev_dbg(dev, "found PDP context %p\n", pctx);
switch (pctx->gtp_version) { rt = ip4_route_output_gtp(&fl4, pctx->sk, pctx->sgsn_addr_ip4.s_addr);
case GTP_V0:
if (gtp->sk0)
sk = gtp->sk0;
else
sk = NULL;
break;
case GTP_V1:
if (gtp->sk1u)
sk = gtp->sk1u;
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), &fl4, gtp->sk0,
pctx->sgsn_addr_ip4.s_addr);
if (IS_ERR(rt)) { if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to SSGN %pI4\n", netdev_dbg(dev, "no route to SSGN %pI4\n",
&pctx->sgsn_addr_ip4.s_addr); &pctx->sgsn_addr_ip4.s_addr);
...@@ -561,7 +534,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, ...@@ -561,7 +534,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
goto err_rt; goto err_rt;
} }
gtp_set_pktinfo_ipv4(pktinfo, sk, iph, pctx, rt, &fl4, dev); gtp_set_pktinfo_ipv4(pktinfo, pctx->sk, iph, pctx, rt, &fl4, dev);
gtp_push_header(skb, pktinfo); gtp_push_header(skb, pktinfo);
return 0; return 0;
...@@ -916,7 +889,8 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info) ...@@ -916,7 +889,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)
{ {
struct net_device *dev = gtp->dev; struct net_device *dev = gtp->dev;
u32 hash_ms, hash_tid = 0; u32 hash_ms, hash_tid = 0;
...@@ -957,6 +931,8 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info) ...@@ -957,6 +931,8 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info)
if (pctx == NULL) if (pctx == NULL)
return -ENOMEM; return -ENOMEM;
sock_hold(sk);
pctx->sk = sk;
pctx->dev = gtp->dev; pctx->dev = gtp->dev;
ipv4_pdp_fill(pctx, info); ipv4_pdp_fill(pctx, info);
atomic_set(&pctx->tx_seq, 0); atomic_set(&pctx->tx_seq, 0);
...@@ -994,16 +970,26 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info) ...@@ -994,16 +970,26 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info)
return 0; 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) static void pdp_context_delete(struct pdp_ctx *pctx)
{ {
hlist_del_rcu(&pctx->hlist_tid); hlist_del_rcu(&pctx->hlist_tid);
hlist_del_rcu(&pctx->hlist_addr); hlist_del_rcu(&pctx->hlist_addr);
kfree_rcu(pctx, rcu_head); call_rcu(&pctx->rcu_head, pdp_context_free);
} }
static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
{ {
unsigned int version;
struct gtp_dev *gtp; struct gtp_dev *gtp;
struct sock *sk;
int err; int err;
if (!info->attrs[GTPA_VERSION] || if (!info->attrs[GTPA_VERSION] ||
...@@ -1012,7 +998,9 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) ...@@ -1012,7 +998,9 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
!info->attrs[GTPA_MS_ADDRESS]) !info->attrs[GTPA_MS_ADDRESS])
return -EINVAL; return -EINVAL;
switch (nla_get_u32(info->attrs[GTPA_VERSION])) { version = nla_get_u32(info->attrs[GTPA_VERSION]);
switch (version) {
case GTP_V0: case GTP_V0:
if (!info->attrs[GTPA_TID] || if (!info->attrs[GTPA_TID] ||
!info->attrs[GTPA_FLOW]) !info->attrs[GTPA_FLOW])
...@@ -1036,7 +1024,19 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) ...@@ -1036,7 +1024,19 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
goto out_unlock; goto out_unlock;
} }
err = ipv4_pdp_add(gtp, info); if (version == GTP_V0)
sk = gtp->sk0;
else if (version == GTP_V1)
sk = gtp->sk1u;
else
sk = NULL;
if (!sk) {
err = -ENODEV;
goto out_unlock;
}
err = ipv4_pdp_add(gtp, sk, info);
out_unlock: out_unlock:
rcu_read_unlock(); rcu_read_unlock();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册