Commit 50aba46c authored by Nicolas Dichtel's avatar Nicolas Dichtel Committed by David S. Miller

gtp: add notification mechanism

Like all other network functions, let's notify gtp context on creation and
deletion.
Signed-off-by: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
Tested-by: default avatarGabriel Ganne <gabriel.ganne@6wind.com>
Acked-by: default avatarHarald Welte <laforge@gnumonks.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 44771ea5
...@@ -928,8 +928,8 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info) ...@@ -928,8 +928,8 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
} }
} }
static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
struct genl_info *info) struct genl_info *info)
{ {
struct pdp_ctx *pctx, *pctx_tid = NULL; struct pdp_ctx *pctx, *pctx_tid = NULL;
struct net_device *dev = gtp->dev; struct net_device *dev = gtp->dev;
...@@ -956,12 +956,12 @@ static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, ...@@ -956,12 +956,12 @@ static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
if (found) { if (found) {
if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) if (info->nlhdr->nlmsg_flags & NLM_F_EXCL)
return -EEXIST; return ERR_PTR(-EEXIST);
if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE) if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP; return ERR_PTR(-EOPNOTSUPP);
if (pctx && pctx_tid) if (pctx && pctx_tid)
return -EEXIST; return ERR_PTR(-EEXIST);
if (!pctx) if (!pctx)
pctx = pctx_tid; pctx = pctx_tid;
...@@ -974,13 +974,13 @@ static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, ...@@ -974,13 +974,13 @@ static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
netdev_dbg(dev, "GTPv1-U: update tunnel id = %x/%x (pdp %p)\n", netdev_dbg(dev, "GTPv1-U: update tunnel id = %x/%x (pdp %p)\n",
pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx); pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
return 0; return pctx;
} }
pctx = kmalloc(sizeof(*pctx), GFP_ATOMIC); pctx = kmalloc(sizeof(*pctx), GFP_ATOMIC);
if (pctx == NULL) if (pctx == NULL)
return -ENOMEM; return ERR_PTR(-ENOMEM);
sock_hold(sk); sock_hold(sk);
pctx->sk = sk; pctx->sk = sk;
...@@ -1018,7 +1018,7 @@ static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, ...@@ -1018,7 +1018,7 @@ static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
break; break;
} }
return 0; return pctx;
} }
static void pdp_context_free(struct rcu_head *head) static void pdp_context_free(struct rcu_head *head)
...@@ -1036,9 +1036,12 @@ static void pdp_context_delete(struct pdp_ctx *pctx) ...@@ -1036,9 +1036,12 @@ static void pdp_context_delete(struct pdp_ctx *pctx)
call_rcu(&pctx->rcu_head, pdp_context_free); call_rcu(&pctx->rcu_head, pdp_context_free);
} }
static int gtp_tunnel_notify(struct pdp_ctx *pctx, u8 cmd);
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; unsigned int version;
struct pdp_ctx *pctx;
struct gtp_dev *gtp; struct gtp_dev *gtp;
struct sock *sk; struct sock *sk;
int err; int err;
...@@ -1088,7 +1091,13 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) ...@@ -1088,7 +1091,13 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
goto out_unlock; goto out_unlock;
} }
err = gtp_pdp_add(gtp, sk, info); pctx = gtp_pdp_add(gtp, sk, info);
if (IS_ERR(pctx)) {
err = PTR_ERR(pctx);
} else {
gtp_tunnel_notify(pctx, GTP_CMD_NEWPDP);
err = 0;
}
out_unlock: out_unlock:
rcu_read_unlock(); rcu_read_unlock();
...@@ -1159,6 +1168,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info) ...@@ -1159,6 +1168,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", 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); pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
gtp_tunnel_notify(pctx, GTP_CMD_DELPDP);
pdp_context_delete(pctx); pdp_context_delete(pctx);
out_unlock: out_unlock:
...@@ -1168,6 +1178,14 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info) ...@@ -1168,6 +1178,14 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
static struct genl_family gtp_genl_family; static struct genl_family gtp_genl_family;
enum gtp_multicast_groups {
GTP_GENL_MCGRP,
};
static const struct genl_multicast_group gtp_genl_mcgrps[] = {
[GTP_GENL_MCGRP] = { .name = GTP_GENL_MCGRP_NAME },
};
static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq,
int flags, u32 type, struct pdp_ctx *pctx) int flags, u32 type, struct pdp_ctx *pctx)
{ {
...@@ -1204,6 +1222,26 @@ static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, ...@@ -1204,6 +1222,26 @@ static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq,
return -EMSGSIZE; return -EMSGSIZE;
} }
static int gtp_tunnel_notify(struct pdp_ctx *pctx, u8 cmd)
{
struct sk_buff *msg;
int ret;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!msg)
return -ENOMEM;
ret = gtp_genl_fill_info(msg, 0, 0, 0, cmd, pctx);
if (ret < 0) {
nlmsg_free(msg);
return ret;
}
ret = genlmsg_multicast_netns(&gtp_genl_family, dev_net(pctx->dev), msg,
0, GTP_GENL_MCGRP, GFP_ATOMIC);
return ret;
}
static int gtp_genl_get_pdp(struct sk_buff *skb, struct genl_info *info) static int gtp_genl_get_pdp(struct sk_buff *skb, struct genl_info *info)
{ {
struct pdp_ctx *pctx = NULL; struct pdp_ctx *pctx = NULL;
...@@ -1334,6 +1372,8 @@ static struct genl_family gtp_genl_family __ro_after_init = { ...@@ -1334,6 +1372,8 @@ static struct genl_family gtp_genl_family __ro_after_init = {
.module = THIS_MODULE, .module = THIS_MODULE,
.ops = gtp_genl_ops, .ops = gtp_genl_ops,
.n_ops = ARRAY_SIZE(gtp_genl_ops), .n_ops = ARRAY_SIZE(gtp_genl_ops),
.mcgrps = gtp_genl_mcgrps,
.n_mcgrps = ARRAY_SIZE(gtp_genl_mcgrps),
}; };
static int __net_init gtp_net_init(struct net *net) static int __net_init gtp_net_init(struct net *net)
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#ifndef _UAPI_LINUX_GTP_H_ #ifndef _UAPI_LINUX_GTP_H_
#define _UAPI_LINUX_GTP_H_ #define _UAPI_LINUX_GTP_H_
#define GTP_GENL_MCGRP_NAME "gtp"
enum gtp_genl_cmds { enum gtp_genl_cmds {
GTP_CMD_NEWPDP, GTP_CMD_NEWPDP,
GTP_CMD_DELPDP, GTP_CMD_DELPDP,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment