Skip to content

Commit

Permalink
l2tp : multicast notification to the registered listeners
Browse files Browse the repository at this point in the history
Previously l2tp module did not provide any means for the user space to
get notified when tunnels/sessions are added/modified/deleted.
This change contains the following
- create a multicast group for the listeners to register.
- notify the registered listeners when the tunnels/sessions are
  created/modified/deleted.

Signed-off-by: Bill Hong <bhong@brocade.com>
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Sven-Thorsten Dietrich <sven@brocade.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Bill Hong authored and davem330 committed Dec 31, 2014
1 parent 957f094 commit 33f72e6
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 10 deletions.
1 change: 1 addition & 0 deletions include/uapi/linux/l2tp.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,5 +178,6 @@ enum l2tp_seqmode {
*/
#define L2TP_GENL_NAME "l2tp"
#define L2TP_GENL_VERSION 0x1
#define L2TP_GENL_MCGROUP "l2tp"

#endif /* _UAPI_LINUX_L2TP_H_ */
101 changes: 91 additions & 10 deletions net/l2tp/l2tp_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ static struct genl_family l2tp_nl_family = {
.netnsok = true,
};

static const struct genl_multicast_group l2tp_multicast_group[] = {
{
.name = L2TP_GENL_MCGROUP,
},
};

static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq,
int flags, struct l2tp_tunnel *tunnel, u8 cmd);
static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq,
int flags, struct l2tp_session *session,
u8 cmd);

/* Accessed under genl lock */
static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX];

Expand Down Expand Up @@ -97,6 +109,52 @@ static int l2tp_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
return ret;
}

static int l2tp_tunnel_notify(struct genl_family *family,
struct genl_info *info,
struct l2tp_tunnel *tunnel,
u8 cmd)
{
struct sk_buff *msg;
int ret;

msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;

ret = l2tp_nl_tunnel_send(msg, info->snd_portid, info->snd_seq,
NLM_F_ACK, tunnel, cmd);

if (ret >= 0)
return genlmsg_multicast_allns(family, msg, 0, 0, GFP_ATOMIC);

nlmsg_free(msg);

return ret;
}

static int l2tp_session_notify(struct genl_family *family,
struct genl_info *info,
struct l2tp_session *session,
u8 cmd)
{
struct sk_buff *msg;
int ret;

msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;

ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq,
NLM_F_ACK, session, cmd);

if (ret >= 0)
return genlmsg_multicast_allns(family, msg, 0, 0, GFP_ATOMIC);

nlmsg_free(msg);

return ret;
}

static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info)
{
u32 tunnel_id;
Expand Down Expand Up @@ -188,6 +246,9 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
break;
}

if (ret >= 0)
ret = l2tp_tunnel_notify(&l2tp_nl_family, info,
tunnel, L2TP_CMD_TUNNEL_CREATE);
out:
return ret;
}
Expand All @@ -211,6 +272,9 @@ static int l2tp_nl_cmd_tunnel_delete(struct sk_buff *skb, struct genl_info *info
goto out;
}

l2tp_tunnel_notify(&l2tp_nl_family, info,
tunnel, L2TP_CMD_TUNNEL_DELETE);

(void) l2tp_tunnel_delete(tunnel);

out:
Expand Down Expand Up @@ -239,12 +303,15 @@ static int l2tp_nl_cmd_tunnel_modify(struct sk_buff *skb, struct genl_info *info
if (info->attrs[L2TP_ATTR_DEBUG])
tunnel->debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);

ret = l2tp_tunnel_notify(&l2tp_nl_family, info,
tunnel, L2TP_CMD_TUNNEL_MODIFY);

out:
return ret;
}

static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int flags,
struct l2tp_tunnel *tunnel)
struct l2tp_tunnel *tunnel, u8 cmd)
{
void *hdr;
struct nlattr *nest;
Expand All @@ -254,8 +321,7 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla
struct ipv6_pinfo *np = NULL;
#endif

hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags,
L2TP_CMD_TUNNEL_GET);
hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, cmd);
if (!hdr)
return -EMSGSIZE;

Expand Down Expand Up @@ -359,7 +425,7 @@ static int l2tp_nl_cmd_tunnel_get(struct sk_buff *skb, struct genl_info *info)
}

ret = l2tp_nl_tunnel_send(msg, info->snd_portid, info->snd_seq,
NLM_F_ACK, tunnel);
NLM_F_ACK, tunnel, L2TP_CMD_TUNNEL_GET);
if (ret < 0)
goto err_out;

Expand All @@ -385,7 +451,7 @@ static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback

if (l2tp_nl_tunnel_send(skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
tunnel) <= 0)
tunnel, L2TP_CMD_TUNNEL_GET) <= 0)
goto out;

ti++;
Expand Down Expand Up @@ -539,6 +605,13 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
ret = (*l2tp_nl_cmd_ops[cfg.pw_type]->session_create)(net, tunnel_id,
session_id, peer_session_id, &cfg);

if (ret >= 0) {
session = l2tp_session_find(net, tunnel, session_id);
if (session)
ret = l2tp_session_notify(&l2tp_nl_family, info, session,
L2TP_CMD_SESSION_CREATE);
}

out:
return ret;
}
Expand All @@ -555,6 +628,9 @@ static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *inf
goto out;
}

l2tp_session_notify(&l2tp_nl_family, info,
session, L2TP_CMD_SESSION_DELETE);

pw_type = session->pwtype;
if (pw_type < __L2TP_PWTYPE_MAX)
if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete)
Expand Down Expand Up @@ -601,12 +677,15 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf
if (info->attrs[L2TP_ATTR_MRU])
session->mru = nla_get_u16(info->attrs[L2TP_ATTR_MRU]);

ret = l2tp_session_notify(&l2tp_nl_family, info,
session, L2TP_CMD_SESSION_MODIFY);

out:
return ret;
}

static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int flags,
struct l2tp_session *session)
struct l2tp_session *session, u8 cmd)
{
void *hdr;
struct nlattr *nest;
Expand All @@ -615,7 +694,7 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl

sk = tunnel->sock;

hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, L2TP_CMD_SESSION_GET);
hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, cmd);
if (!hdr)
return -EMSGSIZE;

Expand Down Expand Up @@ -699,7 +778,7 @@ static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info)
}

ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq,
0, session);
0, session, L2TP_CMD_SESSION_GET);
if (ret < 0)
goto err_out;

Expand Down Expand Up @@ -737,7 +816,7 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback

if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
session) <= 0)
session, L2TP_CMD_SESSION_GET) <= 0)
break;

si++;
Expand Down Expand Up @@ -896,7 +975,9 @@ EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops);
static int l2tp_nl_init(void)
{
pr_info("L2TP netlink interface\n");
return genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops);
return genl_register_family_with_ops_groups(&l2tp_nl_family,
l2tp_nl_ops,
l2tp_multicast_group);
}

static void l2tp_nl_cleanup(void)
Expand Down

0 comments on commit 33f72e6

Please sign in to comment.