net: pppoe - code cleanup and helpers
Subsystems (2)
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/5 net: pppoe - code cleanup and helpers
- Introduce PPPOE_HASH_MASK.
- Remove redundant declaration of pppoe_chan_ops.
- Introduce stage_session helper.
- Tabs, space, long-line-split cleanup.
--- drivers/net/pppoe.c | 167 ++++++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 81 deletions(-)
drivers/net/pppoe.c +86 -81
@@ -84,32 +84,43 @@#include <asm/uaccess.h> #define PPPOE_HASH_BITS 4 -#define PPPOE_HASH_SIZE (1<<PPPOE_HASH_BITS) - -static struct ppp_channel_ops pppoe_chan_ops; +#define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS) +#define PPPOE_HASH_MASK (PPPOE_HASH_SIZE - 1)static int pppoe_ioctl (struct socket *sock,unsigned int cmd,unsigned long arg);static int pppoe_xmit (struct ppp_channel *chan,struct sk_buff *skb);static int __pppoe_xmit (struct sock *sk,struct sk_buff *skb);static const struct proto_ops pppoe_ops; +static struct ppp_channel_ops pppoe_chan_ops;static DEFINE_RWLOCK (pppoe_hash_lock); -static struct ppp_channel_ops pppoe_chan_ops; +/* +* PPPoE could be in the following stages: +* 1) Discovery stage (to obtain remote MAC and Session ID) +* 2) Session stage (MAC and SID are known) +* +* Ethernet frames have a special tag for this but +* we use simplier approach based on session id +*/ +static inline bool stage_session (__be16 sid) +{ +return sid !=0 ; +}static inline int cmp_2_addr (struct pppoe_addr *a,struct pppoe_addr *b) { -return (a->sid == b->sid && - (memcmp (a->remote, b->remote,ETH_ALEN ) ==0 )); +return a->sid == b->sid && + (memcmp (a->remote, b->remote,ETH_ALEN ) ==0 ); }static inline int cmp_addr (struct pppoe_addr *a,__be16 sid,char *addr) { -return (a->sid == sid && - (memcmp (a->remote,addr,ETH_ALEN ) ==0 )); +return a->sid == sid && + (memcmp (a->remote, addr,ETH_ALEN ) ==0 ); } -#if 8 %PPPOE_HASH_BITS +#if 8 %PPPOE_HASH_BITS #error 8 must be a multiple of PPPOE_HASH_BITS#endif
@@ -118,17 +129,14 @@ static int hash_item(__be16 sid, unsigneunsigned char hash =0 ;unsigned int i; -for (i =0 ; i <ETH_ALEN ; i++) { +for (i =0 ; i <ETH_ALEN ; i++) hash ^= addr[i]; - } -for (i =0 ; i <sizeof (sid_t)*8 ; i +=8 ){ - hash ^= (__force __u32 )sid>>i; - } -for (i =8 ; (i>>=1 ) >=PPPOE_HASH_BITS ; ) { - hash ^= hash>>i; - } +for (i =0 ; i <sizeof (sid_t) *8 ; i +=8 ) + hash ^= (__force __u32 )sid >> i; +for (i =8 ; (i >>=1 ) >=PPPOE_HASH_BITS ;) + hash ^= hash >> i; -return hash & (PPPOE_HASH_SIZE -1 ); +return hash &PPPOE_HASH_MASK ; }/* zeroed because its in .bss */
@@ -146,10 +154,15 @@ static struct pppox_sock *__get_item(__b ret = item_hash_table[hash]; -while (ret && !(cmp_addr (&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex)) +while (ret) { +if (cmp_addr (&ret->pppoe_pa, sid, addr) && + ret->pppoe_ifindex == ifindex) +return ret; + ret = ret->next; + } -return ret; +return NULL ; }static int __set_item (struct pppox_sock *po)
@@ -159,7 +172,8 @@ static int __set_item(struct pppox_sock ret = item_hash_table[hash];while (ret) { -if (cmp_2_addr (&ret->pppoe_pa, &po->pppoe_pa) && ret->pppoe_ifindex == po->pppoe_ifindex) +if (cmp_2_addr (&ret->pppoe_pa, &po->pppoe_pa) && + ret->pppoe_ifindex == po->pppoe_ifindex)return -EALREADY ; ret = ret->next;
@@ -180,7 +194,8 @@ static struct pppox_sock *__delete_item( src = &item_hash_table[hash];while (ret) { -if (cmp_addr (&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex) { +if (cmp_addr (&ret->pppoe_pa, sid, addr) && + ret->pppoe_ifindex == ifindex) { *src = ret->next;break ; }
@@ -217,7 +232,7 @@ static inline struct pppox_sock *get_iteint ifindex; dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); -if (!dev) +if (!dev)return NULL ; ifindex = dev->ifindex;dev_put (dev);
@@ -329,7 +344,6 @@ static struct notifier_block pppoe_notif .notifier_call = pppoe_device_event, }; -/************************************************************************ * * Do the real work of receiving a PPPoE Session frame.
@@ -383,7 +397,8 @@ static int pppoe_rcv(struct sk_buff *skbstruct pppox_sock *po;int len; -if (!(skb =skb_share_check (skb,GFP_ATOMIC ))) + skb =skb_share_check (skb,GFP_ATOMIC ); +if (!skb) goto out;if (dev_net (dev) != &init_net)
@@ -432,7 +447,8 @@ static int pppoe_disc_rcv(struct sk_buffif (dev_net (dev) != &init_net) goto abort; -if (!(skb =skb_share_check (skb,GFP_ATOMIC ))) + skb =skb_share_check (skb,GFP_ATOMIC ); +if (!skb) goto out;if (!pskb_may_pull (skb,sizeof (struct pppoe_hdr )))
@@ -493,12 +509,11 @@ static struct proto pppoe_sk_proto = {**********************************************************************/ static int pppoe_create (struct net *net,struct socket *sock) { -int error = -ENOMEM ;struct sock *sk; sk =sk_alloc (net,PF_PPPOX ,GFP_KERNEL , &pppoe_sk_proto);if (!sk) - goto out; +return -ENOMEM ;sock_init_data (sock, sk);
@@ -511,8 +526,7 @@ static int pppoe_create(struct net *net, sk->sk_family =PF_PPPOX ; sk->sk_protocol =PX_PROTO_OE ; - error =0 ; -out:return error; +return 0 ; }static int pppoe_release (struct socket *sock)
@@ -524,7 +538,7 @@ static int pppoe_release(struct socket *return 0 ;lock_sock (sk); -if (sock_flag (sk,SOCK_DEAD )){ +if (sock_flag (sk,SOCK_DEAD )) {release_sock (sk);return -EBADF ; }
@@ -542,7 +556,7 @@ static int pppoe_release(struct socket *write_lock_bh (&pppoe_hash_lock); po =pppox_sk (sk); -if (po->pppoe_pa.sid) { +if (stage_session (po->pppoe_pa.sid)) {__delete_item (po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); }
@@ -564,7 +578,6 @@ static int pppoe_release(struct socket *return 0 ; } -static int pppoe_connect (struct socket *sock,struct sockaddr *uservaddr,int sockaddr_len,int flags) {
@@ -582,32 +595,31 @@ static int pppoe_connect(struct socket */* Check for already bound sockets */ error = -EBUSY ; -if ((sk->sk_state &PPPOX_CONNECTED ) && sp->sa_addr.pppoe.sid) +if ((sk->sk_state &PPPOX_CONNECTED ) && +stage_session (sp->sa_addr.pppoe.sid)) goto end;/* Check for already disconnected sockets, on attempts to disconnect */ error = -EALREADY ; -if ((sk->sk_state &PPPOX_DEAD ) && !sp->sa_addr.pppoe.sid ) +if ((sk->sk_state &PPPOX_DEAD ) && + !stage_session (sp->sa_addr.pppoe.sid)) goto end; error =0 ; -if (po->pppoe_pa.sid) { -pppox_unbind_sock (sk); - -/* Delete the old binding */ -delete_item (po->pppoe_pa.sid,po->pppoe_pa.remote,po->pppoe_ifindex); -if (po->pppoe_dev) +/* Delete the old binding */ +if (stage_session (po->pppoe_pa.sid)) { +pppox_unbind_sock (sk); +delete_item (po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); +if (po->pppoe_dev)dev_put (po->pppoe_dev); -memset (sk_pppox (po) +1 ,0 ,sizeof (struct pppox_sock ) -sizeof (struct sock )); - sk->sk_state =PPPOX_NONE ; } -/* Don't re-bind if sid==0 */ -if (sp->sa_addr.pppoe.sid !=0 ) { +/* Re-bind in session stage only */ +if (stage_session (sp->sa_addr.pppoe.sid)) { dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); error = -ENODEV ;
@@ -618,7 +630,7 @@ static int pppoe_connect(struct socket * po->pppoe_ifindex = dev->ifindex;write_lock_bh (&pppoe_hash_lock); -if (!(dev->flags &IFF_UP )){ +if (!(dev->flags &IFF_UP )) {write_unlock_bh (&pppoe_hash_lock); goto err_put; }
@@ -648,7 +660,7 @@ static int pppoe_connect(struct socket * po->num = sp->sa_addr.pppoe.sid; - end: +end:release_sock (sk);return error; err_put:
@@ -659,7 +671,6 @@ err_put: goto end; } -static int pppoe_getname (struct socket *sock,struct sockaddr *uaddr,int *usockaddr_len,int peer) {
@@ -678,7 +689,6 @@ static int pppoe_getname(struct socket *return 0 ; } -static int pppoe_ioctl (struct socket *sock,unsigned int cmd,unsigned long arg) {
@@ -709,7 +719,7 @@ static int pppoe_ioctl(struct socket *sobreak ; err = -EFAULT ; -if (get_user (val,(int __user *) arg)) +if (get_user (val, (int __user *)arg))break ; if (val < (po->pppoe_dev->mtu
@@ -722,7 +732,7 @@ static int pppoe_ioctl(struct socket *socase PPPIOCSFLAGS : err = -EFAULT ; -if (get_user (val, (int __user *) arg)) +if (get_user (val, (int __user *)arg))break ; err =0 ;break ;
@@ -749,7 +759,7 @@ static int pppoe_ioctl(struct socket *so err = -EINVAL ;if (po->pppoe_relay.sa_family !=AF_PPPOX || - po->pppoe_relay.sa_protocol!=PX_PROTO_OE ) + po->pppoe_relay.sa_protocol !=PX_PROTO_OE )break ;/* Check that the socket referenced by the address
@@ -781,7 +791,6 @@ static int pppoe_ioctl(struct socket *soreturn err; } -static int pppoe_sendmsg (struct kiocb *iocb,struct socket *sock,struct msghdr *m,size_t total_len) {
@@ -808,7 +817,7 @@ static int pppoe_sendmsg(struct kiocb *i dev = po->pppoe_dev; error = -EMSGSIZE ; -if (total_len > (dev->mtu + dev->hard_header_len)) +if (total_len > (dev->mtu + dev->hard_header_len)) goto end;
@@ -853,7 +862,6 @@ end:return error; } -/************************************************************************ * * xmit function for internal use.
@@ -903,7 +911,6 @@ abort:return 1 ; } -/************************************************************************ * * xmit function called by generic PPP driver
@@ -916,7 +923,6 @@ static int pppoe_xmit(struct ppp_channelreturn __pppoe_xmit (sk, skb); } -static struct ppp_channel_ops pppoe_chan_ops = { .start_xmit = pppoe_xmit, };
@@ -976,9 +982,9 @@ out:static __inline__struct pppox_sock *pppoe_get_idx (loff_t pos) {struct pppox_sock *po; -int i =0 ; +int i; -for (; i <PPPOE_HASH_SIZE ; i++) { +for (i =0 ; i <PPPOE_HASH_SIZE ; i++) { po = item_hash_table[i];while (po) {if (!pos--)
@@ -1064,32 +1070,31 @@ static inline int pppoe_proc_init(void)#endif /* CONFIG_PROC_FS */ static const struct proto_ops pppoe_ops = { - .family =AF_PPPOX , - .owner =THIS_MODULE , - .release = pppoe_release, - .bind = sock_no_bind, - .connect = pppoe_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = pppoe_getname, - .poll = datagram_poll, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt, - .sendmsg = pppoe_sendmsg, - .recvmsg = pppoe_recvmsg, - .mmap = sock_no_mmap, - .ioctl = pppox_ioctl, + .family =AF_PPPOX , + .owner =THIS_MODULE , + .release = pppoe_release, + .bind = sock_no_bind, + .connect = pppoe_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = pppoe_getname, + .poll = datagram_poll, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt, + .sendmsg = pppoe_sendmsg, + .recvmsg = pppoe_recvmsg, + .mmap = sock_no_mmap, + .ioctl = pppox_ioctl, };static struct pppox_proto pppoe_proto = { - .create = pppoe_create, - .ioctl = pppoe_ioctl, - .owner =THIS_MODULE , + .create = pppoe_create, + .ioctl = pppoe_ioctl, + .owner =THIS_MODULE , }; -static int __init pppoe_init (void ) {int err =proto_register (&pppoe_sk_proto,0 );
@@ -1097,7 +1102,7 @@ static int __init pppoe_init(void)if (err) goto out; - err =register_pppox_proto (PX_PROTO_OE , &pppoe_proto); + err =register_pppox_proto (PX_PROTO_OE , &pppoe_proto);if (err) goto out_unregister_pppoe_proto;
PATCH 1/5 net: pppoe - code cleanup and helpers
In reply to a message not in the archive- Introduce PPPOE_HASH_MASK.
- Remove redundant declaration of pppoe_chan_ops.
- Introduce stage_session helper.
- Tabs, space, long-line-split cleanup.
--- drivers/net/pppoe.c | 167 ++++++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 81 deletions(-)
drivers/net/pppoe.c +86 -81
@@ -84,32 +84,43 @@#include <asm/uaccess.h> #define PPPOE_HASH_BITS 4 -#define PPPOE_HASH_SIZE (1<<PPPOE_HASH_BITS) - -static struct ppp_channel_ops pppoe_chan_ops; +#define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS) +#define PPPOE_HASH_MASK (PPPOE_HASH_SIZE - 1)static int pppoe_ioctl (struct socket *sock,unsigned int cmd,unsigned long arg);static int pppoe_xmit (struct ppp_channel *chan,struct sk_buff *skb);static int __pppoe_xmit (struct sock *sk,struct sk_buff *skb);static const struct proto_ops pppoe_ops; +static struct ppp_channel_ops pppoe_chan_ops;static DEFINE_RWLOCK (pppoe_hash_lock); -static struct ppp_channel_ops pppoe_chan_ops; +/* +* PPPoE could be in the following stages: +* 1) Discovery stage (to obtain remote MAC and Session ID) +* 2) Session stage (MAC and SID are known) +* +* Ethernet frames have a special tag for this but +* we use simplier approach based on session id +*/ +static inline bool stage_session (__be16 sid) +{ +return sid !=0 ; +}static inline int cmp_2_addr (struct pppoe_addr *a,struct pppoe_addr *b) { -return (a->sid == b->sid && - (memcmp (a->remote, b->remote,ETH_ALEN ) ==0 )); +return a->sid == b->sid && + (memcmp (a->remote, b->remote,ETH_ALEN ) ==0 ); }static inline int cmp_addr (struct pppoe_addr *a,__be16 sid,char *addr) { -return (a->sid == sid && - (memcmp (a->remote,addr,ETH_ALEN ) ==0 )); +return a->sid == sid && + (memcmp (a->remote, addr,ETH_ALEN ) ==0 ); } -#if 8 %PPPOE_HASH_BITS +#if 8 %PPPOE_HASH_BITS #error 8 must be a multiple of PPPOE_HASH_BITS#endif
@@ -118,17 +129,14 @@ static int hash_item(__be16 sid, unsigneunsigned char hash =0 ;unsigned int i; -for (i =0 ; i <ETH_ALEN ; i++) { +for (i =0 ; i <ETH_ALEN ; i++) hash ^= addr[i]; - } -for (i =0 ; i <sizeof (sid_t)*8 ; i +=8 ){ - hash ^= (__force __u32 )sid>>i; - } -for (i =8 ; (i>>=1 ) >=PPPOE_HASH_BITS ; ) { - hash ^= hash>>i; - } +for (i =0 ; i <sizeof (sid_t) *8 ; i +=8 ) + hash ^= (__force __u32 )sid >> i; +for (i =8 ; (i >>=1 ) >=PPPOE_HASH_BITS ;) + hash ^= hash >> i; -return hash & (PPPOE_HASH_SIZE -1 ); +return hash &PPPOE_HASH_MASK ; }/* zeroed because its in .bss */
@@ -146,10 +154,15 @@ static struct pppox_sock *__get_item(__b ret = item_hash_table[hash]; -while (ret && !(cmp_addr (&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex)) +while (ret) { +if (cmp_addr (&ret->pppoe_pa, sid, addr) && + ret->pppoe_ifindex == ifindex) +return ret; + ret = ret->next; + } -return ret; +return NULL ; }static int __set_item (struct pppox_sock *po)
@@ -159,7 +172,8 @@ static int __set_item(struct pppox_sock ret = item_hash_table[hash];while (ret) { -if (cmp_2_addr (&ret->pppoe_pa, &po->pppoe_pa) && ret->pppoe_ifindex == po->pppoe_ifindex) +if (cmp_2_addr (&ret->pppoe_pa, &po->pppoe_pa) && + ret->pppoe_ifindex == po->pppoe_ifindex)return -EALREADY ; ret = ret->next;
@@ -180,7 +194,8 @@ static struct pppox_sock *__delete_item( src = &item_hash_table[hash];while (ret) { -if (cmp_addr (&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex) { +if (cmp_addr (&ret->pppoe_pa, sid, addr) && + ret->pppoe_ifindex == ifindex) { *src = ret->next;break ; }
@@ -217,7 +232,7 @@ static inline struct pppox_sock *get_iteint ifindex; dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); -if (!dev) +if (!dev)return NULL ; ifindex = dev->ifindex;dev_put (dev);
@@ -329,7 +344,6 @@ static struct notifier_block pppoe_notif .notifier_call = pppoe_device_event, }; -/************************************************************************ * * Do the real work of receiving a PPPoE Session frame.
@@ -383,7 +397,8 @@ static int pppoe_rcv(struct sk_buff *skbstruct pppox_sock *po;int len; -if (!(skb =skb_share_check (skb,GFP_ATOMIC ))) + skb =skb_share_check (skb,GFP_ATOMIC ); +if (!skb) goto out;if (dev_net (dev) != &init_net)
@@ -432,7 +447,8 @@ static int pppoe_disc_rcv(struct sk_buffif (dev_net (dev) != &init_net) goto abort; -if (!(skb =skb_share_check (skb,GFP_ATOMIC ))) + skb =skb_share_check (skb,GFP_ATOMIC ); +if (!skb) goto out;if (!pskb_may_pull (skb,sizeof (struct pppoe_hdr )))
@@ -493,12 +509,11 @@ static struct proto pppoe_sk_proto = {**********************************************************************/ static int pppoe_create (struct net *net,struct socket *sock) { -int error = -ENOMEM ;struct sock *sk; sk =sk_alloc (net,PF_PPPOX ,GFP_KERNEL , &pppoe_sk_proto);if (!sk) - goto out; +return -ENOMEM ;sock_init_data (sock, sk);
@@ -511,8 +526,7 @@ static int pppoe_create(struct net *net, sk->sk_family =PF_PPPOX ; sk->sk_protocol =PX_PROTO_OE ; - error =0 ; -out:return error; +return 0 ; }static int pppoe_release (struct socket *sock)
@@ -524,7 +538,7 @@ static int pppoe_release(struct socket *return 0 ;lock_sock (sk); -if (sock_flag (sk,SOCK_DEAD )){ +if (sock_flag (sk,SOCK_DEAD )) {release_sock (sk);return -EBADF ; }
@@ -542,7 +556,7 @@ static int pppoe_release(struct socket *write_lock_bh (&pppoe_hash_lock); po =pppox_sk (sk); -if (po->pppoe_pa.sid) { +if (stage_session (po->pppoe_pa.sid)) {__delete_item (po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); }
@@ -564,7 +578,6 @@ static int pppoe_release(struct socket *return 0 ; } -static int pppoe_connect (struct socket *sock,struct sockaddr *uservaddr,int sockaddr_len,int flags) {
@@ -582,32 +595,31 @@ static int pppoe_connect(struct socket */* Check for already bound sockets */ error = -EBUSY ; -if ((sk->sk_state &PPPOX_CONNECTED ) && sp->sa_addr.pppoe.sid) +if ((sk->sk_state &PPPOX_CONNECTED ) && +stage_session (sp->sa_addr.pppoe.sid)) goto end;/* Check for already disconnected sockets, on attempts to disconnect */ error = -EALREADY ; -if ((sk->sk_state &PPPOX_DEAD ) && !sp->sa_addr.pppoe.sid ) +if ((sk->sk_state &PPPOX_DEAD ) && + !stage_session (sp->sa_addr.pppoe.sid)) goto end; error =0 ; -if (po->pppoe_pa.sid) { -pppox_unbind_sock (sk); - -/* Delete the old binding */ -delete_item (po->pppoe_pa.sid,po->pppoe_pa.remote,po->pppoe_ifindex); -if (po->pppoe_dev) +/* Delete the old binding */ +if (stage_session (po->pppoe_pa.sid)) { +pppox_unbind_sock (sk); +delete_item (po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); +if (po->pppoe_dev)dev_put (po->pppoe_dev); -memset (sk_pppox (po) +1 ,0 ,sizeof (struct pppox_sock ) -sizeof (struct sock )); - sk->sk_state =PPPOX_NONE ; } -/* Don't re-bind if sid==0 */ -if (sp->sa_addr.pppoe.sid !=0 ) { +/* Re-bind in session stage only */ +if (stage_session (sp->sa_addr.pppoe.sid)) { dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); error = -ENODEV ;
@@ -618,7 +630,7 @@ static int pppoe_connect(struct socket * po->pppoe_ifindex = dev->ifindex;write_lock_bh (&pppoe_hash_lock); -if (!(dev->flags &IFF_UP )){ +if (!(dev->flags &IFF_UP )) {write_unlock_bh (&pppoe_hash_lock); goto err_put; }
@@ -648,7 +660,7 @@ static int pppoe_connect(struct socket * po->num = sp->sa_addr.pppoe.sid; - end: +end:release_sock (sk);return error; err_put:
@@ -659,7 +671,6 @@ err_put: goto end; } -static int pppoe_getname (struct socket *sock,struct sockaddr *uaddr,int *usockaddr_len,int peer) {
@@ -678,7 +689,6 @@ static int pppoe_getname(struct socket *return 0 ; } -static int pppoe_ioctl (struct socket *sock,unsigned int cmd,unsigned long arg) {
@@ -709,7 +719,7 @@ static int pppoe_ioctl(struct socket *sobreak ; err = -EFAULT ; -if (get_user (val,(int __user *) arg)) +if (get_user (val, (int __user *)arg))break ; if (val < (po->pppoe_dev->mtu
@@ -722,7 +732,7 @@ static int pppoe_ioctl(struct socket *socase PPPIOCSFLAGS : err = -EFAULT ; -if (get_user (val, (int __user *) arg)) +if (get_user (val, (int __user *)arg))break ; err =0 ;break ;
@@ -749,7 +759,7 @@ static int pppoe_ioctl(struct socket *so err = -EINVAL ;if (po->pppoe_relay.sa_family !=AF_PPPOX || - po->pppoe_relay.sa_protocol!=PX_PROTO_OE ) + po->pppoe_relay.sa_protocol !=PX_PROTO_OE )break ;/* Check that the socket referenced by the address
@@ -781,7 +791,6 @@ static int pppoe_ioctl(struct socket *soreturn err; } -static int pppoe_sendmsg (struct kiocb *iocb,struct socket *sock,struct msghdr *m,size_t total_len) {
@@ -808,7 +817,7 @@ static int pppoe_sendmsg(struct kiocb *i dev = po->pppoe_dev; error = -EMSGSIZE ; -if (total_len > (dev->mtu + dev->hard_header_len)) +if (total_len > (dev->mtu + dev->hard_header_len)) goto end;
@@ -853,7 +862,6 @@ end:return error; } -/************************************************************************ * * xmit function for internal use.
@@ -903,7 +911,6 @@ abort:return 1 ; } -/************************************************************************ * * xmit function called by generic PPP driver
@@ -916,7 +923,6 @@ static int pppoe_xmit(struct ppp_channelreturn __pppoe_xmit (sk, skb); } -static struct ppp_channel_ops pppoe_chan_ops = { .start_xmit = pppoe_xmit, };
@@ -976,9 +982,9 @@ out:static __inline__struct pppox_sock *pppoe_get_idx (loff_t pos) {struct pppox_sock *po; -int i =0 ; +int i; -for (; i <PPPOE_HASH_SIZE ; i++) { +for (i =0 ; i <PPPOE_HASH_SIZE ; i++) { po = item_hash_table[i];while (po) {if (!pos--)
@@ -1064,32 +1070,31 @@ static inline int pppoe_proc_init(void)#endif /* CONFIG_PROC_FS */ static const struct proto_ops pppoe_ops = { - .family =AF_PPPOX , - .owner =THIS_MODULE , - .release = pppoe_release, - .bind = sock_no_bind, - .connect = pppoe_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = pppoe_getname, - .poll = datagram_poll, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt, - .sendmsg = pppoe_sendmsg, - .recvmsg = pppoe_recvmsg, - .mmap = sock_no_mmap, - .ioctl = pppox_ioctl, + .family =AF_PPPOX , + .owner =THIS_MODULE , + .release = pppoe_release, + .bind = sock_no_bind, + .connect = pppoe_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = pppoe_getname, + .poll = datagram_poll, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt, + .sendmsg = pppoe_sendmsg, + .recvmsg = pppoe_recvmsg, + .mmap = sock_no_mmap, + .ioctl = pppox_ioctl, };static struct pppox_proto pppoe_proto = { - .create = pppoe_create, - .ioctl = pppoe_ioctl, - .owner =THIS_MODULE , + .create = pppoe_create, + .ioctl = pppoe_ioctl, + .owner =THIS_MODULE , }; -static int __init pppoe_init (void ) {int err =proto_register (&pppoe_sk_proto,0 );
@@ -1097,7 +1102,7 @@ static int __init pppoe_init(void)if (err) goto out; - err =register_pppox_proto (PX_PROTO_OE , &pppoe_proto); + err =register_pppox_proto (PX_PROTO_OE , &pppoe_proto);if (err) goto out_unregister_pppoe_proto;
PATCH 1/5 net: pppoe - code cleanup and helpers
In reply to a message not in the archive- Introduce PPPOE_HASH_MASK.
- Remove redundant declaration of pppoe_chan_ops.
- Introduce stage_session helper.
- Tabs, space, long-line-split cleanup.
--- drivers/net/pppoe.c | 167 ++++++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 81 deletions(-)
drivers/net/pppoe.c +86 -81
@@ -84,32 +84,43 @@#include <asm/uaccess.h> #define PPPOE_HASH_BITS 4 -#define PPPOE_HASH_SIZE (1<<PPPOE_HASH_BITS) - -static struct ppp_channel_ops pppoe_chan_ops; +#define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS) +#define PPPOE_HASH_MASK (PPPOE_HASH_SIZE - 1)static int pppoe_ioctl (struct socket *sock,unsigned int cmd,unsigned long arg);static int pppoe_xmit (struct ppp_channel *chan,struct sk_buff *skb);static int __pppoe_xmit (struct sock *sk,struct sk_buff *skb);static const struct proto_ops pppoe_ops; +static struct ppp_channel_ops pppoe_chan_ops;static DEFINE_RWLOCK (pppoe_hash_lock); -static struct ppp_channel_ops pppoe_chan_ops; +/* +* PPPoE could be in the following stages: +* 1) Discovery stage (to obtain remote MAC and Session ID) +* 2) Session stage (MAC and SID are known) +* +* Ethernet frames have a special tag for this but +* we use simplier approach based on session id +*/ +static inline bool stage_session (__be16 sid) +{ +return sid !=0 ; +}static inline int cmp_2_addr (struct pppoe_addr *a,struct pppoe_addr *b) { -return (a->sid == b->sid && - (memcmp (a->remote, b->remote,ETH_ALEN ) ==0 )); +return a->sid == b->sid && + (memcmp (a->remote, b->remote,ETH_ALEN ) ==0 ); }static inline int cmp_addr (struct pppoe_addr *a,__be16 sid,char *addr) { -return (a->sid == sid && - (memcmp (a->remote,addr,ETH_ALEN ) ==0 )); +return a->sid == sid && + (memcmp (a->remote, addr,ETH_ALEN ) ==0 ); } -#if 8 %PPPOE_HASH_BITS +#if 8 %PPPOE_HASH_BITS #error 8 must be a multiple of PPPOE_HASH_BITS#endif
@@ -118,17 +129,14 @@ static int hash_item(__be16 sid, unsigneunsigned char hash =0 ;unsigned int i; -for (i =0 ; i <ETH_ALEN ; i++) { +for (i =0 ; i <ETH_ALEN ; i++) hash ^= addr[i]; - } -for (i =0 ; i <sizeof (sid_t)*8 ; i +=8 ){ - hash ^= (__force __u32 )sid>>i; - } -for (i =8 ; (i>>=1 ) >=PPPOE_HASH_BITS ; ) { - hash ^= hash>>i; - } +for (i =0 ; i <sizeof (sid_t) *8 ; i +=8 ) + hash ^= (__force __u32 )sid >> i; +for (i =8 ; (i >>=1 ) >=PPPOE_HASH_BITS ;) + hash ^= hash >> i; -return hash & (PPPOE_HASH_SIZE -1 ); +return hash &PPPOE_HASH_MASK ; }/* zeroed because its in .bss */
@@ -146,10 +154,15 @@ static struct pppox_sock *__get_item(__b ret = item_hash_table[hash]; -while (ret && !(cmp_addr (&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex)) +while (ret) { +if (cmp_addr (&ret->pppoe_pa, sid, addr) && + ret->pppoe_ifindex == ifindex) +return ret; + ret = ret->next; + } -return ret; +return NULL ; }static int __set_item (struct pppox_sock *po)
@@ -159,7 +172,8 @@ static int __set_item(struct pppox_sock ret = item_hash_table[hash];while (ret) { -if (cmp_2_addr (&ret->pppoe_pa, &po->pppoe_pa) && ret->pppoe_ifindex == po->pppoe_ifindex) +if (cmp_2_addr (&ret->pppoe_pa, &po->pppoe_pa) && + ret->pppoe_ifindex == po->pppoe_ifindex)return -EALREADY ; ret = ret->next;
@@ -180,7 +194,8 @@ static struct pppox_sock *__delete_item( src = &item_hash_table[hash];while (ret) { -if (cmp_addr (&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex) { +if (cmp_addr (&ret->pppoe_pa, sid, addr) && + ret->pppoe_ifindex == ifindex) { *src = ret->next;break ; }
@@ -217,7 +232,7 @@ static inline struct pppox_sock *get_iteint ifindex; dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); -if (!dev) +if (!dev)return NULL ; ifindex = dev->ifindex;dev_put (dev);
@@ -329,7 +344,6 @@ static struct notifier_block pppoe_notif .notifier_call = pppoe_device_event, }; -/************************************************************************ * * Do the real work of receiving a PPPoE Session frame.
@@ -383,7 +397,8 @@ static int pppoe_rcv(struct sk_buff *skbstruct pppox_sock *po;int len; -if (!(skb =skb_share_check (skb,GFP_ATOMIC ))) + skb =skb_share_check (skb,GFP_ATOMIC ); +if (!skb) goto out;if (dev_net (dev) != &init_net)
@@ -432,7 +447,8 @@ static int pppoe_disc_rcv(struct sk_buffif (dev_net (dev) != &init_net) goto abort; -if (!(skb =skb_share_check (skb,GFP_ATOMIC ))) + skb =skb_share_check (skb,GFP_ATOMIC ); +if (!skb) goto out;if (!pskb_may_pull (skb,sizeof (struct pppoe_hdr )))
@@ -493,12 +509,11 @@ static struct proto pppoe_sk_proto = {**********************************************************************/ static int pppoe_create (struct net *net,struct socket *sock) { -int error = -ENOMEM ;struct sock *sk; sk =sk_alloc (net,PF_PPPOX ,GFP_KERNEL , &pppoe_sk_proto);if (!sk) - goto out; +return -ENOMEM ;sock_init_data (sock, sk);
@@ -511,8 +526,7 @@ static int pppoe_create(struct net *net, sk->sk_family =PF_PPPOX ; sk->sk_protocol =PX_PROTO_OE ; - error =0 ; -out:return error; +return 0 ; }static int pppoe_release (struct socket *sock)
@@ -524,7 +538,7 @@ static int pppoe_release(struct socket *return 0 ;lock_sock (sk); -if (sock_flag (sk,SOCK_DEAD )){ +if (sock_flag (sk,SOCK_DEAD )) {release_sock (sk);return -EBADF ; }
@@ -542,7 +556,7 @@ static int pppoe_release(struct socket *write_lock_bh (&pppoe_hash_lock); po =pppox_sk (sk); -if (po->pppoe_pa.sid) { +if (stage_session (po->pppoe_pa.sid)) {__delete_item (po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); }
@@ -564,7 +578,6 @@ static int pppoe_release(struct socket *return 0 ; } -static int pppoe_connect (struct socket *sock,struct sockaddr *uservaddr,int sockaddr_len,int flags) {
@@ -582,32 +595,31 @@ static int pppoe_connect(struct socket */* Check for already bound sockets */ error = -EBUSY ; -if ((sk->sk_state &PPPOX_CONNECTED ) && sp->sa_addr.pppoe.sid) +if ((sk->sk_state &PPPOX_CONNECTED ) && +stage_session (sp->sa_addr.pppoe.sid)) goto end;/* Check for already disconnected sockets, on attempts to disconnect */ error = -EALREADY ; -if ((sk->sk_state &PPPOX_DEAD ) && !sp->sa_addr.pppoe.sid ) +if ((sk->sk_state &PPPOX_DEAD ) && + !stage_session (sp->sa_addr.pppoe.sid)) goto end; error =0 ; -if (po->pppoe_pa.sid) { -pppox_unbind_sock (sk); - -/* Delete the old binding */ -delete_item (po->pppoe_pa.sid,po->pppoe_pa.remote,po->pppoe_ifindex); -if (po->pppoe_dev) +/* Delete the old binding */ +if (stage_session (po->pppoe_pa.sid)) { +pppox_unbind_sock (sk); +delete_item (po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); +if (po->pppoe_dev)dev_put (po->pppoe_dev); -memset (sk_pppox (po) +1 ,0 ,sizeof (struct pppox_sock ) -sizeof (struct sock )); - sk->sk_state =PPPOX_NONE ; } -/* Don't re-bind if sid==0 */ -if (sp->sa_addr.pppoe.sid !=0 ) { +/* Re-bind in session stage only */ +if (stage_session (sp->sa_addr.pppoe.sid)) { dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); error = -ENODEV ;
@@ -618,7 +630,7 @@ static int pppoe_connect(struct socket * po->pppoe_ifindex = dev->ifindex;write_lock_bh (&pppoe_hash_lock); -if (!(dev->flags &IFF_UP )){ +if (!(dev->flags &IFF_UP )) {write_unlock_bh (&pppoe_hash_lock); goto err_put; }
@@ -648,7 +660,7 @@ static int pppoe_connect(struct socket * po->num = sp->sa_addr.pppoe.sid; - end: +end:release_sock (sk);return error; err_put:
@@ -659,7 +671,6 @@ err_put: goto end; } -static int pppoe_getname (struct socket *sock,struct sockaddr *uaddr,int *usockaddr_len,int peer) {
@@ -678,7 +689,6 @@ static int pppoe_getname(struct socket *return 0 ; } -static int pppoe_ioctl (struct socket *sock,unsigned int cmd,unsigned long arg) {
@@ -709,7 +719,7 @@ static int pppoe_ioctl(struct socket *sobreak ; err = -EFAULT ; -if (get_user (val,(int __user *) arg)) +if (get_user (val, (int __user *)arg))break ; if (val < (po->pppoe_dev->mtu
@@ -722,7 +732,7 @@ static int pppoe_ioctl(struct socket *socase PPPIOCSFLAGS : err = -EFAULT ; -if (get_user (val, (int __user *) arg)) +if (get_user (val, (int __user *)arg))break ; err =0 ;break ;
@@ -749,7 +759,7 @@ static int pppoe_ioctl(struct socket *so err = -EINVAL ;if (po->pppoe_relay.sa_family !=AF_PPPOX || - po->pppoe_relay.sa_protocol!=PX_PROTO_OE ) + po->pppoe_relay.sa_protocol !=PX_PROTO_OE )break ;/* Check that the socket referenced by the address
@@ -781,7 +791,6 @@ static int pppoe_ioctl(struct socket *soreturn err; } -static int pppoe_sendmsg (struct kiocb *iocb,struct socket *sock,struct msghdr *m,size_t total_len) {
@@ -808,7 +817,7 @@ static int pppoe_sendmsg(struct kiocb *i dev = po->pppoe_dev; error = -EMSGSIZE ; -if (total_len > (dev->mtu + dev->hard_header_len)) +if (total_len > (dev->mtu + dev->hard_header_len)) goto end;
@@ -853,7 +862,6 @@ end:return error; } -/************************************************************************ * * xmit function for internal use.
@@ -903,7 +911,6 @@ abort:return 1 ; } -/************************************************************************ * * xmit function called by generic PPP driver
@@ -916,7 +923,6 @@ static int pppoe_xmit(struct ppp_channelreturn __pppoe_xmit (sk, skb); } -static struct ppp_channel_ops pppoe_chan_ops = { .start_xmit = pppoe_xmit, };
@@ -976,9 +982,9 @@ out:static __inline__struct pppox_sock *pppoe_get_idx (loff_t pos) {struct pppox_sock *po; -int i =0 ; +int i; -for (; i <PPPOE_HASH_SIZE ; i++) { +for (i =0 ; i <PPPOE_HASH_SIZE ; i++) { po = item_hash_table[i];while (po) {if (!pos--)
@@ -1064,32 +1070,31 @@ static inline int pppoe_proc_init(void)#endif /* CONFIG_PROC_FS */ static const struct proto_ops pppoe_ops = { - .family =AF_PPPOX , - .owner =THIS_MODULE , - .release = pppoe_release, - .bind = sock_no_bind, - .connect = pppoe_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = pppoe_getname, - .poll = datagram_poll, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt, - .sendmsg = pppoe_sendmsg, - .recvmsg = pppoe_recvmsg, - .mmap = sock_no_mmap, - .ioctl = pppox_ioctl, + .family =AF_PPPOX , + .owner =THIS_MODULE , + .release = pppoe_release, + .bind = sock_no_bind, + .connect = pppoe_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = pppoe_getname, + .poll = datagram_poll, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt, + .sendmsg = pppoe_sendmsg, + .recvmsg = pppoe_recvmsg, + .mmap = sock_no_mmap, + .ioctl = pppox_ioctl, };static struct pppox_proto pppoe_proto = { - .create = pppoe_create, - .ioctl = pppoe_ioctl, - .owner =THIS_MODULE , + .create = pppoe_create, + .ioctl = pppoe_ioctl, + .owner =THIS_MODULE , }; -static int __init pppoe_init (void ) {int err =proto_register (&pppoe_sk_proto,0 );
@@ -1097,7 +1102,7 @@ static int __init pppoe_init(void)if (err) goto out; - err =register_pppox_proto (PX_PROTO_OE , &pppoe_proto); + err =register_pppox_proto (PX_PROTO_OE , &pppoe_proto);if (err) goto out_unregister_pppoe_proto;
PATCH 2/5 net: pppoe - introduce net-namespace functionality
In reply to a message not in the archive- each net-namespace for pppoe module is having own hash table and appropriate locks wich are allocated at time of namespace intialization. It requires about 140 bytes of memory for every new namespace but such approach allow us to escape from hash chains growing and additional lock contends (especially in SMP environment).
- pppox code allows to create per-namespace sockets for PX_PROTO_OE protocol only (since at this moment support for pppol2tp net-namespace is not implemented yet).
--- drivers/net/pppoe.c | 377 +++++++++++++++++++++++++++++++++------------------- drivers/net/pppox.c | 7 2 files changed, 248 insertions(+), 136 deletions(-)
drivers/net/pppoe.c +244 -133
@@ -78,7 +78,9 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/nsproxy.h> #include <net/net_namespace.h> +#include <net/netns/generic.h> #include <net/sock.h> #include <asm/uaccess.h>
@@ -93,7 +95,24 @@ static int __pppoe_xmit(struct sock *sk,static const struct proto_ops pppoe_ops;static struct ppp_channel_ops pppoe_chan_ops; -static DEFINE_RWLOCK (pppoe_hash_lock); + +/* per-net private data for this module */ +static unsigned int pppoe_net_id; +struct pppoe_net { +/* +* we could use _single_ hash table for all +* nets by injecting net id into the hash but +* it would increase hash chains and add +* a few additional math comparations messy +* as well, moreover in case of SMP less locking +* controversy here +*/ +struct pppox_sock *hash_table[PPPOE_HASH_SIZE ]; +rwlock_t hash_lock; +}; + +/* to eliminate a race btw pppoe_flush_dev and pppoe_release */ +static DEFINE_SPINLOCK (flush_lock);/* * PPPoE could be in the following stages:
@@ -108,16 +127,21 @@ static inline bool stage_session(__be16return sid !=0 ; } +static inline struct pppoe_net *pppoe_pernet (struct net *net) +{ +BUG_ON (!net); + +return net_generic (net, pppoe_net_id); +} +static inline int cmp_2_addr (struct pppoe_addr *a,struct pppoe_addr *b) { -return a->sid == b->sid && - (memcmp (a->remote, b->remote,ETH_ALEN ) ==0 ); +return a->sid == b->sid && !memcmp (a->remote, b->remote,ETH_ALEN ); }static inline int cmp_addr (struct pppoe_addr *a,__be16 sid,char *addr) { -return a->sid == sid && - (memcmp (a->remote, addr,ETH_ALEN ) ==0 ); +return a->sid == sid && !memcmp (a->remote, addr,ETH_ALEN ); }#if 8 %PPPOE_HASH_BITS
@@ -139,21 +163,18 @@ static int hash_item(__be16 sid, unsignereturn hash &PPPOE_HASH_MASK ; } -/* zeroed because its in .bss */ -static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE ]; -/********************************************************************** * * Set/get/delete/rehash items (internal versions) * **********************************************************************/ -static struct pppox_sock *__get_item (__be16 sid,unsigned char *addr,int ifindex) +static struct pppox_sock *__get_item (struct pppoe_net *pn,__be16 sid, +unsigned char *addr,int ifindex) {int hash =hash_item (sid, addr);struct pppox_sock *ret; - ret = item_hash_table[hash]; - + ret = pn->hash_table[hash];while (ret) {if (cmp_addr (&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex)
@@ -165,12 +186,12 @@ static struct pppox_sock *__get_item(__breturn NULL ; } -static int __set_item (struct pppox_sock *po) +static int __set_item (struct pppoe_net *pn,struct pppox_sock *po) {int hash =hash_item (po->pppoe_pa.sid, po->pppoe_pa.remote);struct pppox_sock *ret; - ret = item_hash_table[hash]; + ret = pn->hash_table[hash];while (ret) {if (cmp_2_addr (&ret->pppoe_pa, &po->pppoe_pa) && ret->pppoe_ifindex == po->pppoe_ifindex)
@@ -179,19 +200,20 @@ static int __set_item(struct pppox_sock ret = ret->next; } - po->next = item_hash_table[hash]; - item_hash_table[hash] = po; + po->next = pn->hash_table[hash]; + pn->hash_table[hash] = po;return 0 ; } -static struct pppox_sock *__delete_item (__be16 sid,char *addr,int ifindex) +static struct pppox_sock *__delete_item (struct pppoe_net *pn,__be16 sid, +char *addr,int ifindex) {int hash =hash_item (sid, addr);struct pppox_sock *ret, **src; - ret = item_hash_table[hash]; - src = &item_hash_table[hash]; + ret = pn->hash_table[hash]; + src = &pn->hash_table[hash];while (ret) { if (cmp_addr(&ret->pppoe_pa, sid, addr) &&
@@ -212,46 +234,54 @@ static struct pppox_sock *__delete_item(* Set/get/delete/rehash items * **********************************************************************/ -static inline struct pppox_sock *get_item (__be16 sid, -unsigned char *addr,int ifindex) +static inline struct pppox_sock *get_item (struct pppoe_net *pn,__be16 sid, +unsigned char *addr,int ifindex) {struct pppox_sock *po; -read_lock_bh (&pppoe_hash_lock); - po =__get_item (sid, addr, ifindex); +read_lock_bh (&pn->hash_lock); + po =__get_item (pn, sid, addr, ifindex);if (po)sock_hold (sk_pppox (po)); -read_unlock_bh (&pppoe_hash_lock); +read_unlock_bh (&pn->hash_lock);return po; } -static inline struct pppox_sock *get_item_by_addr (struct sockaddr_pppox *sp) +static inline struct pppox_sock *get_item_by_addr (struct net *net, +struct sockaddr_pppox *sp) {struct net_device *dev; +struct pppoe_net *pn; +struct pppox_sock *pppox_sock; +int ifindex; - dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); + dev =dev_get_by_name (net, sp->sa_addr.pppoe.dev);if (!dev)return NULL ; + ifindex = dev->ifindex; + pn =net_generic (net, pppoe_net_id); + pppox_sock =get_item (pn, sp->sa_addr.pppoe.sid, + sp->sa_addr.pppoe.remote, ifindex);dev_put (dev); -return get_item (sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex); + +return pppox_sock; } -static inline struct pppox_sock *delete_item (__be16 sid,char *addr,int ifindex) +static inline struct pppox_sock *delete_item (struct pppoe_net *pn,__be16 sid, +char *addr,int ifindex) {struct pppox_sock *ret; -write_lock_bh (&pppoe_hash_lock); - ret =__delete_item (sid, addr, ifindex); -write_unlock_bh (&pppoe_hash_lock); +write_lock_bh (&pn->hash_lock); + ret =__delete_item (pn, sid, addr, ifindex); +write_unlock_bh (&pn->hash_lock);return ret; } - -/*************************************************************************** * * Handler for device events.
@@ -261,25 +291,33 @@ static inline struct pppox_sock *delete_static void pppoe_flush_dev (struct net_device *dev) { -int hash; +struct pppoe_net *pn; +int i; +BUG_ON (dev ==NULL ); -write_lock_bh (&pppoe_hash_lock); -for (hash =0 ; hash <PPPOE_HASH_SIZE ; hash++) { -struct pppox_sock *po = item_hash_table[hash]; + pn =pppoe_pernet (dev_net (dev)); +if (!pn)/* already freed */ +return ; + +write_lock_bh (&pn->hash_lock); +for (i =0 ; i <PPPOE_HASH_SIZE ; i++) { +struct pppox_sock *po = pn->hash_table[i];while (po !=NULL ) { -struct sock *sk =sk_pppox (po); +struct sock *sk;if (po->pppoe_dev != dev) { po = po->next;continue ; } + sk =sk_pppox (po); +spin_lock (&flush_lock); po->pppoe_dev =NULL ; +spin_unlock (&flush_lock);dev_put (dev); -/* We always grab the socket lock, followed by the -* pppoe_hash_lock, in that order. Since we should +* hash_lock, in that order. Since we should * hold the sock lock while doing any unbinding, * we need to release the lock we're holding. * Hold a reference to the sock so it doesn't disappear
@@ -288,7 +326,7 @@ static void pppoe_flush_dev(struct net_dsock_hold (sk); -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock);lock_sock (sk);if (sk->sk_state & (PPPOX_CONNECTED |PPPOX_BOUND )) {
@@ -304,20 +342,17 @@ static void pppoe_flush_dev(struct net_d* While the lock was dropped the chain contents may * have changed. */ -write_lock_bh (&pppoe_hash_lock); - po = item_hash_table[hash]; +write_lock_bh (&pn->hash_lock); + po = pn->hash_table[i]; } } -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock); }static int pppoe_device_event (struct notifier_block *this,unsigned long event,void *ptr) { -struct net_device *dev = (struct net_device *) ptr; - -if (dev_net (dev) != &init_net) -return NOTIFY_DONE ; +struct net_device *dev = (struct net_device *)ptr;/* Only look at sockets that are using this specific device. */ switch (event) {
@@ -339,7 +374,6 @@ static int pppoe_device_event(struct notreturn NOTIFY_DONE ; } -static struct notifier_block pppoe_notifier = { .notifier_call = pppoe_device_event, };
@@ -357,8 +391,8 @@ static int pppoe_rcv_core(struct sock *sif (sk->sk_state &PPPOX_BOUND ) {ppp_input (&po->chan, skb); }else if (sk->sk_state &PPPOX_RELAY ) { - relay_po =get_item_by_addr (&po->pppoe_relay); - + relay_po =get_item_by_addr (dev_net (po->pppoe_dev), + &po->pppoe_relay);if (relay_po ==NULL ) goto abort_kfree;
@@ -387,23 +421,18 @@ abort_kfree:* Receive wrapper called in BH context. * ***********************************************************************/ -static int pppoe_rcv (struct sk_buff *skb, -struct net_device *dev, -struct packet_type *pt, -struct net_device *orig_dev) - +static int pppoe_rcv (struct sk_buff *skb,struct net_device *dev, +struct packet_type *pt,struct net_device *orig_dev) {struct pppoe_hdr *ph;struct pppox_sock *po; +struct pppoe_net *pn;int len; skb =skb_share_check (skb,GFP_ATOMIC );if (!skb) goto out; -if (dev_net (dev) != &init_net) - goto drop; -if (!pskb_may_pull (skb,sizeof (struct pppoe_hdr ))) goto drop;
@@ -417,7 +446,8 @@ static int pppoe_rcv(struct sk_buff *skbif (pskb_trim_rcsum (skb, len)) goto drop; - po =get_item (ph->sid,eth_hdr (skb)->h_source, dev->ifindex); + pn =pppoe_pernet (dev_net (dev)); + po =get_item (pn, ph->sid,eth_hdr (skb)->h_source, dev->ifindex);if (!po) goto drop;
@@ -435,17 +465,13 @@ out:* This is solely for detection of PADT frames * ***********************************************************************/ -static int pppoe_disc_rcv (struct sk_buff *skb, -struct net_device *dev, -struct packet_type *pt, -struct net_device *orig_dev) +static int pppoe_disc_rcv (struct sk_buff *skb,struct net_device *dev, +struct packet_type *pt,struct net_device *orig_dev) {struct pppoe_hdr *ph;struct pppox_sock *po; - -if (dev_net (dev) != &init_net) - goto abort; +struct pppoe_net *pn; skb =skb_share_check (skb,GFP_ATOMIC );if (!skb)
@@ -458,7 +484,8 @@ static int pppoe_disc_rcv(struct sk_buffif (ph->code !=PADT_CODE ) goto abort; - po =get_item (ph->sid,eth_hdr (skb)->h_source, dev->ifindex); + pn =pppoe_pernet (dev_net (dev)); + po =get_item (pn, ph->sid,eth_hdr (skb)->h_source, dev->ifindex);if (po) {struct sock *sk =sk_pppox (po);
@@ -517,14 +544,14 @@ static int pppoe_create(struct net *net,sock_init_data (sock, sk); - sock->state =SS_UNCONNECTED ; - sock->ops = &pppoe_ops; + sock->state =SS_UNCONNECTED ; + sock->ops = &pppoe_ops; - sk->sk_backlog_rcv = pppoe_rcv_core; - sk->sk_state =PPPOX_NONE ; - sk->sk_type =SOCK_STREAM ; - sk->sk_family =PF_PPPOX ; - sk->sk_protocol =PX_PROTO_OE ; + sk->sk_backlog_rcv = pppoe_rcv_core; + sk->sk_state =PPPOX_NONE ; + sk->sk_type =SOCK_STREAM ; + sk->sk_family =PF_PPPOX ; + sk->sk_protocol =PX_PROTO_OE ;return 0 ; }
@@ -533,6 +560,7 @@ static int pppoe_release(struct socket * {struct sock *sk = sock->sk;struct pppox_sock *po; +struct pppoe_net *pn;if (!sk)return 0 ;
@@ -548,26 +576,39 @@ static int pppoe_release(struct socket */* Signal the death of the socket. */ sk->sk_state =PPPOX_DEAD ; +/* +* pppoe_flush_dev could lead to a race with +* this routine so we use flush_lock to eliminate +* such a case (we only need per-net specific data) +*/ +spin_lock (&flush_lock); + po =pppox_sk (sk); +if (!po->pppoe_dev) { +spin_unlock (&flush_lock); + goto out; + } + pn =pppoe_pernet (dev_net (po->pppoe_dev)); +spin_unlock (&flush_lock); -/* Write lock on hash lock protects the entire "po" struct from -* concurrent updates via pppoe_flush_dev. The "po" struct should -* be considered part of the hash table contents, thus protected -* by the hash table lock */ -write_lock_bh (&pppoe_hash_lock); +/* +* protect "po" from concurrent updates +* on pppoe_flush_dev +*/ +write_lock_bh (&pn->hash_lock); po =pppox_sk (sk); -if (stage_session (po->pppoe_pa.sid)) { -__delete_item (po->pppoe_pa.sid, - po->pppoe_pa.remote, po->pppoe_ifindex); - } +if (stage_session (po->pppoe_pa.sid)) +__delete_item (pn, po->pppoe_pa.sid, po->pppoe_pa.remote, + po->pppoe_ifindex);if (po->pppoe_dev) {dev_put (po->pppoe_dev); po->pppoe_dev =NULL ; } -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock); +out:sock_orphan (sk); sock->sk =NULL ;
@@ -582,9 +623,10 @@ static int pppoe_connect(struct socket * int sockaddr_len, int flags) {struct sock *sk = sock->sk; -struct net_device *dev; -struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; +struct sockaddr_pppox *sp = (struct sockaddr_pppox *)uservaddr;struct pppox_sock *po =pppox_sk (sk); +struct net_device *dev; +struct pppoe_net *pn;int error;lock_sock (sk);
@@ -610,9 +652,12 @@ static int pppoe_connect(struct socket */* Delete the old binding */ if (stage_session (po->pppoe_pa.sid)) {pppox_unbind_sock (sk); -delete_item (po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); -if (po->pppoe_dev) +if (po->pppoe_dev) { + pn =pppoe_pernet (dev_net (po->pppoe_dev)); +delete_item (pn, po->pppoe_pa.sid, + po->pppoe_pa.remote, po->pppoe_ifindex);dev_put (po->pppoe_dev); + }memset (sk_pppox (po) +1 ,0 ,sizeof (struct pppox_sock ) -sizeof (struct sock )); sk->sk_state =PPPOX_NONE ;
@@ -620,18 +665,17 @@ static int pppoe_connect(struct socket */* Re-bind in session stage only */ if (stage_session (sp->sa_addr.pppoe.sid)) { - dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); - error = -ENODEV ; + dev =dev_get_by_name (sock_net (sk), sp->sa_addr.pppoe.dev);if (!dev) goto end; po->pppoe_dev = dev; po->pppoe_ifindex = dev->ifindex; - -write_lock_bh (&pppoe_hash_lock); + pn =pppoe_pernet (dev_net (dev)); +write_lock_bh (&pn->hash_lock);if (!(dev->flags &IFF_UP )) { -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock); goto err_put; }
@@ -639,8 +683,8 @@ static int pppoe_connect(struct socket * &sp->sa_addr.pppoe, sizeof(struct pppoe_addr)); - error =__set_item (po); -write_unlock_bh (&pppoe_hash_lock); + error =__set_item (pn, po); +write_unlock_bh (&pn->hash_lock);if (error <0 ) goto err_put;
@@ -700,7 +744,6 @@ static int pppoe_ioctl(struct socket *soswitch (cmd) {case PPPIOCGMRU : err = -ENXIO ; -if (!(sk->sk_state &PPPOX_CONNECTED ))break ;
@@ -708,7 +751,7 @@ static int pppoe_ioctl(struct socket *soif (put_user (po->pppoe_dev->mtu -sizeof (struct pppoe_hdr ) -PPP_HDRLEN , - (int __user *) arg)) + (int __user *)arg))break ; err =0 ;break ;
@@ -764,8 +807,7 @@ static int pppoe_ioctl(struct socket *so/* Check that the socket referenced by the address actually exists. */ - relay_po =get_item_by_addr (&po->pppoe_relay); - + relay_po =get_item_by_addr (sock_net (sk), &po->pppoe_relay);if (!relay_po)break ;
@@ -837,11 +879,10 @@ static int pppoe_sendmsg(struct kiocb *i skb->priority = sk->sk_priority; skb->protocol =__constant_htons (ETH_P_PPP_SES ); - ph = (struct pppoe_hdr *)skb_put (skb, total_len +sizeof (struct pppoe_hdr )); - start = (char *) &ph->tag[0 ]; + ph = (struct pppoe_hdr *)skb_put (skb, total_len +sizeof (struct pppoe_hdr )); + start = (char *)&ph->tag[0 ]; error =memcpy_fromiovec (start, m->msg_iov, total_len); -if (error <0 ) {kfree_skb (skb); goto end;
@@ -919,7 +960,7 @@ abort:***********************************************************************/ static int pppoe_xmit (struct ppp_channel *chan,struct sk_buff *skb) { -struct sock *sk = (struct sock *) chan->private; +struct sock *sk = (struct sock *)chan->private;return __pppoe_xmit (sk, skb); }
@@ -941,7 +982,6 @@ static int pppoe_recvmsg(struct kiocb *i skb =skb_recv_datagram (sk, flags & ~MSG_DONTWAIT , flags &MSG_DONTWAIT , &error); -if (error <0 ) goto end;
@@ -964,6 +1004,7 @@ static int pppoe_seq_show(struct seq_fil {struct pppox_sock *po;char *dev_name; +DECLARE_MAC_BUF (mac);if (v ==SEQ_START_TOKEN ) {seq_puts (seq,"Id Address Device\n" );
@@ -974,44 +1015,47 @@ static int pppoe_seq_show(struct seq_fil dev_name = po->pppoe_pa.dev;seq_printf (seq,"%08X %pM %8s\n" , - po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); + po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); out:return 0 ; } -static __inline__struct pppox_sock *pppoe_get_idx (loff_t pos) +static inline struct pppox_sock *pppoe_get_idx (struct pppoe_net *pn,loff_t pos) {struct pppox_sock *po;int i;for (i =0 ; i <PPPOE_HASH_SIZE ; i++) { - po = item_hash_table[i]; + po = pn->hash_table[i];while (po) {if (!pos--) goto out; po = po->next; } } + out:return po; }static void *pppoe_seq_start (struct seq_file *seq,loff_t *pos) -__acquires (pppoe_hash_lock) + __acquires(pn->hash_lock) { +struct pppoe_net *pn =pppoe_pernet (seq->private);loff_t l = *pos; -read_lock_bh (&pppoe_hash_lock); -return l ?pppoe_get_idx (--l) :SEQ_START_TOKEN ; +read_lock_bh (&pn->hash_lock); +return l ?pppoe_get_idx (pn, --l) :SEQ_START_TOKEN ; }static void *pppoe_seq_next (struct seq_file *seq,void *v,loff_t *pos) { +struct pppoe_net *pn =pppoe_pernet (seq->private);struct pppox_sock *po; ++*pos;if (v ==SEQ_START_TOKEN ) { - po =pppoe_get_idx (0 ); + po =pppoe_get_idx (pn,0 ); goto out; } po = v;
@@ -1021,19 +1065,21 @@ static void *pppoe_seq_next(struct seq_fint hash =hash_item (po->pppoe_pa.sid, po->pppoe_pa.remote);while (++hash <PPPOE_HASH_SIZE ) { - po = item_hash_table[hash]; + po = pn->hash_table[hash];if (po)break ; } } + out:return po; }static void pppoe_seq_stop (struct seq_file *seq,void *v) -__releases (pppoe_hash_lock) + __releases(pn->hash_lock) { -read_unlock_bh (&pppoe_hash_lock); +struct pppoe_net *pn =pppoe_pernet (seq->private); +read_unlock_bh (&pn->hash_lock); }static struct seq_operations pppoe_seq_ops = {
@@ -1045,7 +1091,30 @@ static struct seq_operations pppoe_seq_ostatic int pppoe_seq_open (struct inode *inode,struct file *file) { -return seq_open (file, &pppoe_seq_ops); +struct seq_file *m; +struct net *net; +int err; + + err =seq_open (file, &pppoe_seq_ops); +if (err) +return err; + + m = file->private_data; + net =maybe_get_net (PDE_NET (PDE (inode))); +BUG_ON (!net); + m->private = net; + +return err; +} + +static int pppoe_seq_release (struct inode *inode,struct file *file) +{ +struct seq_file *m; + + m = file->private_data; +put_net ((struct net *)m->private); + +return seq_release (inode, file); }static const struct file_operations pppoe_seq_fops = {
@@ -1053,20 +1122,9 @@ static const struct file_operations pppo .open = pppoe_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = pppoe_seq_release, }; -static int __init pppoe_proc_init (void ) -{ -struct proc_dir_entry *p; - - p =proc_net_fops_create (&init_net,"pppoe" ,S_IRUGO , &pppoe_seq_fops); -if (!p) -return -ENOMEM ; -return 0 ; -} -#else /* CONFIG_PROC_FS */ -static inline int pppoe_proc_init (void ) {return 0 ; }#endif /* CONFIG_PROC_FS */ static const struct proto_ops pppoe_ops = {
@@ -1095,10 +1153,61 @@ static struct pppox_proto pppoe_proto = .owner = THIS_MODULE, }; +static __net_init int pppoe_init_net (struct net *net) +{ +struct pppoe_net *pn; +struct proc_dir_entry *pde; +int err; + + pn =kzalloc (sizeof (*pn),GFP_KERNEL ); +if (!pn) +return -ENOMEM ; + +rwlock_init (&pn->hash_lock); + + err =net_assign_generic (net, pppoe_net_id, pn); +if (err) + goto out; + + pde =proc_net_fops_create (net,"pppoe" ,S_IRUGO , &pppoe_seq_fops); +#ifdef CONFIG_PROC_FS +if (!pde) { + err = -ENOMEM ; + goto out; + } +#endif + +return 0 ; + +out: +kfree (pn); +return err; +} + +static __net_exit void pppoe_exit_net(struct net *net) +{ +struct pppoe_net *pn; + +proc_net_remove (net,"pppoe" ); + pn =net_generic (net, pppoe_net_id); +/* +* if someone has cached our net then +* further net_generic call will return NULL +*/ +net_assign_generic (net, pppoe_net_id,NULL ); +kfree (pn); +} + +static __net_initdata struct pernet_operations pppoe_net_ops = { + .init = pppoe_init_net, + .exit = pppoe_exit_net, +}; +static int __init pppoe_init (void ) { -int err =proto_register (&pppoe_sk_proto,0 ); +int err; + err =proto_register (&pppoe_sk_proto,0 );if (err) goto out;
@@ -1106,20 +1215,22 @@ static int __init pppoe_init(void)if (err) goto out_unregister_pppoe_proto; - err =pppoe_proc_init (); + err =register_pernet_gen_device (&pppoe_net_id, &pppoe_net_ops);if (err) goto out_unregister_pppox_proto;dev_add_pack (&pppoes_ptype);dev_add_pack (&pppoed_ptype);register_netdevice_notifier (&pppoe_notifier); -out: -return err; + +return 0 ; + out_unregister_pppox_proto:unregister_pppox_proto (PX_PROTO_OE ); out_unregister_pppoe_proto:proto_unregister (&pppoe_sk_proto); - goto out; +out: +return err; } static void __exit pppoe_exit(void)
@@ -1128,7 +1239,7 @@ static void __exit pppoe_exit(void)dev_remove_pack (&pppoes_ptype);dev_remove_pack (&pppoed_ptype);unregister_netdevice_notifier (&pppoe_notifier); -remove_proc_entry ("pppoe" , init_net.proc_net); +unregister_pernet_gen_device (pppoe_net_id, &pppoe_net_ops);proto_unregister (&pppoe_sk_proto); }
drivers/net/pppox.c +4 -3
@@ -108,12 +108,13 @@ static int pppox_create(struct net *net, {int rc = -EPROTOTYPE ; -if (net != &init_net) -return -EAFNOSUPPORT ; -if (protocol <0 || protocol >PX_MAX_PROTO ) goto out; +/* we support net-namespaces for PPPoE only (yet) */ +if (protocol !=PX_PROTO_OE && net != &init_net) +return -EAFNOSUPPORT ; + rc = -EPROTONOSUPPORT ;if (!pppox_protos[protocol])request_module ("pppox-proto-%d" , protocol);
PATCH 2/5 net: pppoe - introduce net-namespace functionality
In reply to a message not in the archive- each net-namespace for pppoe module is having own hash table and appropriate locks wich are allocated at time of namespace intialization. It requires about 140 bytes of memory for every new namespace but such approach allow us to escape from hash chains growing and additional lock contends (especially in SMP environment).
- pppox code allows to create per-namespace sockets for PX_PROTO_OE protocol only (since at this moment support for pppol2tp net-namespace is not implemented yet).
--- drivers/net/pppoe.c | 377 +++++++++++++++++++++++++++++++++------------------- drivers/net/pppox.c | 7 2 files changed, 248 insertions(+), 136 deletions(-)
drivers/net/pppoe.c +244 -133
@@ -78,7 +78,9 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/nsproxy.h> #include <net/net_namespace.h> +#include <net/netns/generic.h> #include <net/sock.h> #include <asm/uaccess.h>
@@ -93,7 +95,24 @@ static int __pppoe_xmit(struct sock *sk,static const struct proto_ops pppoe_ops;static struct ppp_channel_ops pppoe_chan_ops; -static DEFINE_RWLOCK (pppoe_hash_lock); + +/* per-net private data for this module */ +static unsigned int pppoe_net_id; +struct pppoe_net { +/* +* we could use _single_ hash table for all +* nets by injecting net id into the hash but +* it would increase hash chains and add +* a few additional math comparations messy +* as well, moreover in case of SMP less locking +* controversy here +*/ +struct pppox_sock *hash_table[PPPOE_HASH_SIZE ]; +rwlock_t hash_lock; +}; + +/* to eliminate a race btw pppoe_flush_dev and pppoe_release */ +static DEFINE_SPINLOCK (flush_lock);/* * PPPoE could be in the following stages:
@@ -108,16 +127,21 @@ static inline bool stage_session(__be16return sid !=0 ; } +static inline struct pppoe_net *pppoe_pernet (struct net *net) +{ +BUG_ON (!net); + +return net_generic (net, pppoe_net_id); +} +static inline int cmp_2_addr (struct pppoe_addr *a,struct pppoe_addr *b) { -return a->sid == b->sid && - (memcmp (a->remote, b->remote,ETH_ALEN ) ==0 ); +return a->sid == b->sid && !memcmp (a->remote, b->remote,ETH_ALEN ); }static inline int cmp_addr (struct pppoe_addr *a,__be16 sid,char *addr) { -return a->sid == sid && - (memcmp (a->remote, addr,ETH_ALEN ) ==0 ); +return a->sid == sid && !memcmp (a->remote, addr,ETH_ALEN ); }#if 8 %PPPOE_HASH_BITS
@@ -139,21 +163,18 @@ static int hash_item(__be16 sid, unsignereturn hash &PPPOE_HASH_MASK ; } -/* zeroed because its in .bss */ -static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE ]; -/********************************************************************** * * Set/get/delete/rehash items (internal versions) * **********************************************************************/ -static struct pppox_sock *__get_item (__be16 sid,unsigned char *addr,int ifindex) +static struct pppox_sock *__get_item (struct pppoe_net *pn,__be16 sid, +unsigned char *addr,int ifindex) {int hash =hash_item (sid, addr);struct pppox_sock *ret; - ret = item_hash_table[hash]; - + ret = pn->hash_table[hash];while (ret) {if (cmp_addr (&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex)
@@ -165,12 +186,12 @@ static struct pppox_sock *__get_item(__breturn NULL ; } -static int __set_item (struct pppox_sock *po) +static int __set_item (struct pppoe_net *pn,struct pppox_sock *po) {int hash =hash_item (po->pppoe_pa.sid, po->pppoe_pa.remote);struct pppox_sock *ret; - ret = item_hash_table[hash]; + ret = pn->hash_table[hash];while (ret) {if (cmp_2_addr (&ret->pppoe_pa, &po->pppoe_pa) && ret->pppoe_ifindex == po->pppoe_ifindex)
@@ -179,19 +200,20 @@ static int __set_item(struct pppox_sock ret = ret->next; } - po->next = item_hash_table[hash]; - item_hash_table[hash] = po; + po->next = pn->hash_table[hash]; + pn->hash_table[hash] = po;return 0 ; } -static struct pppox_sock *__delete_item (__be16 sid,char *addr,int ifindex) +static struct pppox_sock *__delete_item (struct pppoe_net *pn,__be16 sid, +char *addr,int ifindex) {int hash =hash_item (sid, addr);struct pppox_sock *ret, **src; - ret = item_hash_table[hash]; - src = &item_hash_table[hash]; + ret = pn->hash_table[hash]; + src = &pn->hash_table[hash];while (ret) { if (cmp_addr(&ret->pppoe_pa, sid, addr) &&
@@ -212,46 +234,54 @@ static struct pppox_sock *__delete_item(* Set/get/delete/rehash items * **********************************************************************/ -static inline struct pppox_sock *get_item (__be16 sid, -unsigned char *addr,int ifindex) +static inline struct pppox_sock *get_item (struct pppoe_net *pn,__be16 sid, +unsigned char *addr,int ifindex) {struct pppox_sock *po; -read_lock_bh (&pppoe_hash_lock); - po =__get_item (sid, addr, ifindex); +read_lock_bh (&pn->hash_lock); + po =__get_item (pn, sid, addr, ifindex);if (po)sock_hold (sk_pppox (po)); -read_unlock_bh (&pppoe_hash_lock); +read_unlock_bh (&pn->hash_lock);return po; } -static inline struct pppox_sock *get_item_by_addr (struct sockaddr_pppox *sp) +static inline struct pppox_sock *get_item_by_addr (struct net *net, +struct sockaddr_pppox *sp) {struct net_device *dev; +struct pppoe_net *pn; +struct pppox_sock *pppox_sock; +int ifindex; - dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); + dev =dev_get_by_name (net, sp->sa_addr.pppoe.dev);if (!dev)return NULL ; + ifindex = dev->ifindex; + pn =net_generic (net, pppoe_net_id); + pppox_sock =get_item (pn, sp->sa_addr.pppoe.sid, + sp->sa_addr.pppoe.remote, ifindex);dev_put (dev); -return get_item (sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex); + +return pppox_sock; } -static inline struct pppox_sock *delete_item (__be16 sid,char *addr,int ifindex) +static inline struct pppox_sock *delete_item (struct pppoe_net *pn,__be16 sid, +char *addr,int ifindex) {struct pppox_sock *ret; -write_lock_bh (&pppoe_hash_lock); - ret =__delete_item (sid, addr, ifindex); -write_unlock_bh (&pppoe_hash_lock); +write_lock_bh (&pn->hash_lock); + ret =__delete_item (pn, sid, addr, ifindex); +write_unlock_bh (&pn->hash_lock);return ret; } - -/*************************************************************************** * * Handler for device events.
@@ -261,25 +291,33 @@ static inline struct pppox_sock *delete_static void pppoe_flush_dev (struct net_device *dev) { -int hash; +struct pppoe_net *pn; +int i; +BUG_ON (dev ==NULL ); -write_lock_bh (&pppoe_hash_lock); -for (hash =0 ; hash <PPPOE_HASH_SIZE ; hash++) { -struct pppox_sock *po = item_hash_table[hash]; + pn =pppoe_pernet (dev_net (dev)); +if (!pn)/* already freed */ +return ; + +write_lock_bh (&pn->hash_lock); +for (i =0 ; i <PPPOE_HASH_SIZE ; i++) { +struct pppox_sock *po = pn->hash_table[i];while (po !=NULL ) { -struct sock *sk =sk_pppox (po); +struct sock *sk;if (po->pppoe_dev != dev) { po = po->next;continue ; } + sk =sk_pppox (po); +spin_lock (&flush_lock); po->pppoe_dev =NULL ; +spin_unlock (&flush_lock);dev_put (dev); -/* We always grab the socket lock, followed by the -* pppoe_hash_lock, in that order. Since we should +* hash_lock, in that order. Since we should * hold the sock lock while doing any unbinding, * we need to release the lock we're holding. * Hold a reference to the sock so it doesn't disappear
@@ -288,7 +326,7 @@ static void pppoe_flush_dev(struct net_dsock_hold (sk); -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock);lock_sock (sk);if (sk->sk_state & (PPPOX_CONNECTED |PPPOX_BOUND )) {
@@ -304,20 +342,17 @@ static void pppoe_flush_dev(struct net_d* While the lock was dropped the chain contents may * have changed. */ -write_lock_bh (&pppoe_hash_lock); - po = item_hash_table[hash]; +write_lock_bh (&pn->hash_lock); + po = pn->hash_table[i]; } } -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock); }static int pppoe_device_event (struct notifier_block *this,unsigned long event,void *ptr) { -struct net_device *dev = (struct net_device *) ptr; - -if (dev_net (dev) != &init_net) -return NOTIFY_DONE ; +struct net_device *dev = (struct net_device *)ptr;/* Only look at sockets that are using this specific device. */ switch (event) {
@@ -339,7 +374,6 @@ static int pppoe_device_event(struct notreturn NOTIFY_DONE ; } -static struct notifier_block pppoe_notifier = { .notifier_call = pppoe_device_event, };
@@ -357,8 +391,8 @@ static int pppoe_rcv_core(struct sock *sif (sk->sk_state &PPPOX_BOUND ) {ppp_input (&po->chan, skb); }else if (sk->sk_state &PPPOX_RELAY ) { - relay_po =get_item_by_addr (&po->pppoe_relay); - + relay_po =get_item_by_addr (dev_net (po->pppoe_dev), + &po->pppoe_relay);if (relay_po ==NULL ) goto abort_kfree;
@@ -387,23 +421,18 @@ abort_kfree:* Receive wrapper called in BH context. * ***********************************************************************/ -static int pppoe_rcv (struct sk_buff *skb, -struct net_device *dev, -struct packet_type *pt, -struct net_device *orig_dev) - +static int pppoe_rcv (struct sk_buff *skb,struct net_device *dev, +struct packet_type *pt,struct net_device *orig_dev) {struct pppoe_hdr *ph;struct pppox_sock *po; +struct pppoe_net *pn;int len; skb =skb_share_check (skb,GFP_ATOMIC );if (!skb) goto out; -if (dev_net (dev) != &init_net) - goto drop; -if (!pskb_may_pull (skb,sizeof (struct pppoe_hdr ))) goto drop;
@@ -417,7 +446,8 @@ static int pppoe_rcv(struct sk_buff *skbif (pskb_trim_rcsum (skb, len)) goto drop; - po =get_item (ph->sid,eth_hdr (skb)->h_source, dev->ifindex); + pn =pppoe_pernet (dev_net (dev)); + po =get_item (pn, ph->sid,eth_hdr (skb)->h_source, dev->ifindex);if (!po) goto drop;
@@ -435,17 +465,13 @@ out:* This is solely for detection of PADT frames * ***********************************************************************/ -static int pppoe_disc_rcv (struct sk_buff *skb, -struct net_device *dev, -struct packet_type *pt, -struct net_device *orig_dev) +static int pppoe_disc_rcv (struct sk_buff *skb,struct net_device *dev, +struct packet_type *pt,struct net_device *orig_dev) {struct pppoe_hdr *ph;struct pppox_sock *po; - -if (dev_net (dev) != &init_net) - goto abort; +struct pppoe_net *pn; skb =skb_share_check (skb,GFP_ATOMIC );if (!skb)
@@ -458,7 +484,8 @@ static int pppoe_disc_rcv(struct sk_buffif (ph->code !=PADT_CODE ) goto abort; - po =get_item (ph->sid,eth_hdr (skb)->h_source, dev->ifindex); + pn =pppoe_pernet (dev_net (dev)); + po =get_item (pn, ph->sid,eth_hdr (skb)->h_source, dev->ifindex);if (po) {struct sock *sk =sk_pppox (po);
@@ -517,14 +544,14 @@ static int pppoe_create(struct net *net,sock_init_data (sock, sk); - sock->state =SS_UNCONNECTED ; - sock->ops = &pppoe_ops; + sock->state =SS_UNCONNECTED ; + sock->ops = &pppoe_ops; - sk->sk_backlog_rcv = pppoe_rcv_core; - sk->sk_state =PPPOX_NONE ; - sk->sk_type =SOCK_STREAM ; - sk->sk_family =PF_PPPOX ; - sk->sk_protocol =PX_PROTO_OE ; + sk->sk_backlog_rcv = pppoe_rcv_core; + sk->sk_state =PPPOX_NONE ; + sk->sk_type =SOCK_STREAM ; + sk->sk_family =PF_PPPOX ; + sk->sk_protocol =PX_PROTO_OE ;return 0 ; }
@@ -533,6 +560,7 @@ static int pppoe_release(struct socket * {struct sock *sk = sock->sk;struct pppox_sock *po; +struct pppoe_net *pn;if (!sk)return 0 ;
@@ -548,26 +576,39 @@ static int pppoe_release(struct socket */* Signal the death of the socket. */ sk->sk_state =PPPOX_DEAD ; +/* +* pppoe_flush_dev could lead to a race with +* this routine so we use flush_lock to eliminate +* such a case (we only need per-net specific data) +*/ +spin_lock (&flush_lock); + po =pppox_sk (sk); +if (!po->pppoe_dev) { +spin_unlock (&flush_lock); + goto out; + } + pn =pppoe_pernet (dev_net (po->pppoe_dev)); +spin_unlock (&flush_lock); -/* Write lock on hash lock protects the entire "po" struct from -* concurrent updates via pppoe_flush_dev. The "po" struct should -* be considered part of the hash table contents, thus protected -* by the hash table lock */ -write_lock_bh (&pppoe_hash_lock); +/* +* protect "po" from concurrent updates +* on pppoe_flush_dev +*/ +write_lock_bh (&pn->hash_lock); po =pppox_sk (sk); -if (stage_session (po->pppoe_pa.sid)) { -__delete_item (po->pppoe_pa.sid, - po->pppoe_pa.remote, po->pppoe_ifindex); - } +if (stage_session (po->pppoe_pa.sid)) +__delete_item (pn, po->pppoe_pa.sid, po->pppoe_pa.remote, + po->pppoe_ifindex);if (po->pppoe_dev) {dev_put (po->pppoe_dev); po->pppoe_dev =NULL ; } -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock); +out:sock_orphan (sk); sock->sk =NULL ;
@@ -582,9 +623,10 @@ static int pppoe_connect(struct socket * int sockaddr_len, int flags) {struct sock *sk = sock->sk; -struct net_device *dev; -struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; +struct sockaddr_pppox *sp = (struct sockaddr_pppox *)uservaddr;struct pppox_sock *po =pppox_sk (sk); +struct net_device *dev; +struct pppoe_net *pn;int error;lock_sock (sk);
@@ -610,9 +652,12 @@ static int pppoe_connect(struct socket */* Delete the old binding */ if (stage_session (po->pppoe_pa.sid)) {pppox_unbind_sock (sk); -delete_item (po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); -if (po->pppoe_dev) +if (po->pppoe_dev) { + pn =pppoe_pernet (dev_net (po->pppoe_dev)); +delete_item (pn, po->pppoe_pa.sid, + po->pppoe_pa.remote, po->pppoe_ifindex);dev_put (po->pppoe_dev); + }memset (sk_pppox (po) +1 ,0 ,sizeof (struct pppox_sock ) -sizeof (struct sock )); sk->sk_state =PPPOX_NONE ;
@@ -620,18 +665,17 @@ static int pppoe_connect(struct socket */* Re-bind in session stage only */ if (stage_session (sp->sa_addr.pppoe.sid)) { - dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); - error = -ENODEV ; + dev =dev_get_by_name (sock_net (sk), sp->sa_addr.pppoe.dev);if (!dev) goto end; po->pppoe_dev = dev; po->pppoe_ifindex = dev->ifindex; - -write_lock_bh (&pppoe_hash_lock); + pn =pppoe_pernet (dev_net (dev)); +write_lock_bh (&pn->hash_lock);if (!(dev->flags &IFF_UP )) { -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock); goto err_put; }
@@ -639,8 +683,8 @@ static int pppoe_connect(struct socket * &sp->sa_addr.pppoe, sizeof(struct pppoe_addr)); - error =__set_item (po); -write_unlock_bh (&pppoe_hash_lock); + error =__set_item (pn, po); +write_unlock_bh (&pn->hash_lock);if (error <0 ) goto err_put;
@@ -700,7 +744,6 @@ static int pppoe_ioctl(struct socket *soswitch (cmd) {case PPPIOCGMRU : err = -ENXIO ; -if (!(sk->sk_state &PPPOX_CONNECTED ))break ;
@@ -708,7 +751,7 @@ static int pppoe_ioctl(struct socket *soif (put_user (po->pppoe_dev->mtu -sizeof (struct pppoe_hdr ) -PPP_HDRLEN , - (int __user *) arg)) + (int __user *)arg))break ; err =0 ;break ;
@@ -764,8 +807,7 @@ static int pppoe_ioctl(struct socket *so/* Check that the socket referenced by the address actually exists. */ - relay_po =get_item_by_addr (&po->pppoe_relay); - + relay_po =get_item_by_addr (sock_net (sk), &po->pppoe_relay);if (!relay_po)break ;
@@ -837,11 +879,10 @@ static int pppoe_sendmsg(struct kiocb *i skb->priority = sk->sk_priority; skb->protocol =__constant_htons (ETH_P_PPP_SES ); - ph = (struct pppoe_hdr *)skb_put (skb, total_len +sizeof (struct pppoe_hdr )); - start = (char *) &ph->tag[0 ]; + ph = (struct pppoe_hdr *)skb_put (skb, total_len +sizeof (struct pppoe_hdr )); + start = (char *)&ph->tag[0 ]; error =memcpy_fromiovec (start, m->msg_iov, total_len); -if (error <0 ) {kfree_skb (skb); goto end;
@@ -919,7 +960,7 @@ abort:***********************************************************************/ static int pppoe_xmit (struct ppp_channel *chan,struct sk_buff *skb) { -struct sock *sk = (struct sock *) chan->private; +struct sock *sk = (struct sock *)chan->private;return __pppoe_xmit (sk, skb); }
@@ -941,7 +982,6 @@ static int pppoe_recvmsg(struct kiocb *i skb =skb_recv_datagram (sk, flags & ~MSG_DONTWAIT , flags &MSG_DONTWAIT , &error); -if (error <0 ) goto end;
@@ -964,6 +1004,7 @@ static int pppoe_seq_show(struct seq_fil {struct pppox_sock *po;char *dev_name; +DECLARE_MAC_BUF (mac);if (v ==SEQ_START_TOKEN ) {seq_puts (seq,"Id Address Device\n" );
@@ -974,44 +1015,47 @@ static int pppoe_seq_show(struct seq_fil dev_name = po->pppoe_pa.dev;seq_printf (seq,"%08X %pM %8s\n" , - po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); + po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); out:return 0 ; } -static __inline__struct pppox_sock *pppoe_get_idx (loff_t pos) +static inline struct pppox_sock *pppoe_get_idx (struct pppoe_net *pn,loff_t pos) {struct pppox_sock *po;int i;for (i =0 ; i <PPPOE_HASH_SIZE ; i++) { - po = item_hash_table[i]; + po = pn->hash_table[i];while (po) {if (!pos--) goto out; po = po->next; } } + out:return po; }static void *pppoe_seq_start (struct seq_file *seq,loff_t *pos) -__acquires (pppoe_hash_lock) + __acquires(pn->hash_lock) { +struct pppoe_net *pn =pppoe_pernet (seq->private);loff_t l = *pos; -read_lock_bh (&pppoe_hash_lock); -return l ?pppoe_get_idx (--l) :SEQ_START_TOKEN ; +read_lock_bh (&pn->hash_lock); +return l ?pppoe_get_idx (pn, --l) :SEQ_START_TOKEN ; }static void *pppoe_seq_next (struct seq_file *seq,void *v,loff_t *pos) { +struct pppoe_net *pn =pppoe_pernet (seq->private);struct pppox_sock *po; ++*pos;if (v ==SEQ_START_TOKEN ) { - po =pppoe_get_idx (0 ); + po =pppoe_get_idx (pn,0 ); goto out; } po = v;
@@ -1021,19 +1065,21 @@ static void *pppoe_seq_next(struct seq_fint hash =hash_item (po->pppoe_pa.sid, po->pppoe_pa.remote);while (++hash <PPPOE_HASH_SIZE ) { - po = item_hash_table[hash]; + po = pn->hash_table[hash];if (po)break ; } } + out:return po; }static void pppoe_seq_stop (struct seq_file *seq,void *v) -__releases (pppoe_hash_lock) + __releases(pn->hash_lock) { -read_unlock_bh (&pppoe_hash_lock); +struct pppoe_net *pn =pppoe_pernet (seq->private); +read_unlock_bh (&pn->hash_lock); }static struct seq_operations pppoe_seq_ops = {
@@ -1045,7 +1091,30 @@ static struct seq_operations pppoe_seq_ostatic int pppoe_seq_open (struct inode *inode,struct file *file) { -return seq_open (file, &pppoe_seq_ops); +struct seq_file *m; +struct net *net; +int err; + + err =seq_open (file, &pppoe_seq_ops); +if (err) +return err; + + m = file->private_data; + net =maybe_get_net (PDE_NET (PDE (inode))); +BUG_ON (!net); + m->private = net; + +return err; +} + +static int pppoe_seq_release (struct inode *inode,struct file *file) +{ +struct seq_file *m; + + m = file->private_data; +put_net ((struct net *)m->private); + +return seq_release (inode, file); }static const struct file_operations pppoe_seq_fops = {
@@ -1053,20 +1122,9 @@ static const struct file_operations pppo .open = pppoe_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = pppoe_seq_release, }; -static int __init pppoe_proc_init (void ) -{ -struct proc_dir_entry *p; - - p =proc_net_fops_create (&init_net,"pppoe" ,S_IRUGO , &pppoe_seq_fops); -if (!p) -return -ENOMEM ; -return 0 ; -} -#else /* CONFIG_PROC_FS */ -static inline int pppoe_proc_init (void ) {return 0 ; }#endif /* CONFIG_PROC_FS */ static const struct proto_ops pppoe_ops = {
@@ -1095,10 +1153,61 @@ static struct pppox_proto pppoe_proto = .owner = THIS_MODULE, }; +static __net_init int pppoe_init_net (struct net *net) +{ +struct pppoe_net *pn; +struct proc_dir_entry *pde; +int err; + + pn =kzalloc (sizeof (*pn),GFP_KERNEL ); +if (!pn) +return -ENOMEM ; + +rwlock_init (&pn->hash_lock); + + err =net_assign_generic (net, pppoe_net_id, pn); +if (err) + goto out; + + pde =proc_net_fops_create (net,"pppoe" ,S_IRUGO , &pppoe_seq_fops); +#ifdef CONFIG_PROC_FS +if (!pde) { + err = -ENOMEM ; + goto out; + } +#endif + +return 0 ; + +out: +kfree (pn); +return err; +} + +static __net_exit void pppoe_exit_net(struct net *net) +{ +struct pppoe_net *pn; + +proc_net_remove (net,"pppoe" ); + pn =net_generic (net, pppoe_net_id); +/* +* if someone has cached our net then +* further net_generic call will return NULL +*/ +net_assign_generic (net, pppoe_net_id,NULL ); +kfree (pn); +} + +static __net_initdata struct pernet_operations pppoe_net_ops = { + .init = pppoe_init_net, + .exit = pppoe_exit_net, +}; +static int __init pppoe_init (void ) { -int err =proto_register (&pppoe_sk_proto,0 ); +int err; + err =proto_register (&pppoe_sk_proto,0 );if (err) goto out;
@@ -1106,20 +1215,22 @@ static int __init pppoe_init(void)if (err) goto out_unregister_pppoe_proto; - err =pppoe_proc_init (); + err =register_pernet_gen_device (&pppoe_net_id, &pppoe_net_ops);if (err) goto out_unregister_pppox_proto;dev_add_pack (&pppoes_ptype);dev_add_pack (&pppoed_ptype);register_netdevice_notifier (&pppoe_notifier); -out: -return err; + +return 0 ; + out_unregister_pppox_proto:unregister_pppox_proto (PX_PROTO_OE ); out_unregister_pppoe_proto:proto_unregister (&pppoe_sk_proto); - goto out; +out: +return err; } static void __exit pppoe_exit(void)
@@ -1128,7 +1239,7 @@ static void __exit pppoe_exit(void)dev_remove_pack (&pppoes_ptype);dev_remove_pack (&pppoed_ptype);unregister_netdevice_notifier (&pppoe_notifier); -remove_proc_entry ("pppoe" , init_net.proc_net); +unregister_pernet_gen_device (pppoe_net_id, &pppoe_net_ops);proto_unregister (&pppoe_sk_proto); }
drivers/net/pppox.c +4 -3
@@ -108,12 +108,13 @@ static int pppox_create(struct net *net, {int rc = -EPROTOTYPE ; -if (net != &init_net) -return -EAFNOSUPPORT ; -if (protocol <0 || protocol >PX_MAX_PROTO ) goto out; +/* we support net-namespaces for PPPoE only (yet) */ +if (protocol !=PX_PROTO_OE && net != &init_net) +return -EAFNOSUPPORT ; + rc = -EPROTONOSUPPORT ;if (!pppox_protos[protocol])request_module ("pppox-proto-%d" , protocol);
PATCH 2/5 net: pppoe - introduce net-namespace functionality
In reply to a message not in the archive- each net-namespace for pppoe module is having own hash table and appropriate locks wich are allocated at time of namespace intialization. It requires about 140 bytes of memory for every new namespace but such approach allow us to escape from hash chains growing and additional lock contends (especially in SMP environment).
- pppox code allows to create per-namespace sockets for PX_PROTO_OE protocol only (since at this moment support for pppol2tp net-namespace is not implemented yet).
--- drivers/net/pppoe.c | 377 +++++++++++++++++++++++++++++++++------------------- drivers/net/pppox.c | 7 2 files changed, 248 insertions(+), 136 deletions(-)
drivers/net/pppoe.c +244 -133
@@ -78,7 +78,9 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/nsproxy.h> #include <net/net_namespace.h> +#include <net/netns/generic.h> #include <net/sock.h> #include <asm/uaccess.h>
@@ -93,7 +95,24 @@ static int __pppoe_xmit(struct sock *sk,static const struct proto_ops pppoe_ops;static struct ppp_channel_ops pppoe_chan_ops; -static DEFINE_RWLOCK (pppoe_hash_lock); + +/* per-net private data for this module */ +static unsigned int pppoe_net_id; +struct pppoe_net { +/* +* we could use _single_ hash table for all +* nets by injecting net id into the hash but +* it would increase hash chains and add +* a few additional math comparations messy +* as well, moreover in case of SMP less locking +* controversy here +*/ +struct pppox_sock *hash_table[PPPOE_HASH_SIZE ]; +rwlock_t hash_lock; +}; + +/* to eliminate a race btw pppoe_flush_dev and pppoe_release */ +static DEFINE_SPINLOCK (flush_lock);/* * PPPoE could be in the following stages:
@@ -108,16 +127,21 @@ static inline bool stage_session(__be16return sid !=0 ; } +static inline struct pppoe_net *pppoe_pernet (struct net *net) +{ +BUG_ON (!net); + +return net_generic (net, pppoe_net_id); +} +static inline int cmp_2_addr (struct pppoe_addr *a,struct pppoe_addr *b) { -return a->sid == b->sid && - (memcmp (a->remote, b->remote,ETH_ALEN ) ==0 ); +return a->sid == b->sid && !memcmp (a->remote, b->remote,ETH_ALEN ); }static inline int cmp_addr (struct pppoe_addr *a,__be16 sid,char *addr) { -return a->sid == sid && - (memcmp (a->remote, addr,ETH_ALEN ) ==0 ); +return a->sid == sid && !memcmp (a->remote, addr,ETH_ALEN ); }#if 8 %PPPOE_HASH_BITS
@@ -139,21 +163,18 @@ static int hash_item(__be16 sid, unsignereturn hash &PPPOE_HASH_MASK ; } -/* zeroed because its in .bss */ -static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE ]; -/********************************************************************** * * Set/get/delete/rehash items (internal versions) * **********************************************************************/ -static struct pppox_sock *__get_item (__be16 sid,unsigned char *addr,int ifindex) +static struct pppox_sock *__get_item (struct pppoe_net *pn,__be16 sid, +unsigned char *addr,int ifindex) {int hash =hash_item (sid, addr);struct pppox_sock *ret; - ret = item_hash_table[hash]; - + ret = pn->hash_table[hash];while (ret) {if (cmp_addr (&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex)
@@ -165,12 +186,12 @@ static struct pppox_sock *__get_item(__breturn NULL ; } -static int __set_item (struct pppox_sock *po) +static int __set_item (struct pppoe_net *pn,struct pppox_sock *po) {int hash =hash_item (po->pppoe_pa.sid, po->pppoe_pa.remote);struct pppox_sock *ret; - ret = item_hash_table[hash]; + ret = pn->hash_table[hash];while (ret) {if (cmp_2_addr (&ret->pppoe_pa, &po->pppoe_pa) && ret->pppoe_ifindex == po->pppoe_ifindex)
@@ -179,19 +200,20 @@ static int __set_item(struct pppox_sock ret = ret->next; } - po->next = item_hash_table[hash]; - item_hash_table[hash] = po; + po->next = pn->hash_table[hash]; + pn->hash_table[hash] = po;return 0 ; } -static struct pppox_sock *__delete_item (__be16 sid,char *addr,int ifindex) +static struct pppox_sock *__delete_item (struct pppoe_net *pn,__be16 sid, +char *addr,int ifindex) {int hash =hash_item (sid, addr);struct pppox_sock *ret, **src; - ret = item_hash_table[hash]; - src = &item_hash_table[hash]; + ret = pn->hash_table[hash]; + src = &pn->hash_table[hash];while (ret) { if (cmp_addr(&ret->pppoe_pa, sid, addr) &&
@@ -212,46 +234,54 @@ static struct pppox_sock *__delete_item(* Set/get/delete/rehash items * **********************************************************************/ -static inline struct pppox_sock *get_item (__be16 sid, -unsigned char *addr,int ifindex) +static inline struct pppox_sock *get_item (struct pppoe_net *pn,__be16 sid, +unsigned char *addr,int ifindex) {struct pppox_sock *po; -read_lock_bh (&pppoe_hash_lock); - po =__get_item (sid, addr, ifindex); +read_lock_bh (&pn->hash_lock); + po =__get_item (pn, sid, addr, ifindex);if (po)sock_hold (sk_pppox (po)); -read_unlock_bh (&pppoe_hash_lock); +read_unlock_bh (&pn->hash_lock);return po; } -static inline struct pppox_sock *get_item_by_addr (struct sockaddr_pppox *sp) +static inline struct pppox_sock *get_item_by_addr (struct net *net, +struct sockaddr_pppox *sp) {struct net_device *dev; +struct pppoe_net *pn; +struct pppox_sock *pppox_sock; +int ifindex; - dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); + dev =dev_get_by_name (net, sp->sa_addr.pppoe.dev);if (!dev)return NULL ; + ifindex = dev->ifindex; + pn =net_generic (net, pppoe_net_id); + pppox_sock =get_item (pn, sp->sa_addr.pppoe.sid, + sp->sa_addr.pppoe.remote, ifindex);dev_put (dev); -return get_item (sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex); + +return pppox_sock; } -static inline struct pppox_sock *delete_item (__be16 sid,char *addr,int ifindex) +static inline struct pppox_sock *delete_item (struct pppoe_net *pn,__be16 sid, +char *addr,int ifindex) {struct pppox_sock *ret; -write_lock_bh (&pppoe_hash_lock); - ret =__delete_item (sid, addr, ifindex); -write_unlock_bh (&pppoe_hash_lock); +write_lock_bh (&pn->hash_lock); + ret =__delete_item (pn, sid, addr, ifindex); +write_unlock_bh (&pn->hash_lock);return ret; } - -/*************************************************************************** * * Handler for device events.
@@ -261,25 +291,33 @@ static inline struct pppox_sock *delete_static void pppoe_flush_dev (struct net_device *dev) { -int hash; +struct pppoe_net *pn; +int i; +BUG_ON (dev ==NULL ); -write_lock_bh (&pppoe_hash_lock); -for (hash =0 ; hash <PPPOE_HASH_SIZE ; hash++) { -struct pppox_sock *po = item_hash_table[hash]; + pn =pppoe_pernet (dev_net (dev)); +if (!pn)/* already freed */ +return ; + +write_lock_bh (&pn->hash_lock); +for (i =0 ; i <PPPOE_HASH_SIZE ; i++) { +struct pppox_sock *po = pn->hash_table[i];while (po !=NULL ) { -struct sock *sk =sk_pppox (po); +struct sock *sk;if (po->pppoe_dev != dev) { po = po->next;continue ; } + sk =sk_pppox (po); +spin_lock (&flush_lock); po->pppoe_dev =NULL ; +spin_unlock (&flush_lock);dev_put (dev); -/* We always grab the socket lock, followed by the -* pppoe_hash_lock, in that order. Since we should +* hash_lock, in that order. Since we should * hold the sock lock while doing any unbinding, * we need to release the lock we're holding. * Hold a reference to the sock so it doesn't disappear
@@ -288,7 +326,7 @@ static void pppoe_flush_dev(struct net_dsock_hold (sk); -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock);lock_sock (sk);if (sk->sk_state & (PPPOX_CONNECTED |PPPOX_BOUND )) {
@@ -304,20 +342,17 @@ static void pppoe_flush_dev(struct net_d* While the lock was dropped the chain contents may * have changed. */ -write_lock_bh (&pppoe_hash_lock); - po = item_hash_table[hash]; +write_lock_bh (&pn->hash_lock); + po = pn->hash_table[i]; } } -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock); }static int pppoe_device_event (struct notifier_block *this,unsigned long event,void *ptr) { -struct net_device *dev = (struct net_device *) ptr; - -if (dev_net (dev) != &init_net) -return NOTIFY_DONE ; +struct net_device *dev = (struct net_device *)ptr;/* Only look at sockets that are using this specific device. */ switch (event) {
@@ -339,7 +374,6 @@ static int pppoe_device_event(struct notreturn NOTIFY_DONE ; } -static struct notifier_block pppoe_notifier = { .notifier_call = pppoe_device_event, };
@@ -357,8 +391,8 @@ static int pppoe_rcv_core(struct sock *sif (sk->sk_state &PPPOX_BOUND ) {ppp_input (&po->chan, skb); }else if (sk->sk_state &PPPOX_RELAY ) { - relay_po =get_item_by_addr (&po->pppoe_relay); - + relay_po =get_item_by_addr (dev_net (po->pppoe_dev), + &po->pppoe_relay);if (relay_po ==NULL ) goto abort_kfree;
@@ -387,23 +421,18 @@ abort_kfree:* Receive wrapper called in BH context. * ***********************************************************************/ -static int pppoe_rcv (struct sk_buff *skb, -struct net_device *dev, -struct packet_type *pt, -struct net_device *orig_dev) - +static int pppoe_rcv (struct sk_buff *skb,struct net_device *dev, +struct packet_type *pt,struct net_device *orig_dev) {struct pppoe_hdr *ph;struct pppox_sock *po; +struct pppoe_net *pn;int len; skb =skb_share_check (skb,GFP_ATOMIC );if (!skb) goto out; -if (dev_net (dev) != &init_net) - goto drop; -if (!pskb_may_pull (skb,sizeof (struct pppoe_hdr ))) goto drop;
@@ -417,7 +446,8 @@ static int pppoe_rcv(struct sk_buff *skbif (pskb_trim_rcsum (skb, len)) goto drop; - po =get_item (ph->sid,eth_hdr (skb)->h_source, dev->ifindex); + pn =pppoe_pernet (dev_net (dev)); + po =get_item (pn, ph->sid,eth_hdr (skb)->h_source, dev->ifindex);if (!po) goto drop;
@@ -435,17 +465,13 @@ out:* This is solely for detection of PADT frames * ***********************************************************************/ -static int pppoe_disc_rcv (struct sk_buff *skb, -struct net_device *dev, -struct packet_type *pt, -struct net_device *orig_dev) +static int pppoe_disc_rcv (struct sk_buff *skb,struct net_device *dev, +struct packet_type *pt,struct net_device *orig_dev) {struct pppoe_hdr *ph;struct pppox_sock *po; - -if (dev_net (dev) != &init_net) - goto abort; +struct pppoe_net *pn; skb =skb_share_check (skb,GFP_ATOMIC );if (!skb)
@@ -458,7 +484,8 @@ static int pppoe_disc_rcv(struct sk_buffif (ph->code !=PADT_CODE ) goto abort; - po =get_item (ph->sid,eth_hdr (skb)->h_source, dev->ifindex); + pn =pppoe_pernet (dev_net (dev)); + po =get_item (pn, ph->sid,eth_hdr (skb)->h_source, dev->ifindex);if (po) {struct sock *sk =sk_pppox (po);
@@ -517,14 +544,14 @@ static int pppoe_create(struct net *net,sock_init_data (sock, sk); - sock->state =SS_UNCONNECTED ; - sock->ops = &pppoe_ops; + sock->state =SS_UNCONNECTED ; + sock->ops = &pppoe_ops; - sk->sk_backlog_rcv = pppoe_rcv_core; - sk->sk_state =PPPOX_NONE ; - sk->sk_type =SOCK_STREAM ; - sk->sk_family =PF_PPPOX ; - sk->sk_protocol =PX_PROTO_OE ; + sk->sk_backlog_rcv = pppoe_rcv_core; + sk->sk_state =PPPOX_NONE ; + sk->sk_type =SOCK_STREAM ; + sk->sk_family =PF_PPPOX ; + sk->sk_protocol =PX_PROTO_OE ;return 0 ; }
@@ -533,6 +560,7 @@ static int pppoe_release(struct socket * {struct sock *sk = sock->sk;struct pppox_sock *po; +struct pppoe_net *pn;if (!sk)return 0 ;
@@ -548,26 +576,39 @@ static int pppoe_release(struct socket */* Signal the death of the socket. */ sk->sk_state =PPPOX_DEAD ; +/* +* pppoe_flush_dev could lead to a race with +* this routine so we use flush_lock to eliminate +* such a case (we only need per-net specific data) +*/ +spin_lock (&flush_lock); + po =pppox_sk (sk); +if (!po->pppoe_dev) { +spin_unlock (&flush_lock); + goto out; + } + pn =pppoe_pernet (dev_net (po->pppoe_dev)); +spin_unlock (&flush_lock); -/* Write lock on hash lock protects the entire "po" struct from -* concurrent updates via pppoe_flush_dev. The "po" struct should -* be considered part of the hash table contents, thus protected -* by the hash table lock */ -write_lock_bh (&pppoe_hash_lock); +/* +* protect "po" from concurrent updates +* on pppoe_flush_dev +*/ +write_lock_bh (&pn->hash_lock); po =pppox_sk (sk); -if (stage_session (po->pppoe_pa.sid)) { -__delete_item (po->pppoe_pa.sid, - po->pppoe_pa.remote, po->pppoe_ifindex); - } +if (stage_session (po->pppoe_pa.sid)) +__delete_item (pn, po->pppoe_pa.sid, po->pppoe_pa.remote, + po->pppoe_ifindex);if (po->pppoe_dev) {dev_put (po->pppoe_dev); po->pppoe_dev =NULL ; } -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock); +out:sock_orphan (sk); sock->sk =NULL ;
@@ -582,9 +623,10 @@ static int pppoe_connect(struct socket * int sockaddr_len, int flags) {struct sock *sk = sock->sk; -struct net_device *dev; -struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; +struct sockaddr_pppox *sp = (struct sockaddr_pppox *)uservaddr;struct pppox_sock *po =pppox_sk (sk); +struct net_device *dev; +struct pppoe_net *pn;int error;lock_sock (sk);
@@ -610,9 +652,12 @@ static int pppoe_connect(struct socket */* Delete the old binding */ if (stage_session (po->pppoe_pa.sid)) {pppox_unbind_sock (sk); -delete_item (po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); -if (po->pppoe_dev) +if (po->pppoe_dev) { + pn =pppoe_pernet (dev_net (po->pppoe_dev)); +delete_item (pn, po->pppoe_pa.sid, + po->pppoe_pa.remote, po->pppoe_ifindex);dev_put (po->pppoe_dev); + }memset (sk_pppox (po) +1 ,0 ,sizeof (struct pppox_sock ) -sizeof (struct sock )); sk->sk_state =PPPOX_NONE ;
@@ -620,18 +665,17 @@ static int pppoe_connect(struct socket */* Re-bind in session stage only */ if (stage_session (sp->sa_addr.pppoe.sid)) { - dev =dev_get_by_name (&init_net, sp->sa_addr.pppoe.dev); - error = -ENODEV ; + dev =dev_get_by_name (sock_net (sk), sp->sa_addr.pppoe.dev);if (!dev) goto end; po->pppoe_dev = dev; po->pppoe_ifindex = dev->ifindex; - -write_lock_bh (&pppoe_hash_lock); + pn =pppoe_pernet (dev_net (dev)); +write_lock_bh (&pn->hash_lock);if (!(dev->flags &IFF_UP )) { -write_unlock_bh (&pppoe_hash_lock); +write_unlock_bh (&pn->hash_lock); goto err_put; }
@@ -639,8 +683,8 @@ static int pppoe_connect(struct socket * &sp->sa_addr.pppoe, sizeof(struct pppoe_addr)); - error =__set_item (po); -write_unlock_bh (&pppoe_hash_lock); + error =__set_item (pn, po); +write_unlock_bh (&pn->hash_lock);if (error <0 ) goto err_put;
@@ -700,7 +744,6 @@ static int pppoe_ioctl(struct socket *soswitch (cmd) {case PPPIOCGMRU : err = -ENXIO ; -if (!(sk->sk_state &PPPOX_CONNECTED ))break ;
@@ -708,7 +751,7 @@ static int pppoe_ioctl(struct socket *soif (put_user (po->pppoe_dev->mtu -sizeof (struct pppoe_hdr ) -PPP_HDRLEN , - (int __user *) arg)) + (int __user *)arg))break ; err =0 ;break ;
@@ -764,8 +807,7 @@ static int pppoe_ioctl(struct socket *so/* Check that the socket referenced by the address actually exists. */ - relay_po =get_item_by_addr (&po->pppoe_relay); - + relay_po =get_item_by_addr (sock_net (sk), &po->pppoe_relay);if (!relay_po)break ;
@@ -837,11 +879,10 @@ static int pppoe_sendmsg(struct kiocb *i skb->priority = sk->sk_priority; skb->protocol =__constant_htons (ETH_P_PPP_SES ); - ph = (struct pppoe_hdr *)skb_put (skb, total_len +sizeof (struct pppoe_hdr )); - start = (char *) &ph->tag[0 ]; + ph = (struct pppoe_hdr *)skb_put (skb, total_len +sizeof (struct pppoe_hdr )); + start = (char *)&ph->tag[0 ]; error =memcpy_fromiovec (start, m->msg_iov, total_len); -if (error <0 ) {kfree_skb (skb); goto end;
@@ -919,7 +960,7 @@ abort:***********************************************************************/ static int pppoe_xmit (struct ppp_channel *chan,struct sk_buff *skb) { -struct sock *sk = (struct sock *) chan->private; +struct sock *sk = (struct sock *)chan->private;return __pppoe_xmit (sk, skb); }
@@ -941,7 +982,6 @@ static int pppoe_recvmsg(struct kiocb *i skb =skb_recv_datagram (sk, flags & ~MSG_DONTWAIT , flags &MSG_DONTWAIT , &error); -if (error <0 ) goto end;
@@ -964,6 +1004,7 @@ static int pppoe_seq_show(struct seq_fil {struct pppox_sock *po;char *dev_name; +DECLARE_MAC_BUF (mac);if (v ==SEQ_START_TOKEN ) {seq_puts (seq,"Id Address Device\n" );
@@ -974,44 +1015,47 @@ static int pppoe_seq_show(struct seq_fil dev_name = po->pppoe_pa.dev;seq_printf (seq,"%08X %pM %8s\n" , - po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); + po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); out:return 0 ; } -static __inline__struct pppox_sock *pppoe_get_idx (loff_t pos) +static inline struct pppox_sock *pppoe_get_idx (struct pppoe_net *pn,loff_t pos) {struct pppox_sock *po;int i;for (i =0 ; i <PPPOE_HASH_SIZE ; i++) { - po = item_hash_table[i]; + po = pn->hash_table[i];while (po) {if (!pos--) goto out; po = po->next; } } + out:return po; }static void *pppoe_seq_start (struct seq_file *seq,loff_t *pos) -__acquires (pppoe_hash_lock) + __acquires(pn->hash_lock) { +struct pppoe_net *pn =pppoe_pernet (seq->private);loff_t l = *pos; -read_lock_bh (&pppoe_hash_lock); -return l ?pppoe_get_idx (--l) :SEQ_START_TOKEN ; +read_lock_bh (&pn->hash_lock); +return l ?pppoe_get_idx (pn, --l) :SEQ_START_TOKEN ; }static void *pppoe_seq_next (struct seq_file *seq,void *v,loff_t *pos) { +struct pppoe_net *pn =pppoe_pernet (seq->private);struct pppox_sock *po; ++*pos;if (v ==SEQ_START_TOKEN ) { - po =pppoe_get_idx (0 ); + po =pppoe_get_idx (pn,0 ); goto out; } po = v;
@@ -1021,19 +1065,21 @@ static void *pppoe_seq_next(struct seq_fint hash =hash_item (po->pppoe_pa.sid, po->pppoe_pa.remote);while (++hash <PPPOE_HASH_SIZE ) { - po = item_hash_table[hash]; + po = pn->hash_table[hash];if (po)break ; } } + out:return po; }static void pppoe_seq_stop (struct seq_file *seq,void *v) -__releases (pppoe_hash_lock) + __releases(pn->hash_lock) { -read_unlock_bh (&pppoe_hash_lock); +struct pppoe_net *pn =pppoe_pernet (seq->private); +read_unlock_bh (&pn->hash_lock); }static struct seq_operations pppoe_seq_ops = {
@@ -1045,7 +1091,30 @@ static struct seq_operations pppoe_seq_ostatic int pppoe_seq_open (struct inode *inode,struct file *file) { -return seq_open (file, &pppoe_seq_ops); +struct seq_file *m; +struct net *net; +int err; + + err =seq_open (file, &pppoe_seq_ops); +if (err) +return err; + + m = file->private_data; + net =maybe_get_net (PDE_NET (PDE (inode))); +BUG_ON (!net); + m->private = net; + +return err; +} + +static int pppoe_seq_release (struct inode *inode,struct file *file) +{ +struct seq_file *m; + + m = file->private_data; +put_net ((struct net *)m->private); + +return seq_release (inode, file); }static const struct file_operations pppoe_seq_fops = {
@@ -1053,20 +1122,9 @@ static const struct file_operations pppo .open = pppoe_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = pppoe_seq_release, }; -static int __init pppoe_proc_init (void ) -{ -struct proc_dir_entry *p; - - p =proc_net_fops_create (&init_net,"pppoe" ,S_IRUGO , &pppoe_seq_fops); -if (!p) -return -ENOMEM ; -return 0 ; -} -#else /* CONFIG_PROC_FS */ -static inline int pppoe_proc_init (void ) {return 0 ; }#endif /* CONFIG_PROC_FS */ static const struct proto_ops pppoe_ops = {
@@ -1095,10 +1153,61 @@ static struct pppox_proto pppoe_proto = .owner = THIS_MODULE, }; +static __net_init int pppoe_init_net (struct net *net) +{ +struct pppoe_net *pn; +struct proc_dir_entry *pde; +int err; + + pn =kzalloc (sizeof (*pn),GFP_KERNEL ); +if (!pn) +return -ENOMEM ; + +rwlock_init (&pn->hash_lock); + + err =net_assign_generic (net, pppoe_net_id, pn); +if (err) + goto out; + + pde =proc_net_fops_create (net,"pppoe" ,S_IRUGO , &pppoe_seq_fops); +#ifdef CONFIG_PROC_FS +if (!pde) { + err = -ENOMEM ; + goto out; + } +#endif + +return 0 ; + +out: +kfree (pn); +return err; +} + +static __net_exit void pppoe_exit_net(struct net *net) +{ +struct pppoe_net *pn; + +proc_net_remove (net,"pppoe" ); + pn =net_generic (net, pppoe_net_id); +/* +* if someone has cached our net then +* further net_generic call will return NULL +*/ +net_assign_generic (net, pppoe_net_id,NULL ); +kfree (pn); +} + +static __net_initdata struct pernet_operations pppoe_net_ops = { + .init = pppoe_init_net, + .exit = pppoe_exit_net, +}; +static int __init pppoe_init (void ) { -int err =proto_register (&pppoe_sk_proto,0 ); +int err; + err =proto_register (&pppoe_sk_proto,0 );if (err) goto out;
@@ -1106,20 +1215,22 @@ static int __init pppoe_init(void)if (err) goto out_unregister_pppoe_proto; - err =pppoe_proc_init (); + err =register_pernet_gen_device (&pppoe_net_id, &pppoe_net_ops);if (err) goto out_unregister_pppox_proto;dev_add_pack (&pppoes_ptype);dev_add_pack (&pppoed_ptype);register_netdevice_notifier (&pppoe_notifier); -out: -return err; + +return 0 ; + out_unregister_pppox_proto:unregister_pppox_proto (PX_PROTO_OE ); out_unregister_pppoe_proto:proto_unregister (&pppoe_sk_proto); - goto out; +out: +return err; } static void __exit pppoe_exit(void)
@@ -1128,7 +1239,7 @@ static void __exit pppoe_exit(void)dev_remove_pack (&pppoes_ptype);dev_remove_pack (&pppoed_ptype);unregister_netdevice_notifier (&pppoe_notifier); -remove_proc_entry ("pppoe" , init_net.proc_net); +unregister_pernet_gen_device (pppoe_net_id, &pppoe_net_ops);proto_unregister (&pppoe_sk_proto); }
drivers/net/pppox.c +4 -3
@@ -108,12 +108,13 @@ static int pppox_create(struct net *net, {int rc = -EPROTOTYPE ; -if (net != &init_net) -return -EAFNOSUPPORT ; -if (protocol <0 || protocol >PX_MAX_PROTO ) goto out; +/* we support net-namespaces for PPPoE only (yet) */ +if (protocol !=PX_PROTO_OE && net != &init_net) +return -EAFNOSUPPORT ; + rc = -EPROTONOSUPPORT ;if (!pppox_protos[protocol])request_module ("pppox-proto-%d" , protocol);
PATCH 3/5 net: pppol2tp - introduce net-namespace functionality
In reply to a message not in the archive- Each tunnel and appropriate lock are inside own namespace now.
- pppox code allows to create per-namespace sockets for both PX_PROTO_OE and PX_PROTO_OL2TP protocols. Actually since now pppox_create support net-namespaces new PPPo... protocols (if they ever will be) should support net-namespace too otherwise explicit check for &init_net would be needed.
--- drivers/net/pppol2tp.c | 160 +++++++++++++++++++++++++++++++++++-------------- drivers/net/pppox.c | 4 - 2 files changed, 117 insertions(+), 47 deletions(-)
drivers/net/pppol2tp.c +117 -43
@@ -90,7 +90,9 @@#include <linux/hash.h> #include <linux/sort.h> #include <linux/proc_fs.h> +#include <linux/nsproxy.h> #include <net/net_namespace.h> +#include <net/netns/generic.h> #include <net/dst.h> #include <net/ip.h> #include <net/udp.h>
@@ -204,6 +206,7 @@ struct pppol2tp_tunnelstruct sock *sock;/* Parent socket */ struct list_head list;/* Keep a list of all open * prepared sockets */ +struct net *pppol2tp_net;/* the net we belong to */ atomic_t ref_count; };
@@ -227,8 +230,20 @@ static atomic_t pppol2tp_tunnel_count;static atomic_t pppol2tp_session_count;static struct ppp_channel_ops pppol2tp_chan_ops = { pppol2tp_xmit ,NULL };static struct proto_ops pppol2tp_ops; -static LIST_HEAD (pppol2tp_tunnel_list); -static DEFINE_RWLOCK (pppol2tp_tunnel_list_lock); + +/* per-net private data for this module */ +static unsigned int pppol2tp_net_id; +struct pppol2tp_net { +struct list_head pppol2tp_tunnel_list; +rwlock_t pppol2tp_tunnel_list_lock; +}; + +static inline struct pppol2tp_net *pppol2tp_pernet (struct net *net) +{ +BUG_ON (!net); + +return net_generic (net, pppol2tp_net_id); +}/* Helpers to obtain tunnel/session contexts from sockets. */
@@ -321,18 +336,19 @@ pppol2tp_session_find(struct pppol2tp_tu/* Lookup a tunnel by id */ -static struct pppol2tp_tunnel *pppol2tp_tunnel_find (u16 tunnel_id) +static struct pppol2tp_tunnel *pppol2tp_tunnel_find (struct net *net,u16 tunnel_id) { -struct pppol2tp_tunnel *tunnel =NULL ; +struct pppol2tp_tunnel *tunnel; +struct pppol2tp_net *pn =pppol2tp_pernet (net); -read_lock_bh (&pppol2tp_tunnel_list_lock); -list_for_each_entry (tunnel, &pppol2tp_tunnel_list, list) { +read_lock_bh (&pn->pppol2tp_tunnel_list_lock); +list_for_each_entry (tunnel, &pn->pppol2tp_tunnel_list, list) {if (tunnel->stats.tunnel_id == tunnel_id) { -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return tunnel; } } -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return NULL ; }
@@ -1287,10 +1303,12 @@ again:*/ static void pppol2tp_tunnel_free (struct pppol2tp_tunnel *tunnel) { +struct pppol2tp_net *pn =pppol2tp_pernet (tunnel->pppol2tp_net); +/* Remove from socket list */ -write_lock_bh (&pppol2tp_tunnel_list_lock); +write_lock_bh (&pn->pppol2tp_tunnel_list_lock);list_del_init (&tunnel->list); -write_unlock_bh (&pppol2tp_tunnel_list_lock); +write_unlock_bh (&pn->pppol2tp_tunnel_list_lock);atomic_dec (&pppol2tp_tunnel_count);kfree (tunnel);
@@ -1444,13 +1462,14 @@ error:/* Internal function to prepare a tunnel (UDP) socket to have PPPoX * sockets attached to it. */ -static struct sock *pppol2tp_prepare_tunnel_socket (int fd,u16 tunnel_id, -int *error) +static struct sock *pppol2tp_prepare_tunnel_socket (struct net *net, +int fd,u16 tunnel_id,int *error) {int err;struct socket *sock =NULL ;struct sock *sk;struct pppol2tp_tunnel *tunnel; +struct pppol2tp_net *pn;struct sock *ret =NULL ;/* Get the tunnel UDP socket from the fd, which was opened by
@@ -1524,11 +1543,15 @@ static struct sock *pppol2tp_prepare_tun/* Misc init */ rwlock_init (&tunnel->hlist_lock); +/* The net we belong to */ + tunnel->pppol2tp_net = net; + pn =pppol2tp_pernet (net); +/* Add tunnel to our list */ INIT_LIST_HEAD (&tunnel->list); -write_lock_bh (&pppol2tp_tunnel_list_lock); -list_add (&tunnel->list, &pppol2tp_tunnel_list); -write_unlock_bh (&pppol2tp_tunnel_list_lock); +write_lock_bh (&pn->pppol2tp_tunnel_list_lock); +list_add (&tunnel->list, &pn->pppol2tp_tunnel_list); +write_unlock_bh (&pn->pppol2tp_tunnel_list_lock);atomic_inc (&pppol2tp_tunnel_count);/* Bump the reference count. The tunnel context is deleted
@@ -1629,7 +1652,8 @@ static int pppol2tp_connect(struct socke* tunnel id. */ if ((sp->pppol2tp.s_session ==0 ) && (sp->pppol2tp.d_session ==0 )) { - tunnel_sock =pppol2tp_prepare_tunnel_socket (sp->pppol2tp.fd, + tunnel_sock =pppol2tp_prepare_tunnel_socket (sock_net (sk), + sp->pppol2tp.fd, sp->pppol2tp.s_tunnel, &error);if (tunnel_sock ==NULL )
@@ -1637,7 +1661,7 @@ static int pppol2tp_connect(struct socke tunnel = tunnel_sock->sk_user_data; }else { - tunnel =pppol2tp_tunnel_find (sp->pppol2tp.s_tunnel); + tunnel =pppol2tp_tunnel_find (sock_net (sk), sp->pppol2tp.s_tunnel);/* Error if we can't find the tunnel */ error = -ENOENT ;
@@ -2347,8 +2371,9 @@ end:#include <linux/seq_file.h> struct pppol2tp_seq_data { -struct pppol2tp_tunnel *tunnel;/* current tunnel */ -struct pppol2tp_session *session;/* NULL means get first session in tunnel */ +struct net *seq_net;/* net of inode */ +struct pppol2tp_tunnel *tunnel;/* current tunnel */ +struct pppol2tp_session *session;/* NULL means get first session in tunnel */ };static struct pppol2tp_session *next_session (struct pppol2tp_tunnel *tunnel,struct pppol2tp_session *curr)
@@ -2384,17 +2409,18 @@ out:return session; } -static struct pppol2tp_tunnel *next_tunnel (struct pppol2tp_tunnel *curr) +static struct pppol2tp_tunnel *next_tunnel (struct pppol2tp_net *pn, +struct pppol2tp_tunnel *curr) {struct pppol2tp_tunnel *tunnel =NULL ; -read_lock_bh (&pppol2tp_tunnel_list_lock); -if (list_is_last (&curr->list, &pppol2tp_tunnel_list)) { +read_lock_bh (&pn->pppol2tp_tunnel_list_lock); +if (list_is_last (&curr->list, &pn->pppol2tp_tunnel_list)) { goto out; } tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list); out: -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return tunnel; }
@@ -2402,6 +2428,7 @@ out:static void *pppol2tp_seq_start (struct seq_file *m,loff_t *offs) {struct pppol2tp_seq_data *pd =SEQ_START_TOKEN ; +struct pppol2tp_net *pn;loff_t pos = *offs;if (!pos)
@@ -2409,14 +2436,15 @@ static void *pppol2tp_seq_start(struct sBUG_ON (m->private ==NULL ); pd = m->private; + pn =pppol2tp_pernet (pd->seq_net);if (pd->tunnel ==NULL ) { -if (!list_empty (&pppol2tp_tunnel_list)) - pd->tunnel = list_entry(pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list); +if (!list_empty (&pn->pppol2tp_tunnel_list)) + pd->tunnel = list_entry(pn->pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list); }else { pd->session =next_session (pd->tunnel, pd->session);if (pd->session ==NULL ) { - pd->tunnel =next_tunnel (pd->tunnel); + pd->tunnel =next_tunnel (pn, pd->tunnel); } }
@@ -2532,6 +2560,7 @@ static int pppol2tp_proc_open(struct ino {struct seq_file *m;struct pppol2tp_seq_data *pd; +struct net *net;int ret =0 ; ret =seq_open (file, &pppol2tp_seq_ops);
@@ -2542,12 +2571,15 @@ static int pppol2tp_proc_open(struct ino/* Allocate and fill our proc_data for access later */ ret = -ENOMEM ; - m->private =kzalloc (sizeof (struct pppol2tp_seq_data ),GFP_KERNEL ); + m->private =kzalloc (sizeof (*pd),GFP_KERNEL );if (m->private ==NULL ) goto out; pd = m->private; - ret =0 ; + net =maybe_get_net (PDE_NET (PDE (inode))); +BUG_ON (!net); + pd->seq_net = net; +return 0 ; out:return ret;
@@ -2558,6 +2590,9 @@ out:static int pppol2tp_proc_release (struct inode *inode,struct file *file) {struct seq_file *m = (struct seq_file *)file->private_data; +struct pppol2tp_seq_data *pd = m->private; + +put_net (pd->seq_net);kfree (m->private); m->private =NULL ;
@@ -2573,8 +2608,6 @@ static struct file_operations pppol2tp_p .release = pppol2tp_proc_release, }; -static struct proc_dir_entry *pppol2tp_proc; -#endif /* CONFIG_PROC_FS */ /*****************************************************************************
@@ -2606,6 +2639,57 @@ static struct pppox_proto pppol2tp_proto .ioctl = pppol2tp_ioctl }; +static __net_init int pppol2tp_init_net (struct net *net) +{ +struct pppol2tp_net *pn; +struct proc_dir_entry *pde; +int err; + + pn =kzalloc (sizeof (*pn),GFP_KERNEL ); +if (!pn) +return -ENOMEM ; + +INIT_LIST_HEAD (&pn->pppol2tp_tunnel_list); +rwlock_init (&pn->pppol2tp_tunnel_list_lock); + + err =net_assign_generic (net, pppol2tp_net_id, pn); +if (err) + goto out; + + pde =proc_net_fops_create (net,"pppol2tp" ,S_IRUGO , &pppol2tp_proc_fops); +#ifdef CONFIG_PROC_FS +if (!pde) { + err = -ENOMEM ; + goto out; + } +#endif + +return 0 ; + +out: +kfree (pn); +return err; +} + +static __net_exit void pppol2tp_exit_net(struct net *net) +{ +struct pppoe_net *pn; + +proc_net_remove (net,"pppol2tp" ); + pn =net_generic (net, pppol2tp_net_id); +/* +* if someone has cached our net then +* further net_generic call will return NULL +*/ +net_assign_generic (net, pppol2tp_net_id,NULL ); +kfree (pn); +} + +static __net_initdata struct pernet_operations pppol2tp_net_ops = { + .init = pppol2tp_init_net, + .exit = pppol2tp_exit_net, +}; +static int __init pppol2tp_init (void ) {int err;
@@ -2617,23 +2701,17 @@ static int __init pppol2tp_init(void)if (err) goto out_unregister_pppol2tp_proto; -#ifdef CONFIG_PROC_FS - pppol2tp_proc =proc_net_fops_create (&init_net,"pppol2tp" ,0 , - &pppol2tp_proc_fops); -if (!pppol2tp_proc) { - err = -ENOMEM ; + err =register_pernet_gen_device (&pppol2tp_net_id, &pppol2tp_net_ops); +if (err) goto out_unregister_pppox_proto; - } -#endif /* CONFIG_PROC_FS */ +printk (KERN_INFO "PPPoL2TP kernel driver, %s\n" ,PPPOL2TP_DRV_VERSION ); out:return err; -#ifdef CONFIG_PROC_FS out_unregister_pppox_proto:unregister_pppox_proto (PX_PROTO_OL2TP ); -#endif out_unregister_pppol2tp_proto:proto_unregister (&pppol2tp_sk_proto); goto out;
@@ -2642,10 +2720,6 @@ out_unregister_pppol2tp_proto: static void __exit pppol2tp_exit(void) {unregister_pppox_proto (PX_PROTO_OL2TP ); - -#ifdef CONFIG_PROC_FS -remove_proc_entry ("pppol2tp" , init_net.proc_net); -#endif proto_unregister (&pppol2tp_sk_proto); }
drivers/net/pppox.c +0 -4
@@ -111,10 +111,6 @@ static int pppox_create(struct net *net,if (protocol <0 || protocol >PX_MAX_PROTO ) goto out; -/* we support net-namespaces for PPPoE only (yet) */ -if (protocol !=PX_PROTO_OE && net != &init_net) -return -EAFNOSUPPORT ; - rc = -EPROTONOSUPPORT ;if (!pppox_protos[protocol])request_module ("pppox-proto-%d" , protocol);
PATCH 3/5 net: pppol2tp - introduce net-namespace functionality
In reply to a message not in the archive- Each tunnel and appropriate lock are inside own namespace now.
- pppox code allows to create per-namespace sockets for both PX_PROTO_OE and PX_PROTO_OL2TP protocols. Actually since now pppox_create support net-namespaces new PPPo... protocols (if they ever will be) should support net-namespace too otherwise explicit check for &init_net would be needed.
--- drivers/net/pppol2tp.c | 160 +++++++++++++++++++++++++++++++++++-------------- drivers/net/pppox.c | 4 - 2 files changed, 117 insertions(+), 47 deletions(-)
drivers/net/pppol2tp.c +117 -43
@@ -90,7 +90,9 @@#include <linux/hash.h> #include <linux/sort.h> #include <linux/proc_fs.h> +#include <linux/nsproxy.h> #include <net/net_namespace.h> +#include <net/netns/generic.h> #include <net/dst.h> #include <net/ip.h> #include <net/udp.h>
@@ -204,6 +206,7 @@ struct pppol2tp_tunnelstruct sock *sock;/* Parent socket */ struct list_head list;/* Keep a list of all open * prepared sockets */ +struct net *pppol2tp_net;/* the net we belong to */ atomic_t ref_count; };
@@ -227,8 +230,20 @@ static atomic_t pppol2tp_tunnel_count;static atomic_t pppol2tp_session_count;static struct ppp_channel_ops pppol2tp_chan_ops = { pppol2tp_xmit ,NULL };static struct proto_ops pppol2tp_ops; -static LIST_HEAD (pppol2tp_tunnel_list); -static DEFINE_RWLOCK (pppol2tp_tunnel_list_lock); + +/* per-net private data for this module */ +static unsigned int pppol2tp_net_id; +struct pppol2tp_net { +struct list_head pppol2tp_tunnel_list; +rwlock_t pppol2tp_tunnel_list_lock; +}; + +static inline struct pppol2tp_net *pppol2tp_pernet (struct net *net) +{ +BUG_ON (!net); + +return net_generic (net, pppol2tp_net_id); +}/* Helpers to obtain tunnel/session contexts from sockets. */
@@ -321,18 +336,19 @@ pppol2tp_session_find(struct pppol2tp_tu/* Lookup a tunnel by id */ -static struct pppol2tp_tunnel *pppol2tp_tunnel_find (u16 tunnel_id) +static struct pppol2tp_tunnel *pppol2tp_tunnel_find (struct net *net,u16 tunnel_id) { -struct pppol2tp_tunnel *tunnel =NULL ; +struct pppol2tp_tunnel *tunnel; +struct pppol2tp_net *pn =pppol2tp_pernet (net); -read_lock_bh (&pppol2tp_tunnel_list_lock); -list_for_each_entry (tunnel, &pppol2tp_tunnel_list, list) { +read_lock_bh (&pn->pppol2tp_tunnel_list_lock); +list_for_each_entry (tunnel, &pn->pppol2tp_tunnel_list, list) {if (tunnel->stats.tunnel_id == tunnel_id) { -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return tunnel; } } -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return NULL ; }
@@ -1287,10 +1303,12 @@ again:*/ static void pppol2tp_tunnel_free (struct pppol2tp_tunnel *tunnel) { +struct pppol2tp_net *pn =pppol2tp_pernet (tunnel->pppol2tp_net); +/* Remove from socket list */ -write_lock_bh (&pppol2tp_tunnel_list_lock); +write_lock_bh (&pn->pppol2tp_tunnel_list_lock);list_del_init (&tunnel->list); -write_unlock_bh (&pppol2tp_tunnel_list_lock); +write_unlock_bh (&pn->pppol2tp_tunnel_list_lock);atomic_dec (&pppol2tp_tunnel_count);kfree (tunnel);
@@ -1444,13 +1462,14 @@ error:/* Internal function to prepare a tunnel (UDP) socket to have PPPoX * sockets attached to it. */ -static struct sock *pppol2tp_prepare_tunnel_socket (int fd,u16 tunnel_id, -int *error) +static struct sock *pppol2tp_prepare_tunnel_socket (struct net *net, +int fd,u16 tunnel_id,int *error) {int err;struct socket *sock =NULL ;struct sock *sk;struct pppol2tp_tunnel *tunnel; +struct pppol2tp_net *pn;struct sock *ret =NULL ;/* Get the tunnel UDP socket from the fd, which was opened by
@@ -1524,11 +1543,15 @@ static struct sock *pppol2tp_prepare_tun/* Misc init */ rwlock_init (&tunnel->hlist_lock); +/* The net we belong to */ + tunnel->pppol2tp_net = net; + pn =pppol2tp_pernet (net); +/* Add tunnel to our list */ INIT_LIST_HEAD (&tunnel->list); -write_lock_bh (&pppol2tp_tunnel_list_lock); -list_add (&tunnel->list, &pppol2tp_tunnel_list); -write_unlock_bh (&pppol2tp_tunnel_list_lock); +write_lock_bh (&pn->pppol2tp_tunnel_list_lock); +list_add (&tunnel->list, &pn->pppol2tp_tunnel_list); +write_unlock_bh (&pn->pppol2tp_tunnel_list_lock);atomic_inc (&pppol2tp_tunnel_count);/* Bump the reference count. The tunnel context is deleted
@@ -1629,7 +1652,8 @@ static int pppol2tp_connect(struct socke* tunnel id. */ if ((sp->pppol2tp.s_session ==0 ) && (sp->pppol2tp.d_session ==0 )) { - tunnel_sock =pppol2tp_prepare_tunnel_socket (sp->pppol2tp.fd, + tunnel_sock =pppol2tp_prepare_tunnel_socket (sock_net (sk), + sp->pppol2tp.fd, sp->pppol2tp.s_tunnel, &error);if (tunnel_sock ==NULL )
@@ -1637,7 +1661,7 @@ static int pppol2tp_connect(struct socke tunnel = tunnel_sock->sk_user_data; }else { - tunnel =pppol2tp_tunnel_find (sp->pppol2tp.s_tunnel); + tunnel =pppol2tp_tunnel_find (sock_net (sk), sp->pppol2tp.s_tunnel);/* Error if we can't find the tunnel */ error = -ENOENT ;
@@ -2347,8 +2371,9 @@ end:#include <linux/seq_file.h> struct pppol2tp_seq_data { -struct pppol2tp_tunnel *tunnel;/* current tunnel */ -struct pppol2tp_session *session;/* NULL means get first session in tunnel */ +struct net *seq_net;/* net of inode */ +struct pppol2tp_tunnel *tunnel;/* current tunnel */ +struct pppol2tp_session *session;/* NULL means get first session in tunnel */ };static struct pppol2tp_session *next_session (struct pppol2tp_tunnel *tunnel,struct pppol2tp_session *curr)
@@ -2384,17 +2409,18 @@ out:return session; } -static struct pppol2tp_tunnel *next_tunnel (struct pppol2tp_tunnel *curr) +static struct pppol2tp_tunnel *next_tunnel (struct pppol2tp_net *pn, +struct pppol2tp_tunnel *curr) {struct pppol2tp_tunnel *tunnel =NULL ; -read_lock_bh (&pppol2tp_tunnel_list_lock); -if (list_is_last (&curr->list, &pppol2tp_tunnel_list)) { +read_lock_bh (&pn->pppol2tp_tunnel_list_lock); +if (list_is_last (&curr->list, &pn->pppol2tp_tunnel_list)) { goto out; } tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list); out: -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return tunnel; }
@@ -2402,6 +2428,7 @@ out:static void *pppol2tp_seq_start (struct seq_file *m,loff_t *offs) {struct pppol2tp_seq_data *pd =SEQ_START_TOKEN ; +struct pppol2tp_net *pn;loff_t pos = *offs;if (!pos)
@@ -2409,14 +2436,15 @@ static void *pppol2tp_seq_start(struct sBUG_ON (m->private ==NULL ); pd = m->private; + pn =pppol2tp_pernet (pd->seq_net);if (pd->tunnel ==NULL ) { -if (!list_empty (&pppol2tp_tunnel_list)) - pd->tunnel = list_entry(pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list); +if (!list_empty (&pn->pppol2tp_tunnel_list)) + pd->tunnel = list_entry(pn->pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list); }else { pd->session =next_session (pd->tunnel, pd->session);if (pd->session ==NULL ) { - pd->tunnel =next_tunnel (pd->tunnel); + pd->tunnel =next_tunnel (pn, pd->tunnel); } }
@@ -2532,6 +2560,7 @@ static int pppol2tp_proc_open(struct ino {struct seq_file *m;struct pppol2tp_seq_data *pd; +struct net *net;int ret =0 ; ret =seq_open (file, &pppol2tp_seq_ops);
@@ -2542,12 +2571,15 @@ static int pppol2tp_proc_open(struct ino/* Allocate and fill our proc_data for access later */ ret = -ENOMEM ; - m->private =kzalloc (sizeof (struct pppol2tp_seq_data ),GFP_KERNEL ); + m->private =kzalloc (sizeof (*pd),GFP_KERNEL );if (m->private ==NULL ) goto out; pd = m->private; - ret =0 ; + net =maybe_get_net (PDE_NET (PDE (inode))); +BUG_ON (!net); + pd->seq_net = net; +return 0 ; out:return ret;
@@ -2558,6 +2590,9 @@ out:static int pppol2tp_proc_release (struct inode *inode,struct file *file) {struct seq_file *m = (struct seq_file *)file->private_data; +struct pppol2tp_seq_data *pd = m->private; + +put_net (pd->seq_net);kfree (m->private); m->private =NULL ;
@@ -2573,8 +2608,6 @@ static struct file_operations pppol2tp_p .release = pppol2tp_proc_release, }; -static struct proc_dir_entry *pppol2tp_proc; -#endif /* CONFIG_PROC_FS */ /*****************************************************************************
@@ -2606,6 +2639,57 @@ static struct pppox_proto pppol2tp_proto .ioctl = pppol2tp_ioctl }; +static __net_init int pppol2tp_init_net (struct net *net) +{ +struct pppol2tp_net *pn; +struct proc_dir_entry *pde; +int err; + + pn =kzalloc (sizeof (*pn),GFP_KERNEL ); +if (!pn) +return -ENOMEM ; + +INIT_LIST_HEAD (&pn->pppol2tp_tunnel_list); +rwlock_init (&pn->pppol2tp_tunnel_list_lock); + + err =net_assign_generic (net, pppol2tp_net_id, pn); +if (err) + goto out; + + pde =proc_net_fops_create (net,"pppol2tp" ,S_IRUGO , &pppol2tp_proc_fops); +#ifdef CONFIG_PROC_FS +if (!pde) { + err = -ENOMEM ; + goto out; + } +#endif + +return 0 ; + +out: +kfree (pn); +return err; +} + +static __net_exit void pppol2tp_exit_net(struct net *net) +{ +struct pppoe_net *pn; + +proc_net_remove (net,"pppol2tp" ); + pn =net_generic (net, pppol2tp_net_id); +/* +* if someone has cached our net then +* further net_generic call will return NULL +*/ +net_assign_generic (net, pppol2tp_net_id,NULL ); +kfree (pn); +} + +static __net_initdata struct pernet_operations pppol2tp_net_ops = { + .init = pppol2tp_init_net, + .exit = pppol2tp_exit_net, +}; +static int __init pppol2tp_init (void ) {int err;
@@ -2617,23 +2701,17 @@ static int __init pppol2tp_init(void)if (err) goto out_unregister_pppol2tp_proto; -#ifdef CONFIG_PROC_FS - pppol2tp_proc =proc_net_fops_create (&init_net,"pppol2tp" ,0 , - &pppol2tp_proc_fops); -if (!pppol2tp_proc) { - err = -ENOMEM ; + err =register_pernet_gen_device (&pppol2tp_net_id, &pppol2tp_net_ops); +if (err) goto out_unregister_pppox_proto; - } -#endif /* CONFIG_PROC_FS */ +printk (KERN_INFO "PPPoL2TP kernel driver, %s\n" ,PPPOL2TP_DRV_VERSION ); out:return err; -#ifdef CONFIG_PROC_FS out_unregister_pppox_proto:unregister_pppox_proto (PX_PROTO_OL2TP ); -#endif out_unregister_pppol2tp_proto:proto_unregister (&pppol2tp_sk_proto); goto out;
@@ -2642,10 +2720,6 @@ out_unregister_pppol2tp_proto: static void __exit pppol2tp_exit(void) {unregister_pppox_proto (PX_PROTO_OL2TP ); - -#ifdef CONFIG_PROC_FS -remove_proc_entry ("pppol2tp" , init_net.proc_net); -#endif proto_unregister (&pppol2tp_sk_proto); }
drivers/net/pppox.c +0 -4
@@ -111,10 +111,6 @@ static int pppox_create(struct net *net,if (protocol <0 || protocol >PX_MAX_PROTO ) goto out; -/* we support net-namespaces for PPPoE only (yet) */ -if (protocol !=PX_PROTO_OE && net != &init_net) -return -EAFNOSUPPORT ; - rc = -EPROTONOSUPPORT ;if (!pppox_protos[protocol])request_module ("pppox-proto-%d" , protocol);
Re: [PATCH 3/5] net: pppol2tp - introduce net-namespace functionality
Quoted 9 lines · Cyrill Gorcunov
- Each tunnel and appropriate lock are inside own namespace now.
- pppox code allows to create per-namespace sockets for bothPX_PROTO_OEandPX_PROTO_OL2TPprotocols. Actually since nowpppox_createsupport net-namespaces new PPPo... protocols (if they ever will be) should support net-namespace too otherwise explicit check for&init_netwould be needed.CC James Chapman <[email protected]>Signed-off-by Cyrill Gorcunov <[email protected]>
Changes look fine for pppol2tp. I tested again in my L2TP setup.
Quoted 365 lines
--- drivers/net/pppol2tp.c | 160 +++++++++++++++++++++++++++++++++++-------------- drivers/net/pppox.c | 4 - 2 files changed, 117 insertions(+), 47 deletions(-)Index:
linux-2.6.git/drivers/net/pppol2tp.c
===================================================================drivers/net/pppol2tp.c +117
-43@@ -90,7 +90,9 @@#include <linux/hash.h> #include <linux/sort.h> #include <linux/proc_fs.h> +#include <linux/nsproxy.h> #include <net/net_namespace.h> +#include <net/netns/generic.h> #include <net/dst.h> #include <net/ip.h> #include <net/udp.h> @@ -204,6 +206,7 @@ struct pppol2tp_tunnelstruct sock *sock;/* Parent socket */ struct list_head list;/* Keep a list of all open * prepared sockets */ +struct net *pppol2tp_net;/* the net we belong to */ atomic_t ref_count; };@@ -227,8 +230,20 @@ static atomic_t pppol2tp_tunnel_count;static atomic_t pppol2tp_session_count;static struct ppp_channel_ops pppol2tp_chan_ops = { pppol2tp_xmit ,NULL };static struct proto_ops pppol2tp_ops; -static LIST_HEAD (pppol2tp_tunnel_list); -static DEFINE_RWLOCK (pppol2tp_tunnel_list_lock); + +/* per-net private data for this module */ +static unsigned int pppol2tp_net_id; +struct pppol2tp_net { +struct list_head pppol2tp_tunnel_list; +rwlock_t pppol2tp_tunnel_list_lock; +}; + +static inline struct pppol2tp_net *pppol2tp_pernet (struct net *net) +{ +BUG_ON (!net); + +return net_generic (net, pppol2tp_net_id); +}/* Helpers to obtain tunnel/session contexts from sockets. */ @@ -321,18 +336,19 @@ pppol2tp_session_find(struct pppol2tp_tu/* Lookup a tunnel by id */ -static struct pppol2tp_tunnel *pppol2tp_tunnel_find (u16 tunnel_id) +static struct pppol2tp_tunnel *pppol2tp_tunnel_find (struct net *net,u16 tunnel_id) { -struct pppol2tp_tunnel *tunnel =NULL ; +struct pppol2tp_tunnel *tunnel; +struct pppol2tp_net *pn =pppol2tp_pernet (net); -read_lock_bh (&pppol2tp_tunnel_list_lock); -list_for_each_entry (tunnel, &pppol2tp_tunnel_list, list) { +read_lock_bh (&pn->pppol2tp_tunnel_list_lock); +list_for_each_entry (tunnel, &pn->pppol2tp_tunnel_list, list) {if (tunnel->stats.tunnel_id == tunnel_id) { -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return tunnel; } } -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return NULL ; }@@ -1287,10 +1303,12 @@ again:*/ static void pppol2tp_tunnel_free (struct pppol2tp_tunnel *tunnel) { +struct pppol2tp_net *pn =pppol2tp_pernet (tunnel->pppol2tp_net); +/* Remove from socket list */ -write_lock_bh (&pppol2tp_tunnel_list_lock); +write_lock_bh (&pn->pppol2tp_tunnel_list_lock);list_del_init (&tunnel->list); -write_unlock_bh (&pppol2tp_tunnel_list_lock); +write_unlock_bh (&pn->pppol2tp_tunnel_list_lock);atomic_dec (&pppol2tp_tunnel_count);kfree (tunnel);@@ -1444,13 +1462,14 @@ error:/* Internal function to prepare a tunnel (UDP) socket to have PPPoX * sockets attached to it. */ -static struct sock *pppol2tp_prepare_tunnel_socket (int fd,u16 tunnel_id, -int *error) +static struct sock *pppol2tp_prepare_tunnel_socket (struct net *net, +int fd,u16 tunnel_id,int *error) {int err;struct socket *sock =NULL ;struct sock *sk;struct pppol2tp_tunnel *tunnel; +struct pppol2tp_net *pn;struct sock *ret =NULL ;/* Get the tunnel UDP socket from the fd, which was opened by @@ -1524,11 +1543,15 @@ static struct sock *pppol2tp_prepare_tun/* Misc init */ rwlock_init (&tunnel->hlist_lock); +/* The net we belong to */ + tunnel->pppol2tp_net = net; + pn =pppol2tp_pernet (net); +/* Add tunnel to our list */ INIT_LIST_HEAD (&tunnel->list); -write_lock_bh (&pppol2tp_tunnel_list_lock); -list_add (&tunnel->list, &pppol2tp_tunnel_list); -write_unlock_bh (&pppol2tp_tunnel_list_lock); +write_lock_bh (&pn->pppol2tp_tunnel_list_lock); +list_add (&tunnel->list, &pn->pppol2tp_tunnel_list); +write_unlock_bh (&pn->pppol2tp_tunnel_list_lock);atomic_inc (&pppol2tp_tunnel_count);/* Bump the reference count. The tunnel context is deleted @@ -1629,7 +1652,8 @@ static int pppol2tp_connect(struct socke* tunnel id. */ if ((sp->pppol2tp.s_session ==0 ) && (sp->pppol2tp.d_session ==0 )) { - tunnel_sock =pppol2tp_prepare_tunnel_socket (sp->pppol2tp.fd, + tunnel_sock =pppol2tp_prepare_tunnel_socket (sock_net (sk), + sp->pppol2tp.fd, sp->pppol2tp.s_tunnel, &error);if (tunnel_sock ==NULL )@@ -1637,7 +1661,7 @@ static int pppol2tp_connect(struct socke tunnel = tunnel_sock->sk_user_data; }else { - tunnel =pppol2tp_tunnel_find (sp->pppol2tp.s_tunnel); + tunnel =pppol2tp_tunnel_find (sock_net (sk), sp->pppol2tp.s_tunnel);/* Error if we can't find the tunnel */ error = -ENOENT ;@@ -2347,8 +2371,9 @@ end:#include <linux/seq_file.h> struct pppol2tp_seq_data { -struct pppol2tp_tunnel *tunnel;/* current tunnel */ -struct pppol2tp_session *session;/* NULL means get first session in tunnel */ +struct net *seq_net;/* net of inode */ +struct pppol2tp_tunnel *tunnel;/* current tunnel */ +struct pppol2tp_session *session;/* NULL means get first session in tunnel */ };static struct pppol2tp_session *next_session (struct pppol2tp_tunnel *tunnel,struct pppol2tp_session *curr)@@ -2384,17 +2409,18 @@ out:return session; } -static struct pppol2tp_tunnel *next_tunnel (struct pppol2tp_tunnel *curr) +static struct pppol2tp_tunnel *next_tunnel (struct pppol2tp_net *pn, +struct pppol2tp_tunnel *curr) {struct pppol2tp_tunnel *tunnel =NULL ; -read_lock_bh (&pppol2tp_tunnel_list_lock); -if (list_is_last (&curr->list, &pppol2tp_tunnel_list)) { +read_lock_bh (&pn->pppol2tp_tunnel_list_lock); +if (list_is_last (&curr->list, &pn->pppol2tp_tunnel_list)) { goto out; } tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list); out: -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return tunnel; }@@ -2402,6 +2428,7 @@ out:static void *pppol2tp_seq_start (struct seq_file *m,loff_t *offs) {struct pppol2tp_seq_data *pd =SEQ_START_TOKEN ; +struct pppol2tp_net *pn;loff_t pos = *offs;if (!pos)@@ -2409,14 +2436,15 @@ static void *pppol2tp_seq_start(struct sBUG_ON (m->private ==NULL ); pd = m->private; + pn =pppol2tp_pernet (pd->seq_net);if (pd->tunnel ==NULL ) { -if (!list_empty (&pppol2tp_tunnel_list)) - pd->tunnel = list_entry(pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list); +if (!list_empty (&pn->pppol2tp_tunnel_list)) + pd->tunnel = list_entry(pn->pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list); }else { pd->session =next_session (pd->tunnel, pd->session);if (pd->session ==NULL ) { - pd->tunnel =next_tunnel (pd->tunnel); + pd->tunnel =next_tunnel (pn, pd->tunnel); } }@@ -2532,6 +2560,7 @@ static int pppol2tp_proc_open(struct ino {struct seq_file *m;struct pppol2tp_seq_data *pd; +struct net *net;int ret =0 ; ret =seq_open (file, &pppol2tp_seq_ops);@@ -2542,12 +2571,15 @@ static int pppol2tp_proc_open(struct ino/* Allocate and fill our proc_data for access later */ ret = -ENOMEM ; - m->private =kzalloc (sizeof (struct pppol2tp_seq_data ),GFP_KERNEL ); + m->private =kzalloc (sizeof (*pd),GFP_KERNEL );if (m->private ==NULL ) goto out; pd = m->private; - ret =0 ; + net =maybe_get_net (PDE_NET (PDE (inode))); +BUG_ON (!net); + pd->seq_net = net; +return 0 ; out:return ret;@@ -2558,6 +2590,9 @@ out:static int pppol2tp_proc_release (struct inode *inode,struct file *file) {struct seq_file *m = (struct seq_file *)file->private_data; +struct pppol2tp_seq_data *pd = m->private; + +put_net (pd->seq_net);kfree (m->private); m->private =NULL ;@@ -2573,8 +2608,6 @@ static struct file_operations pppol2tp_p .release = pppol2tp_proc_release, }; -static struct proc_dir_entry *pppol2tp_proc; -#endif /* CONFIG_PROC_FS */ /***************************************************************************** @@ -2606,6 +2639,57 @@ static struct pppox_proto pppol2tp_proto .ioctl = pppol2tp_ioctl }; +static __net_init int pppol2tp_init_net (struct net *net) +{ +struct pppol2tp_net *pn; +struct proc_dir_entry *pde; +int err; + + pn =kzalloc (sizeof (*pn),GFP_KERNEL ); +if (!pn) +return -ENOMEM ; + +INIT_LIST_HEAD (&pn->pppol2tp_tunnel_list); +rwlock_init (&pn->pppol2tp_tunnel_list_lock); + + err =net_assign_generic (net, pppol2tp_net_id, pn); +if (err) + goto out; + + pde =proc_net_fops_create (net,"pppol2tp" ,S_IRUGO , &pppol2tp_proc_fops); +#ifdef CONFIG_PROC_FS +if (!pde) { + err = -ENOMEM ; + goto out; + } +#endif + +return 0 ; + +out: +kfree (pn); +return err; +} + +static __net_exit void pppol2tp_exit_net(struct net *net) +{ +struct pppoe_net *pn; + +proc_net_remove (net,"pppol2tp" ); + pn =net_generic (net, pppol2tp_net_id); +/* +* if someone has cached our net then +* further net_generic call will return NULL +*/ +net_assign_generic (net, pppol2tp_net_id,NULL ); +kfree (pn); +} + +static __net_initdata struct pernet_operations pppol2tp_net_ops = { + .init = pppol2tp_init_net, + .exit = pppol2tp_exit_net, +}; +static int __init pppol2tp_init (void ) {int err;@@ -2617,23 +2701,17 @@ static int __init pppol2tp_init(void)if (err) goto out_unregister_pppol2tp_proto; -#ifdef CONFIG_PROC_FS - pppol2tp_proc =proc_net_fops_create (&init_net,"pppol2tp" ,0 , - &pppol2tp_proc_fops); -if (!pppol2tp_proc) { - err = -ENOMEM ; + err =register_pernet_gen_device (&pppol2tp_net_id, &pppol2tp_net_ops); +if (err) goto out_unregister_pppox_proto; - } -#endif /* CONFIG_PROC_FS */ +printk (KERN_INFO "PPPoL2TP kernel driver, %s\n" ,PPPOL2TP_DRV_VERSION ); out:return err; -#ifdef CONFIG_PROC_FS out_unregister_pppox_proto:unregister_pppox_proto (PX_PROTO_OL2TP ); -#endif out_unregister_pppol2tp_proto:proto_unregister (&pppol2tp_sk_proto); goto out;@@ -2642,10 +2720,6 @@ out_unregister_pppol2tp_proto: static void __exit pppol2tp_exit(void) {unregister_pppox_proto (PX_PROTO_OL2TP ); - -#ifdef CONFIG_PROC_FS -remove_proc_entry ("pppol2tp" , init_net.proc_net); -#endif proto_unregister (&pppol2tp_sk_proto); }Index:
linux-2.6.git/drivers/net/pppox.c
===================================================================drivers/net/pppox.c +0
-4@@ -111,10 +111,6 @@ static int pppox_create(struct net *net,if (protocol <0 || protocol >PX_MAX_PROTO ) goto out; -/* we support net-namespaces for PPPoE only (yet) */ -if (protocol !=PX_PROTO_OE && net != &init_net) -return -EAFNOSUPPORT ; - rc = -EPROTONOSUPPORT ;if (!pppox_protos[protocol])request_module ("pppox-proto-%d" , protocol);
Signature · 4 lines
James Chapman Katalix Systems Ltd http://www.katalix.com Catalysts for your Embedded Linux software development
PATCH 3/5 net: pppol2tp - introduce net-namespace functionality
In reply to a message not in the archive- Each tunnel and appropriate lock are inside own namespace now.
- pppox code allows to create per-namespace sockets for both PX_PROTO_OE and PX_PROTO_OL2TP protocols. Actually since now pppox_create support net-namespaces new PPPo... protocols (if they ever will be) should support net-namespace too otherwise explicit check for &init_net would be needed.
--- drivers/net/pppol2tp.c | 160 +++++++++++++++++++++++++++++++++++-------------- drivers/net/pppox.c | 4 - 2 files changed, 117 insertions(+), 47 deletions(-)
drivers/net/pppol2tp.c +117 -43
@@ -90,7 +90,9 @@#include <linux/hash.h> #include <linux/sort.h> #include <linux/proc_fs.h> +#include <linux/nsproxy.h> #include <net/net_namespace.h> +#include <net/netns/generic.h> #include <net/dst.h> #include <net/ip.h> #include <net/udp.h>
@@ -204,6 +206,7 @@ struct pppol2tp_tunnelstruct sock *sock;/* Parent socket */ struct list_head list;/* Keep a list of all open * prepared sockets */ +struct net *pppol2tp_net;/* the net we belong to */ atomic_t ref_count; };
@@ -227,8 +230,20 @@ static atomic_t pppol2tp_tunnel_count;static atomic_t pppol2tp_session_count;static struct ppp_channel_ops pppol2tp_chan_ops = { pppol2tp_xmit ,NULL };static struct proto_ops pppol2tp_ops; -static LIST_HEAD (pppol2tp_tunnel_list); -static DEFINE_RWLOCK (pppol2tp_tunnel_list_lock); + +/* per-net private data for this module */ +static unsigned int pppol2tp_net_id; +struct pppol2tp_net { +struct list_head pppol2tp_tunnel_list; +rwlock_t pppol2tp_tunnel_list_lock; +}; + +static inline struct pppol2tp_net *pppol2tp_pernet (struct net *net) +{ +BUG_ON (!net); + +return net_generic (net, pppol2tp_net_id); +}/* Helpers to obtain tunnel/session contexts from sockets. */
@@ -321,18 +336,19 @@ pppol2tp_session_find(struct pppol2tp_tu/* Lookup a tunnel by id */ -static struct pppol2tp_tunnel *pppol2tp_tunnel_find (u16 tunnel_id) +static struct pppol2tp_tunnel *pppol2tp_tunnel_find (struct net *net,u16 tunnel_id) { -struct pppol2tp_tunnel *tunnel =NULL ; +struct pppol2tp_tunnel *tunnel; +struct pppol2tp_net *pn =pppol2tp_pernet (net); -read_lock_bh (&pppol2tp_tunnel_list_lock); -list_for_each_entry (tunnel, &pppol2tp_tunnel_list, list) { +read_lock_bh (&pn->pppol2tp_tunnel_list_lock); +list_for_each_entry (tunnel, &pn->pppol2tp_tunnel_list, list) {if (tunnel->stats.tunnel_id == tunnel_id) { -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return tunnel; } } -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return NULL ; }
@@ -1287,10 +1303,12 @@ again:*/ static void pppol2tp_tunnel_free (struct pppol2tp_tunnel *tunnel) { +struct pppol2tp_net *pn =pppol2tp_pernet (tunnel->pppol2tp_net); +/* Remove from socket list */ -write_lock_bh (&pppol2tp_tunnel_list_lock); +write_lock_bh (&pn->pppol2tp_tunnel_list_lock);list_del_init (&tunnel->list); -write_unlock_bh (&pppol2tp_tunnel_list_lock); +write_unlock_bh (&pn->pppol2tp_tunnel_list_lock);atomic_dec (&pppol2tp_tunnel_count);kfree (tunnel);
@@ -1444,13 +1462,14 @@ error:/* Internal function to prepare a tunnel (UDP) socket to have PPPoX * sockets attached to it. */ -static struct sock *pppol2tp_prepare_tunnel_socket (int fd,u16 tunnel_id, -int *error) +static struct sock *pppol2tp_prepare_tunnel_socket (struct net *net, +int fd,u16 tunnel_id,int *error) {int err;struct socket *sock =NULL ;struct sock *sk;struct pppol2tp_tunnel *tunnel; +struct pppol2tp_net *pn;struct sock *ret =NULL ;/* Get the tunnel UDP socket from the fd, which was opened by
@@ -1524,11 +1543,15 @@ static struct sock *pppol2tp_prepare_tun/* Misc init */ rwlock_init (&tunnel->hlist_lock); +/* The net we belong to */ + tunnel->pppol2tp_net = net; + pn =pppol2tp_pernet (net); +/* Add tunnel to our list */ INIT_LIST_HEAD (&tunnel->list); -write_lock_bh (&pppol2tp_tunnel_list_lock); -list_add (&tunnel->list, &pppol2tp_tunnel_list); -write_unlock_bh (&pppol2tp_tunnel_list_lock); +write_lock_bh (&pn->pppol2tp_tunnel_list_lock); +list_add (&tunnel->list, &pn->pppol2tp_tunnel_list); +write_unlock_bh (&pn->pppol2tp_tunnel_list_lock);atomic_inc (&pppol2tp_tunnel_count);/* Bump the reference count. The tunnel context is deleted
@@ -1629,7 +1652,8 @@ static int pppol2tp_connect(struct socke* tunnel id. */ if ((sp->pppol2tp.s_session ==0 ) && (sp->pppol2tp.d_session ==0 )) { - tunnel_sock =pppol2tp_prepare_tunnel_socket (sp->pppol2tp.fd, + tunnel_sock =pppol2tp_prepare_tunnel_socket (sock_net (sk), + sp->pppol2tp.fd, sp->pppol2tp.s_tunnel, &error);if (tunnel_sock ==NULL )
@@ -1637,7 +1661,7 @@ static int pppol2tp_connect(struct socke tunnel = tunnel_sock->sk_user_data; }else { - tunnel =pppol2tp_tunnel_find (sp->pppol2tp.s_tunnel); + tunnel =pppol2tp_tunnel_find (sock_net (sk), sp->pppol2tp.s_tunnel);/* Error if we can't find the tunnel */ error = -ENOENT ;
@@ -2347,8 +2371,9 @@ end:#include <linux/seq_file.h> struct pppol2tp_seq_data { -struct pppol2tp_tunnel *tunnel;/* current tunnel */ -struct pppol2tp_session *session;/* NULL means get first session in tunnel */ +struct net *seq_net;/* net of inode */ +struct pppol2tp_tunnel *tunnel;/* current tunnel */ +struct pppol2tp_session *session;/* NULL means get first session in tunnel */ };static struct pppol2tp_session *next_session (struct pppol2tp_tunnel *tunnel,struct pppol2tp_session *curr)
@@ -2384,17 +2409,18 @@ out:return session; } -static struct pppol2tp_tunnel *next_tunnel (struct pppol2tp_tunnel *curr) +static struct pppol2tp_tunnel *next_tunnel (struct pppol2tp_net *pn, +struct pppol2tp_tunnel *curr) {struct pppol2tp_tunnel *tunnel =NULL ; -read_lock_bh (&pppol2tp_tunnel_list_lock); -if (list_is_last (&curr->list, &pppol2tp_tunnel_list)) { +read_lock_bh (&pn->pppol2tp_tunnel_list_lock); +if (list_is_last (&curr->list, &pn->pppol2tp_tunnel_list)) { goto out; } tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list); out: -read_unlock_bh (&pppol2tp_tunnel_list_lock); +read_unlock_bh (&pn->pppol2tp_tunnel_list_lock);return tunnel; }
@@ -2402,6 +2428,7 @@ out:static void *pppol2tp_seq_start (struct seq_file *m,loff_t *offs) {struct pppol2tp_seq_data *pd =SEQ_START_TOKEN ; +struct pppol2tp_net *pn;loff_t pos = *offs;if (!pos)
@@ -2409,14 +2436,15 @@ static void *pppol2tp_seq_start(struct sBUG_ON (m->private ==NULL ); pd = m->private; + pn =pppol2tp_pernet (pd->seq_net);if (pd->tunnel ==NULL ) { -if (!list_empty (&pppol2tp_tunnel_list)) - pd->tunnel = list_entry(pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list); +if (!list_empty (&pn->pppol2tp_tunnel_list)) + pd->tunnel = list_entry(pn->pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list); }else { pd->session =next_session (pd->tunnel, pd->session);if (pd->session ==NULL ) { - pd->tunnel =next_tunnel (pd->tunnel); + pd->tunnel =next_tunnel (pn, pd->tunnel); } }
@@ -2532,6 +2560,7 @@ static int pppol2tp_proc_open(struct ino {struct seq_file *m;struct pppol2tp_seq_data *pd; +struct net *net;int ret =0 ; ret =seq_open (file, &pppol2tp_seq_ops);
@@ -2542,12 +2571,15 @@ static int pppol2tp_proc_open(struct ino/* Allocate and fill our proc_data for access later */ ret = -ENOMEM ; - m->private =kzalloc (sizeof (struct pppol2tp_seq_data ),GFP_KERNEL ); + m->private =kzalloc (sizeof (*pd),GFP_KERNEL );if (m->private ==NULL ) goto out; pd = m->private; - ret =0 ; + net =maybe_get_net (PDE_NET (PDE (inode))); +BUG_ON (!net); + pd->seq_net = net; +return 0 ; out:return ret;
@@ -2558,6 +2590,9 @@ out:static int pppol2tp_proc_release (struct inode *inode,struct file *file) {struct seq_file *m = (struct seq_file *)file->private_data; +struct pppol2tp_seq_data *pd = m->private; + +put_net (pd->seq_net);kfree (m->private); m->private =NULL ;
@@ -2573,8 +2608,6 @@ static struct file_operations pppol2tp_p .release = pppol2tp_proc_release, }; -static struct proc_dir_entry *pppol2tp_proc; -#endif /* CONFIG_PROC_FS */ /*****************************************************************************
@@ -2606,6 +2639,57 @@ static struct pppox_proto pppol2tp_proto .ioctl = pppol2tp_ioctl }; +static __net_init int pppol2tp_init_net (struct net *net) +{ +struct pppol2tp_net *pn; +struct proc_dir_entry *pde; +int err; + + pn =kzalloc (sizeof (*pn),GFP_KERNEL ); +if (!pn) +return -ENOMEM ; + +INIT_LIST_HEAD (&pn->pppol2tp_tunnel_list); +rwlock_init (&pn->pppol2tp_tunnel_list_lock); + + err =net_assign_generic (net, pppol2tp_net_id, pn); +if (err) + goto out; + + pde =proc_net_fops_create (net,"pppol2tp" ,S_IRUGO , &pppol2tp_proc_fops); +#ifdef CONFIG_PROC_FS +if (!pde) { + err = -ENOMEM ; + goto out; + } +#endif + +return 0 ; + +out: +kfree (pn); +return err; +} + +static __net_exit void pppol2tp_exit_net(struct net *net) +{ +struct pppoe_net *pn; + +proc_net_remove (net,"pppol2tp" ); + pn =net_generic (net, pppol2tp_net_id); +/* +* if someone has cached our net then +* further net_generic call will return NULL +*/ +net_assign_generic (net, pppol2tp_net_id,NULL ); +kfree (pn); +} + +static __net_initdata struct pernet_operations pppol2tp_net_ops = { + .init = pppol2tp_init_net, + .exit = pppol2tp_exit_net, +}; +static int __init pppol2tp_init (void ) {int err;
@@ -2617,23 +2701,17 @@ static int __init pppol2tp_init(void)if (err) goto out_unregister_pppol2tp_proto; -#ifdef CONFIG_PROC_FS - pppol2tp_proc =proc_net_fops_create (&init_net,"pppol2tp" ,0 , - &pppol2tp_proc_fops); -if (!pppol2tp_proc) { - err = -ENOMEM ; + err =register_pernet_gen_device (&pppol2tp_net_id, &pppol2tp_net_ops); +if (err) goto out_unregister_pppox_proto; - } -#endif /* CONFIG_PROC_FS */ +printk (KERN_INFO "PPPoL2TP kernel driver, %s\n" ,PPPOL2TP_DRV_VERSION ); out:return err; -#ifdef CONFIG_PROC_FS out_unregister_pppox_proto:unregister_pppox_proto (PX_PROTO_OL2TP ); -#endif out_unregister_pppol2tp_proto:proto_unregister (&pppol2tp_sk_proto); goto out;
@@ -2642,10 +2720,6 @@ out_unregister_pppol2tp_proto: static void __exit pppol2tp_exit(void) {unregister_pppox_proto (PX_PROTO_OL2TP ); - -#ifdef CONFIG_PROC_FS -remove_proc_entry ("pppol2tp" , init_net.proc_net); -#endif proto_unregister (&pppol2tp_sk_proto); }
drivers/net/pppox.c +0 -4
@@ -111,10 +111,6 @@ static int pppox_create(struct net *net,if (protocol <0 || protocol >PX_MAX_PROTO ) goto out; -/* we support net-namespaces for PPPoE only (yet) */ -if (protocol !=PX_PROTO_OE && net != &init_net) -return -EAFNOSUPPORT ; - rc = -EPROTONOSUPPORT ;if (!pppox_protos[protocol])request_module ("pppox-proto-%d" , protocol);
PATCH 4/5 net: ppp_generic - introduce net-namespace functionality v2
In reply to a message not in the archive- Each namespace contains ppp channels and units separately with appropriate locks
--- drivers/net/ppp_generic.c | 275 +++++++++++++++++++++++++++++++------------- include/linux/ppp_channel.h | 4 2 files changed, 202 insertions(+), 77 deletions(-)
drivers/net/ppp_generic.c +198 -77
@@ -49,6 +49,10 @@#include <net/slhc_vj.h> #include <asm/atomic.h> +#include <linux/nsproxy.h> +#include <net/net_namespace.h> +#include <net/netns/generic.h> +#define PPP_VERSION "2.4.2"/*
@@ -131,6 +135,7 @@ struct ppp {struct sock_filter *active_filter;/* filter for pkts to reset idle */ unsigned pass_len, active_len;#endif /* CONFIG_PPP_FILTER */ +struct net *ppp_net;/* the net we belong to */ };/*
@@ -155,6 +160,7 @@ struct channel {struct rw_semaphore chan_sem;/* protects `chan' during chan ioctl */ spinlock_t downl;/* protects `chan', file.xq dequeue */ struct ppp *ppp;/* ppp unit we're connected to */ +struct net *chan_net;/* the net channel belongs to */ struct list_head clist;/* link in list of channels per unit */ rwlock_t upl;/* protects `ppp' */ #ifdef CONFIG_PPP_MULTILINK
@@ -173,26 +179,35 @@ struct channel {* channel.downl. */ -/* -* all_ppp_mutex protects the all_ppp_units mapping. -* It also ensures that finding a ppp unit in the all_ppp_units map -* and updating its file.refcnt field is atomic. -*/ -static DEFINE_MUTEX (all_ppp_mutex);static atomic_t ppp_unit_count =ATOMIC_INIT (0 ); -static DEFINE_IDR (ppp_units_idr); - -/* -* all_channels_lock protects all_channels and last_channel_index, -* and the atomicity of find a channel and updating its file.refcnt -* field. -*/ -static DEFINE_SPINLOCK (all_channels_lock); -static LIST_HEAD (all_channels); -static LIST_HEAD (new_channels); -static int last_channel_index;static atomic_t channel_count =ATOMIC_INIT (0 ); +/* per-net private data for this module */ +static unsigned int ppp_net_id; +struct ppp_net { +/* units to ppp mapping */ +struct idr units_idr; + +/* +* all_ppp_mutex protects the units_idr mapping. +* It also ensures that finding a ppp unit in the units_idr +* map and updating its file.refcnt field is atomic. +*/ +struct mutex all_ppp_mutex; + +/* channels */ +struct list_head all_channels; +struct list_head new_channels; +int last_channel_index; + +/* +* all_channels_lock protects all_channels and +* last_channel_index, and the atomicity of find +* a channel and updating its file.refcnt field. +*/ +spinlock_t all_channels_lock; +}; +/* Get the PPP protocol number from a skb */ #define PPP_PROTO (skb) (((skb)->data[0] << 8) + (skb)->data[1])
@@ -216,8 +231,8 @@ static atomic_t channel_count = ATOMIC_I#define seq_after (a, b) ((s32)((a) - (b)) > 0)/* Prototypes. */ -static int ppp_unattached_ioctl (struct ppp_file *pf,struct file *file, -unsigned int cmd,unsigned long arg); +static int ppp_unattached_ioctl (struct net *net,struct ppp_file *pf, +struct file *file,unsigned int cmd,unsigned long arg);static void ppp_xmit_process (struct ppp *ppp);static void ppp_send_frame (struct ppp *ppp,struct sk_buff *skb);static void ppp_push (struct ppp *ppp);
@@ -240,12 +255,12 @@ static void ppp_ccp_peek(struct ppp *pppstatic void ppp_ccp_closed (struct ppp *ppp);static struct compressor *find_compressor (int type);static void ppp_get_stats (struct ppp *ppp,struct ppp_stats *st); -static struct ppp *ppp_create_interface (int unit,int *retp); +static struct ppp *ppp_create_interface (struct net *net,int unit,int *retp);static void init_ppp_file (struct ppp_file *pf,int kind);static void ppp_shutdown_interface (struct ppp *ppp);static void ppp_destroy_interface (struct ppp *ppp); -static struct ppp *ppp_find_unit (int unit); -static struct channel *ppp_find_channel (int unit); +static struct ppp *ppp_find_unit (struct ppp_net *pn,int unit); +static struct channel *ppp_find_channel (struct ppp_net *pn,int unit);static int ppp_connect_channel (struct channel *pch,int unit);static int ppp_disconnect_channel (struct channel *pch);static void ppp_destroy_channel (struct channel *pch);
@@ -256,6 +271,14 @@ static void *unit_find(struct idr *p, instatic struct class *ppp_class; +/* per net-namespace data */ +static inline struct ppp_net *ppp_pernet (struct net *net) +{ +BUG_ON (!net); + +return net_generic (net, ppp_net_id); +} +/* Translates a PPP protocol number to a NP index (NP == network protocol) */ static inline int proto_to_npindex (int proto) {
@@ -544,7 +567,8 @@ static long ppp_ioctl(struct file *file,int __user *p = argp;if (!pf) -return ppp_unattached_ioctl (pf, file, cmd, arg); +return ppp_unattached_ioctl (current->nsproxy->net_ns, + pf, file, cmd, arg);if (cmd ==PPPIOCDETACH ) {/*
@@ -763,12 +787,13 @@ static long ppp_ioctl(struct file *file,return err; } -static int ppp_unattached_ioctl (struct ppp_file *pf,struct file *file, -unsigned int cmd,unsigned long arg) +static int ppp_unattached_ioctl (struct net *net,struct ppp_file *pf, +struct file *file,unsigned int cmd,unsigned long arg) {int unit, err = -EFAULT ;struct ppp *ppp;struct channel *chan; +struct ppp_net *pn;int __user *p = (int __user *)arg;lock_kernel ();
@@ -777,7 +802,7 @@ static int ppp_unattached_ioctl(struct p/* Create a new ppp unit */ if (get_user (unit, p))break ; - ppp =ppp_create_interface (unit, &err); + ppp =ppp_create_interface (net, unit, &err);if (!ppp)break ; file->private_data = &ppp->file;
@@ -792,29 +817,31 @@ static int ppp_unattached_ioctl(struct p/* Attach to an existing ppp unit */ if (get_user (unit, p))break ; -mutex_lock (&all_ppp_mutex); err = -ENXIO ; - ppp =ppp_find_unit (unit); + pn =ppp_pernet (net); +mutex_lock (&pn->all_ppp_mutex); + ppp =ppp_find_unit (pn, unit);if (ppp) {atomic_inc (&ppp->file.refcnt); file->private_data = &ppp->file; err =0 ; } -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex);break ;case PPPIOCATTCHAN :if (get_user (unit, p))break ; -spin_lock_bh (&all_channels_lock); err = -ENXIO ; - chan =ppp_find_channel (unit); + pn =ppp_pernet (net); +spin_lock_bh (&pn->all_channels_lock); + chan =ppp_find_channel (pn, unit);if (chan) {atomic_inc (&chan->file.refcnt); file->private_data = &chan->file; err =0 ; } -spin_unlock_bh (&all_channels_lock); +spin_unlock_bh (&pn->all_channels_lock);break ;default :
@@ -834,6 +861,51 @@ static const struct file_operations ppp_ .release = ppp_release }; +static __net_init int ppp_init_net (struct net *net) +{ +struct ppp_net *pn; +int err; + + pn =kzalloc (sizeof (*pn),GFP_KERNEL ); +if (!pn) +return -ENOMEM ; + +idr_init (&pn->units_idr); +mutex_init (&pn->all_ppp_mutex); + +INIT_LIST_HEAD (&pn->all_channels); +INIT_LIST_HEAD (&pn->new_channels); + +spin_lock_init (&pn->all_channels_lock); + + err =net_assign_generic (net, ppp_net_id, pn); +if (err) { +kfree (pn); +return err; + } + +return 0 ; +} + +static __net_exit void ppp_exit_net(struct net *net) +{ +struct ppp_net *pn; + + pn =net_generic (net, ppp_net_id); +idr_destroy (&pn->units_idr); +/* +* if someone has cached our net then +* further net_generic call will return NULL +*/ +net_assign_generic (net, ppp_net_id,NULL ); +kfree (pn); +} + +static __net_initdata struct pernet_operations ppp_net_ops = { + .init = ppp_init_net, + .exit = ppp_exit_net, +}; +#define PPP_MAJOR 108/* Called at boot time if ppp is compiled into the kernel,
@@ -843,25 +915,36 @@ static int __init ppp_init(void)int err;printk (KERN_INFO "PPP generic driver version " PPP_VERSION "\n" ); - err =register_chrdev (PPP_MAJOR ,"ppp" , &ppp_device_fops); -if (!err) { - ppp_class =class_create (THIS_MODULE ,"ppp" ); -if (IS_ERR (ppp_class)) { - err =PTR_ERR (ppp_class); - goto out_chrdev; - } -device_create (ppp_class,NULL ,MKDEV (PPP_MAJOR ,0 ),NULL , -"ppp" ); + + err =register_pernet_gen_device (&ppp_net_id, &ppp_net_ops); +if (err) { +printk (KERN_ERR "failed to register PPP pernet device (%d)\n" , err); + goto out; } -out: -if (err) + err =register_chrdev (PPP_MAJOR ,"ppp" , &ppp_device_fops); +if (err) {printk (KERN_ERR "failed to register PPP device (%d)\n" , err); -return err; + goto out_net; + } + + ppp_class =class_create (THIS_MODULE ,"ppp" ); +if (IS_ERR (ppp_class)) { + err =PTR_ERR (ppp_class); + goto out_chrdev; + } + +/* not a big deal if we fail here :-) */ +device_create (ppp_class,NULL ,MKDEV (PPP_MAJOR ,0 ),NULL ,"ppp" ); + +return 0 ; out_chrdev:unregister_chrdev (PPP_MAJOR ,"ppp" ); - goto out; +out_net: +unregister_pernet_gen_device (ppp_net_id, &ppp_net_ops); +out: +return err; }/*
@@ -969,6 +1052,7 @@ static void ppp_setup(struct net_device dev->tx_queue_len =3 ; dev->type =ARPHRD_PPP ; dev->flags =IFF_POINTOPOINT |IFF_NOARP |IFF_MULTICAST ; + dev->features |=NETIF_F_NETNS_LOCAL ; }/*
@@ -1986,19 +2070,27 @@ ppp_mp_reconstruct(struct ppp *ppp)* Channel interface. */ -/* -* Create a new, unattached ppp channel. -*/ -int -ppp_register_channel (struct ppp_channel *chan) +/* Create a new, unattached ppp channel. */ +int ppp_register_channel (struct ppp_channel *chan) +{ +return ppp_register_net_channel (current->nsproxy->net_ns, chan); +} + +/* Create a new, unattached ppp channel for specified net. */ +int ppp_register_net_channel (struct net *net,struct ppp_channel *chan) {struct channel *pch; +struct ppp_net *pn; pch =kzalloc (sizeof (struct channel ),GFP_KERNEL );if (!pch)return -ENOMEM ; + + pn =ppp_pernet (net); + pch->ppp =NULL ; pch->chan = chan; + pch->chan_net = net; chan->ppp = pch;init_ppp_file (&pch->file,CHANNEL ); pch->file.hdrlen = chan->hdrlen;
@@ -2008,11 +2100,13 @@ ppp_register_channel(struct ppp_channelinit_rwsem (&pch->chan_sem);spin_lock_init (&pch->downl);rwlock_init (&pch->upl); -spin_lock_bh (&all_channels_lock); - pch->file.index = ++last_channel_index; -list_add (&pch->list, &new_channels); + +spin_lock_bh (&pn->all_channels_lock); + pch->file.index = ++pn->last_channel_index; +list_add (&pch->list, &pn->new_channels);atomic_inc (&channel_count); -spin_unlock_bh (&all_channels_lock); +spin_unlock_bh (&pn->all_channels_lock); +return 0 ; }
@@ -2053,9 +2147,11 @@ void ppp_unregister_channel(struct ppp_channel *chan) {struct channel *pch = chan->ppp; +struct ppp_net *pn;if (!pch)return ;/* should never happen */ + chan->ppp =NULL ;/*
@@ -2068,9 +2164,12 @@ ppp_unregister_channel(struct ppp_channespin_unlock_bh (&pch->downl);up_write (&pch->chan_sem);ppp_disconnect_channel (pch); -spin_lock_bh (&all_channels_lock); + + pn =ppp_pernet (pch->chan_net); +spin_lock_bh (&pn->all_channels_lock);list_del (&pch->list); -spin_unlock_bh (&all_channels_lock); +spin_unlock_bh (&pn->all_channels_lock); + pch->file.dead =1 ;wake_up_interruptible (&pch->file.rwait);if (atomic_dec_and_test (&pch->file.refcnt))
@@ -2395,9 +2494,10 @@ ppp_get_stats(struct ppp *ppp, struct pp* unit == -1 means allocate a new number. */ static struct ppp * -ppp_create_interface (int unit,int *retp) +ppp_create_interface (struct net *net,int unit,int *retp) {struct ppp *ppp; +struct ppp_net *pn;struct net_device *dev =NULL ;int ret = -ENOMEM ;int i;
@@ -2406,6 +2506,8 @@ ppp_create_interface(int unit, int *retpif (!dev) goto out1; + pn =ppp_pernet (net); + ppp =netdev_priv (dev); ppp->dev = dev; ppp->mru =PPP_MRU ;
@@ -2421,17 +2523,23 @@ ppp_create_interface(int unit, int *retpskb_queue_head_init (&ppp->mrq);#endif /* CONFIG_PPP_MULTILINK */ +/* +* drum roll: don't forget to set +* the net device is belong to +*/ +dev_net_set (dev, net); + ret = -EEXIST ; -mutex_lock (&all_ppp_mutex); +mutex_lock (&pn->all_ppp_mutex);if (unit <0 ) { - unit =unit_get (&ppp_units_idr, ppp); + unit =unit_get (&pn->units_idr, ppp);if (unit <0 ) { *retp = unit; goto out2; } }else { -if (unit_find (&ppp_units_idr, unit)) +if (unit_find (&pn->units_idr, unit)) goto out2;/* unit already exists */ /* * if caller need a specified unit number
@@ -2442,7 +2550,7 @@ ppp_create_interface(int unit, int *retp* fair but at least pppd will ask us to allocate * new unit in this case so user is happy :) */ - unit =unit_set (&ppp_units_idr, ppp, unit); + unit =unit_set (&pn->units_idr, ppp, unit);if (unit <0 ) goto out2; }
@@ -2453,20 +2561,22 @@ ppp_create_interface(int unit, int *retp ret =register_netdev (dev);if (ret !=0 ) { -unit_put (&ppp_units_idr, unit); +unit_put (&pn->units_idr, unit);printk (KERN_ERR "PPP: couldn't register device %s (%d)\n" , dev->name, ret); goto out2; } + ppp->ppp_net = net; +atomic_inc (&ppp_unit_count); -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex); *retp =0 ;return ppp; out2: -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex);free_netdev (dev); out1: *retp = ret;
@@ -2492,7 +2602,11 @@ init_ppp_file(struct ppp_file *pf, int k*/ static void ppp_shutdown_interface (struct ppp *ppp) { -mutex_lock (&all_ppp_mutex); +struct ppp_net *pn; + + pn =ppp_pernet (ppp->ppp_net); +mutex_lock (&pn->all_ppp_mutex); +/* This will call dev_close() for us. */ ppp_lock (ppp);if (!ppp->closing) {
@@ -2502,11 +2616,12 @@ static void ppp_shutdown_interface(struc }else ppp_unlock (ppp); -unit_put (&ppp_units_idr, ppp->file.index); +unit_put (&pn->units_idr, ppp->file.index); ppp->file.dead =1 ; ppp->owner =NULL ;wake_up_interruptible (&ppp->file.rwait); -mutex_unlock (&all_ppp_mutex); + +mutex_unlock (&pn->all_ppp_mutex); }/*
@@ -2554,9 +2669,9 @@ static void ppp_destroy_interface(struct* The caller should have locked the all_ppp_mutex. */ static struct ppp * -ppp_find_unit (int unit) +ppp_find_unit (struct ppp_net *pn,int unit) { -return unit_find (&ppp_units_idr, unit); +return unit_find (&pn->units_idr, unit); }/*
@@ -2568,20 +2683,22 @@ ppp_find_unit(int unit)* when we have a lot of channels in use. */ static struct channel * -ppp_find_channel (int unit) +ppp_find_channel (struct ppp_net *pn,int unit) {struct channel *pch; -list_for_each_entry (pch, &new_channels, list) { +list_for_each_entry (pch, &pn->new_channels, list) {if (pch->file.index == unit) { -list_move (&pch->list, &all_channels); +list_move (&pch->list, &pn->all_channels);return pch; } } -list_for_each_entry (pch, &all_channels, list) { + +list_for_each_entry (pch, &pn->all_channels, list) {if (pch->file.index == unit)return pch; } +return NULL ; }
@@ -2592,11 +2709,14 @@ static int ppp_connect_channel(struct channel *pch, int unit) {struct ppp *ppp; +struct ppp_net *pn;int ret = -ENXIO ;int hdrlen; -mutex_lock (&all_ppp_mutex); - ppp =ppp_find_unit (unit); + pn =ppp_pernet (pch->chan_net); + +mutex_lock (&pn->all_ppp_mutex); + ppp =ppp_find_unit (pn, unit);if (!ppp) goto out;write_lock_bh (&pch->upl);
@@ -2620,7 +2740,7 @@ ppp_connect_channel(struct channel *pch, outl:write_unlock_bh (&pch->upl); out: -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex);return ret; }
@@ -2677,7 +2797,7 @@ static void __exit ppp_cleanup(void)unregister_chrdev (PPP_MAJOR ,"ppp" );device_destroy (ppp_class,MKDEV (PPP_MAJOR ,0 ));class_destroy (ppp_class); -idr_destroy (&ppp_units_idr); +unregister_pernet_gen_device (ppp_net_id, &ppp_net_ops); }/*
@@ -2743,6 +2863,7 @@ static void *unit_find(struct idr *p, inmodule_init (ppp_init);module_exit (ppp_cleanup); +EXPORT_SYMBOL (ppp_register_net_channel);EXPORT_SYMBOL (ppp_register_channel);EXPORT_SYMBOL (ppp_unregister_channel);EXPORT_SYMBOL (ppp_channel_index);
include/linux/ppp_channel.h +4 -0
@@ -22,6 +22,7 @@#include <linux/list.h> #include <linux/skbuff.h> #include <linux/poll.h> +#include <net/net_namespace.h> struct ppp_channel ;
@@ -56,6 +57,9 @@ extern void ppp_input(struct ppp_channelthat we may have missed a packet. */ extern void ppp_input_error (struct ppp_channel *,int code); +/* Attach a channel to a given PPP unit in specified net. */ +extern int ppp_register_net_channel (struct net *,struct ppp_channel *); +/* Attach a channel to a given PPP unit. */ extern int ppp_register_channel (struct ppp_channel *);
PATCH 4/5 net: ppp_generic - introduce net-namespace functionality v2
In reply to a message not in the archive- Each namespace contains ppp channels and units separately with appropriate locks
--- drivers/net/ppp_generic.c | 275 +++++++++++++++++++++++++++++++------------- include/linux/ppp_channel.h | 4 2 files changed, 202 insertions(+), 77 deletions(-)
drivers/net/ppp_generic.c +198 -77
@@ -49,6 +49,10 @@#include <net/slhc_vj.h> #include <asm/atomic.h> +#include <linux/nsproxy.h> +#include <net/net_namespace.h> +#include <net/netns/generic.h> +#define PPP_VERSION "2.4.2"/*
@@ -131,6 +135,7 @@ struct ppp {struct sock_filter *active_filter;/* filter for pkts to reset idle */ unsigned pass_len, active_len;#endif /* CONFIG_PPP_FILTER */ +struct net *ppp_net;/* the net we belong to */ };/*
@@ -155,6 +160,7 @@ struct channel {struct rw_semaphore chan_sem;/* protects `chan' during chan ioctl */ spinlock_t downl;/* protects `chan', file.xq dequeue */ struct ppp *ppp;/* ppp unit we're connected to */ +struct net *chan_net;/* the net channel belongs to */ struct list_head clist;/* link in list of channels per unit */ rwlock_t upl;/* protects `ppp' */ #ifdef CONFIG_PPP_MULTILINK
@@ -173,26 +179,35 @@ struct channel {* channel.downl. */ -/* -* all_ppp_mutex protects the all_ppp_units mapping. -* It also ensures that finding a ppp unit in the all_ppp_units map -* and updating its file.refcnt field is atomic. -*/ -static DEFINE_MUTEX (all_ppp_mutex);static atomic_t ppp_unit_count =ATOMIC_INIT (0 ); -static DEFINE_IDR (ppp_units_idr); - -/* -* all_channels_lock protects all_channels and last_channel_index, -* and the atomicity of find a channel and updating its file.refcnt -* field. -*/ -static DEFINE_SPINLOCK (all_channels_lock); -static LIST_HEAD (all_channels); -static LIST_HEAD (new_channels); -static int last_channel_index;static atomic_t channel_count =ATOMIC_INIT (0 ); +/* per-net private data for this module */ +static unsigned int ppp_net_id; +struct ppp_net { +/* units to ppp mapping */ +struct idr units_idr; + +/* +* all_ppp_mutex protects the units_idr mapping. +* It also ensures that finding a ppp unit in the units_idr +* map and updating its file.refcnt field is atomic. +*/ +struct mutex all_ppp_mutex; + +/* channels */ +struct list_head all_channels; +struct list_head new_channels; +int last_channel_index; + +/* +* all_channels_lock protects all_channels and +* last_channel_index, and the atomicity of find +* a channel and updating its file.refcnt field. +*/ +spinlock_t all_channels_lock; +}; +/* Get the PPP protocol number from a skb */ #define PPP_PROTO (skb) (((skb)->data[0] << 8) + (skb)->data[1])
@@ -216,8 +231,8 @@ static atomic_t channel_count = ATOMIC_I#define seq_after (a, b) ((s32)((a) - (b)) > 0)/* Prototypes. */ -static int ppp_unattached_ioctl (struct ppp_file *pf,struct file *file, -unsigned int cmd,unsigned long arg); +static int ppp_unattached_ioctl (struct net *net,struct ppp_file *pf, +struct file *file,unsigned int cmd,unsigned long arg);static void ppp_xmit_process (struct ppp *ppp);static void ppp_send_frame (struct ppp *ppp,struct sk_buff *skb);static void ppp_push (struct ppp *ppp);
@@ -240,12 +255,12 @@ static void ppp_ccp_peek(struct ppp *pppstatic void ppp_ccp_closed (struct ppp *ppp);static struct compressor *find_compressor (int type);static void ppp_get_stats (struct ppp *ppp,struct ppp_stats *st); -static struct ppp *ppp_create_interface (int unit,int *retp); +static struct ppp *ppp_create_interface (struct net *net,int unit,int *retp);static void init_ppp_file (struct ppp_file *pf,int kind);static void ppp_shutdown_interface (struct ppp *ppp);static void ppp_destroy_interface (struct ppp *ppp); -static struct ppp *ppp_find_unit (int unit); -static struct channel *ppp_find_channel (int unit); +static struct ppp *ppp_find_unit (struct ppp_net *pn,int unit); +static struct channel *ppp_find_channel (struct ppp_net *pn,int unit);static int ppp_connect_channel (struct channel *pch,int unit);static int ppp_disconnect_channel (struct channel *pch);static void ppp_destroy_channel (struct channel *pch);
@@ -256,6 +271,14 @@ static void *unit_find(struct idr *p, instatic struct class *ppp_class; +/* per net-namespace data */ +static inline struct ppp_net *ppp_pernet (struct net *net) +{ +BUG_ON (!net); + +return net_generic (net, ppp_net_id); +} +/* Translates a PPP protocol number to a NP index (NP == network protocol) */ static inline int proto_to_npindex (int proto) {
@@ -544,7 +567,8 @@ static long ppp_ioctl(struct file *file,int __user *p = argp;if (!pf) -return ppp_unattached_ioctl (pf, file, cmd, arg); +return ppp_unattached_ioctl (current->nsproxy->net_ns, + pf, file, cmd, arg);if (cmd ==PPPIOCDETACH ) {/*
@@ -763,12 +787,13 @@ static long ppp_ioctl(struct file *file,return err; } -static int ppp_unattached_ioctl (struct ppp_file *pf,struct file *file, -unsigned int cmd,unsigned long arg) +static int ppp_unattached_ioctl (struct net *net,struct ppp_file *pf, +struct file *file,unsigned int cmd,unsigned long arg) {int unit, err = -EFAULT ;struct ppp *ppp;struct channel *chan; +struct ppp_net *pn;int __user *p = (int __user *)arg;lock_kernel ();
@@ -777,7 +802,7 @@ static int ppp_unattached_ioctl(struct p/* Create a new ppp unit */ if (get_user (unit, p))break ; - ppp =ppp_create_interface (unit, &err); + ppp =ppp_create_interface (net, unit, &err);if (!ppp)break ; file->private_data = &ppp->file;
@@ -792,29 +817,31 @@ static int ppp_unattached_ioctl(struct p/* Attach to an existing ppp unit */ if (get_user (unit, p))break ; -mutex_lock (&all_ppp_mutex); err = -ENXIO ; - ppp =ppp_find_unit (unit); + pn =ppp_pernet (net); +mutex_lock (&pn->all_ppp_mutex); + ppp =ppp_find_unit (pn, unit);if (ppp) {atomic_inc (&ppp->file.refcnt); file->private_data = &ppp->file; err =0 ; } -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex);break ;case PPPIOCATTCHAN :if (get_user (unit, p))break ; -spin_lock_bh (&all_channels_lock); err = -ENXIO ; - chan =ppp_find_channel (unit); + pn =ppp_pernet (net); +spin_lock_bh (&pn->all_channels_lock); + chan =ppp_find_channel (pn, unit);if (chan) {atomic_inc (&chan->file.refcnt); file->private_data = &chan->file; err =0 ; } -spin_unlock_bh (&all_channels_lock); +spin_unlock_bh (&pn->all_channels_lock);break ;default :
@@ -834,6 +861,51 @@ static const struct file_operations ppp_ .release = ppp_release }; +static __net_init int ppp_init_net (struct net *net) +{ +struct ppp_net *pn; +int err; + + pn =kzalloc (sizeof (*pn),GFP_KERNEL ); +if (!pn) +return -ENOMEM ; + +idr_init (&pn->units_idr); +mutex_init (&pn->all_ppp_mutex); + +INIT_LIST_HEAD (&pn->all_channels); +INIT_LIST_HEAD (&pn->new_channels); + +spin_lock_init (&pn->all_channels_lock); + + err =net_assign_generic (net, ppp_net_id, pn); +if (err) { +kfree (pn); +return err; + } + +return 0 ; +} + +static __net_exit void ppp_exit_net(struct net *net) +{ +struct ppp_net *pn; + + pn =net_generic (net, ppp_net_id); +idr_destroy (&pn->units_idr); +/* +* if someone has cached our net then +* further net_generic call will return NULL +*/ +net_assign_generic (net, ppp_net_id,NULL ); +kfree (pn); +} + +static __net_initdata struct pernet_operations ppp_net_ops = { + .init = ppp_init_net, + .exit = ppp_exit_net, +}; +#define PPP_MAJOR 108/* Called at boot time if ppp is compiled into the kernel,
@@ -843,25 +915,36 @@ static int __init ppp_init(void)int err;printk (KERN_INFO "PPP generic driver version " PPP_VERSION "\n" ); - err =register_chrdev (PPP_MAJOR ,"ppp" , &ppp_device_fops); -if (!err) { - ppp_class =class_create (THIS_MODULE ,"ppp" ); -if (IS_ERR (ppp_class)) { - err =PTR_ERR (ppp_class); - goto out_chrdev; - } -device_create (ppp_class,NULL ,MKDEV (PPP_MAJOR ,0 ),NULL , -"ppp" ); + + err =register_pernet_gen_device (&ppp_net_id, &ppp_net_ops); +if (err) { +printk (KERN_ERR "failed to register PPP pernet device (%d)\n" , err); + goto out; } -out: -if (err) + err =register_chrdev (PPP_MAJOR ,"ppp" , &ppp_device_fops); +if (err) {printk (KERN_ERR "failed to register PPP device (%d)\n" , err); -return err; + goto out_net; + } + + ppp_class =class_create (THIS_MODULE ,"ppp" ); +if (IS_ERR (ppp_class)) { + err =PTR_ERR (ppp_class); + goto out_chrdev; + } + +/* not a big deal if we fail here :-) */ +device_create (ppp_class,NULL ,MKDEV (PPP_MAJOR ,0 ),NULL ,"ppp" ); + +return 0 ; out_chrdev:unregister_chrdev (PPP_MAJOR ,"ppp" ); - goto out; +out_net: +unregister_pernet_gen_device (ppp_net_id, &ppp_net_ops); +out: +return err; }/*
@@ -969,6 +1052,7 @@ static void ppp_setup(struct net_device dev->tx_queue_len =3 ; dev->type =ARPHRD_PPP ; dev->flags =IFF_POINTOPOINT |IFF_NOARP |IFF_MULTICAST ; + dev->features |=NETIF_F_NETNS_LOCAL ; }/*
@@ -1986,19 +2070,27 @@ ppp_mp_reconstruct(struct ppp *ppp)* Channel interface. */ -/* -* Create a new, unattached ppp channel. -*/ -int -ppp_register_channel (struct ppp_channel *chan) +/* Create a new, unattached ppp channel. */ +int ppp_register_channel (struct ppp_channel *chan) +{ +return ppp_register_net_channel (current->nsproxy->net_ns, chan); +} + +/* Create a new, unattached ppp channel for specified net. */ +int ppp_register_net_channel (struct net *net,struct ppp_channel *chan) {struct channel *pch; +struct ppp_net *pn; pch =kzalloc (sizeof (struct channel ),GFP_KERNEL );if (!pch)return -ENOMEM ; + + pn =ppp_pernet (net); + pch->ppp =NULL ; pch->chan = chan; + pch->chan_net = net; chan->ppp = pch;init_ppp_file (&pch->file,CHANNEL ); pch->file.hdrlen = chan->hdrlen;
@@ -2008,11 +2100,13 @@ ppp_register_channel(struct ppp_channelinit_rwsem (&pch->chan_sem);spin_lock_init (&pch->downl);rwlock_init (&pch->upl); -spin_lock_bh (&all_channels_lock); - pch->file.index = ++last_channel_index; -list_add (&pch->list, &new_channels); + +spin_lock_bh (&pn->all_channels_lock); + pch->file.index = ++pn->last_channel_index; +list_add (&pch->list, &pn->new_channels);atomic_inc (&channel_count); -spin_unlock_bh (&all_channels_lock); +spin_unlock_bh (&pn->all_channels_lock); +return 0 ; }
@@ -2053,9 +2147,11 @@ void ppp_unregister_channel(struct ppp_channel *chan) {struct channel *pch = chan->ppp; +struct ppp_net *pn;if (!pch)return ;/* should never happen */ + chan->ppp =NULL ;/*
@@ -2068,9 +2164,12 @@ ppp_unregister_channel(struct ppp_channespin_unlock_bh (&pch->downl);up_write (&pch->chan_sem);ppp_disconnect_channel (pch); -spin_lock_bh (&all_channels_lock); + + pn =ppp_pernet (pch->chan_net); +spin_lock_bh (&pn->all_channels_lock);list_del (&pch->list); -spin_unlock_bh (&all_channels_lock); +spin_unlock_bh (&pn->all_channels_lock); + pch->file.dead =1 ;wake_up_interruptible (&pch->file.rwait);if (atomic_dec_and_test (&pch->file.refcnt))
@@ -2395,9 +2494,10 @@ ppp_get_stats(struct ppp *ppp, struct pp* unit == -1 means allocate a new number. */ static struct ppp * -ppp_create_interface (int unit,int *retp) +ppp_create_interface (struct net *net,int unit,int *retp) {struct ppp *ppp; +struct ppp_net *pn;struct net_device *dev =NULL ;int ret = -ENOMEM ;int i;
@@ -2406,6 +2506,8 @@ ppp_create_interface(int unit, int *retpif (!dev) goto out1; + pn =ppp_pernet (net); + ppp =netdev_priv (dev); ppp->dev = dev; ppp->mru =PPP_MRU ;
@@ -2421,17 +2523,23 @@ ppp_create_interface(int unit, int *retpskb_queue_head_init (&ppp->mrq);#endif /* CONFIG_PPP_MULTILINK */ +/* +* drum roll: don't forget to set +* the net device is belong to +*/ +dev_net_set (dev, net); + ret = -EEXIST ; -mutex_lock (&all_ppp_mutex); +mutex_lock (&pn->all_ppp_mutex);if (unit <0 ) { - unit =unit_get (&ppp_units_idr, ppp); + unit =unit_get (&pn->units_idr, ppp);if (unit <0 ) { *retp = unit; goto out2; } }else { -if (unit_find (&ppp_units_idr, unit)) +if (unit_find (&pn->units_idr, unit)) goto out2;/* unit already exists */ /* * if caller need a specified unit number
@@ -2442,7 +2550,7 @@ ppp_create_interface(int unit, int *retp* fair but at least pppd will ask us to allocate * new unit in this case so user is happy :) */ - unit =unit_set (&ppp_units_idr, ppp, unit); + unit =unit_set (&pn->units_idr, ppp, unit);if (unit <0 ) goto out2; }
@@ -2453,20 +2561,22 @@ ppp_create_interface(int unit, int *retp ret =register_netdev (dev);if (ret !=0 ) { -unit_put (&ppp_units_idr, unit); +unit_put (&pn->units_idr, unit);printk (KERN_ERR "PPP: couldn't register device %s (%d)\n" , dev->name, ret); goto out2; } + ppp->ppp_net = net; +atomic_inc (&ppp_unit_count); -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex); *retp =0 ;return ppp; out2: -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex);free_netdev (dev); out1: *retp = ret;
@@ -2492,7 +2602,11 @@ init_ppp_file(struct ppp_file *pf, int k*/ static void ppp_shutdown_interface (struct ppp *ppp) { -mutex_lock (&all_ppp_mutex); +struct ppp_net *pn; + + pn =ppp_pernet (ppp->ppp_net); +mutex_lock (&pn->all_ppp_mutex); +/* This will call dev_close() for us. */ ppp_lock (ppp);if (!ppp->closing) {
@@ -2502,11 +2616,12 @@ static void ppp_shutdown_interface(struc }else ppp_unlock (ppp); -unit_put (&ppp_units_idr, ppp->file.index); +unit_put (&pn->units_idr, ppp->file.index); ppp->file.dead =1 ; ppp->owner =NULL ;wake_up_interruptible (&ppp->file.rwait); -mutex_unlock (&all_ppp_mutex); + +mutex_unlock (&pn->all_ppp_mutex); }/*
@@ -2554,9 +2669,9 @@ static void ppp_destroy_interface(struct* The caller should have locked the all_ppp_mutex. */ static struct ppp * -ppp_find_unit (int unit) +ppp_find_unit (struct ppp_net *pn,int unit) { -return unit_find (&ppp_units_idr, unit); +return unit_find (&pn->units_idr, unit); }/*
@@ -2568,20 +2683,22 @@ ppp_find_unit(int unit)* when we have a lot of channels in use. */ static struct channel * -ppp_find_channel (int unit) +ppp_find_channel (struct ppp_net *pn,int unit) {struct channel *pch; -list_for_each_entry (pch, &new_channels, list) { +list_for_each_entry (pch, &pn->new_channels, list) {if (pch->file.index == unit) { -list_move (&pch->list, &all_channels); +list_move (&pch->list, &pn->all_channels);return pch; } } -list_for_each_entry (pch, &all_channels, list) { + +list_for_each_entry (pch, &pn->all_channels, list) {if (pch->file.index == unit)return pch; } +return NULL ; }
@@ -2592,11 +2709,14 @@ static int ppp_connect_channel(struct channel *pch, int unit) {struct ppp *ppp; +struct ppp_net *pn;int ret = -ENXIO ;int hdrlen; -mutex_lock (&all_ppp_mutex); - ppp =ppp_find_unit (unit); + pn =ppp_pernet (pch->chan_net); + +mutex_lock (&pn->all_ppp_mutex); + ppp =ppp_find_unit (pn, unit);if (!ppp) goto out;write_lock_bh (&pch->upl);
@@ -2620,7 +2740,7 @@ ppp_connect_channel(struct channel *pch, outl:write_unlock_bh (&pch->upl); out: -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex);return ret; }
@@ -2677,7 +2797,7 @@ static void __exit ppp_cleanup(void)unregister_chrdev (PPP_MAJOR ,"ppp" );device_destroy (ppp_class,MKDEV (PPP_MAJOR ,0 ));class_destroy (ppp_class); -idr_destroy (&ppp_units_idr); +unregister_pernet_gen_device (ppp_net_id, &ppp_net_ops); }/*
@@ -2743,6 +2863,7 @@ static void *unit_find(struct idr *p, inmodule_init (ppp_init);module_exit (ppp_cleanup); +EXPORT_SYMBOL (ppp_register_net_channel);EXPORT_SYMBOL (ppp_register_channel);EXPORT_SYMBOL (ppp_unregister_channel);EXPORT_SYMBOL (ppp_channel_index);
include/linux/ppp_channel.h +4 -0
@@ -22,6 +22,7 @@#include <linux/list.h> #include <linux/skbuff.h> #include <linux/poll.h> +#include <net/net_namespace.h> struct ppp_channel ;
@@ -56,6 +57,9 @@ extern void ppp_input(struct ppp_channelthat we may have missed a packet. */ extern void ppp_input_error (struct ppp_channel *,int code); +/* Attach a channel to a given PPP unit in specified net. */ +extern int ppp_register_net_channel (struct net *,struct ppp_channel *); +/* Attach a channel to a given PPP unit. */ extern int ppp_register_channel (struct ppp_channel *);
PATCH 4/5 net: ppp_generic - introduce net-namespace functionality v2
In reply to a message not in the archive- Each namespace contains ppp channels and units separately with appropriate locks
--- drivers/net/ppp_generic.c | 275 +++++++++++++++++++++++++++++++------------- include/linux/ppp_channel.h | 4 2 files changed, 202 insertions(+), 77 deletions(-)
drivers/net/ppp_generic.c +198 -77
@@ -49,6 +49,10 @@#include <net/slhc_vj.h> #include <asm/atomic.h> +#include <linux/nsproxy.h> +#include <net/net_namespace.h> +#include <net/netns/generic.h> +#define PPP_VERSION "2.4.2"/*
@@ -131,6 +135,7 @@ struct ppp {struct sock_filter *active_filter;/* filter for pkts to reset idle */ unsigned pass_len, active_len;#endif /* CONFIG_PPP_FILTER */ +struct net *ppp_net;/* the net we belong to */ };/*
@@ -155,6 +160,7 @@ struct channel {struct rw_semaphore chan_sem;/* protects `chan' during chan ioctl */ spinlock_t downl;/* protects `chan', file.xq dequeue */ struct ppp *ppp;/* ppp unit we're connected to */ +struct net *chan_net;/* the net channel belongs to */ struct list_head clist;/* link in list of channels per unit */ rwlock_t upl;/* protects `ppp' */ #ifdef CONFIG_PPP_MULTILINK
@@ -173,26 +179,35 @@ struct channel {* channel.downl. */ -/* -* all_ppp_mutex protects the all_ppp_units mapping. -* It also ensures that finding a ppp unit in the all_ppp_units map -* and updating its file.refcnt field is atomic. -*/ -static DEFINE_MUTEX (all_ppp_mutex);static atomic_t ppp_unit_count =ATOMIC_INIT (0 ); -static DEFINE_IDR (ppp_units_idr); - -/* -* all_channels_lock protects all_channels and last_channel_index, -* and the atomicity of find a channel and updating its file.refcnt -* field. -*/ -static DEFINE_SPINLOCK (all_channels_lock); -static LIST_HEAD (all_channels); -static LIST_HEAD (new_channels); -static int last_channel_index;static atomic_t channel_count =ATOMIC_INIT (0 ); +/* per-net private data for this module */ +static unsigned int ppp_net_id; +struct ppp_net { +/* units to ppp mapping */ +struct idr units_idr; + +/* +* all_ppp_mutex protects the units_idr mapping. +* It also ensures that finding a ppp unit in the units_idr +* map and updating its file.refcnt field is atomic. +*/ +struct mutex all_ppp_mutex; + +/* channels */ +struct list_head all_channels; +struct list_head new_channels; +int last_channel_index; + +/* +* all_channels_lock protects all_channels and +* last_channel_index, and the atomicity of find +* a channel and updating its file.refcnt field. +*/ +spinlock_t all_channels_lock; +}; +/* Get the PPP protocol number from a skb */ #define PPP_PROTO (skb) (((skb)->data[0] << 8) + (skb)->data[1])
@@ -216,8 +231,8 @@ static atomic_t channel_count = ATOMIC_I#define seq_after (a, b) ((s32)((a) - (b)) > 0)/* Prototypes. */ -static int ppp_unattached_ioctl (struct ppp_file *pf,struct file *file, -unsigned int cmd,unsigned long arg); +static int ppp_unattached_ioctl (struct net *net,struct ppp_file *pf, +struct file *file,unsigned int cmd,unsigned long arg);static void ppp_xmit_process (struct ppp *ppp);static void ppp_send_frame (struct ppp *ppp,struct sk_buff *skb);static void ppp_push (struct ppp *ppp);
@@ -240,12 +255,12 @@ static void ppp_ccp_peek(struct ppp *pppstatic void ppp_ccp_closed (struct ppp *ppp);static struct compressor *find_compressor (int type);static void ppp_get_stats (struct ppp *ppp,struct ppp_stats *st); -static struct ppp *ppp_create_interface (int unit,int *retp); +static struct ppp *ppp_create_interface (struct net *net,int unit,int *retp);static void init_ppp_file (struct ppp_file *pf,int kind);static void ppp_shutdown_interface (struct ppp *ppp);static void ppp_destroy_interface (struct ppp *ppp); -static struct ppp *ppp_find_unit (int unit); -static struct channel *ppp_find_channel (int unit); +static struct ppp *ppp_find_unit (struct ppp_net *pn,int unit); +static struct channel *ppp_find_channel (struct ppp_net *pn,int unit);static int ppp_connect_channel (struct channel *pch,int unit);static int ppp_disconnect_channel (struct channel *pch);static void ppp_destroy_channel (struct channel *pch);
@@ -256,6 +271,14 @@ static void *unit_find(struct idr *p, instatic struct class *ppp_class; +/* per net-namespace data */ +static inline struct ppp_net *ppp_pernet (struct net *net) +{ +BUG_ON (!net); + +return net_generic (net, ppp_net_id); +} +/* Translates a PPP protocol number to a NP index (NP == network protocol) */ static inline int proto_to_npindex (int proto) {
@@ -544,7 +567,8 @@ static long ppp_ioctl(struct file *file,int __user *p = argp;if (!pf) -return ppp_unattached_ioctl (pf, file, cmd, arg); +return ppp_unattached_ioctl (current->nsproxy->net_ns, + pf, file, cmd, arg);if (cmd ==PPPIOCDETACH ) {/*
@@ -763,12 +787,13 @@ static long ppp_ioctl(struct file *file,return err; } -static int ppp_unattached_ioctl (struct ppp_file *pf,struct file *file, -unsigned int cmd,unsigned long arg) +static int ppp_unattached_ioctl (struct net *net,struct ppp_file *pf, +struct file *file,unsigned int cmd,unsigned long arg) {int unit, err = -EFAULT ;struct ppp *ppp;struct channel *chan; +struct ppp_net *pn;int __user *p = (int __user *)arg;lock_kernel ();
@@ -777,7 +802,7 @@ static int ppp_unattached_ioctl(struct p/* Create a new ppp unit */ if (get_user (unit, p))break ; - ppp =ppp_create_interface (unit, &err); + ppp =ppp_create_interface (net, unit, &err);if (!ppp)break ; file->private_data = &ppp->file;
@@ -792,29 +817,31 @@ static int ppp_unattached_ioctl(struct p/* Attach to an existing ppp unit */ if (get_user (unit, p))break ; -mutex_lock (&all_ppp_mutex); err = -ENXIO ; - ppp =ppp_find_unit (unit); + pn =ppp_pernet (net); +mutex_lock (&pn->all_ppp_mutex); + ppp =ppp_find_unit (pn, unit);if (ppp) {atomic_inc (&ppp->file.refcnt); file->private_data = &ppp->file; err =0 ; } -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex);break ;case PPPIOCATTCHAN :if (get_user (unit, p))break ; -spin_lock_bh (&all_channels_lock); err = -ENXIO ; - chan =ppp_find_channel (unit); + pn =ppp_pernet (net); +spin_lock_bh (&pn->all_channels_lock); + chan =ppp_find_channel (pn, unit);if (chan) {atomic_inc (&chan->file.refcnt); file->private_data = &chan->file; err =0 ; } -spin_unlock_bh (&all_channels_lock); +spin_unlock_bh (&pn->all_channels_lock);break ;default :
@@ -834,6 +861,51 @@ static const struct file_operations ppp_ .release = ppp_release }; +static __net_init int ppp_init_net (struct net *net) +{ +struct ppp_net *pn; +int err; + + pn =kzalloc (sizeof (*pn),GFP_KERNEL ); +if (!pn) +return -ENOMEM ; + +idr_init (&pn->units_idr); +mutex_init (&pn->all_ppp_mutex); + +INIT_LIST_HEAD (&pn->all_channels); +INIT_LIST_HEAD (&pn->new_channels); + +spin_lock_init (&pn->all_channels_lock); + + err =net_assign_generic (net, ppp_net_id, pn); +if (err) { +kfree (pn); +return err; + } + +return 0 ; +} + +static __net_exit void ppp_exit_net(struct net *net) +{ +struct ppp_net *pn; + + pn =net_generic (net, ppp_net_id); +idr_destroy (&pn->units_idr); +/* +* if someone has cached our net then +* further net_generic call will return NULL +*/ +net_assign_generic (net, ppp_net_id,NULL ); +kfree (pn); +} + +static __net_initdata struct pernet_operations ppp_net_ops = { + .init = ppp_init_net, + .exit = ppp_exit_net, +}; +#define PPP_MAJOR 108/* Called at boot time if ppp is compiled into the kernel,
@@ -843,25 +915,36 @@ static int __init ppp_init(void)int err;printk (KERN_INFO "PPP generic driver version " PPP_VERSION "\n" ); - err =register_chrdev (PPP_MAJOR ,"ppp" , &ppp_device_fops); -if (!err) { - ppp_class =class_create (THIS_MODULE ,"ppp" ); -if (IS_ERR (ppp_class)) { - err =PTR_ERR (ppp_class); - goto out_chrdev; - } -device_create (ppp_class,NULL ,MKDEV (PPP_MAJOR ,0 ),NULL , -"ppp" ); + + err =register_pernet_gen_device (&ppp_net_id, &ppp_net_ops); +if (err) { +printk (KERN_ERR "failed to register PPP pernet device (%d)\n" , err); + goto out; } -out: -if (err) + err =register_chrdev (PPP_MAJOR ,"ppp" , &ppp_device_fops); +if (err) {printk (KERN_ERR "failed to register PPP device (%d)\n" , err); -return err; + goto out_net; + } + + ppp_class =class_create (THIS_MODULE ,"ppp" ); +if (IS_ERR (ppp_class)) { + err =PTR_ERR (ppp_class); + goto out_chrdev; + } + +/* not a big deal if we fail here :-) */ +device_create (ppp_class,NULL ,MKDEV (PPP_MAJOR ,0 ),NULL ,"ppp" ); + +return 0 ; out_chrdev:unregister_chrdev (PPP_MAJOR ,"ppp" ); - goto out; +out_net: +unregister_pernet_gen_device (ppp_net_id, &ppp_net_ops); +out: +return err; }/*
@@ -969,6 +1052,7 @@ static void ppp_setup(struct net_device dev->tx_queue_len =3 ; dev->type =ARPHRD_PPP ; dev->flags =IFF_POINTOPOINT |IFF_NOARP |IFF_MULTICAST ; + dev->features |=NETIF_F_NETNS_LOCAL ; }/*
@@ -1986,19 +2070,27 @@ ppp_mp_reconstruct(struct ppp *ppp)* Channel interface. */ -/* -* Create a new, unattached ppp channel. -*/ -int -ppp_register_channel (struct ppp_channel *chan) +/* Create a new, unattached ppp channel. */ +int ppp_register_channel (struct ppp_channel *chan) +{ +return ppp_register_net_channel (current->nsproxy->net_ns, chan); +} + +/* Create a new, unattached ppp channel for specified net. */ +int ppp_register_net_channel (struct net *net,struct ppp_channel *chan) {struct channel *pch; +struct ppp_net *pn; pch =kzalloc (sizeof (struct channel ),GFP_KERNEL );if (!pch)return -ENOMEM ; + + pn =ppp_pernet (net); + pch->ppp =NULL ; pch->chan = chan; + pch->chan_net = net; chan->ppp = pch;init_ppp_file (&pch->file,CHANNEL ); pch->file.hdrlen = chan->hdrlen;
@@ -2008,11 +2100,13 @@ ppp_register_channel(struct ppp_channelinit_rwsem (&pch->chan_sem);spin_lock_init (&pch->downl);rwlock_init (&pch->upl); -spin_lock_bh (&all_channels_lock); - pch->file.index = ++last_channel_index; -list_add (&pch->list, &new_channels); + +spin_lock_bh (&pn->all_channels_lock); + pch->file.index = ++pn->last_channel_index; +list_add (&pch->list, &pn->new_channels);atomic_inc (&channel_count); -spin_unlock_bh (&all_channels_lock); +spin_unlock_bh (&pn->all_channels_lock); +return 0 ; }
@@ -2053,9 +2147,11 @@ void ppp_unregister_channel(struct ppp_channel *chan) {struct channel *pch = chan->ppp; +struct ppp_net *pn;if (!pch)return ;/* should never happen */ + chan->ppp =NULL ;/*
@@ -2068,9 +2164,12 @@ ppp_unregister_channel(struct ppp_channespin_unlock_bh (&pch->downl);up_write (&pch->chan_sem);ppp_disconnect_channel (pch); -spin_lock_bh (&all_channels_lock); + + pn =ppp_pernet (pch->chan_net); +spin_lock_bh (&pn->all_channels_lock);list_del (&pch->list); -spin_unlock_bh (&all_channels_lock); +spin_unlock_bh (&pn->all_channels_lock); + pch->file.dead =1 ;wake_up_interruptible (&pch->file.rwait);if (atomic_dec_and_test (&pch->file.refcnt))
@@ -2395,9 +2494,10 @@ ppp_get_stats(struct ppp *ppp, struct pp* unit == -1 means allocate a new number. */ static struct ppp * -ppp_create_interface (int unit,int *retp) +ppp_create_interface (struct net *net,int unit,int *retp) {struct ppp *ppp; +struct ppp_net *pn;struct net_device *dev =NULL ;int ret = -ENOMEM ;int i;
@@ -2406,6 +2506,8 @@ ppp_create_interface(int unit, int *retpif (!dev) goto out1; + pn =ppp_pernet (net); + ppp =netdev_priv (dev); ppp->dev = dev; ppp->mru =PPP_MRU ;
@@ -2421,17 +2523,23 @@ ppp_create_interface(int unit, int *retpskb_queue_head_init (&ppp->mrq);#endif /* CONFIG_PPP_MULTILINK */ +/* +* drum roll: don't forget to set +* the net device is belong to +*/ +dev_net_set (dev, net); + ret = -EEXIST ; -mutex_lock (&all_ppp_mutex); +mutex_lock (&pn->all_ppp_mutex);if (unit <0 ) { - unit =unit_get (&ppp_units_idr, ppp); + unit =unit_get (&pn->units_idr, ppp);if (unit <0 ) { *retp = unit; goto out2; } }else { -if (unit_find (&ppp_units_idr, unit)) +if (unit_find (&pn->units_idr, unit)) goto out2;/* unit already exists */ /* * if caller need a specified unit number
@@ -2442,7 +2550,7 @@ ppp_create_interface(int unit, int *retp* fair but at least pppd will ask us to allocate * new unit in this case so user is happy :) */ - unit =unit_set (&ppp_units_idr, ppp, unit); + unit =unit_set (&pn->units_idr, ppp, unit);if (unit <0 ) goto out2; }
@@ -2453,20 +2561,22 @@ ppp_create_interface(int unit, int *retp ret =register_netdev (dev);if (ret !=0 ) { -unit_put (&ppp_units_idr, unit); +unit_put (&pn->units_idr, unit);printk (KERN_ERR "PPP: couldn't register device %s (%d)\n" , dev->name, ret); goto out2; } + ppp->ppp_net = net; +atomic_inc (&ppp_unit_count); -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex); *retp =0 ;return ppp; out2: -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex);free_netdev (dev); out1: *retp = ret;
@@ -2492,7 +2602,11 @@ init_ppp_file(struct ppp_file *pf, int k*/ static void ppp_shutdown_interface (struct ppp *ppp) { -mutex_lock (&all_ppp_mutex); +struct ppp_net *pn; + + pn =ppp_pernet (ppp->ppp_net); +mutex_lock (&pn->all_ppp_mutex); +/* This will call dev_close() for us. */ ppp_lock (ppp);if (!ppp->closing) {
@@ -2502,11 +2616,12 @@ static void ppp_shutdown_interface(struc }else ppp_unlock (ppp); -unit_put (&ppp_units_idr, ppp->file.index); +unit_put (&pn->units_idr, ppp->file.index); ppp->file.dead =1 ; ppp->owner =NULL ;wake_up_interruptible (&ppp->file.rwait); -mutex_unlock (&all_ppp_mutex); + +mutex_unlock (&pn->all_ppp_mutex); }/*
@@ -2554,9 +2669,9 @@ static void ppp_destroy_interface(struct* The caller should have locked the all_ppp_mutex. */ static struct ppp * -ppp_find_unit (int unit) +ppp_find_unit (struct ppp_net *pn,int unit) { -return unit_find (&ppp_units_idr, unit); +return unit_find (&pn->units_idr, unit); }/*
@@ -2568,20 +2683,22 @@ ppp_find_unit(int unit)* when we have a lot of channels in use. */ static struct channel * -ppp_find_channel (int unit) +ppp_find_channel (struct ppp_net *pn,int unit) {struct channel *pch; -list_for_each_entry (pch, &new_channels, list) { +list_for_each_entry (pch, &pn->new_channels, list) {if (pch->file.index == unit) { -list_move (&pch->list, &all_channels); +list_move (&pch->list, &pn->all_channels);return pch; } } -list_for_each_entry (pch, &all_channels, list) { + +list_for_each_entry (pch, &pn->all_channels, list) {if (pch->file.index == unit)return pch; } +return NULL ; }
@@ -2592,11 +2709,14 @@ static int ppp_connect_channel(struct channel *pch, int unit) {struct ppp *ppp; +struct ppp_net *pn;int ret = -ENXIO ;int hdrlen; -mutex_lock (&all_ppp_mutex); - ppp =ppp_find_unit (unit); + pn =ppp_pernet (pch->chan_net); + +mutex_lock (&pn->all_ppp_mutex); + ppp =ppp_find_unit (pn, unit);if (!ppp) goto out;write_lock_bh (&pch->upl);
@@ -2620,7 +2740,7 @@ ppp_connect_channel(struct channel *pch, outl:write_unlock_bh (&pch->upl); out: -mutex_unlock (&all_ppp_mutex); +mutex_unlock (&pn->all_ppp_mutex);return ret; }
@@ -2677,7 +2797,7 @@ static void __exit ppp_cleanup(void)unregister_chrdev (PPP_MAJOR ,"ppp" );device_destroy (ppp_class,MKDEV (PPP_MAJOR ,0 ));class_destroy (ppp_class); -idr_destroy (&ppp_units_idr); +unregister_pernet_gen_device (ppp_net_id, &ppp_net_ops); }/*
@@ -2743,6 +2863,7 @@ static void *unit_find(struct idr *p, inmodule_init (ppp_init);module_exit (ppp_cleanup); +EXPORT_SYMBOL (ppp_register_net_channel);EXPORT_SYMBOL (ppp_register_channel);EXPORT_SYMBOL (ppp_unregister_channel);EXPORT_SYMBOL (ppp_channel_index);
include/linux/ppp_channel.h +4 -0
@@ -22,6 +22,7 @@#include <linux/list.h> #include <linux/skbuff.h> #include <linux/poll.h> +#include <net/net_namespace.h> struct ppp_channel ;
@@ -56,6 +57,9 @@ extern void ppp_input(struct ppp_channelthat we may have missed a packet. */ extern void ppp_input_error (struct ppp_channel *,int code); +/* Attach a channel to a given PPP unit in specified net. */ +extern int ppp_register_net_channel (struct net *,struct ppp_channel *); +/* Attach a channel to a given PPP unit. */ extern int ppp_register_channel (struct ppp_channel *);
PATCH 5/5 net: pppoe,pppol2tp - register channels with explicit net
In reply to a message not in the archiveIn PPPo[E|L2TP] we could explicitly point which net namespace we're going to use for channels - make it so.
--- drivers/net/pppoe.c | 2 +- drivers/net/pppol2tp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/pppoe.c +1 -1
@@ -695,7 +695,7 @@ static int pppoe_connect(struct socket * po->chan.private = sk; po->chan.ops = &pppoe_chan_ops; - error =ppp_register_channel (&po->chan); + error =ppp_register_net_channel (dev_net (dev), &po->chan);if (error) goto err_put;
drivers/net/pppol2tp.c +1 -1
@@ -1749,7 +1749,7 @@ static int pppol2tp_connect(struct socke po->chan.ops = &pppol2tp_chan_ops; po->chan.mtu = session->mtu; - error =ppp_register_channel (&po->chan); + error =ppp_register_net_channel (sock_net (sk), &po->chan);if (error) goto end_put_tun;
PATCH 5/5 net: pppoe,pppol2tp - register channels with explicit net
In reply to a message not in the archiveIn PPPo[E|L2TP] we could explicitly point which net namespace we're going to use for channels - make it so.
--- drivers/net/pppoe.c | 2 +- drivers/net/pppol2tp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/pppoe.c +1 -1
@@ -695,7 +695,7 @@ static int pppoe_connect(struct socket * po->chan.private = sk; po->chan.ops = &pppoe_chan_ops; - error =ppp_register_channel (&po->chan); + error =ppp_register_net_channel (dev_net (dev), &po->chan);if (error) goto err_put;
drivers/net/pppol2tp.c +1 -1
@@ -1749,7 +1749,7 @@ static int pppol2tp_connect(struct socke po->chan.ops = &pppol2tp_chan_ops; po->chan.mtu = session->mtu; - error =ppp_register_channel (&po->chan); + error =ppp_register_net_channel (sock_net (sk), &po->chan);if (error) goto end_put_tun;
Re: [PATCH 5/5] net: pppoe,pppol2tp - register channels with explicit net
Quoted 6 lines · Cyrill Gorcunov
In PPPo[E|L2TP] we could explicitly point which net namespace we're going to use for channels - make it so.
CC James Chapman <[email protected]>CC Michal Ostrowski <[email protected]>Signed-off-by Cyrill Gorcunov <[email protected]>
This one's ok by me too for pppol2tp.
Quoted 32 lines
--- drivers/net/pppoe.c | 2 +- drivers/net/pppol2tp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)Index:
linux-2.6.git/drivers/net/pppoe.c
===================================================================drivers/net/pppoe.c +1
-1@@ -695,7 +695,7 @@ static int pppoe_connect(struct socket * po->chan.private = sk; po->chan.ops = &pppoe_chan_ops; - error =ppp_register_channel (&po->chan); + error =ppp_register_net_channel (dev_net (dev), &po->chan);if (error) goto err_put;Index:
linux-2.6.git/drivers/net/pppol2tp.c
===================================================================drivers/net/pppol2tp.c +1
-1@@ -1749,7 +1749,7 @@ static int pppol2tp_connect(struct socke po->chan.ops = &pppol2tp_chan_ops; po->chan.mtu = session->mtu; - error =ppp_register_channel (&po->chan); + error =ppp_register_net_channel (sock_net (sk), &po->chan);if (error) goto end_put_tun;
Signature · 4 lines
James Chapman Katalix Systems Ltd http://www.katalix.com Catalysts for your Embedded Linux software development
Re: [PATCH 5/5] net: pppoe,pppol2tp - register channels with explicit net
[James Chapman - Tue, Jan 20, 2009 at 09:56:32PM +0000]
| Cyrill Gorcunov wrote: | > In PPPo[E|L2TP] we could explicitly point which net namespace | > we're going to use for channels - make it so. | > | > CC: James Chapman <[email protected]> | > CC: Michal Ostrowski <[email protected]> | > Signed-off-by: Cyrill Gorcunov <[email protected]> | | This one's ok by me too for pppol2tp. | | Signed-off-by: James Chapman <[email protected]> |
...
| | | -- | James Chapman | Katalix Systems Ltd | http://www.katalix.com | Catalysts for your Embedded Linux software development |
Thanks a lot for testing, James! I really appreciate!
- Cyrill -
Re: [PATCH 5/5] net: pppoe,pppol2tp - register channels with explicit net
In reply to Cyrill GorcunovQuoted 4 lines · Cyrill Gorcunov
In PPPo[E|L2TP] we could explicitly point which net namespace we're going to use for channels - make it so.
Hi Cyrill,
For some reason, I see your your mail' date pointing to 12/31/1969.
Cheers,
Divy
David Miller
maintainerRe: [PATCH 5/5] net: pppoe,pppol2tp - register channels with explicit net
From: Divy Le Ray <[email protected]>
Date: Tue, 20 Jan 2009 16:09:00 -0800
Quoted 1 line
For some reason, I see your your mail' date pointing to 12/31/1969.
Yes, he knows. It's a quilt hiccup.
PATCH 5/5 net: pppoe,pppol2tp - register channels with explicit net
In reply to a message not in the archiveIn PPPo[E|L2TP] we could explicitly point which net namespace we're going to use for channels - make it so.
--- drivers/net/pppoe.c | 2 +- drivers/net/pppol2tp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/pppoe.c +1 -1
@@ -695,7 +695,7 @@ static int pppoe_connect(struct socket * po->chan.private = sk; po->chan.ops = &pppoe_chan_ops; - error =ppp_register_channel (&po->chan); + error =ppp_register_net_channel (dev_net (dev), &po->chan);if (error) goto err_put;
drivers/net/pppol2tp.c +1 -1
@@ -1749,7 +1749,7 @@ static int pppol2tp_connect(struct socke po->chan.ops = &pppol2tp_chan_ops; po->chan.mtu = session->mtu; - error =ppp_register_channel (&po->chan); + error =ppp_register_net_channel (sock_net (sk), &po->chan);if (error) goto end_put_tun;