[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <4BB08672.7030506@katalix.com>
Date: Mon, 29 Mar 2010 11:52:34 +0100
From: James Chapman <jchapman@...alix.com>
To: Eric Dumazet <eric.dumazet@...il.com>
CC: netdev@...r.kernel.org
Subject: Re: [PATCH v2 11/12] l2tp: Add support for static unmanaged L2TPv3
tunnels
Eric Dumazet wrote:
> Le lundi 29 mars 2010 à 10:57 +0100, James Chapman a écrit :
>> This patch adds support for static (unmanaged) L2TPv3 tunnels, where
>> the tunnel socket is created by the kernel rather than being created
>> by userspace. This means L2TP tunnels and sessions can be created
>> manually, without needing an L2TP control protocol implemented in
>> userspace. This might be useful where the user wants a simple ethernet
>> over IP tunnel.
>>
>> A patch to iproute2 adds a new command set under "ip l2tp" to make use
>> of this feature. This will be submitted separately.
>>
>> Signed-off-by: James Chapman <jchapman@...alix.com>
>> Reviewed-by: Randy Dunlap <randy.dunlap@...cle.com>
>> ---
>> net/l2tp/l2tp_core.c | 111 +++++++++++++++++++++++++++++++++++++++++++----
>> net/l2tp/l2tp_core.h | 7 +++
>> net/l2tp/l2tp_netlink.c | 18 ++++++--
>> 3 files changed, 122 insertions(+), 14 deletions(-)
>>
>> diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
>> index c08c859..1431b39 100644
>> --- a/net/l2tp/l2tp_core.c
>> +++ b/net/l2tp/l2tp_core.c
>> @@ -1259,6 +1259,78 @@ void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
>> }
>> EXPORT_SYMBOL_GPL(l2tp_tunnel_free);
>>
>> +/* Create a socket for the tunnel, if one isn't set up by
>> + * userspace. This is used for static tunnels where there is no
>> + * managing L2TP daemon.
>> + */
>> +static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct socket **sockp)
>> +{
>> + int err = -EINVAL;
>> + struct sockaddr_in udp_addr;
>> + struct sockaddr_l2tpip ip_addr;
>> + struct socket *sock;
>> +
>> + switch (cfg->encap) {
>> + case L2TP_ENCAPTYPE_UDP:
>> + err = sock_create(AF_INET, SOCK_DGRAM, 0, sockp);
>> + if (err < 0)
>> + goto out;
>> +
>> + sock = *sockp;
>> +
>> + memset(&udp_addr, 0, sizeof(udp_addr));
>> + udp_addr.sin_family = AF_INET;
>> + udp_addr.sin_addr = cfg->local_ip;
>> + udp_addr.sin_port = htons(cfg->local_udp_port);
>> + err = kernel_bind(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
>> + if (err < 0)
>> + goto out;
>> +
>
> I cant see how you use cfg->use_udp_checksums, something like : ?
>
> if (!cfg->use_udp_checksums)
> sk->sk_no_check = UDP_CSUM_NOXMIT;
Good point. I forgot to add control of UDP checksums for the kernel
socket case. Thanks!
>
>> + udp_addr.sin_family = AF_INET;
>> + udp_addr.sin_addr = cfg->peer_ip;
>> + udp_addr.sin_port = htons(cfg->peer_udp_port);
>> + err = kernel_connect(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr), 0);
>> + if (err < 0)
>> + goto out;
>> +
>> + break;
>> + case L2TP_ENCAPTYPE_IP:
>> + err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, sockp);
>> + if (err < 0)
>> + goto out;
>> +
>> + sock = *sockp;
>> +
>> + memset(&ip_addr, 0, sizeof(ip_addr));
>> + ip_addr.l2tp_family = AF_INET;
>> + ip_addr.l2tp_addr = cfg->local_ip;
>> + ip_addr.l2tp_conn_id = tunnel_id;
>> + err = kernel_bind(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr));
>> + if (err < 0)
>> + goto out;
>> +
>> + ip_addr.l2tp_family = AF_INET;
>> + ip_addr.l2tp_addr = cfg->peer_ip;
>> + ip_addr.l2tp_conn_id = peer_tunnel_id;
>> + err = kernel_connect(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr), 0);
>> + if (err < 0)
>> + goto out;
>> +
>> + break;
>> +
>> + default:
>> + goto out;
>> + }
>> +
>> +out:
>> + if ((err < 0) && sock) {
>> + sock_release(sock);
>> + *sockp = NULL;
>> + }
>> +
>> + return err;
>> +}
>> +
>> int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp)
>> {
>> struct l2tp_tunnel *tunnel = NULL;
>> @@ -1269,14 +1341,21 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
>> enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP;
>>
>> /* Get the tunnel socket from the fd, which was opened by
>> - * the userspace L2TP daemon.
>> + * the userspace L2TP daemon. If not specified, create a
>> + * kernel socket.
>> */
>> - err = -EBADF;
>> - sock = sockfd_lookup(fd, &err);
>> - if (!sock) {
>> - printk(KERN_ERR "tunl %hu: sockfd_lookup(fd=%d) returned %d\n",
>> - tunnel_id, fd, err);
>> - goto err;
>> + if (fd < 0) {
>> + err = l2tp_tunnel_sock_create(tunnel_id, peer_tunnel_id, cfg, &sock);
>> + if (err < 0)
>> + goto err;
>> + } else {
>> + err = -EBADF;
>> + sock = sockfd_lookup(fd, &err);
>> + if (!sock) {
>> + printk(KERN_ERR "tunl %hu: sockfd_lookup(fd=%d) returned %d\n",
>> + tunnel_id, fd, err);
>> + goto err;
>> + }
>> }
>>
>> sk = sock->sk;
>> @@ -1369,7 +1448,10 @@ err:
>> if (tunnelp)
>> *tunnelp = tunnel;
>>
>> - if (sock)
>> + /* If tunnel's socket was created by the kernel, it doesn't
>> + * have a file.
>> + */
>> + if (sock && sock->file)
>> sockfd_put(sock);
>>
>> return err;
>> @@ -1381,13 +1463,22 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create);
>> int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)
>> {
>> int err = 0;
>> + struct socket *sock = tunnel->sock ? tunnel->sock->sk_socket : NULL;
>>
>> /* Force the tunnel socket to close. This will eventually
>> * cause the tunnel to be deleted via the normal socket close
>> * mechanisms when userspace closes the tunnel socket.
>> */
>> - if ((tunnel->sock != NULL) && (tunnel->sock->sk_socket != NULL))
>> - err = inet_shutdown(tunnel->sock->sk_socket, 2);
>> + if (sock != NULL) {
>> + err = inet_shutdown(sock, 2);
>> +
>> + /* If the tunnel's socket was created by the kernel,
>> + * close the socket here since the socket was not
>> + * created by userspace.
>> + */
>> + if (sock->file == NULL)
>> + err = inet_release(sock);
>> + }
>>
>> return err;
>> }
>> diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
>> index c5f2cc9..7e3387b 100644
>> --- a/net/l2tp/l2tp_core.h
>> +++ b/net/l2tp/l2tp_core.h
>> @@ -146,6 +146,13 @@ struct l2tp_tunnel_cfg {
>> int debug; /* bitmask of debug message
>> * categories */
>> enum l2tp_encap_type encap;
>> +
>> + /* Used only for kernel-created sockets */
>> + struct in_addr local_ip;
>> + struct in_addr peer_ip;
>> + u16 local_udp_port;
>> + u16 peer_udp_port;
>> + int use_udp_checksums:1;
>> };
>>
>> struct l2tp_tunnel {
>> diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
>> index e051c13..115ea01 100644
>> --- a/net/l2tp/l2tp_netlink.c
>> +++ b/net/l2tp/l2tp_netlink.c
>> @@ -129,11 +129,21 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
>> }
>> cfg.encap = nla_get_u16(info->attrs[L2TP_ATTR_ENCAP_TYPE]);
>>
>> - if (!info->attrs[L2TP_ATTR_FD]) {
>> - ret = -EINVAL;
>> - goto out;
>> + fd = -1;
>> + if (info->attrs[L2TP_ATTR_FD]) {
>> + fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
>> + } else {
>> + if (info->attrs[L2TP_ATTR_IP_SADDR])
>> + cfg.local_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_SADDR]);
>> + if (info->attrs[L2TP_ATTR_IP_DADDR])
>> + cfg.peer_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_DADDR]);
>> + if (info->attrs[L2TP_ATTR_UDP_SPORT])
>> + cfg.local_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_SPORT]);
>> + if (info->attrs[L2TP_ATTR_UDP_DPORT])
>> + cfg.peer_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_DPORT]);
>> + if (info->attrs[L2TP_ATTR_UDP_CSUM])
>> + cfg.use_udp_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_CSUM]);
>> }
>> - fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
>>
>> if (info->attrs[L2TP_ATTR_DEBUG])
>> cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
>>
>
>
>
--
James Chapman
Katalix Systems Ltd
http://www.katalix.com
Catalysts for your Embedded Linux software development
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists