[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1269859231.2164.16.camel@edumazet-laptop>
Date: Mon, 29 Mar 2010 12:40:31 +0200
From: Eric Dumazet <eric.dumazet@...il.com>
To: James Chapman <jchapman@...alix.com>
Cc: netdev@...r.kernel.org
Subject: Re: [PATCH v2 11/12] l2tp: Add support for static unmanaged L2TPv3
tunnels
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;
> + 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]);
>
--
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