* [PATCH 0/2] Fix some multiqueue TUN problems
From: Paul Moore @ 2013-01-14 17:12 UTC (permalink / raw)
To: netdev, linux-security-module, selinux
No significant changes to this patchset since the last posting, just a
slight merge with the recent changes in tun_set_queue() and some
Acked-by and Tested-by additions. I believe all the concerns have been
addressed and this patch is ready for merging.
Dave, I think it makes the most sense for this to get pulled in via the
netdev tree but if you think otherwise let me know and I'll go bug
James and Eric.
-Paul
---
Paul Moore (2):
selinux: add the "attach_queue" permission to the "tun_socket" class
tun: fix LSM/SELinux labeling of tun/tap devices
drivers/net/tun.c | 23 +++++++++++---
include/linux/security.h | 59 +++++++++++++++++++++++++++--------
security/capability.c | 24 ++++++++++++--
security/security.c | 28 ++++++++++++++---
security/selinux/hooks.c | 50 +++++++++++++++++++++++-------
security/selinux/include/classmap.h | 2 +
security/selinux/include/objsec.h | 4 ++
7 files changed, 152 insertions(+), 38 deletions(-)
^ permalink raw reply
* [PATCH 1/2] selinux: add the "attach_queue" permission to the "tun_socket" class
From: Paul Moore @ 2013-01-14 17:12 UTC (permalink / raw)
To: netdev, linux-security-module, selinux; +Cc: Eric Paris, Jason Wang
In-Reply-To: <20130114170837.31874.78897.stgit@localhost>
Add a new permission to align with the new TUN multiqueue support,
"tun_socket:attach_queue".
The corresponding SELinux reference policy patch is show below:
diff --git a/policy/flask/access_vectors b/policy/flask/access_vectors
index 28802c5..a0664a1 100644
--- a/policy/flask/access_vectors
+++ b/policy/flask/access_vectors
@@ -827,6 +827,9 @@ class kernel_service
class tun_socket
inherits socket
+{
+ attach_queue
+}
class x_pointer
inherits x_device
Signed-off-by: Paul Moore <pmoore@redhat.com>
Acked-by: Eric Paris <eparis@parisplace.org>
Tested-by: Jason Wang <jasowang@redhat.com>
---
security/selinux/include/classmap.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index df2de54..14d04e6 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -150,6 +150,6 @@ struct security_class_mapping secclass_map[] = {
NULL } },
{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
{ "tun_socket",
- { COMMON_SOCK_PERMS, NULL } },
+ { COMMON_SOCK_PERMS, "attach_queue", NULL } },
{ NULL }
};
^ permalink raw reply related
* [PATCH 2/2] tun: fix LSM/SELinux labeling of tun/tap devices
From: Paul Moore @ 2013-01-14 17:12 UTC (permalink / raw)
To: netdev, linux-security-module, selinux; +Cc: Eric Paris, Jason Wang
In-Reply-To: <20130114170837.31874.78897.stgit@localhost>
This patch corrects some problems with LSM/SELinux that were introduced
with the multiqueue patchset. The problem stems from the fact that the
multiqueue work changed the relationship between the tun device and its
associated socket; before the socket persisted for the life of the
device, however after the multiqueue changes the socket only persisted
for the life of the userspace connection (fd open). For non-persistent
devices this is not an issue, but for persistent devices this can cause
the tun device to lose its SELinux label.
We correct this problem by adding an opaque LSM security blob to the
tun device struct which allows us to have the LSM security state, e.g.
SELinux labeling information, persist for the lifetime of the tun
device. In the process we tweak the LSM hooks to work with this new
approach to TUN device/socket labeling and introduce a new LSM hook,
security_tun_dev_attach_queue(), to approve requests to attach to a
TUN queue via TUNSETQUEUE.
The SELinux code has been adjusted to match the new LSM hooks, the
other LSMs do not make use of the LSM TUN controls. This patch makes
use of the recently added "tun_socket:attach_queue" permission to
restrict access to the TUNSETQUEUE operation. On older SELinux
policies which do not define the "tun_socket:attach_queue" permission
the access control decision for TUNSETQUEUE will be handled according
to the SELinux policy's unknown permission setting.
Signed-off-by: Paul Moore <pmoore@redhat.com>
Acked-by: Eric Paris <eparis@parisplace.org>
Tested-by: Jason Wang <jasowang@redhat.com>
---
drivers/net/tun.c | 23 +++++++++++---
include/linux/security.h | 59 +++++++++++++++++++++++++++++--------
security/capability.c | 24 +++++++++++++--
security/security.c | 28 ++++++++++++++----
security/selinux/hooks.c | 50 ++++++++++++++++++++++++-------
security/selinux/include/objsec.h | 4 +++
6 files changed, 151 insertions(+), 37 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index af372d0..c81680d 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -185,6 +185,7 @@ struct tun_struct {
unsigned long ageing_time;
unsigned int numdisabled;
struct list_head disabled;
+ void *security;
};
static inline u32 tun_hashfn(u32 rxhash)
@@ -490,6 +491,10 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
struct tun_file *tfile = file->private_data;
int err;
+ err = security_tun_dev_attach(tfile->socket.sk, tun->security);
+ if (err < 0)
+ goto out;
+
err = -EINVAL;
if (rtnl_dereference(tfile->tun))
goto out;
@@ -1373,6 +1378,7 @@ static void tun_free_netdev(struct net_device *dev)
BUG_ON(!(list_empty(&tun->disabled)));
tun_flow_uninit(tun);
+ security_tun_dev_free_security(tun->security);
free_netdev(dev);
}
@@ -1562,7 +1568,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
if (tun_not_capable(tun))
return -EPERM;
- err = security_tun_dev_attach(tfile->socket.sk);
+ err = security_tun_dev_open(tun->security);
if (err < 0)
return err;
@@ -1619,7 +1625,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
spin_lock_init(&tun->lock);
- security_tun_dev_post_create(&tfile->sk);
+ err = security_tun_dev_alloc_security(&tun->security);
+ if (err < 0)
+ goto err_free_dev;
tun_net_init(dev);
@@ -1789,10 +1797,14 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
if (ifr->ifr_flags & IFF_ATTACH_QUEUE) {
tun = tfile->detached;
- if (!tun)
+ if (!tun) {
ret = -EINVAL;
- else
- ret = tun_attach(tun, file);
+ goto unlock;
+ }
+ ret = security_tun_dev_attach_queue(tun->security);
+ if (ret < 0)
+ goto unlock;
+ ret = tun_attach(tun, file);
} else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
tun = rtnl_dereference(tfile->tun);
if (!tun || !(tun->flags & TUN_TAP_MQ))
@@ -1802,6 +1814,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
} else
ret = -EINVAL;
+unlock:
rtnl_unlock();
return ret;
}
diff --git a/include/linux/security.h b/include/linux/security.h
index 0f6afc6..eee7478 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -989,17 +989,29 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* tells the LSM to decrement the number of secmark labeling rules loaded
* @req_classify_flow:
* Sets the flow's sid to the openreq sid.
+ * @tun_dev_alloc_security:
+ * This hook allows a module to allocate a security structure for a TUN
+ * device.
+ * @security pointer to a security structure pointer.
+ * Returns a zero on success, negative values on failure.
+ * @tun_dev_free_security:
+ * This hook allows a module to free the security structure for a TUN
+ * device.
+ * @security pointer to the TUN device's security structure
* @tun_dev_create:
* Check permissions prior to creating a new TUN device.
- * @tun_dev_post_create:
- * This hook allows a module to update or allocate a per-socket security
- * structure.
- * @sk contains the newly created sock structure.
+ * @tun_dev_attach_queue:
+ * Check permissions prior to attaching to a TUN device queue.
+ * @security pointer to the TUN device's security structure.
* @tun_dev_attach:
- * Check permissions prior to attaching to a persistent TUN device. This
- * hook can also be used by the module to update any security state
+ * This hook can be used by the module to update any security state
* associated with the TUN device's sock structure.
* @sk contains the existing sock structure.
+ * @security pointer to the TUN device's security structure.
+ * @tun_dev_open:
+ * This hook can be used by the module to update any security state
+ * associated with the TUN device's security structure.
+ * @security pointer to the TUN devices's security structure.
*
* Security hooks for XFRM operations.
*
@@ -1620,9 +1632,12 @@ struct security_operations {
void (*secmark_refcount_inc) (void);
void (*secmark_refcount_dec) (void);
void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl);
- int (*tun_dev_create)(void);
- void (*tun_dev_post_create)(struct sock *sk);
- int (*tun_dev_attach)(struct sock *sk);
+ int (*tun_dev_alloc_security) (void **security);
+ void (*tun_dev_free_security) (void *security);
+ int (*tun_dev_create) (void);
+ int (*tun_dev_attach_queue) (void *security);
+ int (*tun_dev_attach) (struct sock *sk, void *security);
+ int (*tun_dev_open) (void *security);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -2566,9 +2581,12 @@ void security_inet_conn_established(struct sock *sk,
int security_secmark_relabel_packet(u32 secid);
void security_secmark_refcount_inc(void);
void security_secmark_refcount_dec(void);
+int security_tun_dev_alloc_security(void **security);
+void security_tun_dev_free_security(void *security);
int security_tun_dev_create(void);
-void security_tun_dev_post_create(struct sock *sk);
-int security_tun_dev_attach(struct sock *sk);
+int security_tun_dev_attach_queue(void *security);
+int security_tun_dev_attach(struct sock *sk, void *security);
+int security_tun_dev_open(void *security);
#else /* CONFIG_SECURITY_NETWORK */
static inline int security_unix_stream_connect(struct sock *sock,
@@ -2733,16 +2751,31 @@ static inline void security_secmark_refcount_dec(void)
{
}
+static inline int security_tun_dev_alloc_security(void **security)
+{
+ return 0;
+}
+
+static inline void security_tun_dev_free_security(void *security)
+{
+}
+
static inline int security_tun_dev_create(void)
{
return 0;
}
-static inline void security_tun_dev_post_create(struct sock *sk)
+static inline int security_tun_dev_attach_queue(void *security)
+{
+ return 0;
+}
+
+static inline int security_tun_dev_attach(struct sock *sk, void *security)
{
+ return 0;
}
-static inline int security_tun_dev_attach(struct sock *sk)
+static inline int security_tun_dev_open(void *security)
{
return 0;
}
diff --git a/security/capability.c b/security/capability.c
index 0fe5a02..5797750 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -709,16 +709,31 @@ static void cap_req_classify_flow(const struct request_sock *req,
{
}
+static int cap_tun_dev_alloc_security(void **security)
+{
+ return 0;
+}
+
+static void cap_tun_dev_free_security(void *security)
+{
+}
+
static int cap_tun_dev_create(void)
{
return 0;
}
-static void cap_tun_dev_post_create(struct sock *sk)
+static int cap_tun_dev_attach_queue(void *security)
+{
+ return 0;
+}
+
+static int cap_tun_dev_attach(struct sock *sk, void *security)
{
+ return 0;
}
-static int cap_tun_dev_attach(struct sock *sk)
+static int cap_tun_dev_open(void *security)
{
return 0;
}
@@ -1050,8 +1065,11 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, secmark_refcount_inc);
set_to_cap_if_null(ops, secmark_refcount_dec);
set_to_cap_if_null(ops, req_classify_flow);
+ set_to_cap_if_null(ops, tun_dev_alloc_security);
+ set_to_cap_if_null(ops, tun_dev_free_security);
set_to_cap_if_null(ops, tun_dev_create);
- set_to_cap_if_null(ops, tun_dev_post_create);
+ set_to_cap_if_null(ops, tun_dev_open);
+ set_to_cap_if_null(ops, tun_dev_attach_queue);
set_to_cap_if_null(ops, tun_dev_attach);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
diff --git a/security/security.c b/security/security.c
index daa97f4..7b88c6a 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1254,24 +1254,42 @@ void security_secmark_refcount_dec(void)
}
EXPORT_SYMBOL(security_secmark_refcount_dec);
+int security_tun_dev_alloc_security(void **security)
+{
+ return security_ops->tun_dev_alloc_security(security);
+}
+EXPORT_SYMBOL(security_tun_dev_alloc_security);
+
+void security_tun_dev_free_security(void *security)
+{
+ security_ops->tun_dev_free_security(security);
+}
+EXPORT_SYMBOL(security_tun_dev_free_security);
+
int security_tun_dev_create(void)
{
return security_ops->tun_dev_create();
}
EXPORT_SYMBOL(security_tun_dev_create);
-void security_tun_dev_post_create(struct sock *sk)
+int security_tun_dev_attach_queue(void *security)
{
- return security_ops->tun_dev_post_create(sk);
+ return security_ops->tun_dev_attach_queue(security);
}
-EXPORT_SYMBOL(security_tun_dev_post_create);
+EXPORT_SYMBOL(security_tun_dev_attach_queue);
-int security_tun_dev_attach(struct sock *sk)
+int security_tun_dev_attach(struct sock *sk, void *security)
{
- return security_ops->tun_dev_attach(sk);
+ return security_ops->tun_dev_attach(sk, security);
}
EXPORT_SYMBOL(security_tun_dev_attach);
+int security_tun_dev_open(void *security)
+{
+ return security_ops->tun_dev_open(security);
+}
+EXPORT_SYMBOL(security_tun_dev_open);
+
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 61a5336..ef26e96 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4399,6 +4399,24 @@ static void selinux_req_classify_flow(const struct request_sock *req,
fl->flowi_secid = req->secid;
}
+static int selinux_tun_dev_alloc_security(void **security)
+{
+ struct tun_security_struct *tunsec;
+
+ tunsec = kzalloc(sizeof(*tunsec), GFP_KERNEL);
+ if (!tunsec)
+ return -ENOMEM;
+ tunsec->sid = current_sid();
+
+ *security = tunsec;
+ return 0;
+}
+
+static void selinux_tun_dev_free_security(void *security)
+{
+ kfree(security);
+}
+
static int selinux_tun_dev_create(void)
{
u32 sid = current_sid();
@@ -4414,8 +4432,17 @@ static int selinux_tun_dev_create(void)
NULL);
}
-static void selinux_tun_dev_post_create(struct sock *sk)
+static int selinux_tun_dev_attach_queue(void *security)
{
+ struct tun_security_struct *tunsec = security;
+
+ return avc_has_perm(current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
+ TUN_SOCKET__ATTACH_QUEUE, NULL);
+}
+
+static int selinux_tun_dev_attach(struct sock *sk, void *security)
+{
+ struct tun_security_struct *tunsec = security;
struct sk_security_struct *sksec = sk->sk_security;
/* we don't currently perform any NetLabel based labeling here and it
@@ -4425,20 +4452,19 @@ static void selinux_tun_dev_post_create(struct sock *sk)
* cause confusion to the TUN user that had no idea network labeling
* protocols were being used */
- /* see the comments in selinux_tun_dev_create() about why we don't use
- * the sockcreate SID here */
-
- sksec->sid = current_sid();
+ sksec->sid = tunsec->sid;
sksec->sclass = SECCLASS_TUN_SOCKET;
+
+ return 0;
}
-static int selinux_tun_dev_attach(struct sock *sk)
+static int selinux_tun_dev_open(void *security)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct tun_security_struct *tunsec = security;
u32 sid = current_sid();
int err;
- err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
+ err = avc_has_perm(sid, tunsec->sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__RELABELFROM, NULL);
if (err)
return err;
@@ -4446,8 +4472,7 @@ static int selinux_tun_dev_attach(struct sock *sk)
TUN_SOCKET__RELABELTO, NULL);
if (err)
return err;
-
- sksec->sid = sid;
+ tunsec->sid = sid;
return 0;
}
@@ -5642,9 +5667,12 @@ static struct security_operations selinux_ops = {
.secmark_refcount_inc = selinux_secmark_refcount_inc,
.secmark_refcount_dec = selinux_secmark_refcount_dec,
.req_classify_flow = selinux_req_classify_flow,
+ .tun_dev_alloc_security = selinux_tun_dev_alloc_security,
+ .tun_dev_free_security = selinux_tun_dev_free_security,
.tun_dev_create = selinux_tun_dev_create,
- .tun_dev_post_create = selinux_tun_dev_post_create,
+ .tun_dev_attach_queue = selinux_tun_dev_attach_queue,
.tun_dev_attach = selinux_tun_dev_attach,
+ .tun_dev_open = selinux_tun_dev_open,
#ifdef CONFIG_SECURITY_NETWORK_XFRM
.xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 26c7eee..aa47bca 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -110,6 +110,10 @@ struct sk_security_struct {
u16 sclass; /* sock security class */
};
+struct tun_security_struct {
+ u32 sid; /* SID for the tun device sockets */
+};
+
struct key_security_struct {
u32 sid; /* SID of key */
};
^ permalink raw reply related
* Re: [PATCH] CDC_NCM adding support IFF_NOARP for infineon modem platform
From: Dan Williams @ 2013-01-14 17:19 UTC (permalink / raw)
To: David Miller; +Cc: cpuwolf, gregkh, alexey.orishko, bjorn, linux-usb, netdev
In-Reply-To: <20130112.153533.1713284383322153346.davem@davemloft.net>
On Sat, 2013-01-12 at 15:35 -0800, David Miller wrote:
> From: Wei Shuai <cpuwolf@gmail.com>
> Date: Sat, 12 Jan 2013 19:34:39 +0800
>
> > Infineon(now Intel) HSPA Modem platform NCM cannot support ARP. so I
> > introduce a flag CDC_NCM_DRIVER_DATA_NOARP which is defined in
> > driver_info:data. so later on, if more such buggy devices are found,
> > they could use same flag to handle.
>
> Is it no able to do ARP or, the more likely case, does broadcast
> not work at all?
>
> If it's the latter, IFF_NOARP is just making over the real problem.
>
> I'm not applying this, no hardware device should set IFF_NOARP.
> You probably really want IFF_POINTOPOINT or similar.
IFF_NOARP is already done for other WWAN devices (sierra_net, hso,
cdc-ether, cdc-phonet, lg-vl600, etc) so there is some precedent. Some
drivers (phonet, hso) set *both* POINTTOPOINT and NOARP. Is that
redundant, and should all WWAN drivers be moved to only POINTTOPOINT?
(aside: usbnet has FLAG_POINTTOPOINT, but that's nothing to do with
IFF_POINTTOPOINT, it only controls whether the interface is named usbX
or ethX. Confusing.)
Dan
^ permalink raw reply
* Re: [PATCH net-next 09/10] bnx2x: Added FW GRO bridging support
From: Eric Dumazet @ 2013-01-14 17:22 UTC (permalink / raw)
To: Yuval Mintz; +Cc: davem, netdev, eilong, ariele
In-Reply-To: <1358176310-31504-10-git-send-email-yuvalmin@broadcom.com>
On Mon, 2013-01-14 at 17:11 +0200, Yuval Mintz wrote:
> Since submit 621b4d6 the bnx2x driver support FW GRO.
> However, when using the device with GRO enabled in bridging
> scenarios throughput is very low, as the bridge expects all
> incoming packets to be passed with CHECKSUM_PARTIAL -
> a demand which is satisfied by the SW GRO implementation,
> but was missed in the bnx2x driver implementation (which returned
> CHECKSUM_UNNECESSARY).
>
> Now, given that the traffic is supported by FW GRO (TCP/IP),
> the bnx2x driver calculates the pseudo checksum by itself,
> passing skbs with CHECKSUM_PARTIAL and giving a much better
> throughput when receiving GRO traffic.
>
> Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
> Signed-off-by: Ariel Elior <ariele@broadcom.com>
> Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
> ---
> drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 54 ++++++++++++++++++++++++-
> 1 file changed, 52 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
> index a6f4140..963eb2d 100644
> --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
> +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
> @@ -21,6 +21,7 @@
> #include <linux/if_vlan.h>
> #include <linux/interrupt.h>
> #include <linux/ip.h>
> +#include <net/tcp.h>
> #include <net/ipv6.h>
> #include <net/ip6_checksum.h>
> #include <linux/prefetch.h>
> @@ -506,7 +507,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
> tpa_info->parsing_flags, len_on_bd);
>
> /* set for GRO */
> - if (fp->mode == TPA_MODE_GRO)
> + if (fp->mode == TPA_MODE_GRO && skb_shinfo(skb)->gso_size)
> skb_shinfo(skb)->gso_type =
> (GET_FLAG(tpa_info->parsing_flags,
> PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) ==
> @@ -595,6 +596,55 @@ static void *bnx2x_frag_alloc(const struct bnx2x_fastpath *fp)
> }
>
>
> +#ifdef CONFIG_INET
> +static void bnx2x_gro_ip_csum(struct bnx2x *bp, struct sk_buff *skb)
> +{
> + const struct iphdr *iph = ip_hdr(skb);
> + struct tcphdr *th;
> +
> + skb_set_transport_header(skb, sizeof(struct iphdr));
> + th = tcp_hdr(skb);
> +
> + th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb),
> + iph->saddr, iph->daddr, 0);
> +}
> +
> +static void bnx2x_gro_ipv6_csum(struct bnx2x *bp, struct sk_buff *skb)
> +{
> + struct ipv6hdr *iph = ipv6_hdr(skb);
> + struct tcphdr *th;
> +
> + skb_set_transport_header(skb, sizeof(struct ipv6hdr));
> + th = tcp_hdr(skb);
> +
> + th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
> + &iph->saddr, &iph->daddr, 0);
> +}
> +#endif
> +
> +static void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp,
> + struct sk_buff *skb)
> +{
> +#ifdef CONFIG_INET
> + if (fp->mode == TPA_MODE_GRO && skb_shinfo(skb)->gso_size) {
> + skb_set_network_header(skb, 0);
> + switch (be16_to_cpu(skb->protocol)) {
> + case ETH_P_IP:
> + bnx2x_gro_ip_csum(bp, skb);
> + break;
> + case ETH_P_IPV6:
> + bnx2x_gro_ipv6_csum(bp, skb);
> + break;
> + default:
> + BNX2X_ERR("FW GRO supports only IPv4/IPv6, not 0x%04x\n",
> + be16_to_cpu(skb->protocol));
> + }
> + tcp_gro_complete(skb);
This looks weird to me. This should be called by GRO stack only.
What is the value of gso_segs ?
> + }
> +#endif
> + napi_gro_receive(&fp->napi, skb);
> +}
> +
> static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
> struct bnx2x_agg_info *tpa_info,
> u16 pages,
> @@ -648,7 +698,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
> skb, cqe, cqe_idx)) {
> if (tpa_info->parsing_flags & PARSING_FLAGS_VLAN)
> __vlan_hwaccel_put_tag(skb, tpa_info->vlan_tag);
> - napi_gro_receive(&fp->napi, skb);
> + bnx2x_gro_receive(bp, fp, skb);
> } else {
> DP(NETIF_MSG_RX_STATUS,
> "Failed to allocate new pages - dropping packet!\n");
^ permalink raw reply
* Re: when and where does ep_poll_callback be called ?
From: horseriver @ 2013-01-14 7:52 UTC (permalink / raw)
To: Randy Dunlap; +Cc: netdev
In-Reply-To: <50F433D1.6070809@infradead.org>
On Mon, Jan 14, 2013 at 08:35:29AM -0800, Randy Dunlap wrote:
> On 01/13/13 17:11, horseriver wrote:
> > hi:
> >
> >
> > I'm studying the epoll module , I can not find ep_poll_callback be called somewhere .
>
>
> It's right there in fs/eventpoll.c:
>
>
> /*
> * This is the callback that is used to add our wait queue to the
> * target file wakeup lists.
> */
> static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,
> poll_table *pt)
> {
> struct epitem *epi = ep_item_from_epqueue(pt);
> struct eppoll_entry *pwq;
>
> if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, GFP_KERNEL))) {
> >>>>> init_waitqueue_func_entry(&pwq->wait, ep_poll_callback);
Thanks!
I know this is setting the callbak function into watqueue . But not the called place .
I want to know the code which calls ep_poll_callback .
Perhaps , it is called at tcp layer when a datagram is reached . but I have not find that key code .
> pwq->whead = whead;
> pwq->base = epi;
> add_wait_queue(whead, &pwq->wait);
> list_add_tail(&pwq->llink, &epi->pwqlist);
> epi->nwait++;
>
>
>
> --
> ~Randy
^ permalink raw reply
* Re: [PATCH 15/15] batman-adv: unbloat batadv_priv if debug is not enabled
From: Joe Perches @ 2013-01-14 17:36 UTC (permalink / raw)
To: Antonio Quartulli; +Cc: davem, netdev, b.a.t.m.a.n, Marek Lindner
In-Reply-To: <1358120480-25960-16-git-send-email-ordex@autistici.org>
On Mon, 2013-01-14 at 09:41 +1000, Antonio Quartulli wrote:
> diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
[]
> @@ -284,12 +284,16 @@ struct batadv_priv {
> atomic_t gw_bandwidth; /* gw bandwidth */
> atomic_t orig_interval; /* uint */
> atomic_t hop_penalty; /* uint */
> +#ifdef CONFIG_BATMAN_ADV_DEBUG
> atomic_t log_level; /* uint */
> +#endif
> atomic_t bcast_seqno;
> atomic_t bcast_queue_left;
> atomic_t batman_queue_left;
> char num_ifaces;
> +#ifdef CONFIG_BATMAN_ADV_DEBUG
> struct batadv_debug_log *debug_log;
> +#endif
> struct kobject *mesh_obj;
> struct dentry *debug_dir;
> struct hlist_head forw_bat_list;
How about moving one of these so
there's only one #ifdef block.
^ permalink raw reply
* Re: [PATCH 1/2] usbnet: allow status interrupt URB to always be active
From: Dan Williams @ 2013-01-14 17:52 UTC (permalink / raw)
To: Oliver Neukum; +Cc: Elina Pasheva, netdev, linux-usb, Rory Filer, Phil Sutter
In-Reply-To: <3476529.YzSzbMTfeu@linux-5eaq.site>
On Sat, 2013-01-05 at 12:01 +0100, Oliver Neukum wrote:
> On Friday 04 January 2013 19:26:33 Dan Williams wrote:
> > On Fri, 2013-01-04 at 23:16 +0100, Oliver Neukum wrote:
> > > On Friday 04 January 2013 10:48:16 Dan Williams wrote:
> > > > Some drivers (ex sierra_net) need the status interrupt URB
> > > > active even when the device is closed, because they receive
> > > > custom indications from firmware. Allow sub-drivers to set
> > > > a flag that submits the status interrupt URB on probe and
> > > > keeps the URB alive over device open/close. The URB is still
> > > > killed/re-submitted for suspend/resume, as before.
> > > >
> > > > Signed-off-by: Dan Williams <dcbw@redhat.com>
> > > > ---
> > > > Oliver: alternatively, is there a problem with *always*
> > > > submitting the interrupt URB, and then simply not calling
> > > > the subdriver's .status function when the netdev is
> > > > closed? That would be a much simpler patch.
> > >
> > > That is quite radical. We have no idea what a device
> > > does when we do not react to a status update. I would
> > > much prefer to not take the risk.
> > > Besides, we don't use bandwidth if we don't have to.
> >
> > Ok, so scratch the alternative. Thus, does the posted patch look like
> > the right course of action?
>
> In principle yes.
>
> > If I wasn't clear enough before, sierra_net needs to listen to the
> > status interrupt URB to receive the custom Restart indication as part of
> > the driver's device setup. Thus for sierra_net at least, tying the
> > status interrupt URB submission to device open/close isn't right.
>
> So, there seems to be an inevitable race before probe() is called.
> Have you looked at FLAG_AVOID_UNLINK_URBS ?
So that looks like it only applies to the bulk URBs, what was your
suggestion here? Sierra would want the same behavior as it currently
has (kill data urbs on stop/start) but only the interrupt urb needs to
be kept alive over stop/start.
Dan
^ permalink raw reply
* Re: [PATCH 1/2] usbnet: allow status interrupt URB to always be active
From: Dan Williams @ 2013-01-14 17:23 UTC (permalink / raw)
To: Ming Lei
Cc: Oliver Neukum, Elina Pasheva, netdev, linux-usb, Rory Filer,
Phil Sutter
In-Reply-To: <CACVXFVOAjHMxRC=uok-OWPYjw-7D1MSnbaWo97LcGFAVRq+o2g@mail.gmail.com>
On Fri, 2013-01-11 at 11:06 +0800, Ming Lei wrote:
> On Sat, Jan 5, 2013 at 9:26 AM, Dan Williams <dcbw@redhat.com> wrote:
> > On Fri, 2013-01-04 at 23:16 +0100, Oliver Neukum wrote:
> >> On Friday 04 January 2013 10:48:16 Dan Williams wrote:
> >> > Some drivers (ex sierra_net) need the status interrupt URB
> >> > active even when the device is closed, because they receive
> >> > custom indications from firmware. Allow sub-drivers to set
> >> > a flag that submits the status interrupt URB on probe and
> >> > keeps the URB alive over device open/close. The URB is still
> >> > killed/re-submitted for suspend/resume, as before.
> >> >
> >> > Signed-off-by: Dan Williams <dcbw@redhat.com>
> >> > ---
> >> > Oliver: alternatively, is there a problem with *always*
> >> > submitting the interrupt URB, and then simply not calling
> >> > the subdriver's .status function when the netdev is
> >> > closed? That would be a much simpler patch.
> >>
> >> That is quite radical. We have no idea what a device
> >> does when we do not react to a status update. I would
> >> much prefer to not take the risk.
> >> Besides, we don't use bandwidth if we don't have to.
> >
> > Ok, so scratch the alternative. Thus, does the posted patch look like
> > the right course of action?
> >
> > If I wasn't clear enough before, sierra_net needs to listen to the
> > status interrupt URB to receive the custom Restart indication as part of
> > the driver's device setup. Thus for sierra_net at least, tying the
>
> I am curious who are interested in the 'custom Restart indication'
> information after the interface is closed.
It's actually before the interface is even opened. It's really just a
sync signal that's part of the driver's setup/initialization of the
device.
> If sierra_net provides ways(such as read registers) to query the
> indication event, you can just query the information and setup
> the device in driver_info->reset() during device open, so you can
> avoid submitting interrupt URB always.
As far as I know, it does not, or at least Sierra hasn't released such
information about the firmware API of their devices.
Dan
> > status interrupt URB submission to device open/close isn't right.
>
> In theory, drivers should support to report its link status
> even it is closed, but looks no much actual usage, so guys opt to
> submit the interrupt URB only after it is opened.
>
>
> Thanks,
> --
> Ming Lei
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC Patch net-next] ipv6: look up neighbours on demand in ip6_finish_output2()
From: David Miller @ 2013-01-14 18:30 UTC (permalink / raw)
To: xiyou.wangcong; +Cc: netdev, roland
In-Reply-To: <1358170515-1383-1-git-send-email-xiyou.wangcong@gmail.com>
This is a very incomplete patch.
If this change were so simple, it would have been done by someone
else a long time ago.
You must, in addition to the incredibly obvious changes in the packet
output path, completely eliminate the caching of the neighbour entry
in the ipv6 routes themselves.
This means replacing every rt6->n access or test with something
equivalent.
^ permalink raw reply
* Re: [PATCH 0/6] IPv6: 64bit functions.
From: David Miller @ 2013-01-14 18:33 UTC (permalink / raw)
To: yoshfuji; +Cc: netdev
In-Reply-To: <50F43BD5.3090002@linux-ipv6.org>
From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date: Tue, 15 Jan 2013 02:09:41 +0900
> This series of changes is about low-level address/prefix
> manipulation functions, which basically introduces 64bit
> variants of them.
Series applied, thanks.
^ permalink raw reply
* Re: [PATCH] CDC_NCM adding support IFF_NOARP for infineon modem platform
From: David Miller @ 2013-01-14 18:34 UTC (permalink / raw)
To: dcbw; +Cc: cpuwolf, gregkh, alexey.orishko, bjorn, linux-usb, netdev
In-Reply-To: <1358183953.1713.28.camel@dcbw.foobar.com>
From: Dan Williams <dcbw@redhat.com>
Date: Mon, 14 Jan 2013 11:19:13 -0600
> On Sat, 2013-01-12 at 15:35 -0800, David Miller wrote:
>> From: Wei Shuai <cpuwolf@gmail.com>
>> Date: Sat, 12 Jan 2013 19:34:39 +0800
>>
>> > Infineon(now Intel) HSPA Modem platform NCM cannot support ARP. so I
>> > introduce a flag CDC_NCM_DRIVER_DATA_NOARP which is defined in
>> > driver_info:data. so later on, if more such buggy devices are found,
>> > they could use same flag to handle.
>>
>> Is it no able to do ARP or, the more likely case, does broadcast
>> not work at all?
>>
>> If it's the latter, IFF_NOARP is just making over the real problem.
>>
>> I'm not applying this, no hardware device should set IFF_NOARP.
>> You probably really want IFF_POINTOPOINT or similar.
>
> IFF_NOARP is already done for other WWAN devices (sierra_net, hso,
> cdc-ether, cdc-phonet, lg-vl600, etc) so there is some precedent. Some
> drivers (phonet, hso) set *both* POINTTOPOINT and NOARP. Is that
> redundant, and should all WWAN drivers be moved to only POINTTOPOINT?
>
> (aside: usbnet has FLAG_POINTTOPOINT, but that's nothing to do with
> IFF_POINTTOPOINT, it only controls whether the interface is named usbX
> or ethX. Confusing.)
I can't answer any of your questions unless you tell me what the
real limitation of these devices is.
For the second time, is the problem that these devices cannot
support broadcast packets properly?
^ permalink raw reply
* Re: [PATCH net-next] drivers/net: Clean up orphaned probes in Space.c
From: David Miller @ 2013-01-14 18:34 UTC (permalink / raw)
To: paul.gortmaker; +Cc: netdev
In-Reply-To: <1358139305-17737-1-git-send-email-paul.gortmaker@windriver.com>
From: Paul Gortmaker <paul.gortmaker@windriver.com>
Date: Sun, 13 Jan 2013 23:55:05 -0500
> The removal of the 8390 EISA drivers actually comprises the
> complete content of the EISA probe block, so we can now remove
> that block, and its hook into the unified probe. Note that
> the deleted comment mentions PCI probes, but they long since
> moved elsewhere, so no PCI probes are touched here.
>
> We get rid of the orphaned EISA probe prototypes, and a couple
> of left over MCA probe prototypes at the same time.
>
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next 09/10] bnx2x: Added FW GRO bridging support
From: Eric Dumazet @ 2013-01-14 18:44 UTC (permalink / raw)
To: Yuval Mintz; +Cc: davem, netdev, eilong, ariele
In-Reply-To: <1358184123.8744.3127.camel@edumazet-glaptop>
On Mon, 2013-01-14 at 09:22 -0800, Eric Dumazet wrote:
> This looks weird to me. This should be called by GRO stack only.
>
> What is the value of gso_segs ?
>
>
The reason I am pointing this out is the recent change in commit
1def9238d4aa2146924994aa4b7dc861f03b9362
(net_sched: more precise pkt_len computation)
bnx2x not setting gso_segs means that qdisc accounting on ingress is
completely wrong.
^ permalink raw reply
* [PATCH] atm: fore200e.c: fix uninitialized variable
From: Cong Ding @ 2013-01-14 18:57 UTC (permalink / raw)
To: Chas Williams, linux-atm-general, netdev, linux-kernel; +Cc: Cong Ding
the variable err is uninitialized if all the macros in the function are
disabled.
Signed-off-by: Cong Ding <dinggnu@gmail.com>
---
drivers/atm/fore200e.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 204814e..d4725fc 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -2780,7 +2780,7 @@ static struct pci_driver fore200e_pca_driver = {
static int __init fore200e_module_init(void)
{
- int err;
+ int err = 0;
printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
--
1.7.9.5
^ permalink raw reply related
* [PATCH net-next] ipv6 netevent: Remove old_neigh from netevent_redirect.
From: YOSHIFUJI Hideaki @ 2013-01-14 19:28 UTC (permalink / raw)
To: netdev, davem; +Cc: yoshfuji
The only user is cxgb3 driver.
old_neigh is used to check device change, but it must not happen
on redirect. In this sense, we can remove old_neigh argument.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c | 35 ++++++--------------
include/net/netevent.h | 3 +-
net/ipv6/route.c | 3 +-
3 files changed, 13 insertions(+), 28 deletions(-)
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
index 91d02eb..4232767 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
@@ -64,9 +64,8 @@ static const unsigned int MAX_ATIDS = 64 * 1024;
static const unsigned int ATID_BASE = 0x10000;
static void cxgb_neigh_update(struct neighbour *neigh);
-static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
- struct dst_entry *new, struct neighbour *new_neigh,
- const void *daddr);
+static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
+ struct neighbour *neigh, const void *daddr);
static inline int offload_activated(struct t3cdev *tdev)
{
@@ -970,10 +969,9 @@ static int nb_callback(struct notifier_block *self, unsigned long event,
}
case (NETEVENT_REDIRECT):{
struct netevent_redirect *nr = ctx;
- cxgb_redirect(nr->old, nr->old_neigh,
- nr->new, nr->new_neigh,
+ cxgb_redirect(nr->old, nr->new, nr->neigh,
nr->daddr);
- cxgb_neigh_update(nr->new_neigh);
+ cxgb_neigh_update(nr->neigh);
break;
}
default:
@@ -1109,11 +1107,11 @@ static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
tdev->send(tdev, skb);
}
-static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
- struct dst_entry *new, struct neighbour *new_neigh,
+static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
+ struct neighbour *neigh,
const void *daddr)
{
- struct net_device *olddev, *newdev;
+ struct net_device *dev;
struct tid_info *ti;
struct t3cdev *tdev;
u32 tid;
@@ -1121,26 +1119,15 @@ static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
struct l2t_entry *e;
struct t3c_tid_entry *te;
- olddev = old_neigh->dev;
- newdev = new_neigh->dev;
+ dev = neigh->dev;
- if (!is_offloading(olddev))
- return;
- if (!is_offloading(newdev)) {
- pr_warn("%s: Redirect to non-offload device ignored\n",
- __func__);
+ if (!is_offloading(dev))
return;
- }
- tdev = dev2t3cdev(olddev);
+ tdev = dev2t3cdev(dev);
BUG_ON(!tdev);
- if (tdev != dev2t3cdev(newdev)) {
- pr_warn("%s: Redirect to different offload device ignored\n",
- __func__);
- return;
- }
/* Add new L2T entry */
- e = t3_l2t_get(tdev, new, newdev, daddr);
+ e = t3_l2t_get(tdev, new, dev, daddr);
if (!e) {
pr_err("%s: couldn't allocate new l2t entry!\n", __func__);
return;
diff --git a/include/net/netevent.h b/include/net/netevent.h
index 3ce4988..fe630dd 100644
--- a/include/net/netevent.h
+++ b/include/net/netevent.h
@@ -16,9 +16,8 @@ struct neighbour;
struct netevent_redirect {
struct dst_entry *old;
- struct neighbour *old_neigh;
struct dst_entry *new;
- struct neighbour *new_neigh;
+ struct neighbour *neigh;
const void *daddr;
};
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 34f392f0..7c34c01 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1803,10 +1803,9 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
goto out;
netevent.old = &rt->dst;
- netevent.old_neigh = old_neigh;
netevent.new = &nrt->dst;
- netevent.new_neigh = neigh;
netevent.daddr = &msg->dest;
+ netevent.neigh = neigh;
call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
if (rt->rt6i_flags & RTF_CACHE) {
--
1.7.9.5
^ permalink raw reply related
* [PATCH 0/5]: soreuseport: Bind multiple sockets to the same port
From: Tom Herbert @ 2013-01-14 20:00 UTC (permalink / raw)
To: netdev, davem; +Cc: netdev, eric.dumazet
[-- Attachment #1: Type: TEXT/PLAIN, Size: 2675 bytes --]
Rebasing the soreuseport patches to 3.8. No material changes since
first posted.
---
These patches implements so_reuseport (SO_REUSEPORT socket option) for
TCP and UDP. For TCP, so_reuseport allows multiple listener sockets
to be bound to the same port. In the case of UDP, so_reuseport allows
multiple sockets to bind to the same port. To prevent port hijacking
all sockets bound to the same port using so_reuseport must have the
same uid. Received packets are distributed to multiple sockets bound
to the same port using a 4-tuple hash.
The motivating case for so_resuseport in TCP would be something like
a web server binding to port 80 running with multiple threads, where
each thread might have it's own listener socket. This could be done
as an alternative to other models: 1) have one listener thread which
dispatches completed connections to workers. 2) accept on a single
listener socket from multiple threads. In case #1 the listener thread
can easily become the bottleneck with high connection turn-over rate.
In case #2, the proportion of connections accepted per thread tends
to be uneven under high connection load (assuming simple event loop:
while (1) { accept(); process() }, wakeup does not promote fairness
among the sockets. We have seen the disproportion to be as high
as 3:1 ratio between thread accepting most connections and the one
accepting the fewest. With so_reusport the distribution is
uniform.
The TCP implementation has a problem in that the request sockets for a
listener are attached to a listener socket. If a SYN is received, a
listener socket is chosen and request structure is created (SYN-RECV
state). If the subsequent ack in 3WHS does not match the same port
by so_reusport, the connection state is not found (reset) and the
request structure is orphaned. This scenario would occur when the
number of listener sockets bound to a port changes (new ones are
added, or old ones closed). We are looking for a solution to this,
maybe allow multiple sockets to share the same request table...
The motivating case for so_reuseport in UDP would be something like a
DNS server. An alternative would be to recv on the same socket from
multiple threads. As in the case of TCP, the load across these threads
tends to be disproportionate and we also see a lot of contection on
the socket lock. Note that SO_REUSEADDR already allows multiple UDP
sockets to bind to the same port, however there is no provision to
prevent hijacking and nothing to distribute packets across all the
sockets sharing the same bound port. This patch does not change the
semantics of SO_REUSEADDR, but provides usable functionality of it
for unicast.
^ permalink raw reply
* [PATCH 1/5] soreuseport: infrastructure
From: Tom Herbert @ 2013-01-14 20:00 UTC (permalink / raw)
To: netdev, davem; +Cc: netdev, eric.dumazet
Definitions and macros for implementing soreusport.
Signed-off-by: Tom Herbert <therbert@google.com>
---
include/linux/random.h | 6 ++++++
include/net/sock.h | 5 ++++-
include/uapi/asm-generic/socket.h | 3 +--
net/core/sock.c | 7 +++++++
4 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/include/linux/random.h b/include/linux/random.h
index d984608..347ce55 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -74,4 +74,10 @@ static inline int arch_get_random_int(unsigned int *v)
}
#endif
+/* Pseudo random number generator from numerical recipes. */
+static inline u32 next_pseudo_random32(u32 seed)
+{
+ return seed * 1664525 + 1013904223;
+}
+
#endif /* _LINUX_RANDOM_H */
diff --git a/include/net/sock.h b/include/net/sock.h
index 182ca99..360b412 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -140,6 +140,7 @@ typedef __u64 __bitwise __addrpair;
* @skc_family: network address family
* @skc_state: Connection state
* @skc_reuse: %SO_REUSEADDR setting
+ * @skc_reuseport: %SO_REUSEPORT setting
* @skc_bound_dev_if: bound device index if != 0
* @skc_bind_node: bind hash linkage for various protocol lookup tables
* @skc_portaddr_node: second hash linkage for UDP/UDP-Lite protocol
@@ -179,7 +180,8 @@ struct sock_common {
unsigned short skc_family;
volatile unsigned char skc_state;
- unsigned char skc_reuse;
+ unsigned char skc_reuse:4;
+ unsigned char skc_reuseport:4;
int skc_bound_dev_if;
union {
struct hlist_node skc_bind_node;
@@ -297,6 +299,7 @@ struct sock {
#define sk_family __sk_common.skc_family
#define sk_state __sk_common.skc_state
#define sk_reuse __sk_common.skc_reuse
+#define sk_reuseport __sk_common.skc_reuseport
#define sk_bound_dev_if __sk_common.skc_bound_dev_if
#define sk_bind_node __sk_common.skc_bind_node
#define sk_prot __sk_common.skc_prot
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index 2d32d07..331e322 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -22,8 +22,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
-
+#define SO_REUSEPORT 15
#ifndef SO_PASSCRED /* powerpc only differs in these */
#define SO_PASSCRED 16
#define SO_PEERCRED 17
diff --git a/net/core/sock.c b/net/core/sock.c
index bc131d4..0040832 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -665,6 +665,9 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
case SO_REUSEADDR:
sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE);
break;
+ case SO_REUSEPORT:
+ sk->sk_reuseport = valbool;
+ break;
case SO_TYPE:
case SO_PROTOCOL:
case SO_DOMAIN:
@@ -965,6 +968,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.val = sk->sk_reuse;
break;
+ case SO_REUSEPORT:
+ v.val = sk->sk_reuseport;
+ break;
+
case SO_KEEPALIVE:
v.val = sock_flag(sk, SOCK_KEEPOPEN);
break;
--
1.7.7.3
^ permalink raw reply related
* [PATCH 2/5] soreuseport: TCP/IPv4 implementation
From: Tom Herbert @ 2013-01-14 20:00 UTC (permalink / raw)
To: netdev, davem; +Cc: netdev, eric.dumazet
Allow multiple listener sockets to bind to the same port.
Motivation for soresuseport would be something like a web server
binding to port 80 running with multiple threads, where each thread
might have it's own listener socket. This could be done as an
alternative to other models: 1) have one listener thread which
dispatches completed connections to workers. 2) accept on a single
listener socket from multiple threads. In case #1 the listener thread
can easily become the bottleneck with high connection turn-over rate.
In case #2, the proportion of connections accepted per thread tends
to be uneven under high connection load (assuming simple event loop:
while (1) { accept(); process() }, wakeup does not promote fairness
among the sockets. We have seen the disproportion to be as high
as 3:1 ratio between thread accepting most connections and the one
accepting the fewest. With so_reusport the distribution is
uniform.
Signed-off-by: Tom Herbert <therbert@google.com>
---
include/net/inet_hashtables.h | 13 ++++++++--
net/ipv4/inet_connection_sock.c | 48 ++++++++++++++++++++++++++++++---------
net/ipv4/inet_hashtables.c | 28 +++++++++++++++++-----
net/ipv4/tcp_ipv4.c | 4 ++-
4 files changed, 72 insertions(+), 21 deletions(-)
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 67a8fa0..2968c8f 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -81,7 +81,9 @@ struct inet_bind_bucket {
struct net *ib_net;
#endif
unsigned short port;
- signed short fastreuse;
+ signed char fastreuse;
+ signed char fastreuseport;
+ int fastuid;
int num_owners;
struct hlist_node node;
struct hlist_head owners;
@@ -257,15 +259,19 @@ extern void inet_unhash(struct sock *sk);
extern struct sock *__inet_lookup_listener(struct net *net,
struct inet_hashinfo *hashinfo,
+ const __be32 saddr,
+ const __be16 sport,
const __be32 daddr,
const unsigned short hnum,
const int dif);
static inline struct sock *inet_lookup_listener(struct net *net,
struct inet_hashinfo *hashinfo,
+ __be32 saddr, __be16 sport,
__be32 daddr, __be16 dport, int dif)
{
- return __inet_lookup_listener(net, hashinfo, daddr, ntohs(dport), dif);
+ return __inet_lookup_listener(net, hashinfo, saddr, sport,
+ daddr, ntohs(dport), dif);
}
/* Socket demux engine toys. */
@@ -358,7 +364,8 @@ static inline struct sock *__inet_lookup(struct net *net,
struct sock *sk = __inet_lookup_established(net, hashinfo,
saddr, sport, daddr, hnum, dif);
- return sk ? : __inet_lookup_listener(net, hashinfo, daddr, hnum, dif);
+ return sk ? : __inet_lookup_listener(net, hashinfo, saddr, sport,
+ daddr, hnum, dif);
}
static inline struct sock *inet_lookup(struct net *net,
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index d0670f0..c2ce445 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -59,6 +59,8 @@ int inet_csk_bind_conflict(const struct sock *sk,
struct sock *sk2;
struct hlist_node *node;
int reuse = sk->sk_reuse;
+ int reuseport = sk->sk_reuseport;
+ int uid = sock_i_uid((struct sock *)sk);
/*
* Unlike other sk lookup places we do not check
@@ -73,8 +75,11 @@ int inet_csk_bind_conflict(const struct sock *sk,
(!sk->sk_bound_dev_if ||
!sk2->sk_bound_dev_if ||
sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
- if (!reuse || !sk2->sk_reuse ||
- sk2->sk_state == TCP_LISTEN) {
+ if ((!reuse || !sk2->sk_reuse ||
+ sk2->sk_state == TCP_LISTEN) &&
+ (!reuseport || !sk2->sk_reuseport ||
+ (sk2->sk_state != TCP_TIME_WAIT &&
+ uid != sock_i_uid(sk2)))) {
const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2);
if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) ||
sk2_rcv_saddr == sk_rcv_saddr(sk))
@@ -106,6 +111,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
int ret, attempts = 5;
struct net *net = sock_net(sk);
int smallest_size = -1, smallest_rover;
+ int uid = sock_i_uid(sk);
local_bh_disable();
if (!snum) {
@@ -125,9 +131,12 @@ again:
spin_lock(&head->lock);
inet_bind_bucket_for_each(tb, node, &head->chain)
if (net_eq(ib_net(tb), net) && tb->port == rover) {
- if (tb->fastreuse > 0 &&
- sk->sk_reuse &&
- sk->sk_state != TCP_LISTEN &&
+ if (((tb->fastreuse > 0 &&
+ sk->sk_reuse &&
+ sk->sk_state != TCP_LISTEN) ||
+ (tb->fastreuseport > 0 &&
+ sk->sk_reuseport &&
+ tb->fastuid == uid)) &&
(tb->num_owners < smallest_size || smallest_size == -1)) {
smallest_size = tb->num_owners;
smallest_rover = rover;
@@ -185,14 +194,17 @@ tb_found:
if (sk->sk_reuse == SK_FORCE_REUSE)
goto success;
- if (tb->fastreuse > 0 &&
- sk->sk_reuse && sk->sk_state != TCP_LISTEN &&
+ if (((tb->fastreuse > 0 &&
+ sk->sk_reuse && sk->sk_state != TCP_LISTEN) ||
+ (tb->fastreuseport > 0 &&
+ sk->sk_reuseport && tb->fastuid == uid)) &&
smallest_size == -1) {
goto success;
} else {
ret = 1;
if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, true)) {
- if (sk->sk_reuse && sk->sk_state != TCP_LISTEN &&
+ if (((sk->sk_reuse && sk->sk_state != TCP_LISTEN) ||
+ (sk->sk_reuseport && tb->fastuid == uid)) &&
smallest_size != -1 && --attempts >= 0) {
spin_unlock(&head->lock);
goto again;
@@ -212,9 +224,23 @@ tb_not_found:
tb->fastreuse = 1;
else
tb->fastreuse = 0;
- } else if (tb->fastreuse &&
- (!sk->sk_reuse || sk->sk_state == TCP_LISTEN))
- tb->fastreuse = 0;
+ if (sk->sk_reuseport) {
+ tb->fastreuseport = 1;
+ tb->fastuid = uid;
+ } else {
+ tb->fastreuseport = 0;
+ tb->fastuid = 0;
+ }
+ } else {
+ if (tb->fastreuse &&
+ (!sk->sk_reuse || sk->sk_state == TCP_LISTEN))
+ tb->fastreuse = 0;
+ if (tb->fastreuseport &&
+ (!sk->sk_reuseport || tb->fastuid != uid)) {
+ tb->fastreuseport = 0;
+ tb->fastuid = 0;
+ }
+ }
success:
if (!inet_csk(sk)->icsk_bind_hash)
inet_bind_hash(sk, tb, snum);
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index fa3ae81..491cb85 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -39,6 +39,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep,
write_pnet(&tb->ib_net, hold_net(net));
tb->port = snum;
tb->fastreuse = 0;
+ tb->fastreuseport = 0;
tb->num_owners = 0;
INIT_HLIST_HEAD(&tb->owners);
hlist_add_head(&tb->node, &head->chain);
@@ -151,16 +152,16 @@ static inline int compute_score(struct sock *sk, struct net *net,
if (net_eq(sock_net(sk), net) && inet->inet_num == hnum &&
!ipv6_only_sock(sk)) {
__be32 rcv_saddr = inet->inet_rcv_saddr;
- score = sk->sk_family == PF_INET ? 1 : 0;
+ score = sk->sk_family == PF_INET ? 2 : 1;
if (rcv_saddr) {
if (rcv_saddr != daddr)
return -1;
- score += 2;
+ score += 4;
}
if (sk->sk_bound_dev_if) {
if (sk->sk_bound_dev_if != dif)
return -1;
- score += 2;
+ score += 4;
}
}
return score;
@@ -176,6 +177,7 @@ static inline int compute_score(struct sock *sk, struct net *net,
struct sock *__inet_lookup_listener(struct net *net,
struct inet_hashinfo *hashinfo,
+ const __be32 saddr, __be16 sport,
const __be32 daddr, const unsigned short hnum,
const int dif)
{
@@ -183,17 +185,29 @@ struct sock *__inet_lookup_listener(struct net *net,
struct hlist_nulls_node *node;
unsigned int hash = inet_lhashfn(net, hnum);
struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
- int score, hiscore;
+ int score, hiscore, matches = 0, reuseport = 0;
+ u32 phash = 0;
rcu_read_lock();
begin:
result = NULL;
- hiscore = -1;
+ hiscore = 0;
sk_nulls_for_each_rcu(sk, node, &ilb->head) {
score = compute_score(sk, net, hnum, daddr, dif);
if (score > hiscore) {
result = sk;
hiscore = score;
+ reuseport = sk->sk_reuseport;
+ if (reuseport) {
+ phash = inet_ehashfn(net, daddr, hnum,
+ saddr, sport);
+ matches = 1;
+ }
+ } else if (score == hiscore && reuseport) {
+ matches++;
+ if (((u64)phash * matches) >> 32 == 0)
+ result = sk;
+ phash = next_pseudo_random32(phash);
}
}
/*
@@ -501,7 +515,8 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
inet_bind_bucket_for_each(tb, node, &head->chain) {
if (net_eq(ib_net(tb), net) &&
tb->port == port) {
- if (tb->fastreuse >= 0)
+ if (tb->fastreuse >= 0 ||
+ tb->fastreuseport >= 0)
goto next_port;
WARN_ON(hlist_empty(&tb->owners));
if (!check_established(death_row, sk,
@@ -518,6 +533,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
break;
}
tb->fastreuse = -1;
+ tb->fastreuseport = -1;
goto ok;
next_port:
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index c6ce9ca..bbbdcc5 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -657,7 +657,8 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
* no RST generated if md5 hash doesn't match.
*/
sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev),
- &tcp_hashinfo, ip_hdr(skb)->daddr,
+ &tcp_hashinfo, ip_hdr(skb)->saddr,
+ th->source, ip_hdr(skb)->daddr,
ntohs(th->source), inet_iif(skb));
/* don't send rst if it can't find key */
if (!sk1)
@@ -2074,6 +2075,7 @@ do_time_wait:
case TCP_TW_SYN: {
struct sock *sk2 = inet_lookup_listener(dev_net(skb->dev),
&tcp_hashinfo,
+ iph->saddr, th->source,
iph->daddr, th->dest,
inet_iif(skb));
if (sk2) {
--
1.7.7.3
^ permalink raw reply related
* [PATCH 5/5] soreuseport: UDP/IPv6 implementation
From: Tom Herbert @ 2013-01-14 20:00 UTC (permalink / raw)
To: netdev, davem; +Cc: netdev, eric.dumazet
[-- Attachment #1: Type: TEXT/PLAIN, Size: 2690 bytes --]
Allow multiple UDP sockets to bind to the same port.
Motivation for soreuseport would be something like a DNS server. An
alternative would be to recv on the same socket from multiple threads.
As in the case of TCP, the load across these threads tends to be
disproportionate and we also see a lot of contection on the socket lock.
Note that SO_REUSEADDR already allows multiple UDP sockets to bind to
the same port, however there is no provision to prevent hijacking and
nothing to distribute packets across all the sockets sharing the same
bound port. This patch does not change the semantics of SO_REUSEADDR,
but provides usable functionality of it for unicast.
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv6/udp.c | 30 +++++++++++++++++++++++++++---
1 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 1afb635..779d8c0 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -45,6 +45,7 @@
#include <net/tcp_states.h>
#include <net/ip6_checksum.h>
#include <net/xfrm.h>
+#include <net/inet6_hashtables.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@@ -203,7 +204,8 @@ static struct sock *udp6_lib_lookup2(struct net *net,
{
struct sock *sk, *result;
struct hlist_nulls_node *node;
- int score, badness;
+ int score, badness, matches = 0, reuseport = 0;
+ u32 hash = 0;
begin:
result = NULL;
@@ -214,8 +216,18 @@ begin:
if (score > badness) {
result = sk;
badness = score;
- if (score == SCORE2_MAX)
+ reuseport = sk->sk_reuseport;
+ if (reuseport) {
+ hash = inet6_ehashfn(net, daddr, hnum,
+ saddr, sport);
+ matches = 1;
+ } else if (score == SCORE2_MAX)
goto exact_match;
+ } else if (score == badness && reuseport) {
+ matches++;
+ if (((u64)hash * matches) >> 32 == 0)
+ result = sk;
+ hash = next_pseudo_random32(hash);
}
}
/*
@@ -249,7 +261,8 @@ struct sock *__udp6_lib_lookup(struct net *net,
unsigned short hnum = ntohs(dport);
unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
- int score, badness;
+ int score, badness, matches = 0, reuseport = 0;
+ u32 hash = 0;
rcu_read_lock();
if (hslot->count > 10) {
@@ -284,6 +297,17 @@ begin:
if (score > badness) {
result = sk;
badness = score;
+ reuseport = sk->sk_reuseport;
+ if (reuseport) {
+ hash = inet6_ehashfn(net, daddr, hnum,
+ saddr, sport);
+ matches = 1;
+ }
+ } else if (score == badness && reuseport) {
+ matches++;
+ if (((u64)hash * matches) >> 32 == 0)
+ result = sk;
+ hash = next_pseudo_random32(hash);
}
}
/*
--
1.7.7.3
^ permalink raw reply related
* [RFC net-next] ipv6 route: Do not attach neighbour on route.
From: YOSHIFUJI Hideaki @ 2013-01-14 20:00 UTC (permalink / raw)
To: davem, netdev; +Cc: yoshfuji
Not tested, just an RFC.
Depends on previous new_neigh removal from netevent patch (sorry).
--yoshfuji
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
include/net/ip6_fib.h | 2 -
include/net/ip6_route.h | 8 ++++
net/ipv6/ip6_output.c | 20 ++++++--
net/ipv6/route.c | 120 ++++++++++++-----------------------------------
net/ipv6/xfrm6_policy.c | 1 -
5 files changed, 52 insertions(+), 99 deletions(-)
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index fdc48a9..6919a50 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -89,8 +89,6 @@ struct fib6_table;
struct rt6_info {
struct dst_entry dst;
- struct neighbour *n;
-
/*
* Tail elements of dst_entry (__refcnt etc.)
* and these elements (rarely used in hot path) are in
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 27d8318..439928d 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -21,6 +21,7 @@ struct route_info {
#include <net/flow.h>
#include <net/ip6_fib.h>
#include <net/sock.h>
+#include <linux/route.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
@@ -137,6 +138,13 @@ extern void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk,
extern void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark);
extern void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk);
+static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt, struct in6_addr *dst)
+{
+ if (rt->rt6i_flags & RTF_GATEWAY)
+ return &rt->rt6i_gateway;
+ return dst;
+}
+
struct netlink_callback;
struct rt6_rtnl_dump_arg {
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 9581ffa..af2376d 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -123,10 +123,17 @@ static int ip6_finish_output2(struct sk_buff *skb)
skb->len);
}
+
rt = (struct rt6_info *) dst;
- neigh = rt->n;
- if (neigh)
- return dst_neigh_output(dst, neigh, skb);
+ rcu_read_lock_bh();
+ neigh = __ipv6_neigh_lookup_noref(rt->rt6i_idev->dev,
+ rt6_nexthop(rt, &ipv6_hdr(skb)->daddr));
+ if (neigh) {
+ int ret = dst_neigh_output(dst, neigh, skb);
+ rcu_read_unlock_bh();
+ return ret;
+ }
+ rcu_read_unlock_bh();
IP6_INC_STATS_BH(dev_net(dst->dev),
ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
@@ -912,9 +919,12 @@ static int ip6_dst_lookup_tail(struct sock *sk,
* dst entry and replace it instead with the
* dst entry of the nexthop router
*/
+ rcu_read_lock_bh();
rt = (struct rt6_info *) *dst;
- n = rt->n;
- if (n && !(n->nud_state & NUD_VALID)) {
+ n = __ipv6_neigh_lookup_noref(rt->rt6i_idev->dev, rt6_nexthop(rt, &fl6->daddr));
+ err = n && n->nud_state & NUD_VALID ? 0 : -EINVAL;
+ rcu_read_unlock_bh();
+ if (!err) {
struct inet6_ifaddr *ifp;
struct flowi6 fl_gw6;
int redirect;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 6856e56..b57d0b5 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -151,19 +151,6 @@ static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
return neigh_create(&nd_tbl, daddr, dst->dev);
}
-static int rt6_bind_neighbour(struct rt6_info *rt, struct net_device *dev)
-{
- struct neighbour *n = __ipv6_neigh_lookup(dev, &rt->rt6i_gateway);
- if (!n) {
- n = neigh_create(&nd_tbl, &rt->rt6i_gateway, dev);
- if (IS_ERR(n))
- return PTR_ERR(n);
- }
- rt->n = n;
-
- return 0;
-}
-
static struct dst_ops ip6_dst_ops_template = {
.family = AF_INET6,
.protocol = cpu_to_be16(ETH_P_IPV6),
@@ -301,9 +288,6 @@ static void ip6_dst_destroy(struct dst_entry *dst)
struct rt6_info *rt = (struct rt6_info *)dst;
struct inet6_dev *idev = rt->rt6i_idev;
- if (rt->n)
- neigh_release(rt->n);
-
if (!(rt->dst.flags & DST_HOST))
dst_destroy_metrics_generic(dst);
@@ -354,11 +338,6 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
in6_dev_put(idev);
}
}
- if (rt->n && rt->n->dev == dev) {
- rt->n->dev = loopback_dev;
- dev_hold(loopback_dev);
- dev_put(dev);
- }
}
}
@@ -498,24 +477,32 @@ static void rt6_probe(struct rt6_info *rt)
* Router Reachability Probe MUST be rate-limited
* to no more than one per minute.
*/
- neigh = rt ? rt->n : NULL;
- if (!neigh || (neigh->nud_state & NUD_VALID))
+ rcu_read_lock_bh();
+ neigh = __ipv6_neigh_lookup_noref(rt->rt6i_idev->dev, &rt->rt6i_gateway);
+ if (!neigh || neigh->nud_state & NUD_VALID) {
+ rcu_read_unlock_bh();
return;
- read_lock_bh(&neigh->lock);
+ }
+ read_lock(&neigh->lock);
if (!(neigh->nud_state & NUD_VALID) &&
time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
struct in6_addr mcaddr;
struct in6_addr *target;
neigh->updated = jiffies;
- read_unlock_bh(&neigh->lock);
+
+ neigh_hold(neigh);
+
+ read_unlock(&neigh->lock);
target = (struct in6_addr *)&neigh->primary_key;
addrconf_addr_solict_mult(target, &mcaddr);
ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL);
} else {
- read_unlock_bh(&neigh->lock);
+ read_unlock(&neigh->lock);
}
+ rcu_read_unlock_bh();
+ neigh_release(neigh);
}
#else
static inline void rt6_probe(struct rt6_info *rt)
@@ -542,20 +529,25 @@ static inline bool rt6_check_neigh(struct rt6_info *rt)
struct neighbour *neigh;
bool ret = false;
- neigh = rt->n;
if (rt->rt6i_flags & RTF_NONEXTHOP ||
- !(rt->rt6i_flags & RTF_GATEWAY))
+ !(rt->rt6i_flags & RTF_GATEWAY)) {
ret = true;
- else if (neigh) {
- read_lock_bh(&neigh->lock);
+ goto out;
+ }
+ rcu_read_lock_bh();
+ neigh = __ipv6_neigh_lookup_noref(rt->rt6i_idev->dev, &rt->rt6i_gateway);
+ if (neigh) {
+ read_lock(&neigh->lock);
if (neigh->nud_state & NUD_VALID)
ret = true;
#ifdef CONFIG_IPV6_ROUTER_PREF
else if (!(neigh->nud_state & NUD_FAILED))
ret = true;
#endif
- read_unlock_bh(&neigh->lock);
+ read_unlock(&neigh->lock);
}
+ rcu_read_unlock_bh();
+out:
return ret;
}
@@ -831,8 +823,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
rt = ip6_rt_copy(ort, daddr);
if (rt) {
- int attempts = !in_softirq();
-
if (!(rt->rt6i_flags & RTF_GATEWAY)) {
if (ort->rt6i_dst.plen != 128 &&
ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
@@ -848,32 +838,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
rt->rt6i_src.plen = 128;
}
#endif
-
- retry:
- if (rt6_bind_neighbour(rt, rt->dst.dev)) {
- struct net *net = dev_net(rt->dst.dev);
- int saved_rt_min_interval =
- net->ipv6.sysctl.ip6_rt_gc_min_interval;
- int saved_rt_elasticity =
- net->ipv6.sysctl.ip6_rt_gc_elasticity;
-
- if (attempts-- > 0) {
- net->ipv6.sysctl.ip6_rt_gc_elasticity = 1;
- net->ipv6.sysctl.ip6_rt_gc_min_interval = 0;
-
- ip6_dst_gc(&net->ipv6.ip6_dst_ops);
-
- net->ipv6.sysctl.ip6_rt_gc_elasticity =
- saved_rt_elasticity;
- net->ipv6.sysctl.ip6_rt_gc_min_interval =
- saved_rt_min_interval;
- goto retry;
- }
-
- net_warn_ratelimited("Neighbour table overflow\n");
- dst_free(&rt->dst);
- return NULL;
- }
}
return rt;
@@ -884,10 +848,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
{
struct rt6_info *rt = ip6_rt_copy(ort, daddr);
- if (rt) {
+ if (rt)
rt->rt6i_flags |= RTF_CACHE;
- rt->n = neigh_clone(ort->n);
- }
return rt;
}
@@ -921,7 +883,7 @@ restart:
dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);
- if (!rt->n && !(rt->rt6i_flags & RTF_NONEXTHOP))
+ if (!(rt->rt6i_flags & (RTF_GATEWAY | RTF_NONEXTHOP)))
nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
else if (!(rt->dst.flags & DST_HOST))
nrt = rt6_alloc_clone(rt, &fl6->daddr);
@@ -1271,7 +1233,6 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
rt->dst.flags |= DST_HOST;
rt->dst.output = ip6_output;
- rt->n = neigh;
atomic_set(&rt->dst.__refcnt, 1);
rt->rt6i_dst.addr = fl6->daddr;
rt->rt6i_dst.plen = 128;
@@ -1580,12 +1541,6 @@ int ip6_route_add(struct fib6_config *cfg)
} else
rt->rt6i_prefsrc.plen = 0;
- if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
- err = rt6_bind_neighbour(rt, dev);
- if (err)
- goto out;
- }
-
rt->rt6i_flags = cfg->fc_flags;
install_route:
@@ -1699,7 +1654,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
struct netevent_redirect netevent;
struct rt6_info *rt, *nrt = NULL;
struct ndisc_options ndopts;
- struct neighbour *old_neigh;
struct inet6_dev *in6_dev;
struct neighbour *neigh;
struct rd_msg *msg;
@@ -1772,11 +1726,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
if (!neigh)
return;
- /* Duplicate redirect: silently ignore. */
- old_neigh = rt->n;
- if (neigh == old_neigh)
- goto out;
-
/*
* We have finally decided to accept it.
*/
@@ -1797,7 +1746,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
nrt->rt6i_flags &= ~RTF_GATEWAY;
nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
- nrt->n = neigh_clone(neigh);
if (ip6_ins_rt(nrt))
goto out;
@@ -2111,7 +2059,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
{
struct net *net = dev_net(idev->dev);
struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL);
- int err;
if (!rt) {
net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n");
@@ -2130,11 +2077,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
rt->rt6i_flags |= RTF_ANYCAST;
else
rt->rt6i_flags |= RTF_LOCAL;
- err = rt6_bind_neighbour(rt, rt->dst.dev);
- if (err) {
- dst_free(&rt->dst);
- return ERR_PTR(err);
- }
rt->rt6i_dst.addr = *addr;
rt->rt6i_dst.plen = 128;
@@ -2480,7 +2422,6 @@ static int rt6_fill_node(struct net *net,
struct nlmsghdr *nlh;
long expires;
u32 table;
- struct neighbour *n;
if (prefix) { /* user wants prefix routes only */
if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
@@ -2593,9 +2534,8 @@ static int rt6_fill_node(struct net *net,
if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
goto nla_put_failure;
- n = rt->n;
- if (n) {
- if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0)
+ if (rt->rt6i_flags & RTF_GATEWAY) {
+ if (nla_put(skb, RTA_GATEWAY, 16, &rt->rt6i_gateway) < 0)
goto nla_put_failure;
}
@@ -2790,7 +2730,6 @@ struct rt6_proc_arg
static int rt6_info_route(struct rt6_info *rt, void *p_arg)
{
struct seq_file *m = p_arg;
- struct neighbour *n;
seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
@@ -2799,9 +2738,8 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg)
#else
seq_puts(m, "00000000000000000000000000000000 00 ");
#endif
- n = rt->n;
- if (n) {
- seq_printf(m, "%pi6", n->primary_key);
+ if (rt->rt6i_flags & RTF_GATEWAY) {
+ seq_printf(m, "%pi6", &rt->rt6i_gateway);
} else {
seq_puts(m, "00000000000000000000000000000000");
}
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index c984413..1282737 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -110,7 +110,6 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
/* Sheit... I remember I did this right. Apparently,
* it was magically lost, so this code needs audit */
- xdst->u.rt6.n = neigh_clone(rt->n);
xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
RTF_LOCAL);
xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH net-next] ipv6 netevent: Remove old_neigh from netevent_redirect.
From: David Miller @ 2013-01-14 20:05 UTC (permalink / raw)
To: yoshfuji; +Cc: netdev
In-Reply-To: <50F45C5B.8020507@linux-ipv6.org>
From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date: Tue, 15 Jan 2013 04:28:27 +0900
> The only user is cxgb3 driver.
>
> old_neigh is used to check device change, but it must not happen
> on redirect. In this sense, we can remove old_neigh argument.
>
> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Applied, thanks.
^ permalink raw reply
* [PATCH 3/5] soreuseport: UDP/IPv4 implementation
From: Tom Herbert @ 2013-01-14 20:00 UTC (permalink / raw)
To: netdev, davem; +Cc: netdev, eric.dumazet
[-- Attachment #1: Type: TEXT/PLAIN, Size: 6173 bytes --]
Allow multiple UDP sockets to bind to the same port.
Motivation soreuseport would be something like a DNS server. An
alternative would be to recv on the same socket from multiple threads.
As in the case of TCP, the load across these threads tends to be
disproportionate and we also see a lot of contection on the socketlock.
Note that SO_REUSEADDR already allows multiple UDP sockets to bind to
the same port, however there is no provision to prevent hijacking and
nothing to distribute packets across all the sockets sharing the same
bound port. This patch does not change the semantics of SO_REUSEADDR,
but provides usable functionality of it for unicast.
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv4/udp.c | 61 +++++++++++++++++++++++++++++++++++++++----------------
1 files changed, 43 insertions(+), 18 deletions(-)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 79c8dbe..1dd1e93 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -139,6 +139,7 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
{
struct sock *sk2;
struct hlist_nulls_node *node;
+ int uid = sock_i_uid(sk);
sk_nulls_for_each(sk2, node, &hslot->head)
if (net_eq(sock_net(sk2), net) &&
@@ -147,6 +148,8 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
(!sk2->sk_reuse || !sk->sk_reuse) &&
(!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+ (!sk2->sk_reuseport || !sk->sk_reuseport ||
+ uid != sock_i_uid(sk2)) &&
(*saddr_comp)(sk, sk2)) {
if (bitmap)
__set_bit(udp_sk(sk2)->udp_port_hash >> log,
@@ -169,6 +172,7 @@ static int udp_lib_lport_inuse2(struct net *net, __u16 num,
{
struct sock *sk2;
struct hlist_nulls_node *node;
+ int uid = sock_i_uid(sk);
int res = 0;
spin_lock(&hslot2->lock);
@@ -179,6 +183,8 @@ static int udp_lib_lport_inuse2(struct net *net, __u16 num,
(!sk2->sk_reuse || !sk->sk_reuse) &&
(!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+ (!sk2->sk_reuseport || !sk->sk_reuseport ||
+ uid != sock_i_uid(sk2)) &&
(*saddr_comp)(sk, sk2)) {
res = 1;
break;
@@ -337,26 +343,26 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr,
!ipv6_only_sock(sk)) {
struct inet_sock *inet = inet_sk(sk);
- score = (sk->sk_family == PF_INET ? 1 : 0);
+ score = (sk->sk_family == PF_INET ? 2 : 1);
if (inet->inet_rcv_saddr) {
if (inet->inet_rcv_saddr != daddr)
return -1;
- score += 2;
+ score += 4;
}
if (inet->inet_daddr) {
if (inet->inet_daddr != saddr)
return -1;
- score += 2;
+ score += 4;
}
if (inet->inet_dport) {
if (inet->inet_dport != sport)
return -1;
- score += 2;
+ score += 4;
}
if (sk->sk_bound_dev_if) {
if (sk->sk_bound_dev_if != dif)
return -1;
- score += 2;
+ score += 4;
}
}
return score;
@@ -365,7 +371,6 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr,
/*
* In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, inet_num)
*/
-#define SCORE2_MAX (1 + 2 + 2 + 2)
static inline int compute_score2(struct sock *sk, struct net *net,
__be32 saddr, __be16 sport,
__be32 daddr, unsigned int hnum, int dif)
@@ -380,21 +385,21 @@ static inline int compute_score2(struct sock *sk, struct net *net,
if (inet->inet_num != hnum)
return -1;
- score = (sk->sk_family == PF_INET ? 1 : 0);
+ score = (sk->sk_family == PF_INET ? 2 : 1);
if (inet->inet_daddr) {
if (inet->inet_daddr != saddr)
return -1;
- score += 2;
+ score += 4;
}
if (inet->inet_dport) {
if (inet->inet_dport != sport)
return -1;
- score += 2;
+ score += 4;
}
if (sk->sk_bound_dev_if) {
if (sk->sk_bound_dev_if != dif)
return -1;
- score += 2;
+ score += 4;
}
}
return score;
@@ -409,19 +414,29 @@ static struct sock *udp4_lib_lookup2(struct net *net,
{
struct sock *sk, *result;
struct hlist_nulls_node *node;
- int score, badness;
+ int score, badness, matches = 0, reuseport = 0;
+ u32 hash = 0;
begin:
result = NULL;
- badness = -1;
+ badness = 0;
udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) {
score = compute_score2(sk, net, saddr, sport,
daddr, hnum, dif);
if (score > badness) {
result = sk;
badness = score;
- if (score == SCORE2_MAX)
- goto exact_match;
+ reuseport = sk->sk_reuseport;
+ if (reuseport) {
+ hash = inet_ehashfn(net, daddr, hnum,
+ saddr, htons(sport));
+ matches = 1;
+ }
+ } else if (score == badness && reuseport) {
+ matches++;
+ if (((u64)hash * matches) >> 32 == 0)
+ result = sk;
+ hash = next_pseudo_random32(hash);
}
}
/*
@@ -431,9 +446,7 @@ begin:
*/
if (get_nulls_value(node) != slot2)
goto begin;
-
if (result) {
-exact_match:
if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2)))
result = NULL;
else if (unlikely(compute_score2(result, net, saddr, sport,
@@ -457,7 +470,8 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
unsigned short hnum = ntohs(dport);
unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
- int score, badness;
+ int score, badness, matches = 0, reuseport = 0;
+ u32 hash = 0;
rcu_read_lock();
if (hslot->count > 10) {
@@ -486,13 +500,24 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
}
begin:
result = NULL;
- badness = -1;
+ badness = 0;
sk_nulls_for_each_rcu(sk, node, &hslot->head) {
score = compute_score(sk, net, saddr, hnum, sport,
daddr, dport, dif);
if (score > badness) {
result = sk;
badness = score;
+ reuseport = sk->sk_reuseport;
+ if (reuseport) {
+ hash = inet_ehashfn(net, daddr, hnum,
+ saddr, htons(sport));
+ matches = 1;
+ }
+ } else if (score == badness && reuseport) {
+ matches++;
+ if (((u64)hash * matches) >> 32 == 0)
+ result = sk;
+ hash = next_pseudo_random32(hash);
}
}
/*
--
1.7.7.3
^ permalink raw reply related
* Re: [PATCH net-next] pkt_sched: namespace aware act_mirred
From: David Miller @ 2013-01-14 20:10 UTC (permalink / raw)
To: bcrl; +Cc: eric.dumazet, jhs, netdev
In-Reply-To: <20130114151539.GO5259@kvack.org>
From: Benjamin LaHaise <bcrl@kvack.org>
Date: Mon, 14 Jan 2013 10:15:39 -0500
> Eric Dumazet pointed out that act_mirred needs to find the current net_ns,
> and struct net pointer is not provided in the call chain. His original
> patch made use of current->nsproxy->net_ns to find the network namespace,
> but this fails to work correctly for userspace code that makes use of
> netlink sockets in different network namespaces. Instead, pass the
> "struct net *" down along the call chain to where it is needed.
>
> This version removes the ifb changes as Eric has submitted that patch
> separately, but is otherwise identical to the previous version.
>
> Signed-off-by: Benjamin LaHaise <bcrl@kvack.org>
> Tested-by: Eric Dumazet <eric.dumazet@gmail.com>
> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH net-next] net: phy: remove flags argument from phy_{attach,connect,connect_direct}
From: David Miller @ 2013-01-14 20:12 UTC (permalink / raw)
To: florian; +Cc: netdev, konszert, afleming, linux-kernel
In-Reply-To: <1358160772-29631-1-git-send-email-florian@openwrt.org>
From: Florian Fainelli <florian@openwrt.org>
Date: Mon, 14 Jan 2013 11:52:52 +0100
> The flags argument of the phy_{attach,connect,connect_direct} functions
> is then used to assign a struct phy_device dev_flags with its value.
> All callers but the tg3 driver pass the flag 0, which results in the
> underlying PHY drivers in drivers/net/phy/ not being able to actually
> use any of the flags they would set in dev_flags. This patch gets rid of
> the flags argument, and passes phydev->dev_flags to the internal PHY
> library call phy_attach_direct() such that drivers which actually modify
> a phy device dev_flags get the value preserved for use by the underlying
> phy driver.
>
> Acked-by: Kosta Zertsekel <konszert@marvell.com>
> Signed-off-by: Florian Fainelli <florian@openwrt.org>
Applied, thanks.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox