forked from mirrors/linux
		
	l2tp : multicast notification to the registered listeners
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>
This commit is contained in:
		
							parent
							
								
									957f094f22
								
							
						
					
					
						commit
						33f72e6f0c
					
				
					 2 changed files with 92 additions and 10 deletions
				
			
		| 
						 | 
					@ -178,5 +178,6 @@ enum l2tp_seqmode {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define L2TP_GENL_NAME		"l2tp"
 | 
					#define L2TP_GENL_NAME		"l2tp"
 | 
				
			||||||
#define L2TP_GENL_VERSION	0x1
 | 
					#define L2TP_GENL_VERSION	0x1
 | 
				
			||||||
 | 
					#define L2TP_GENL_MCGROUP       "l2tp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _UAPI_LINUX_L2TP_H_ */
 | 
					#endif /* _UAPI_LINUX_L2TP_H_ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,18 @@ static struct genl_family l2tp_nl_family = {
 | 
				
			||||||
	.netnsok	= true,
 | 
						.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 */
 | 
					/* Accessed under genl lock */
 | 
				
			||||||
static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX];
 | 
					static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,6 +109,52 @@ static int l2tp_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
	return ret;
 | 
						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)
 | 
					static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 tunnel_id;
 | 
						u32 tunnel_id;
 | 
				
			||||||
| 
						 | 
					@ -188,6 +246,9 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret >= 0)
 | 
				
			||||||
 | 
							ret = l2tp_tunnel_notify(&l2tp_nl_family, info,
 | 
				
			||||||
 | 
										 tunnel, L2TP_CMD_TUNNEL_CREATE);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -211,6 +272,9 @@ static int l2tp_nl_cmd_tunnel_delete(struct sk_buff *skb, struct genl_info *info
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						l2tp_tunnel_notify(&l2tp_nl_family, info,
 | 
				
			||||||
 | 
								   tunnel, L2TP_CMD_TUNNEL_DELETE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	(void) l2tp_tunnel_delete(tunnel);
 | 
						(void) l2tp_tunnel_delete(tunnel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
| 
						 | 
					@ -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])
 | 
						if (info->attrs[L2TP_ATTR_DEBUG])
 | 
				
			||||||
		tunnel->debug = nla_get_u32(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:
 | 
					out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int flags,
 | 
					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;
 | 
						void *hdr;
 | 
				
			||||||
	struct nlattr *nest;
 | 
						struct nlattr *nest;
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
						struct ipv6_pinfo *np = NULL;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags,
 | 
						hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, cmd);
 | 
				
			||||||
			  L2TP_CMD_TUNNEL_GET);
 | 
					 | 
				
			||||||
	if (!hdr)
 | 
						if (!hdr)
 | 
				
			||||||
		return -EMSGSIZE;
 | 
							return -EMSGSIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
						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)
 | 
						if (ret < 0)
 | 
				
			||||||
		goto err_out;
 | 
							goto err_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
							if (l2tp_nl_tunnel_send(skb, NETLINK_CB(cb->skb).portid,
 | 
				
			||||||
					cb->nlh->nlmsg_seq, NLM_F_MULTI,
 | 
										cb->nlh->nlmsg_seq, NLM_F_MULTI,
 | 
				
			||||||
					tunnel) <= 0)
 | 
										tunnel, L2TP_CMD_TUNNEL_GET) <= 0)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ti++;
 | 
							ti++;
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
							ret = (*l2tp_nl_cmd_ops[cfg.pw_type]->session_create)(net, tunnel_id,
 | 
				
			||||||
			session_id, peer_session_id, &cfg);
 | 
								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:
 | 
					out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -555,6 +628,9 @@ static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *inf
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						l2tp_session_notify(&l2tp_nl_family, info,
 | 
				
			||||||
 | 
								    session, L2TP_CMD_SESSION_DELETE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_type = session->pwtype;
 | 
						pw_type = session->pwtype;
 | 
				
			||||||
	if (pw_type < __L2TP_PWTYPE_MAX)
 | 
						if (pw_type < __L2TP_PWTYPE_MAX)
 | 
				
			||||||
		if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete)
 | 
							if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete)
 | 
				
			||||||
| 
						 | 
					@ -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])
 | 
						if (info->attrs[L2TP_ATTR_MRU])
 | 
				
			||||||
		session->mru = nla_get_u16(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:
 | 
					out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int flags,
 | 
					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;
 | 
						void *hdr;
 | 
				
			||||||
	struct nlattr *nest;
 | 
						struct nlattr *nest;
 | 
				
			||||||
| 
						 | 
					@ -615,7 +694,7 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sk = tunnel->sock;
 | 
						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)
 | 
						if (!hdr)
 | 
				
			||||||
		return -EMSGSIZE;
 | 
							return -EMSGSIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
						ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq,
 | 
				
			||||||
				   0, session);
 | 
									   0, session, L2TP_CMD_SESSION_GET);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		goto err_out;
 | 
							goto err_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
							if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid,
 | 
				
			||||||
					 cb->nlh->nlmsg_seq, NLM_F_MULTI,
 | 
										 cb->nlh->nlmsg_seq, NLM_F_MULTI,
 | 
				
			||||||
					 session) <= 0)
 | 
										 session, L2TP_CMD_SESSION_GET) <= 0)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		si++;
 | 
							si++;
 | 
				
			||||||
| 
						 | 
					@ -896,7 +975,9 @@ EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops);
 | 
				
			||||||
static int l2tp_nl_init(void)
 | 
					static int l2tp_nl_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pr_info("L2TP netlink interface\n");
 | 
						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)
 | 
					static void l2tp_nl_cleanup(void)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue