* Re: Page allocation failures in guest
From: Pierre Ossman @ 2009-08-13 20:25 UTC (permalink / raw)
To: Rusty Russell
Cc: Avi Kivity, Minchan Kim, kvm, LKML, linux-mm, Wu Fengguang,
KOSAKI Motohiro, Rik van Riel, netdev
In-Reply-To: <200908121501.53167.rusty@rustcorp.com.au>
[-- Attachment #1: Type: text/plain, Size: 1044 bytes --]
On Wed, 12 Aug 2009 15:01:52 +0930
Rusty Russell <rusty@rustcorp.com.au> wrote:
> On Wed, 12 Aug 2009 12:49:51 pm Rusty Russell wrote:
> > On Tue, 11 Aug 2009 04:22:53 pm Avi Kivity wrote:
> > > On 08/11/2009 09:32 AM, Pierre Ossman wrote:
> > > > I doesn't get out of it though, or at least the virtio net driver
> > > > wedges itself.
> >
> > There's a fixme to retry when this happens, but this is the first report
> > I've received. I'll check it out.
>
> Subject: virtio: net refill on out-of-memory
>
> If we run out of memory, use keventd to fill the buffer. There's a
> report of this happening: "Page allocation failures in guest",
> Message-ID: <20090713115158.0a4892b0@mjolnir.ossman.eu>
>
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
>
Patch applied. Now we wait. :)
--
-- Pierre Ossman
WARNING: This correspondence is being monitored by the
Swedish government. Make sure your server uses encryption
for SMTP traffic and consider using PGP for end-to-end
encryption.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [RFC] ipv6: Change %pI6 format to output compacted addresses?
From: Brian Haley @ 2009-08-13 20:24 UTC (permalink / raw)
To: Joe Perches; +Cc: Chuck Lever, Jens Rosenboom, Linux Network Developers
In-Reply-To: <1250190346.28285.120.camel@Joe-Laptop.home>
Joe Perches wrote:
> I suppose ipv6_addr_v4mapped(addr) could be tested instead
>
> Perhaps this on top of last:
>
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index dd02842..7ce34a7 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -25,6 +25,7 @@
> #include <linux/kallsyms.h>
> #include <linux/uaccess.h>
> #include <linux/ioport.h>
> +#include <net/ipv6.h>
I was trying to avoid this by open-coding the v4mapped check, didn't
know if IPv6-specific headers should be pulled-into this generic
code, even though we're printing IPv6 addresses.
-Brian
^ permalink raw reply
* Re: [RFC] ipv6: Change %pI6 format to output compacted addresses?
From: Brian Haley @ 2009-08-13 20:24 UTC (permalink / raw)
To: Joe Perches; +Cc: Jens Rosenboom, Linux Network Developers, Chuck Lever
In-Reply-To: <1250187034.28285.93.camel@Joe-Laptop.home>
Joe Perches wrote:
> On Thu, 2009-08-13 at 12:27 -0400, Brian Haley wrote:
>> Jens Rosenboom wrote:
>>> Here is a new version that also
>>> fixes
>>>
>>> - Leave %pi6 alone
>>> - Don't compress a single :0:
>>> - Do output 0
>>> The results and also the remaining issues can be seen with the attached
>>> test program, that also exposes a bug in glibc for v4-mapped addresses
>>> from 0/16.
>>> To fully conform to the cited draft, we would still have to implement
>>> v4-mapped and also check whether a second run of zeros would be longer
>>> than the first one, although the draft also suggests that operators
>>> should avoid using this kind of addresses, so maybe this second issue
>>> can be neglected.
>> Yes, the "compress the most zeros" would be harder, and require two
>> passes over the address. I had to cut corners somewhere :)
>
> 2 things.
>
> First a question, then a compilable but untested patch.
>
> The patch allows "%p6ic" for compressed and "%p6ic4" for compressed
> with ipv4 last u32.
>
> Can somebody tell me what I'm doing wrong when I link Jens' test?
>
> cc -o test test_ipv6.c lib/vsprintf.o lib/ctype.o
> lib/vsprintf.o: In function `global constructors keyed to
> 65535_0_simple_strtoul':
> /home/joe/linux/linux-2.6/lib/vsprintf.c:1972: undefined reference to
> `__gcov_init'
> lib/vsprintf.o:(.data+0x28): undefined reference to `__gcov_merge_add'
> collect2: ld returned 1 exit status
Is your arch "um"? Seems like those are only defined there, I'm building
a straight x86 kernel.
> Now for the patch. Perhaps something like this (compiled, untested)
This core dumps when running "test", I'm still trying to track down why.
I think we're thinking too hard about this, I would think we'd always
want to print the shortened IPv6 address in debugging messages with %pI6.
The %pi6 places need to stay since they're an API to userspace. I don't
think we need the extra "c" and "c4" support.
One comment on a quick scan of the code:
> static char *ip6_addr_string(char *buf, char *end, u8 *addr,
> - struct printf_spec spec)
> + struct printf_spec spec, const char *fmt)
> {
> - char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */
> + char ip6_addr[7 * 4 + 7 + 4 * 4]; /* (7 * 4 hex digits) + 7 colons +
> + * ipv4 address, and trailing zero */
ip6_addr[8 * 5] is fine here, we won't ever have all eight plus an IPv4 address.
-Brian
^ permalink raw reply
* Re: [PATCH] net/ipv4, linux-2.6.30.4
From: David Miller @ 2009-08-13 20:15 UTC (permalink / raw)
To: hannemann; +Cc: slot.daniel, netdev
In-Reply-To: <4A8409CA.70200@nets.rwth-aachen.de>
From: Arnd Hannemann <hannemann@nets.rwth-aachen.de>
Date: Thu, 13 Aug 2009 14:40:42 +0200
> Please correct me if I'm wrong or just too stupid to understand this stuff.
> (very likely;-)
You may be right, but at least the infrastructure for reordering
detection is there.
So instead of improving the stuff we have, to make it detect
when reordering goes away and potentially re-enable FACK, you're
simply adding something new to replace it.
Why not just fix up for the deficiencies you're aware of?
^ permalink raw reply
* Re: [PATCH] net/ipv4, linux-2.6.30.4
From: David Miller @ 2009-08-13 20:13 UTC (permalink / raw)
To: hannemann; +Cc: slot.daniel, netdev
In-Reply-To: <4A8409CA.70200@nets.rwth-aachen.de>
From: Arnd Hannemann <hannemann@nets.rwth-aachen.de>
Date: Thu, 13 Aug 2009 14:40:42 +0200
> David Miller schrieb:
>> From: Daniel Slot <slot.daniel@gmail.com>
>> Date: Wed, 12 Aug 2009 20:47:44 +0200
>>
>>> RFC 4653 specifies Non-Congestion Robustness (NCR) for TCP.
>>> In the absence of explicit congestion notification from the network, TCP
>>> uses loss as an indication of congestion.
>>> One of the ways TCP detects loss is using the arrival of three duplicate
>>> acknowledgments.
>>> However, this heuristic is not always correct,
>>> notably in the case when network paths reorder segments (for whatever
>>> reason), resulting in degraded performance.
>>
>> Linux's TCP stack already has sophisticated reordering detection.ä
>
>
> Hmm, sophisticated? Sorry, it seemed pretty rudimental/random to me.
It's more sophisticated than what you're proposing, which is a hammer
which requires intervention on the part of the application.
^ permalink raw reply
* Re: [Bonding-devel] [PATCH net-next-2.6] bonding: introduce primary_lazy option
From: Nicolas de Pesloüan @ 2009-08-13 19:41 UTC (permalink / raw)
To: Jiri Pirko; +Cc: davem, netdev, fubar, bonding-devel
In-Reply-To: <20090813150513.GB10449@psychotron.englab.brq.redhat.com>
Jiri Pirko wrote:
> In some cases there is not desirable to switch back to primary interface when
> it's link recovers and rather stay wiith currently active one. We need to avoid
> packetloss as much as we can in some cases. This is solved by introducing
> primary_lazy option. Note that enslaved primary slave is set as current
> active no matter what.
May I suggest that instead of creating a new option to better define how
the "primary" option is expected to behave for active-backup mode, we
try the "weight" slave option I proposed in the thread "alternative to
primary" earlier this year ?
http://sourceforge.net/mailarchive/forum.php?thread_name=49D5357E.4020201%40free.fr&forum_name=bonding-devel
Giving the same "weight" to two different slaves means "chose at random
on startup and keep the active one until it fails". And if the "at
random" behavior is not appropriate, one can force the active slave
using what Jay suggested (/sys/class/net/bond0/bonding/active).
The proposed "weight" slave's option is able to prevent the slaves from
flip-flopping, by stating the fact that two slaves share the same
"primary" level, and may provide several other enhancements as described
in the thread.
Hence, it is a more general configuration interface than what you
proposed. I must admit that despite the fact that I suggested this in
april, I didn't posted any patch for it until now. Unfortunately,
I'didn't had time for it and probably not the proper skills anyway :-).
Nicolas.
^ permalink raw reply
* Re: 8139cp dma-debug warning.
From: Dave Jones @ 2009-08-13 19:28 UTC (permalink / raw)
To: Francois Romieu; +Cc: David Miller, netdev
In-Reply-To: <20090813192326.GA32435@electric-eye.fr.zoreil.com>
On Thu, Aug 13, 2009 at 09:23:26PM +0200, Francois Romieu wrote:
> > Below this, we're still doing an skb_reserve(NET_IP_ALIGN) on new_skb.
> > Although the mapping is now constantly sized, aren't we still wastefully
> > bumping the data/tail of the skb twice ?
>
> $ grep -n NET_IP_ALIGN drivers/net/8139cp.c
> 552: new_skb = netdev_alloc_skb(dev, buflen + NET_IP_ALIGN);
> 558: skb_reserve(new_skb, NET_IP_ALIGN);
> 1059: skb = netdev_alloc_skb(dev, cp->rx_buf_sz + NET_IP_ALIGN);
> 1063: skb_reserve(skb, NET_IP_ALIGN);
>
> I do not get it : netdev_alloc_skb allocates but it does not "bump" as
> skb_reserve does (and skb_reserve does not allocate). Where would the
> double bump come from ?
>
> The mapping is constantly sized but we want the ethernet header following
> IP data to be evenly aligned and thus the mapping to be oddly aligned.
Ah, now I get it. Thanks for the explanation :)
Dave
^ permalink raw reply
* Re: 8139cp dma-debug warning.
From: Francois Romieu @ 2009-08-13 19:23 UTC (permalink / raw)
To: Dave Jones; +Cc: David Miller, netdev
In-Reply-To: <20090813134549.GA2845@redhat.com>
Dave Jones <davej@redhat.com> :
[...]
> > @@ -549,8 +549,7 @@ rx_status_loop:
> > pr_debug("%s: rx slot %d status 0x%x len %d\n",
> > dev->name, rx_tail, status, len);
> >
> > - buflen = cp->rx_buf_sz + NET_IP_ALIGN;
> > - new_skb = netdev_alloc_skb(dev, buflen);
> > + new_skb = netdev_alloc_skb(dev, buflen + NET_IP_ALIGN);
> > if (!new_skb) {
> > dev->stats.rx_dropped++;
> > goto rx_next;
>
> Below this, we're still doing an skb_reserve(NET_IP_ALIGN) on new_skb.
> Although the mapping is now constantly sized, aren't we still wastefully
> bumping the data/tail of the skb twice ?
$ grep -n NET_IP_ALIGN drivers/net/8139cp.c
552: new_skb = netdev_alloc_skb(dev, buflen + NET_IP_ALIGN);
558: skb_reserve(new_skb, NET_IP_ALIGN);
1059: skb = netdev_alloc_skb(dev, cp->rx_buf_sz + NET_IP_ALIGN);
1063: skb_reserve(skb, NET_IP_ALIGN);
I do not get it : netdev_alloc_skb allocates but it does not "bump" as
skb_reserve does (and skb_reserve does not allocate). Where would the
double bump come from ?
The mapping is constantly sized but we want the ethernet header following
IP data to be evenly aligned and thus the mapping to be oddly aligned.
--
Ueimor
^ permalink raw reply
* Re: [RFC] ipv6: Change %pI6 format to output compacted addresses?
From: Joe Perches @ 2009-08-13 19:05 UTC (permalink / raw)
To: Chuck Lever; +Cc: Brian Haley, Jens Rosenboom, Linux Network Developers
In-Reply-To: <5D6A7C11-B300-4E39-BBDF-EF18C4BAE419@oracle.com>
On Thu, 2009-08-13 at 14:39 -0400, Chuck Lever wrote:
> On Aug 13, 2009, at 2:21 PM, Joe Perches wrote:
> > On Thu, 2009-08-13 at 14:15 -0400, Chuck Lever wrote:
> >> On Aug 13, 2009, at 2:10 PM, Joe Perches wrote:
> >>> The patch allows "%p6ic" for compressed and "%p6ic4" for compressed
> >>> with ipv4 last u32.
> >> Why do these need to be separate?
> > Just an option.
> > I think it possible somebody will want "1::" instead of "1::0.0.0.0"
> Hrm.
> With %p6ic4, each call site now has to see that it's an IPv6 address,
> and then decide if the address is a mapped v4 address or not. It's
> the same logic everywhere.
I suppose ipv6_addr_v4mapped(addr) could be tested instead
Perhaps this on top of last:
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index dd02842..7ce34a7 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -25,6 +25,7 @@
#include <linux/kallsyms.h>
#include <linux/uaccess.h>
#include <linux/ioport.h>
+#include <net/ipv6.h>
#include <asm/page.h> /* for PAGE_SIZE */
#include <asm/div64.h>
@@ -701,7 +702,7 @@ static char *ip6_compressed_string(char *buf, char *end, u8 *addr,
u16 *addr16 = (u16 *)addr;
ip6_colon_t colon = DC_START;
- if (fmt[3] == '4') { /* use :: and ipv4 */
+ if (ipv6_addr_v4mapped((const struct in6_addr *)addr)) {
for (i = 0; i < 6; i++) {
p = ip6_compress_u16(p, addr16[i], addr16[i+1],
&colon, &needcolon);
@@ -832,8 +833,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
* Formatted IP supported
* 4: 001.002.003.004
* 6: 0001:0203:...:0708
- * 6c: 1::708
- * 6c4: 1::1.2.3.4
+ * 6c: 1::708 or 1::1.2.3.4
*/
case 'I': /* Contiguous: */
if (fmt[1] == '4' || fmt[1] == '6')
^ permalink raw reply related
* Re: [PATCH 1/3] Networking: use CAP_NET_ADMIN when deciding to call request_module
From: Paul Moore @ 2009-08-13 18:45 UTC (permalink / raw)
To: Eric Paris
Cc: linux-kernel, selinux, netdev, linux-security-module, sds, davem,
shemminger, kees, morgan, casey, dwalsh
In-Reply-To: <20090813134451.29186.41664.stgit@paris.rdu.redhat.com>
On Thursday 13 August 2009 09:44:51 am Eric Paris wrote:
> The networking code checks CAP_SYS_MODULE before using request_module() to
> try to load a kernel module. While this seems reasonable it's actually
> weakening system security since we have to allow CAP_SYS_MODULE for things
> like /sbin/ip and bluetoothd which need to be able to trigger module loads.
> CAP_SYS_MODULE actually grants those binaries the ability to directly load
> any code into the kernel. We should instead be protecting modprobe and the
> modules on disk, rather than granting random programs the ability to load
> code directly into the kernel. Instead we are going to gate those
> networking checks on CAP_NET_ADMIN which still limits them to root but
> which does not grant those processes the ability to load arbitrary code
> into the kernel.
>
> Signed-off-by: Eric Paris <eparis@redhat.com>
Sounds and looks reasonable to me.
Acked-by: Paul Moore <paul.moore@hp.com>
> ---
>
> drivers/staging/comedi/comedi_fops.c | 8 ++++----
> net/core/dev.c | 2 +-
> net/ipv4/tcp_cong.c | 4 ++--
> 3 files changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/staging/comedi/comedi_fops.c
> b/drivers/staging/comedi/comedi_fops.c index 42e4bc4..f54bb9b 100644
> --- a/drivers/staging/comedi/comedi_fops.c
> +++ b/drivers/staging/comedi/comedi_fops.c
> @@ -1772,12 +1772,12 @@ static int comedi_open(struct inode *inode, struct
> file *file) mutex_lock(&dev->mutex);
> if (dev->attached)
> goto ok;
> - if (!capable(CAP_SYS_MODULE) && dev->in_request_module) {
> + if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
> DPRINTK("in request module\n");
> mutex_unlock(&dev->mutex);
> return -ENODEV;
> }
> - if (capable(CAP_SYS_MODULE) && dev->in_request_module)
> + if (capable(CAP_NET_ADMIN) && dev->in_request_module)
> goto ok;
>
> dev->in_request_module = 1;
> @@ -1790,8 +1790,8 @@ static int comedi_open(struct inode *inode, struct
> file *file)
>
> dev->in_request_module = 0;
>
> - if (!dev->attached && !capable(CAP_SYS_MODULE)) {
> - DPRINTK("not attached and not CAP_SYS_MODULE\n");
> + if (!dev->attached && !capable(CAP_NET_ADMIN)) {
> + DPRINTK("not attached and not CAP_NET_ADMIN\n");
> mutex_unlock(&dev->mutex);
> return -ENODEV;
> }
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 09fb03f..2604db9 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -1031,7 +1031,7 @@ void dev_load(struct net *net, const char *name)
> dev = __dev_get_by_name(net, name);
> read_unlock(&dev_base_lock);
>
> - if (!dev && capable(CAP_SYS_MODULE))
> + if (!dev && capable(CAP_NET_ADMIN))
> request_module("%s", name);
> }
>
> diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
> index e92beb9..6428b34 100644
> --- a/net/ipv4/tcp_cong.c
> +++ b/net/ipv4/tcp_cong.c
> @@ -116,7 +116,7 @@ int tcp_set_default_congestion_control(const char
> *name) spin_lock(&tcp_cong_list_lock);
> ca = tcp_ca_find(name);
> #ifdef CONFIG_MODULES
> - if (!ca && capable(CAP_SYS_MODULE)) {
> + if (!ca && capable(CAP_NET_ADMIN)) {
> spin_unlock(&tcp_cong_list_lock);
>
> request_module("tcp_%s", name);
> @@ -246,7 +246,7 @@ int tcp_set_congestion_control(struct sock *sk, const
> char *name)
>
> #ifdef CONFIG_MODULES
> /* not found attempt to autoload module */
> - if (!ca && capable(CAP_SYS_MODULE)) {
> + if (!ca && capable(CAP_NET_ADMIN)) {
> rcu_read_unlock();
> request_module("tcp_%s", name);
> rcu_read_lock();
>
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in the body of a message to
> majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
paul moore
linux @ hp
^ permalink raw reply
* Re: [PATCH 3/3] SELinux: add selinux_kernel_module_request
From: Serge E. Hallyn @ 2009-08-13 18:43 UTC (permalink / raw)
To: Eric Paris
Cc: linux-kernel, selinux, netdev, linux-security-module, sds, davem,
shemminger, kees, morgan, casey, dwalsh
In-Reply-To: <20090813134502.29186.7938.stgit@paris.rdu.redhat.com>
Quoting Eric Paris (eparis@redhat.com):
> This patch adds a new selinux hook so SELinux can arbitrate if a given
> process should be allowed to trigger a request for the kernel to try to
> load a module. This is a different operation than a process trying to load
> a module itself, which is already protected by CAP_SYS_MODULE.
>
> Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: Serge Hallyn <serue@us.ibm.com>
> ---
>
> security/selinux/hooks.c | 6 ++++++
> security/selinux/include/av_perm_to_string.h | 1 +
> security/selinux/include/av_permissions.h | 1 +
> 3 files changed, 8 insertions(+), 0 deletions(-)
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 38afca9..b0d72f1 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -3296,6 +3296,11 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
> return 0;
> }
>
> +static int selinux_kernel_module_request(void)
> +{
> + return task_has_system(current, SYSTEM__MODULE_REQUEST);
> +}
> +
> static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
> {
> return current_has_perm(p, PROCESS__SETPGID);
> @@ -5457,6 +5462,7 @@ static struct security_operations selinux_ops = {
> .cred_prepare = selinux_cred_prepare,
> .kernel_act_as = selinux_kernel_act_as,
> .kernel_create_files_as = selinux_kernel_create_files_as,
> + .kernel_module_request = selinux_kernel_module_request,
> .task_setpgid = selinux_task_setpgid,
> .task_getpgid = selinux_task_getpgid,
> .task_getsid = selinux_task_getsid,
> diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
> index 31df1d7..2b683ad 100644
> --- a/security/selinux/include/av_perm_to_string.h
> +++ b/security/selinux/include/av_perm_to_string.h
> @@ -107,6 +107,7 @@
> S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read")
> S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod")
> S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console")
> + S_(SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, "module_request")
> S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown")
> S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override")
> S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search")
> diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
> index 0b41ad5..0546d61 100644
> --- a/security/selinux/include/av_permissions.h
> +++ b/security/selinux/include/av_permissions.h
> @@ -530,6 +530,7 @@
> #define SYSTEM__SYSLOG_READ 0x00000002UL
> #define SYSTEM__SYSLOG_MOD 0x00000004UL
> #define SYSTEM__SYSLOG_CONSOLE 0x00000008UL
> +#define SYSTEM__MODULE_REQUEST 0x00000010UL
> #define CAPABILITY__CHOWN 0x00000001UL
> #define CAPABILITY__DAC_OVERRIDE 0x00000002UL
> #define CAPABILITY__DAC_READ_SEARCH 0x00000004UL
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" 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: [PATCH 2/3] security: introducing security_request_module
From: Serge E. Hallyn @ 2009-08-13 18:40 UTC (permalink / raw)
To: Eric Paris
Cc: linux-kernel, selinux, netdev, linux-security-module, sds, davem,
shemminger, kees, morgan, casey, dwalsh
In-Reply-To: <20090813134457.29186.7182.stgit@paris.rdu.redhat.com>
Quoting Eric Paris (eparis@redhat.com):
> Calling request_module() will trigger a userspace upcall which will load a
> new module into the kernel. This can be a dangerous event if the process
> able to trigger request_module() is able to control either the modprobe
> binary or the module binary. This patch adds a new security hook to
> request_module() which can be used by an LSM to control a processes ability
> to call request_module().
>
> Signed-off-by: Eric Paris <eparis@redhat.com>
Looks fine code-wise.
Just to match the rest of the documentation, the description in
security.h should probably mention 'Return 0 if allowed'.
Acked-by: Serge Hallyn <serue@us.ibm.com>
> ---
>
> include/linux/security.h | 10 ++++++++++
> kernel/kmod.c | 4 ++++
> security/capability.c | 6 ++++++
> security/security.c | 5 +++++
> 4 files changed, 25 insertions(+), 0 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index d5f6578..34c5465 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -678,6 +678,9 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> * @inode points to the inode to use as a reference.
> * The current task must be the one that nominated @inode.
> * Return 0 if successful.
> + * @kernel_module_request:
> + * Ability to trigger the kernel to automatically upcall to userspace for
> + * userspace to load a kernel module with the given name.
> * @task_setuid:
> * Check permission before setting one or more of the user identity
> * attributes of the current process. The @flags parameter indicates
> @@ -1500,6 +1503,7 @@ struct security_operations {
> void (*cred_commit)(struct cred *new, const struct cred *old);
> int (*kernel_act_as)(struct cred *new, u32 secid);
> int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
> + int (*kernel_module_request)(void);
> int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags);
> int (*task_fix_setuid) (struct cred *new, const struct cred *old,
> int flags);
> @@ -1755,6 +1759,7 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
> void security_commit_creds(struct cred *new, const struct cred *old);
> int security_kernel_act_as(struct cred *new, u32 secid);
> int security_kernel_create_files_as(struct cred *new, struct inode *inode);
> +int security_kernel_module_request(void);
> int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags);
> int security_task_fix_setuid(struct cred *new, const struct cred *old,
> int flags);
> @@ -2306,6 +2311,11 @@ static inline int security_kernel_create_files_as(struct cred *cred,
> return 0;
> }
>
> +static inline int security_kernel_module_request(void)
> +{
> + return 0;
> +}
> +
> static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2,
> int flags)
> {
> diff --git a/kernel/kmod.c b/kernel/kmod.c
> index 385c31a..5a7ae57 100644
> --- a/kernel/kmod.c
> +++ b/kernel/kmod.c
> @@ -78,6 +78,10 @@ int __request_module(bool wait, const char *fmt, ...)
> #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
> static int kmod_loop_msg;
>
> + ret = security_kernel_module_request();
> + if (ret)
> + return ret;
> +
> va_start(args, fmt);
> ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
> va_end(args);
> diff --git a/security/capability.c b/security/capability.c
> index 4f23f4f..06400cf 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -396,6 +396,11 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode)
> return 0;
> }
>
> +static int cap_kernel_module_request(void)
> +{
> + return 0;
> +}
> +
> static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
> {
> return 0;
> @@ -961,6 +966,7 @@ void security_fixup_ops(struct security_operations *ops)
> set_to_cap_if_null(ops, cred_commit);
> set_to_cap_if_null(ops, kernel_act_as);
> set_to_cap_if_null(ops, kernel_create_files_as);
> + set_to_cap_if_null(ops, kernel_module_request);
> set_to_cap_if_null(ops, task_setuid);
> set_to_cap_if_null(ops, task_fix_setuid);
> set_to_cap_if_null(ops, task_setgid);
> diff --git a/security/security.c b/security/security.c
> index b98c684..f88eaf6 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -709,6 +709,11 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode)
> return security_ops->kernel_create_files_as(new, inode);
> }
>
> +int security_kernel_module_request(void)
> +{
> + return security_ops->kernel_module_request();
> +}
> +
> int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
> {
> return security_ops->task_setuid(id0, id1, id2, flags);
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" 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] ipv6: Change %pI6 format to output compacted addresses?
From: Chuck Lever @ 2009-08-13 18:39 UTC (permalink / raw)
To: Joe Perches; +Cc: Brian Haley, Jens Rosenboom, Linux Network Developers
In-Reply-To: <1250187662.28285.97.camel@Joe-Laptop.home>
On Aug 13, 2009, at 2:21 PM, Joe Perches wrote:
> On Thu, 2009-08-13 at 14:15 -0400, Chuck Lever wrote:
>> On Aug 13, 2009, at 2:10 PM, Joe Perches wrote:
>>> The patch allows "%p6ic" for compressed and "%p6ic4" for compressed
>>> with ipv4 last u32.
>>
>> Why do these need to be separate?
>
> Just an option.
> I think it possible somebody will want "1::" instead of "1::0.0.0.0"
Hrm.
Do you have a use case? Really, it's pretty easy to tell when the
mapped v4 presentation format should be used. See
ipv6_addr_v4mapped(). Otherwise the mapped v4 presentation format
should never be used.
A problem with the existing %p[iI] implementation is that each call
site has to have logic that figures out the address family of the
address before calling sprintf(). This makes it difficult to use this
facility with, for example, debugging messages, since you have to add
address family detection logic at every debugging message call site.
Lots of clutter and duplicated code.
With %p6ic4, each call site now has to see that it's an IPv6 address,
and then decide if the address is a mapped v4 address or not. It's
the same logic everywhere.
It seems to me it would be a lot more useful if we had a new %p6
formatter that handled all types of IPv6 addresses properly, the way
inet_ntop(3) does in user space. (Or even a new formatter that could
handle both address families).
--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com
^ permalink raw reply
* Re: [PATCH 2/3] security: introducing security_request_module
From: Serge E. Hallyn @ 2009-08-13 18:31 UTC (permalink / raw)
To: Eric Paris
Cc: linux-kernel, selinux, netdev, linux-security-module, sds, davem,
shemminger, kees, morgan, casey, dwalsh
In-Reply-To: <1250187550.2115.19.camel@dhcp231-106.rdu.redhat.com>
Quoting Eric Paris (eparis@redhat.com):
> On Thu, 2009-08-13 at 12:54 -0500, Serge E. Hallyn wrote:
> > Quoting Eric Paris (eparis@redhat.com):
> > > On Thu, 2009-08-13 at 09:03 -0500, Serge E. Hallyn wrote:
> > > > Quoting Eric Paris (eparis@redhat.com):
> > > > > Calling request_module() will trigger a userspace upcall which will load a
> > > > > new module into the kernel. This can be a dangerous event if the process
> > > > > able to trigger request_module() is able to control either the modprobe
> > > > > binary or the module binary. This patch adds a new security hook to
> > > > > request_module() which can be used by an LSM to control a processes ability
> > > > > to call request_module().
> > > >
> > > > Is there a specific case in which you'd want to deny this ability
> > > > from a real task?
> > >
> > > qemu and any network facing daemon are all programs I don't want to be
> > > able to even ask the kernel to load a module. Clearly you are right,
> >
> > ... What if the network facing daemon might want to use a kernel crypto
> > module? What if qemu needs the tun module loaded?
>
> Loading code into the kernel is a dangerous operation. We should find
> the places where high risk processes are doing this and either choose to
> accept the security risk or make sure they are loaded before the
> dangerous code is run, aka libvirt knows if the guest needs the tun
> device and it should be allowed to trigger it's loading. It's shouldn't
> be the guest doing the triggering.
Well, I continue to be dubious, but the hook does no harm so in case
it sounded otherwise, I don't object.
Mind you the right thing to do would be i.e. in the qemu case to have
a more privileged helper load the needed modules and then fire off a
qemu unable to cause module loads. If userspace is willing to jump
through that rather minimal hoop then this could be useful I suppose.
thanks,
-serge
^ permalink raw reply
* [PATCHv3 2/2] vhost_net: a kernel-level virtio server
From: Michael S. Tsirkin @ 2009-08-13 18:29 UTC (permalink / raw)
To: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm
In-Reply-To: <cover.1250187913.git.mst@redhat.com>
What it is: vhost net is a character device that can be used to reduce
the number of system calls involved in virtio networking.
Existing virtio net code is used in the guest without modification.
There's similarity with vringfd, with some differences and reduced scope
- uses eventfd for signalling
- structures can be moved around in memory at any time (good for migration)
- support memory table and not just an offset (needed for kvm)
common virtio related code has been put in a separate file vhost.c and
can be made into a separate module if/when more backends appear. I used
Rusty's lguest.c as the source for developing this part : this supplied
me with witty comments I wouldn't be able to write myself.
What it is not: vhost net is not a bus, and not a generic new system
call. No assumptions are made on how guest performs hypercalls.
Userspace hypervisors are supported as well as kvm.
How it works: Basically, we connect virtio frontend (configured by
userspace) to a backend. The backend could be a network device, or a
tun-like device. In this version I only support raw socket as a backend,
which can be bound to e.g. SR IOV, or to macvlan device. Backend is
also configured by userspace, including vlan/mac etc.
Status:
This works for me, and I haven't see any crashes.
I have not run any benchmarks yet, compared to userspace, I expect to
see improved latency (as I save up to 4 system calls per packet) but not
bandwidth/CPU (as TSO and interrupt mitigation are not supported).
Features that I plan to look at in the future:
- TSO
- interrupt mitigation
- zero copy
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
MAINTAINERS | 10 +
arch/x86/kvm/Kconfig | 1 +
drivers/Makefile | 1 +
drivers/vhost/Kconfig | 11 +
drivers/vhost/Makefile | 2 +
drivers/vhost/net.c | 429 ++++++++++++++++++++++++++++
drivers/vhost/vhost.c | 663 ++++++++++++++++++++++++++++++++++++++++++++
drivers/vhost/vhost.h | 108 +++++++
include/linux/Kbuild | 1 +
include/linux/miscdevice.h | 1 +
include/linux/vhost.h | 100 +++++++
11 files changed, 1327 insertions(+), 0 deletions(-)
create mode 100644 drivers/vhost/Kconfig
create mode 100644 drivers/vhost/Makefile
create mode 100644 drivers/vhost/net.c
create mode 100644 drivers/vhost/vhost.c
create mode 100644 drivers/vhost/vhost.h
create mode 100644 include/linux/vhost.h
diff --git a/MAINTAINERS b/MAINTAINERS
index ebc2691..eb0c1da 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6312,6 +6312,16 @@ S: Maintained
F: Documentation/filesystems/vfat.txt
F: fs/fat/
+VIRTIO HOST (VHOST)
+P: Michael S. Tsirkin
+M: mst@redhat.com
+L: kvm@vger.kernel.org
+L: virtualization@lists.osdl.org
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/vhost/
+F: include/linux/vhost.h
+
VIA RHINE NETWORK DRIVER
P: Roger Luethi
M: rl@hellgate.ch
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index b84e571..94f44d9 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -64,6 +64,7 @@ config KVM_AMD
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
# the virtualization menu.
+source drivers/vhost/Kconfig
source drivers/lguest/Kconfig
source drivers/virtio/Kconfig
diff --git a/drivers/Makefile b/drivers/Makefile
index bc4205d..1551ae1 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
+obj-$(CONFIG_VHOST_NET) += vhost/
obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
new file mode 100644
index 0000000..d955406
--- /dev/null
+++ b/drivers/vhost/Kconfig
@@ -0,0 +1,11 @@
+config VHOST_NET
+ tristate "Host kernel accelerator for virtio net"
+ depends on NET && EVENTFD
+ ---help---
+ This kernel module can be loaded in host kernel to accelerate
+ guest networking with virtio_net. Not to be confused with virtio_net
+ module itself which needs to be loaded in guest kernel.
+
+ To compile this driver as a module, choose M here: the module will
+ be called vhost_net.
+
diff --git a/drivers/vhost/Makefile b/drivers/vhost/Makefile
new file mode 100644
index 0000000..72dd020
--- /dev/null
+++ b/drivers/vhost/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
new file mode 100644
index 0000000..728094b
--- /dev/null
+++ b/drivers/vhost/net.c
@@ -0,0 +1,429 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * virtio-net server in host kernel.
+ */
+
+#include <linux/compat.h>
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mmu_context.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/file.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+
+#include <asm/mmu_context.h>
+
+#include "vhost.h"
+
+enum {
+ VHOST_NET_VQ_RX = 0,
+ VHOST_NET_VQ_TX = 1,
+ VHOST_NET_VQ_MAX = 2,
+};
+
+struct vhost_net {
+ struct vhost_dev dev;
+ struct vhost_virtqueue vqs[VHOST_NET_VQ_MAX];
+ /* We use a kind of RCU to access sock pointer.
+ * All readers access it from workqueue, which makes it possible to
+ * flush the workqueue instead of synchronize_rcu. Therefore readers do
+ * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
+ * work item execution acts instead of rcu_read_lock() and the end of
+ * work item execution acts instead of rcu_read_lock().
+ * Writers use device mutex. */
+ struct socket *sock;
+ struct vhost_poll poll[VHOST_NET_VQ_MAX];
+};
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_tx(struct vhost_net *net)
+{
+ struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
+ unsigned head, out, in;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_iov = (struct iovec *)vq->iov + 1,
+ .msg_flags = MSG_DONTWAIT,
+ };
+ size_t len;
+ int err;
+ struct socket *sock = rcu_dereference(net->sock);
+ if (!sock || !sock_writeable(sock->sk))
+ return;
+
+ use_mm(net->dev.mm);
+ mutex_lock(&vq->mutex);
+ for (;;) {
+ head = vhost_get_vq_desc(&net->dev, vq, vq->iov, &out, &in);
+ /* Nothing new? Wait for eventfd to tell us they refilled. */
+ if (head == vq->num)
+ break;
+ if (out <= 1 || in) {
+ vq_err(vq, "Unexpected descriptor format for TX: "
+ "out %d, int %d\n", out, in);
+ break;
+ }
+ /* Sanity check */
+ if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+ vq_err(vq, "Unexpected header len for TX: "
+ "%ld expected %zd\n", vq->iov->iov_len,
+ sizeof(struct virtio_net_hdr));
+ break;
+ }
+ /* Skip header. TODO: support TSO. */
+ msg.msg_iovlen = out - 1;
+ len = iov_length(vq->iov + 1, out - 1);
+ /* TODO: Check specific error and bomb out unless ENOBUFS? */
+ err = sock->ops->sendmsg(NULL, sock, &msg, len);
+ if (err < 0) {
+ vhost_discard_vq_desc(vq);
+ break;
+ }
+ if (err != len)
+ pr_err("Truncated TX packet: "
+ " len %d != %zd\n", err, len);
+ vhost_add_used_and_trigger(vq, head,
+ len + sizeof(struct virtio_net_hdr));
+ }
+
+ mutex_unlock(&vq->mutex);
+ unuse_mm(net->dev.mm);
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_rx(struct vhost_net *net)
+{
+ struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
+ unsigned head, out, in;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_control = NULL, /* FIXME: get and handle RX aux data. */
+ .msg_controllen = 0,
+ .msg_iov = vq->iov + 1,
+ .msg_flags = MSG_DONTWAIT,
+ };
+
+ struct virtio_net_hdr hdr = {
+ .flags = 0,
+ .gso_type = VIRTIO_NET_HDR_GSO_NONE
+ };
+
+ size_t len;
+ int err;
+ struct socket *sock = rcu_dereference(net->sock);
+ if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+ return;
+
+ use_mm(net->dev.mm);
+ mutex_lock(&vq->mutex);
+
+ for (;;) {
+ head = vhost_get_vq_desc(&net->dev, vq, vq->iov, &out, &in);
+ if (head == vq->num)
+ break;
+ if (in <= 1 || out) {
+ vq_err(vq, "Unexpected descriptor format for RX: out %d, int %d\n",
+ out, in);
+ break;
+ }
+ /* Sanity check */
+ if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+ vq_err(vq, "Unexpected header len for RX: %ld expected %zd\n",
+ vq->iov->iov_len, sizeof(struct virtio_net_hdr));
+ break;
+ }
+ /* Skip header. TODO: support TSO/mergeable rx buffers. */
+ msg.msg_iovlen = in - 1;
+ len = iov_length(vq->iov + 1, in - 1);
+ err = sock->ops->recvmsg(NULL, sock, &msg,
+ len, MSG_DONTWAIT | MSG_TRUNC);
+ /* TODO: Check specific error and bomb out unless EAGAIN? */
+ if (err < 0) {
+ vhost_discard_vq_desc(vq);
+ break;
+ }
+ /* TODO: Should check and handle checksum. */
+ if (err > len) {
+ pr_err("Discarded truncated rx packet: "
+ " len %d > %zd\n", err, len);
+ vhost_discard_vq_desc(vq);
+ continue;
+ }
+ len = err;
+ err = copy_to_user(vq->iov->iov_base, &hdr, sizeof hdr);
+ if (err) {
+ vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
+ vq->iov->iov_base, err);
+ break;
+ }
+ vhost_add_used_and_trigger(vq, head, len + sizeof hdr);
+ }
+
+ mutex_unlock(&vq->mutex);
+ unuse_mm(net->dev.mm);
+}
+
+static void handle_tx_kick(struct work_struct *work)
+{
+ struct vhost_virtqueue *vq;
+ struct vhost_net *net;
+ vq = container_of(work, struct vhost_virtqueue, poll.work);
+ net = container_of(vq->dev, struct vhost_net, dev);
+ handle_tx(net);
+}
+
+static void handle_rx_kick(struct work_struct *work)
+{
+ struct vhost_virtqueue *vq;
+ struct vhost_net *net;
+ vq = container_of(work, struct vhost_virtqueue, poll.work);
+ net = container_of(vq->dev, struct vhost_net, dev);
+ handle_rx(net);
+}
+
+static void handle_tx_net(struct work_struct *work)
+{
+ struct vhost_net *net;
+ net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_TX].work);
+ handle_tx(net);
+}
+
+static void handle_rx_net(struct work_struct *work)
+{
+ struct vhost_net *net;
+ net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_RX].work);
+ handle_rx(net);
+}
+
+static int vhost_net_open(struct inode *inode, struct file *f)
+{
+ struct vhost_net *n = kzalloc(sizeof *n, GFP_KERNEL);
+ int r;
+ if (!n)
+ return -ENOMEM;
+ f->private_data = n;
+ n->vqs[VHOST_NET_VQ_TX].handle_kick = handle_tx_kick;
+ n->vqs[VHOST_NET_VQ_RX].handle_kick = handle_rx_kick;
+ r = vhost_dev_init(&n->dev, n->vqs, VHOST_NET_VQ_MAX);
+ if (r < 0) {
+ kfree(n);
+ return r;
+ }
+
+ vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT);
+ vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN);
+ return 0;
+}
+
+static struct socket *vhost_net_stop(struct vhost_net *n)
+{
+ struct socket *sock = n->sock;
+ rcu_assign_pointer(n->sock, NULL);
+ if (sock) {
+ vhost_poll_flush(n->poll + VHOST_NET_VQ_TX);
+ vhost_poll_flush(n->poll + VHOST_NET_VQ_RX);
+ }
+ return sock;
+}
+
+static int vhost_net_release(struct inode *inode, struct file *f)
+{
+ struct vhost_net *n = f->private_data;
+ struct socket *sock;
+
+ sock = vhost_net_stop(n);
+ vhost_dev_cleanup(&n->dev);
+ if (sock)
+ fput(sock->file);
+ kfree(n);
+ return 0;
+}
+
+static long vhost_net_set_socket(struct vhost_net *n, int fd)
+{
+ struct {
+ struct sockaddr_ll sa;
+ char buf[MAX_ADDR_LEN];
+ } uaddr;
+ struct socket *sock, *oldsock = NULL;
+ int uaddr_len = sizeof uaddr, r;
+
+ mutex_lock(&n->dev.mutex);
+ r = vhost_dev_check_owner(&n->dev);
+ if (r)
+ goto done;
+
+ if (fd == -1) {
+ /* Disconnect from socket and device. */
+ oldsock = vhost_net_stop(n);
+ goto done;
+ }
+
+ sock = sockfd_lookup(fd, &r);
+ if (!sock) {
+ r = -ENOTSOCK;
+ goto done;
+ }
+
+ /* Parameter checking */
+ if (sock->sk->sk_type != SOCK_RAW) {
+ r = -ESOCKTNOSUPPORT;
+ goto done;
+ }
+
+ r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa,
+ &uaddr_len, 0);
+ if (r)
+ goto done;
+
+ if (uaddr.sa.sll_family != AF_PACKET) {
+ r = -EPFNOSUPPORT;
+ goto done;
+ }
+
+ /* start polling new socket */
+ if (sock == oldsock)
+ goto done;
+
+ if (oldsock) {
+ vhost_poll_stop(n->poll + VHOST_NET_VQ_TX);
+ vhost_poll_stop(n->poll + VHOST_NET_VQ_RX);
+ }
+ oldsock = n->sock;
+ rcu_assign_pointer(n->sock, sock);
+ vhost_poll_start(n->poll + VHOST_NET_VQ_TX, sock->file);
+ vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file);
+done:
+ mutex_unlock(&n->dev.mutex);
+ if (oldsock) {
+ vhost_poll_flush(n->poll + VHOST_NET_VQ_TX);
+ vhost_poll_flush(n->poll + VHOST_NET_VQ_RX);
+ vhost_poll_flush(&n->dev.vqs[VHOST_NET_VQ_TX].poll);
+ vhost_poll_flush(&n->dev.vqs[VHOST_NET_VQ_RX].poll);
+ fput(oldsock->file);
+ }
+ return r;
+}
+
+static long vhost_net_reset_owner(struct vhost_net *n)
+{
+ struct socket *sock = NULL;
+ long r;
+ mutex_lock(&n->dev.mutex);
+ r = vhost_dev_check_owner(&n->dev);
+ if (r)
+ goto done;
+ sock = vhost_net_stop(n);
+ r = vhost_dev_reset_owner(&n->dev);
+done:
+ mutex_unlock(&n->dev.mutex);
+ if (sock)
+ fput(sock->file);
+ return r;
+}
+
+static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
+ unsigned long arg)
+{
+ struct vhost_net *n = f->private_data;
+ void __user *argp = (void __user *)arg;
+ u32 __user *featurep = argp;
+ int __user *fdp = argp;
+ u32 features;
+ int fd, r;
+ switch (ioctl) {
+ case VHOST_NET_SET_SOCKET:
+ r = get_user(fd, fdp);
+ if (r < 0)
+ return r;
+ return vhost_net_set_socket(n, fd);
+ case VHOST_GET_FEATURES:
+ /* No features for now */
+ features = 0;
+ return put_user(features, featurep);
+ case VHOST_ACK_FEATURES:
+ r = get_user(features, featurep);
+ /* No features for now */
+ if (r < 0)
+ return r;
+ if (features)
+ return -EOPNOTSUPP;
+ return 0;
+ case VHOST_RESET_OWNER:
+ return vhost_net_reset_owner(n);
+ default:
+ return vhost_dev_ioctl(&n->dev, ioctl, arg);
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl,
+ unsigned long arg)
+{
+ return vhost_net_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static struct file_operations vhost_net_fops = {
+ .owner = THIS_MODULE,
+ .release = vhost_net_release,
+ .unlocked_ioctl = vhost_net_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vhost_net_compat_ioctl,
+#endif
+ .open = vhost_net_open,
+};
+
+static struct miscdevice vhost_net_misc = {
+ VHOST_NET_MINOR,
+ "vhost-net",
+ &vhost_net_fops,
+};
+
+int vhost_net_init(void)
+{
+ int r = vhost_init();
+ if (r)
+ goto err_init;
+ r = misc_register(&vhost_net_misc);
+ if (r)
+ goto err_reg;
+ return 0;
+err_reg:
+ vhost_cleanup();
+err_init:
+ return r;
+
+}
+module_init(vhost_net_init);
+
+void vhost_net_exit(void)
+{
+ misc_deregister(&vhost_net_misc);
+ vhost_cleanup();
+}
+module_exit(vhost_net_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael S. Tsirkin");
+MODULE_DESCRIPTION("Host kernel accelerator for virtio net");
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
new file mode 100644
index 0000000..a52b18b
--- /dev/null
+++ b/drivers/vhost/vhost.c
@@ -0,0 +1,663 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * Inspiration, some code, and most witty comments come from
+ * Documentation/lguest/lguest.c, by Rusty Russell
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * Generic code for virtio server in host kernel.
+ */
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+
+#include <asm/mmu_context.h>
+
+#include "vhost.h"
+
+enum {
+ VHOST_MEMORY_MAX_NREGIONS = 64,
+};
+
+static struct workqueue_struct *vhost_workqueue;
+
+static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
+ poll_table *pt)
+{
+ struct vhost_poll *poll;
+ poll = container_of(pt, struct vhost_poll, table);
+
+ poll->wqh = wqh;
+ add_wait_queue(wqh, &poll->wait);
+}
+
+static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ struct vhost_poll *poll;
+ poll = container_of(wait, struct vhost_poll, wait);
+ if (!((unsigned long)key & poll->mask))
+ return 0;
+
+ queue_work(vhost_workqueue, &poll->work);
+ return 0;
+}
+
+/* Init poll structure */
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+ unsigned long mask)
+{
+ INIT_WORK(&poll->work, func);
+ init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup);
+ init_poll_funcptr(&poll->table, vhost_poll_func);
+ poll->mask = mask;
+}
+
+/* Start polling a file. We add ourselves to file's wait queue. The user must
+ * keep a reference to a file until after vhost_poll_stop is called. */
+void vhost_poll_start(struct vhost_poll *poll, struct file *file)
+{
+ unsigned long mask;
+ mask = file->f_op->poll(file, &poll->table);
+ if (mask)
+ vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
+}
+
+/* Stop polling a file. After this function returns, it becomes safe to drop the
+ * file reference. You must also flush afterwards. */
+void vhost_poll_stop(struct vhost_poll *poll)
+{
+ remove_wait_queue(poll->wqh, &poll->wait);
+}
+
+/* Flush any work that has been scheduled. When calling this, don't hold any
+ * locks that are also used by the callback. */
+void vhost_poll_flush(struct vhost_poll *poll)
+{
+ flush_work(&poll->work);
+}
+
+long vhost_dev_init(struct vhost_dev *dev, struct vhost_virtqueue *vqs, int nvqs)
+{
+ int i;
+ dev->vqs = vqs;
+ dev->nvqs = nvqs;
+ mutex_init(&dev->mutex);
+
+ for(i = 0; i < dev->nvqs; ++i) {
+ dev->vqs[i].dev = dev;
+ mutex_init(&dev->vqs[i].mutex);
+ if (dev->vqs[i].handle_kick)
+ vhost_poll_init(&dev->vqs[i].poll,
+ dev->vqs[i].handle_kick,
+ POLLIN);
+ }
+ return 0;
+}
+
+/* User should have device mutex */
+long vhost_dev_check_owner(struct vhost_dev *dev)
+{
+ return dev->mm == current->mm ? 0 : -EPERM;
+}
+
+/* User should have device mutex */
+static long vhost_dev_set_owner(struct vhost_dev *dev)
+{
+ if (dev->mm)
+ return -EBUSY;
+ dev->mm = get_task_mm(current);
+ return 0;
+}
+
+/* User should have device mutex */
+long vhost_dev_reset_owner(struct vhost_dev *dev)
+{
+ struct vhost_memory *memory;
+
+ /* Restore memory to default 1:1 mapping. */
+ memory = kmalloc(offsetof(struct vhost_memory, regions) +
+ 2 * sizeof *memory->regions, GFP_KERNEL);
+ if (!memory)
+ return -ENOMEM;
+
+ vhost_dev_cleanup(dev);
+
+ memory->nregions = 2;
+ memory->regions[0].guest_phys_addr = 1;
+ memory->regions[0].userspace_addr = 1;
+ memory->regions[0].memory_size = ~0ULL;
+ memory->regions[1].guest_phys_addr = 0;
+ memory->regions[1].userspace_addr = 0;
+ memory->regions[1].memory_size = 1;
+ dev->memory = memory;
+ return 0;
+}
+
+/* User should have device mutex */
+void vhost_dev_cleanup(struct vhost_dev *dev)
+{
+ int i;
+ for(i = 0; i < dev->nvqs; ++i) {
+ if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
+ vhost_poll_stop(&dev->vqs[i].poll);
+ vhost_poll_flush(&dev->vqs[i].poll);
+ }
+ if (dev->vqs[i].error_ctx)
+ eventfd_ctx_put(dev->vqs[i].error_ctx);
+ if (dev->vqs[i].error)
+ fput(dev->vqs[i].error);
+ if (dev->vqs[i].kick)
+ fput(dev->vqs[i].kick);
+ if (dev->vqs[i].call_ctx)
+ eventfd_ctx_put(dev->vqs[i].call_ctx);
+ if (dev->vqs[i].call)
+ fput(dev->vqs[i].call);
+ dev->vqs[i].error_ctx = NULL;
+ dev->vqs[i].error = NULL;
+ dev->vqs[i].kick = NULL;
+ dev->vqs[i].call_ctx = NULL;
+ dev->vqs[i].call = NULL;
+ }
+ /* No one will access memory at this point */
+ kfree(dev->memory);
+ dev->memory = NULL;
+ if (dev->mm)
+ mmput(dev->mm);
+ dev->mm = NULL;
+}
+
+static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
+{
+ struct vhost_memory mem, *newmem, *oldmem;
+ unsigned long size = offsetof(struct vhost_memory, regions);
+ long r;
+ r = copy_from_user(&mem, m, size);
+ if (r)
+ return r;
+ if (mem.padding)
+ return -EOPNOTSUPP;
+ if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
+ return -E2BIG;
+ newmem = kmalloc(size + mem.nregions * sizeof *m->regions, GFP_KERNEL);
+ if (!newmem)
+ return -ENOMEM;
+
+ memcpy(newmem, &mem, size);
+ r = copy_from_user(newmem->regions, m->regions,
+ mem.nregions * sizeof *m->regions);
+ if (r) {
+ kfree(newmem);
+ return r;
+ }
+ oldmem = d->memory;
+ rcu_assign_pointer(d->memory, newmem);
+ synchronize_rcu();
+ kfree(oldmem);
+ return 0;
+}
+
+static int init_used(struct vhost_virtqueue *vq)
+{
+ u16 flags = 0;
+ int r = put_user(flags, &vq->used->flags);
+ if (r)
+ return r;
+ return get_user(vq->last_used_idx, &vq->used->idx);
+}
+
+static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
+{
+ struct file *eventfp, *filep = NULL, *pollstart = NULL, *pollstop = NULL;
+ struct eventfd_ctx *ctx = NULL;
+ u32 __user *idxp = argp;
+ struct vhost_virtqueue *vq;
+ struct vhost_vring_state s;
+ struct vhost_vring_file f;
+ struct vhost_vring_addr a;
+ u32 idx;
+ long r;
+
+ r = get_user(idx, idxp);
+ if (r < 0)
+ return r;
+ if (idx > d->nvqs)
+ return -ENOBUFS;
+
+ vq = d->vqs + idx;
+
+ mutex_lock(&vq->mutex);
+
+ switch (ioctl) {
+ case VHOST_SET_VRING_NUM:
+ r = copy_from_user(&s, argp, sizeof s);
+ if (r < 0)
+ break;
+ if (s.num > 0xffff) {
+ r = -EINVAL;
+ break;
+ }
+ vq->num = s.num;
+ break;
+ case VHOST_SET_VRING_BASE:
+ r = copy_from_user(&s, argp, sizeof s);
+ if (r < 0)
+ break;
+ if (s.num > 0xffff) {
+ r = -EINVAL;
+ break;
+ }
+ vq->last_avail_idx = s.num;
+ break;
+ case VHOST_GET_VRING_BASE:
+ s.index = idx;
+ s.num = vq->last_avail_idx;
+ r = copy_to_user(argp, &s, sizeof s);
+ break;
+ case VHOST_SET_VRING_DESC:
+ r = copy_from_user(&a, argp, sizeof a);
+ if (r < 0)
+ break;
+ if (a.padding) {
+ r = -EOPNOTSUPP;
+ break;
+ }
+ if ((u64)(long)a.user_addr != a.user_addr) {
+ r = -EFAULT;
+ break;
+ }
+ vq->desc = (void __user *)(long)a.user_addr;
+ break;
+ case VHOST_SET_VRING_AVAIL:
+ r = copy_from_user(&a, argp, sizeof a);
+ if (r < 0)
+ break;
+ if (a.padding) {
+ r = -EOPNOTSUPP;
+ break;
+ }
+ if ((u64)(long)a.user_addr != a.user_addr) {
+ r = -EFAULT;
+ break;
+ }
+ vq->avail = (void __user *)(long)a.user_addr;
+ break;
+ case VHOST_SET_VRING_USED:
+ r = copy_from_user(&a, argp, sizeof a);
+ if (r < 0)
+ break;
+ if (a.padding) {
+ r = -EOPNOTSUPP;
+ break;
+ }
+ if ((u64)(long)a.user_addr != a.user_addr) {
+ r = -EFAULT;
+ break;
+ }
+ vq->used = (void __user *)(long)a.user_addr;
+ r = init_used(vq);
+ if (r)
+ break;
+ break;
+ case VHOST_SET_VRING_KICK:
+ r = copy_from_user(&f, argp, sizeof f);
+ if (r < 0)
+ break;
+ eventfp = f.fd == -1 ? NULL: eventfd_fget(f.fd);
+ if (IS_ERR(eventfp))
+ return PTR_ERR(eventfp);
+ if (eventfp != vq->kick) {
+ pollstop = filep = vq->kick;
+ pollstart = vq->kick = eventfp;
+ } else
+ filep = eventfp;
+ break;
+ case VHOST_SET_VRING_CALL:
+ r = copy_from_user(&f, argp, sizeof f);
+ if (r < 0)
+ break;
+ eventfp = f.fd == -1 ? NULL: eventfd_fget(f.fd);
+ if (IS_ERR(eventfp))
+ return PTR_ERR(eventfp);
+ if (eventfp != vq->call) {
+ filep = vq->call;
+ ctx = vq->call_ctx;
+ vq->call = eventfp;
+ vq->call_ctx = eventfp ?
+ eventfd_ctx_fileget(eventfp) : NULL;
+ } else
+ filep = eventfp;
+ break;
+ case VHOST_SET_VRING_ERR:
+ r = copy_from_user(&f, argp, sizeof f);
+ if (r < 0)
+ break;
+ eventfp = f.fd == -1 ? NULL: eventfd_fget(f.fd);
+ if (IS_ERR(eventfp))
+ return PTR_ERR(eventfp);
+ if (eventfp != vq->error) {
+ filep = vq->error;
+ vq->error = eventfp;
+ ctx = vq->error_ctx;
+ vq->error_ctx = eventfp ?
+ eventfd_ctx_fileget(eventfp) : NULL;
+ } else
+ filep = eventfp;
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ }
+
+ if (pollstop && vq->handle_kick)
+ vhost_poll_stop(&vq->poll);
+
+ if (ctx)
+ eventfd_ctx_put(ctx);
+ if (filep)
+ fput(filep);
+
+ if (pollstart && vq->handle_kick)
+ vhost_poll_start(&vq->poll, vq->kick);
+
+ mutex_unlock(&vq->mutex);
+
+ if (pollstop && vq->handle_kick)
+ vhost_poll_flush(&vq->poll);
+ return 0;
+}
+
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ long r;
+
+ mutex_lock(&d->mutex);
+ if (ioctl == VHOST_SET_OWNER) {
+ r = vhost_dev_set_owner(d);
+ goto done;
+ }
+
+ r = vhost_dev_check_owner(d);
+ if (r)
+ goto done;
+
+ switch (ioctl) {
+ case VHOST_SET_MEM_TABLE:
+ r = vhost_set_memory(d, argp);
+ break;
+ default:
+ r = vhost_set_vring(d, ioctl, argp);
+ break;
+ }
+done:
+ mutex_unlock(&d->mutex);
+ return r;
+}
+
+static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
+ __u64 addr, __u32 len)
+{
+ struct vhost_memory_region *reg;
+ int i;
+ /* linear search is not brilliant, but we really have on the order of 6
+ * regions in practice */
+ for (i = 0; i < mem->nregions; ++i) {
+ reg = mem->regions + i;
+ if (reg->guest_phys_addr <= addr &&
+ reg->guest_phys_addr + reg->memory_size - 1 >= addr)
+ return reg;
+ }
+ return NULL;
+}
+
+/* FIXME: this does not handle a region that spans multiple
+ * address/len pairs */
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+ struct iovec iov[], int iov_count, int iov_size,
+ unsigned *num)
+{
+ const struct vhost_memory_region *reg;
+ struct vhost_memory *mem;
+ struct iovec *_iov;
+ u64 s = 0;
+ int ret = 0;
+
+ rcu_read_lock();
+
+ mem = rcu_dereference(dev->memory);
+ while ((u64)len > s) {
+ u64 size;
+ if (*num + iov_count >= iov_size) {
+ ret = -ENOBUFS;
+ break;
+ }
+ reg = find_region(mem, addr, len);
+ if (!reg) {
+ ret = -EFAULT;
+ break;
+ }
+ _iov = iov + iov_count + *num;
+ size = reg->memory_size - addr + reg->guest_phys_addr;
+ _iov->iov_len = min((u64)len, size);
+ _iov->iov_base = (void *)
+ (reg->userspace_addr + addr - reg->guest_phys_addr);
+ s += size;
+ addr += size;
+ ++*num;
+ }
+
+ rcu_read_unlock();
+ return ret;
+}
+
+/* Each buffer in the virtqueues is actually a chain of descriptors. This
+ * function returns the next descriptor in the chain, or vq->vring.num if we're
+ * at the end. */
+static unsigned next_desc(struct vhost_virtqueue *vq, struct vring_desc *desc)
+{
+ unsigned int next;
+
+ /* If this descriptor says it doesn't chain, we're done. */
+ if (!(desc->flags & VRING_DESC_F_NEXT))
+ return vq->num;
+
+ /* Check they're not leading us off end of descriptors. */
+ next = desc->next;
+ /* Make sure compiler knows to grab that: we don't want it changing! */
+ /* We will use the result as an index in an array, so most
+ * architectures only need a compiler barrier here. */
+ read_barrier_depends();
+
+ if (next >= vq->num) {
+ vq_err(vq, "Desc next is %u > %u", next, vq->num);
+ return vq->num;
+ }
+
+ return next;
+}
+
+/* This looks in the virtqueue and for the first available buffer, and converts
+ * it to an iovec for convenient access. Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function returns the descriptor number found, or vq->num (which
+ * is never a valid descriptor number) if none was found. */
+unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+ struct iovec iov[],
+ unsigned int *out_num, unsigned int *in_num)
+{
+ struct vring_desc desc;
+ unsigned int i, head;
+ u16 last_avail_idx, idx;
+
+ /* Check it isn't doing very strange things with descriptor numbers. */
+ last_avail_idx = vq->last_avail_idx;
+ if (get_user(idx, &vq->avail->idx)) {
+ vq_err(vq, "Failed to access avail idx at %p\n",
+ &vq->avail->idx);
+ return vq->num;
+ }
+
+ if ((u16)(idx - last_avail_idx) > vq->num) {
+ vq_err(vq, "Guest moved used index from %u to %u",
+ last_avail_idx, idx);
+ return vq->num;
+ }
+
+ /* If there's nothing new since last we looked, return invalid. */
+ if (idx == last_avail_idx)
+ return vq->num;
+
+ /* Grab the next descriptor number they're advertising, and increment
+ * the index we've seen. */
+ if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) {
+ vq_err(vq, "Failed to read head: idx %d address %p\n",
+ idx, &vq->avail->ring[last_avail_idx % vq->num]);
+ return vq->num;
+ }
+
+ /* If their number is silly, that's a fatal mistake. */
+ if (head >= vq->num) {
+ vq_err(vq, "Guest says index %u > %u is available",
+ head, vq->num);
+ return vq->num;
+ }
+
+ vq->last_avail_idx++;
+
+ /* When we start there are none of either input nor output. */
+ *out_num = *in_num = 0;
+
+ i = head;
+ do {
+ unsigned *num;
+ unsigned iov_count;
+ if (copy_from_user(&desc, vq->desc + i, sizeof desc)) {
+ vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
+ i, vq->desc + i);
+ return vq->num;
+ }
+ /* If this is an input descriptor, increment that count. */
+ if (desc.flags & VRING_DESC_F_WRITE) {
+ num = in_num;
+ iov_count = *out_num;
+ } else {
+ /* If it's an output descriptor, they're all supposed
+ * to come before any input descriptors. */
+ if (*in_num) {
+ vq_err(vq, "Descriptor has out after in: "
+ "idx %d\n", i);
+ return vq->num;
+ }
+ num = out_num;
+ iov_count = *in_num;
+ }
+ if (translate_desc(dev, desc.addr, desc.len, iov, iov_count,
+ VHOST_NET_MAX_SG, num)) {
+ vq_err(vq, "Failed to translate descriptor: idx %d\n",
+ i);
+ return vq->num;
+ }
+
+ /* If we've got too many, that implies a descriptor loop. */
+ if (*out_num + *in_num > vq->num) {
+ vq_err(vq, "Looped descriptor: idx %d\n", i);
+ return vq->num;
+ }
+ } while ((i = next_desc(vq, &desc)) != vq->num);
+
+ vq->inflight++;
+ return head;
+}
+
+/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
+void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+{
+ vq->last_avail_idx--;
+ vq->inflight--;
+}
+
+/* After we've used one of their buffers, we tell them about it. We'll then
+ * want to send them an interrupt, using vq->call. */
+int vhost_add_used(struct vhost_virtqueue *vq,
+ unsigned int head, int len)
+{
+ struct vring_used_elem *used;
+
+ /* The virtqueue contains a ring of used buffers. Get a pointer to the
+ * next entry in that used ring. */
+ used = &vq->used->ring[vq->last_used_idx % vq->num];
+ if (put_user(head, &used->id)) {
+ vq_err(vq, "Failed to write used id");
+ return -EFAULT;
+ }
+ if (put_user(len, &used->len)) {
+ vq_err(vq, "Failed to write used len");
+ return -EFAULT;
+ }
+ /* Make sure buffer is written before we update index. */
+ wmb();
+ if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+ vq_err(vq, "Failed to increment used idx");
+ return -EFAULT;
+ }
+ vq->last_used_idx++;
+ vq->inflight--;
+ return 0;
+}
+
+/* This actually sends the interrupt for this virtqueue */
+void vhost_trigger_irq(struct vhost_virtqueue *vq)
+{
+ __u16 flags = 0;
+ if (get_user(flags, &vq->avail->flags)) {
+ vq_err(vq, "Failed to get flags");
+ return;
+ }
+
+ /* If they don't want an interrupt, don't send one, unless empty. */
+ if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+ return;
+
+ /* Send the Guest an interrupt tell them we used something up. */
+ if (vq->call_ctx)
+ eventfd_signal(vq->call_ctx, 1);
+}
+
+/* And here's the combo meal deal. Supersize me! */
+void vhost_add_used_and_trigger(struct vhost_virtqueue *vq,
+ unsigned int head, int len)
+{
+ vhost_add_used(vq, head, len);
+ vhost_trigger_irq(vq);
+}
+
+int vhost_init(void)
+{
+ vhost_workqueue = create_workqueue("vhost");
+ if (!vhost_workqueue)
+ return -ENOMEM;
+ return 0;
+}
+
+void vhost_cleanup(void)
+{
+ destroy_workqueue(vhost_workqueue);
+}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
new file mode 100644
index 0000000..7f7ffcd
--- /dev/null
+++ b/drivers/vhost/vhost.h
@@ -0,0 +1,108 @@
+#ifndef _VHOST_H
+#define _VHOST_H
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/skbuff.h>
+
+struct vhost_device;
+
+enum {
+ VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
+};
+
+/* Poll a file (eventfd or socket) */
+/* Note: there's nothing vhost specific about this structure. */
+struct vhost_poll {
+ poll_table table;
+ wait_queue_head_t *wqh;
+ wait_queue_t wait;
+ /* struct which will handle all actual work. */
+ struct work_struct work;
+ unsigned long mask;
+};
+
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+ unsigned long mask);
+void vhost_poll_start(struct vhost_poll *poll, struct file *file);
+void vhost_poll_stop(struct vhost_poll *poll);
+void vhost_poll_flush(struct vhost_poll *poll);
+
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {
+ struct vhost_dev *dev;
+
+ /* The actual ring of buffers. */
+ struct mutex mutex;
+ unsigned int num;
+ struct vring_desc __user *desc;
+ struct vring_avail __user *avail;
+ struct vring_used __user *used;
+ struct file *kick;
+ struct file *call;
+ struct file *error;
+ struct eventfd_ctx *call_ctx;
+ struct eventfd_ctx *error_ctx;
+
+ struct vhost_poll poll;
+
+ /* The routine to call when the Guest pings us, or timeout. */
+ work_func_t handle_kick;
+
+ /* Last available index we saw. */
+ u16 last_avail_idx;
+
+ /* Last index we used. */
+ u16 last_used_idx;
+
+ /* Outstanding buffers */
+ unsigned int inflight;
+
+ /* Is this blocked? */
+ bool blocked;
+
+ struct iovec iov[VHOST_NET_MAX_SG];
+
+} ____cacheline_aligned;
+
+struct vhost_dev {
+ /* Readers use RCU to access memory table pointer.
+ * Writers use mutex below.*/
+ struct vhost_memory *memory;
+ struct mm_struct *mm;
+ struct vhost_virtqueue *vqs;
+ int nvqs;
+ struct mutex mutex;
+};
+
+long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
+long vhost_dev_check_owner(struct vhost_dev *);
+long vhost_dev_reset_owner(struct vhost_dev *);
+void vhost_dev_cleanup(struct vhost_dev *);
+long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
+
+unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
+ struct iovec iov[],
+ unsigned int *out_num, unsigned int *in_num);
+void vhost_discard_vq_desc(struct vhost_virtqueue *);
+
+int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
+void vhost_trigger_irq(struct vhost_virtqueue *);
+void vhost_add_used_and_trigger(struct vhost_virtqueue *,
+ unsigned int head, int len);
+
+int vhost_init(void);
+void vhost_cleanup(void);
+
+#define vq_err(vq, fmt, ...) do { \
+ printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__); \
+ if ((vq)->error_ctx) \
+ eventfd_signal((vq)->error_ctx, 1);\
+ } while (0)
+
+#endif
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index dec2f18..975df9a 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -360,6 +360,7 @@ unifdef-y += uio.h
unifdef-y += unistd.h
unifdef-y += usbdevice_fs.h
unifdef-y += utsname.h
+unifdef-y += vhost.h
unifdef-y += videodev2.h
unifdef-y += videodev.h
unifdef-y += virtio_config.h
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 0521177..781a8bb 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -30,6 +30,7 @@
#define HPET_MINOR 228
#define FUSE_MINOR 229
#define KVM_MINOR 232
+#define VHOST_NET_MINOR 233
#define MISC_DYNAMIC_MINOR 255
struct device;
diff --git a/include/linux/vhost.h b/include/linux/vhost.h
new file mode 100644
index 0000000..9ec6d5f
--- /dev/null
+++ b/include/linux/vhost.h
@@ -0,0 +1,100 @@
+#ifndef _LINUX_VHOST_H
+#define _LINUX_VHOST_H
+/* Userspace interface for in-kernel virtio accelerators. */
+
+/* vhost is used to reduce the number of system calls involved in virtio.
+ *
+ * Existing virtio net code is used in the guest without modification.
+ *
+ * This header includes interface used by userspace hypervisor for
+ * device configuration.
+ */
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_vring_state {
+ unsigned int index;
+ unsigned int num;
+};
+
+struct vhost_vring_file {
+ unsigned int index;
+ int fd;
+};
+
+struct vhost_vring_addr {
+ unsigned int index;
+ unsigned int padding;
+ __u64 user_addr;
+};
+
+struct vhost_memory_region {
+ __u64 guest_phys_addr;
+ __u64 memory_size; /* bytes */
+ __u64 userspace_addr;
+ __u64 padding; /* read/write protection? */
+};
+
+struct vhost_memory {
+ __u32 nregions;
+ __u32 padding;
+ struct vhost_memory_region regions[0];
+};
+
+/* ioctls */
+
+#define VHOST_VIRTIO 0xAF
+
+/* Features bitmask for forward compatibility. Transport bits must be zero. */
+#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u32)
+#define VHOST_ACK_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u32)
+
+/* Set current process as the (exclusive) owner of this file descriptor. This
+ * must be called before any other vhost command. Further calls to
+ * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
+#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
+/* Give up ownership, and reset the device to default values.
+ * Allows subsequent call to VHOST_OWNER_SET to succeed. */
+#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
+
+/* Set up/modify memory layout */
+#define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
+
+/* Ring setup. These parameters can not be modified while ring is running
+ * (bound to a device). */
+/* Set number of descriptors in ring */
+#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
+/* Start of array of descriptors (virtually contiguous) */
+#define VHOST_SET_VRING_DESC _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
+/* Used structure address */
+#define VHOST_SET_VRING_USED _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_addr)
+/* Available structure address */
+#define VHOST_SET_VRING_AVAIL _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_addr)
+/* Base value where queue looks for available descriptors */
+#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)
+/* Get accessor: reads index, writes value in num */
+#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x14, struct vhost_vring_state)
+
+/* The following ioctls use eventfd file descriptors to signal and poll
+ * for events. */
+
+/* Set eventfd to poll for added buffers */
+#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
+/* Set eventfd to signal when buffers have beed used */
+#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
+/* Set eventfd to signal an error */
+#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
+
+/* VHOST_NET specific defines */
+
+/* Attach virtio net device to a raw socket. The socket must be already
+ * bound to an ethernet device, this device will be used for transmit.
+ * Pass -1 to unbind from the socket and the transmit device.
+ * This can be used to stop the device (e.g. for migration). */
+#define VHOST_NET_SET_SOCKET _IOW(VHOST_VIRTIO, 0x30, int)
+
+#endif
--
1.6.2.5
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCHv3 1/2] mm: export use_mm/unuse_mm to modules
From: Michael S. Tsirkin @ 2009-08-13 18:29 UTC (permalink / raw)
To: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, hpa,
gr
In-Reply-To: <cover.1250187913.git.mst@redhat.com>
vhost net module wants to do copy to/from user from a kernel thread,
which needs use_mm (like what fs/aio has). Move that into mm/ and
export to modules.
Acked-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
fs/aio.c | 47 +----------------------------------
include/linux/mmu_context.h | 9 ++++++
mm/Makefile | 2 +-
mm/mmu_context.c | 58 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 69 insertions(+), 47 deletions(-)
create mode 100644 include/linux/mmu_context.h
create mode 100644 mm/mmu_context.c
diff --git a/fs/aio.c b/fs/aio.c
index d065b2c..fc21c23 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -24,6 +24,7 @@
#include <linux/file.h>
#include <linux/mm.h>
#include <linux/mman.h>
+#include <linux/mmu_context.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/aio.h>
@@ -34,7 +35,6 @@
#include <asm/kmap_types.h>
#include <asm/uaccess.h>
-#include <asm/mmu_context.h>
#if DEBUG > 1
#define dprintk printk
@@ -595,51 +595,6 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
}
/*
- * use_mm
- * Makes the calling kernel thread take on the specified
- * mm context.
- * Called by the retry thread execute retries within the
- * iocb issuer's mm context, so that copy_from/to_user
- * operations work seamlessly for aio.
- * (Note: this routine is intended to be called only
- * from a kernel thread context)
- */
-static void use_mm(struct mm_struct *mm)
-{
- struct mm_struct *active_mm;
- struct task_struct *tsk = current;
-
- task_lock(tsk);
- active_mm = tsk->active_mm;
- atomic_inc(&mm->mm_count);
- tsk->mm = mm;
- tsk->active_mm = mm;
- switch_mm(active_mm, mm, tsk);
- task_unlock(tsk);
-
- mmdrop(active_mm);
-}
-
-/*
- * unuse_mm
- * Reverses the effect of use_mm, i.e. releases the
- * specified mm context which was earlier taken on
- * by the calling kernel thread
- * (Note: this routine is intended to be called only
- * from a kernel thread context)
- */
-static void unuse_mm(struct mm_struct *mm)
-{
- struct task_struct *tsk = current;
-
- task_lock(tsk);
- tsk->mm = NULL;
- /* active_mm is still 'mm' */
- enter_lazy_tlb(mm, tsk);
- task_unlock(tsk);
-}
-
-/*
* Queue up a kiocb to be retried. Assumes that the kiocb
* has already been marked as kicked, and places it on
* the retry run list for the corresponding ioctx, if it
diff --git a/include/linux/mmu_context.h b/include/linux/mmu_context.h
new file mode 100644
index 0000000..70fffeb
--- /dev/null
+++ b/include/linux/mmu_context.h
@@ -0,0 +1,9 @@
+#ifndef _LINUX_MMU_CONTEXT_H
+#define _LINUX_MMU_CONTEXT_H
+
+struct mm_struct;
+
+void use_mm(struct mm_struct *mm);
+void unuse_mm(struct mm_struct *mm);
+
+#endif
diff --git a/mm/Makefile b/mm/Makefile
index 5e0bd64..46c3892 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -11,7 +11,7 @@ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
maccess.o page_alloc.o page-writeback.o pdflush.o \
readahead.o swap.o truncate.o vmscan.o shmem.o \
prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
- page_isolation.o mm_init.o $(mmu-y)
+ page_isolation.o mm_init.o mmu_context.o $(mmu-y)
obj-y += init-mm.o
obj-$(CONFIG_PROC_PAGE_MONITOR) += pagewalk.o
diff --git a/mm/mmu_context.c b/mm/mmu_context.c
new file mode 100644
index 0000000..9989c2f
--- /dev/null
+++ b/mm/mmu_context.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ *
+ * See ../COPYING for licensing terms.
+ */
+
+#include <linux/mm.h>
+#include <linux/mmu_context.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+
+#include <asm/mmu_context.h>
+
+/*
+ * use_mm
+ * Makes the calling kernel thread take on the specified
+ * mm context.
+ * Called by the retry thread execute retries within the
+ * iocb issuer's mm context, so that copy_from/to_user
+ * operations work seamlessly for aio.
+ * (Note: this routine is intended to be called only
+ * from a kernel thread context)
+ */
+void use_mm(struct mm_struct *mm)
+{
+ struct mm_struct *active_mm;
+ struct task_struct *tsk = current;
+
+ task_lock(tsk);
+ active_mm = tsk->active_mm;
+ atomic_inc(&mm->mm_count);
+ tsk->mm = mm;
+ tsk->active_mm = mm;
+ switch_mm(active_mm, mm, tsk);
+ task_unlock(tsk);
+
+ mmdrop(active_mm);
+}
+EXPORT_SYMBOL_GPL(use_mm);
+
+/*
+ * unuse_mm
+ * Reverses the effect of use_mm, i.e. releases the
+ * specified mm context which was earlier taken on
+ * by the calling kernel thread
+ * (Note: this routine is intended to be called only
+ * from a kernel thread context)
+ */
+void unuse_mm(struct mm_struct *mm)
+{
+ struct task_struct *tsk = current;
+
+ task_lock(tsk);
+ tsk->mm = NULL;
+ /* active_mm is still 'mm' */
+ enter_lazy_tlb(mm, tsk);
+ task_unlock(tsk);
+}
+EXPORT_SYMBOL_GPL(unuse_mm);
--
1.6.2.5
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCHv3 0/2] vhost: a kernel-level virtio server
From: Michael S. Tsirkin @ 2009-08-13 18:27 UTC (permalink / raw)
To: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm
This implements vhost: a kernel-level backend for virtio,
The main motivation for this work is to reduce virtualization
overhead for virtio by removing system calls on data path,
without guest changes. For virtio-net, this removes up to
4 system calls per packet: vm exit for kick, reentry for kick,
iothread wakeup for packet, interrupt injection for packet.
Some more detailed description attached to the patch itself.
The patches are against 2.6.31-rc4. I'd like them to go into linux-next
and down the road 2.6.32 if possible. Please comment.
Changelog from v2:
- Comments on RCU usage
- Compat ioctl support
- Make variable static
- Copied more idiomatic english from Rusty
Changes from v1:
- Move use_mm/unuse_mm from fs/aio.c to mm instead of copying.
- Reorder code to avoid need for forward declarations
- Kill a couple of debugging printks
Michael S. Tsirkin (2):
mm: export use_mm/unuse_mm to modules
vhost_net: a kernel-level virtio server
MAINTAINERS | 10 +
arch/x86/kvm/Kconfig | 1 +
drivers/Makefile | 1 +
drivers/vhost/Kconfig | 11 +
drivers/vhost/Makefile | 2 +
drivers/vhost/net.c | 429 ++++++++++++++++++++++++++++
drivers/vhost/vhost.c | 663 +++++++++++++++++++++++++++++++++++++++++++
drivers/vhost/vhost.h | 108 +++++++
fs/aio.c | 47 +---
include/linux/Kbuild | 1 +
include/linux/miscdevice.h | 1 +
include/linux/mmu_context.h | 9 +
include/linux/vhost.h | 100 +++++++
mm/Makefile | 2 +-
mm/mmu_context.c | 58 ++++
15 files changed, 1396 insertions(+), 47 deletions(-)
create mode 100644 drivers/vhost/Kconfig
create mode 100644 drivers/vhost/Makefile
create mode 100644 drivers/vhost/net.c
create mode 100644 drivers/vhost/vhost.c
create mode 100644 drivers/vhost/vhost.h
create mode 100644 include/linux/mmu_context.h
create mode 100644 include/linux/vhost.h
create mode 100644 mm/mmu_context.c
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [RFC] ipv6: Change %pI6 format to output compacted addresses?
From: Joe Perches @ 2009-08-13 18:21 UTC (permalink / raw)
To: Chuck Lever; +Cc: Brian Haley, Jens Rosenboom, Linux Network Developers
In-Reply-To: <48AAB7CB-8EEC-4E30-B821-3E0D84531AAA@oracle.com>
On Thu, 2009-08-13 at 14:15 -0400, Chuck Lever wrote:
> On Aug 13, 2009, at 2:10 PM, Joe Perches wrote:
> > The patch allows "%p6ic" for compressed and "%p6ic4" for compressed
> > with ipv4 last u32.
>
> Why do these need to be separate?
Just an option.
I think it possible somebody will want "1::" instead of "1::0.0.0.0"
^ permalink raw reply
* Re: [PATCH 2/3] security: introducing security_request_module
From: Eric Paris @ 2009-08-13 18:19 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: linux-kernel, selinux, netdev, linux-security-module, sds, davem,
shemminger, kees, morgan, casey, dwalsh
In-Reply-To: <20090813175405.GA6824@us.ibm.com>
On Thu, 2009-08-13 at 12:54 -0500, Serge E. Hallyn wrote:
> Quoting Eric Paris (eparis@redhat.com):
> > On Thu, 2009-08-13 at 09:03 -0500, Serge E. Hallyn wrote:
> > > Quoting Eric Paris (eparis@redhat.com):
> > > > Calling request_module() will trigger a userspace upcall which will load a
> > > > new module into the kernel. This can be a dangerous event if the process
> > > > able to trigger request_module() is able to control either the modprobe
> > > > binary or the module binary. This patch adds a new security hook to
> > > > request_module() which can be used by an LSM to control a processes ability
> > > > to call request_module().
> > >
> > > Is there a specific case in which you'd want to deny this ability
> > > from a real task?
> >
> > qemu and any network facing daemon are all programs I don't want to be
> > able to even ask the kernel to load a module. Clearly you are right,
>
> ... What if the network facing daemon might want to use a kernel crypto
> module? What if qemu needs the tun module loaded?
Loading code into the kernel is a dangerous operation. We should find
the places where high risk processes are doing this and either choose to
accept the security risk or make sure they are loaded before the
dangerous code is run, aka libvirt knows if the guest needs the tun
device and it should be allowed to trigger it's loading. It's shouldn't
be the guest doing the triggering.
It was also pointed out to me that stopping processes from being able to
trigger module loads could be useful to keep a subverted process from
loading an uncommon or unloaded module with a vulnerability which they
could then use to exploit the kernel. It's all about hardening.
It won't be a simple task for SELinux policy to do something useful with
this hook as they need to identify all of the legitimate callers of
request_module(), but then again, that should be a lot easier than 90%
of what SELinux already has to do, and until SELinux policy decides to
make use of the new permission things will 'just work'
-Eric
^ permalink raw reply
* Re: WARNING: at net/ipv4/af_inet.c:155 inet_sock_destruct+0x122/0x13a()
From: Tomasz Chmielewski @ 2009-08-13 18:16 UTC (permalink / raw)
To: John Dykstra; +Cc: Vlad Yasevich, Eric Dumazet, David Miller, netdev
In-Reply-To: <1250176905.7289.7.camel@Maple>
John Dykstra wrote:
> On Wed, 2009-08-12 at 16:00 -0400, Vlad Yasevich wrote:
>> BTW, I've seen the same issue in 2.6.28 and 2.6.29 while doing a bunch
>> of NFS-over-UDP testing. I've seen the issue reported in 2.6.27 as well,
>> but it went by ignored. It's not easy to reproduce as it seems like it
>> requires quite a bit traffic over over multiple interfaces.
>
> I've been unable to reproduce it so far. Has bonding always been
> present in the cases you've seen, or are multiple independent interfaces
> sufficient?
>
> In the case you reported initially, openvpn was using UDP, but the peer
> was dead, so there presumably wasn't much traffic from that app. Was
> there lots of NFS-over-UDP traffic also going on?
There was quite a bit of NFS, but over TCP.
The other type of traffic was iSCSI (made with tgt as a target).
--
Tomasz Chmielewski
http://wpkg.org
^ permalink raw reply
* Re: [RFC] ipv6: Change %pI6 format to output compacted addresses?
From: Chuck Lever @ 2009-08-13 18:15 UTC (permalink / raw)
To: Joe Perches; +Cc: Brian Haley, Jens Rosenboom, Linux Network Developers
In-Reply-To: <1250187034.28285.93.camel@Joe-Laptop.home>
On Aug 13, 2009, at 2:10 PM, Joe Perches wrote:
> On Thu, 2009-08-13 at 12:27 -0400, Brian Haley wrote:
>> Jens Rosenboom wrote:
>>> Here is a new version that also
>>> fixes
>>>
>>> - Leave %pi6 alone
>>> - Don't compress a single :0:
>>> - Do output 0
>>> The results and also the remaining issues can be seen with the
>>> attached
>>> test program, that also exposes a bug in glibc for v4-mapped
>>> addresses
>>> from 0/16.
>>> To fully conform to the cited draft, we would still have to
>>> implement
>>> v4-mapped and also check whether a second run of zeros would be
>>> longer
>>> than the first one, although the draft also suggests that operators
>>> should avoid using this kind of addresses, so maybe this second
>>> issue
>>> can be neglected.
>>
>> Yes, the "compress the most zeros" would be harder, and require two
>> passes over the address. I had to cut corners somewhere :)
>
> 2 things.
>
> First a question, then a compilable but untested patch.
>
> The patch allows "%p6ic" for compressed and "%p6ic4" for compressed
> with ipv4 last u32.
Why do these need to be separate?
> Can somebody tell me what I'm doing wrong when I link Jens' test?
>
> cc -o test test_ipv6.c lib/vsprintf.o lib/ctype.o
> lib/vsprintf.o: In function `global constructors keyed to
> 65535_0_simple_strtoul':
> /home/joe/linux/linux-2.6/lib/vsprintf.c:1972: undefined reference to
> `__gcov_init'
> lib/vsprintf.o:(.data+0x28): undefined reference to `__gcov_merge_add'
> collect2: ld returned 1 exit status
>
>
> Now for the patch. Perhaps something like this (compiled, untested)
>
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index 756ccaf..dd02842 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -630,7 +630,7 @@ static char *resource_string(char *buf, char
> *end, struct resource *res,
> }
>
> static char *mac_address_string(char *buf, char *end, u8 *addr,
> - struct printf_spec spec)
> + struct printf_spec spec, const char *fmt)
> {
> char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing
> zero */
> char *p = mac_addr;
> @@ -638,36 +638,128 @@ static char *mac_address_string(char *buf,
> char *end, u8 *addr,
>
> for (i = 0; i < 6; i++) {
> p = pack_hex_byte(p, addr[i]);
> - if (!(spec.flags & SPECIAL) && i != 5)
> + if (!(fmt[0] == 'm') && i != 5)
> *p++ = ':';
> }
> *p = '\0';
> - spec.flags &= ~SPECIAL;
>
> return string(buf, end, mac_addr, spec);
> }
>
> +typedef enum { DC_START, DC_MIDDLE, DC_DONE } ip6_colon_t;
> +
> +static char *ip6_compress_u16(char *p, u16 addr16, u16 addr16_next,
> + ip6_colon_t *colon, bool *needcolon)
> +{
> + bool printhi;
> + u8 hi;
> + u8 lo;
> +
> + if (addr16 == 0 && addr16_next == 0 && *colon == DC_START) {
> + *colon = DC_MIDDLE;
> + return p;
> + }
> + if (*colon == DC_MIDDLE) {
> + if (addr16 == 0)
> + return p;
> + *colon = DC_DONE;
> + *p++ = ':';
> + *p++ = ':';
> + } else if (*needcolon)
> + *p++ = ':';
> +
> + printhi = false;
> + hi = addr16 >> 8;
> + lo = addr16 & 0xff;
> + if (hi) {
> + if (hi > 0x0f)
> + p = pack_hex_byte(p, hi);
> + else
> + *p++ = hex_asc_lo(hi);
> + printhi = true;
> + }
> + /*
> + * If we printed the high-order bits we must print the
> + * low-order ones, even if they're all zeros.
> + */
> + if (printhi || lo > 0x0f)
> + p = pack_hex_byte(p, lo);
> + else
> + *p++ = hex_asc_lo(lo);
> + *needcolon = true;
> +
> + return p;
> +}
> +
> +static char *ip6_compressed_string(char *buf, char *end, u8 *addr,
> + struct printf_spec spec, const char *fmt,
> + char *ip6_addr)
> +{
> + char *p = ip6_addr;
> + int i;
> + bool needcolon = false;
> + u16 *addr16 = (u16 *)addr;
> + ip6_colon_t colon = DC_START;
> +
> + if (fmt[3] == '4') { /* use :: and ipv4 */
> + for (i = 0; i < 6; i++) {
> + p = ip6_compress_u16(p, addr16[i], addr16[i+1],
> + &colon, &needcolon);
> + }
> + if (colon != DC_DONE) {
> + *p++ = ':';
> + *p++ = ':';
> + colon = DC_DONE;
> + }
> + addr += 6 * 2;
> + for (i = 0; i < 4; i++) {
> + p = put_dec_trunc(p, *addr++);
> + if (i != 3)
> + *p++ = '.';
> + }
> + } else {
> + for (i = 0; i < 7; i++) {
> + p = ip6_compress_u16(p, addr16[i], addr16[i+1],
> + &colon, &needcolon);
> + }
> + p = ip6_compress_u16(p, addr16[7], 0xff, &colon, &needcolon);
> + }
> +
> + if (colon == DC_MIDDLE) {
> + *p++ = ':';
> + *p++ = ':';
> + }
> +
> + *p = '\0';
> +
> + return string(buf, end, ip6_addr, spec);
> +}
> +
> static char *ip6_addr_string(char *buf, char *end, u8 *addr,
> - struct printf_spec spec)
> + struct printf_spec spec, const char *fmt)
> {
> - char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing
> zero */
> + char ip6_addr[7 * 4 + 7 + 4 * 4]; /* (7 * 4 hex digits) + 7 colons +
> + * ipv4 address, and trailing zero */
> char *p = ip6_addr;
> int i;
>
> + if (fmt[0] == 'i' && fmt[2] == 'c')
> + return ip6_compressed_string(buf, end, addr, spec, fmt,
> + ip6_addr);
> +
> for (i = 0; i < 8; i++) {
> p = pack_hex_byte(p, addr[2 * i]);
> p = pack_hex_byte(p, addr[2 * i + 1]);
> - if (!(spec.flags & SPECIAL) && i != 7)
> + if (fmt[0] == 'i' && i != 7)
> *p++ = ':';
> }
> *p = '\0';
> - spec.flags &= ~SPECIAL;
>
> return string(buf, end, ip6_addr, spec);
> }
>
> static char *ip4_addr_string(char *buf, char *end, u8 *addr,
> - struct printf_spec spec)
> + struct printf_spec spec)
> {
> char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and
> trailing zero */
> char temp[3]; /* hold each IP quad in reverse order */
> @@ -683,11 +775,18 @@ static char *ip4_addr_string(char *buf, char
> *end, u8 *addr,
> *p++ = '.';
> }
> *p = '\0';
> - spec.flags &= ~SPECIAL;
>
> return string(buf, end, ip4_addr, spec);
> }
>
> +static char *ip_addr_string(char *buf, char *end, u8 *addr,
> + struct printf_spec spec, const char *fmt)
> +{
> + if (fmt[1] == '6')
> + return ip6_addr_string(buf, end, addr, spec, fmt);
> + return ip4_addr_string(buf, end, addr, spec);
> +}
> +
> /*
> * Show a '%p' thing. A kernel extension is that the '%p' is followed
> * by an extra set of alphanumeric characters that are extended format
> @@ -726,20 +825,19 @@ static char *pointer(const char *fmt, char
> *buf, char *end, void *ptr,
> return symbol_string(buf, end, ptr, spec, *fmt);
> case 'R':
> return resource_string(buf, end, ptr, spec);
> - case 'm':
> - spec.flags |= SPECIAL;
> - /* Fallthrough */
> - case 'M':
> - return mac_address_string(buf, end, ptr, spec);
> - case 'i':
> - spec.flags |= SPECIAL;
> - /* Fallthrough */
> - case 'I':
> - if (fmt[1] == '6')
> - return ip6_addr_string(buf, end, ptr, spec);
> - if (fmt[1] == '4')
> - return ip4_addr_string(buf, end, ptr, spec);
> - spec.flags &= ~SPECIAL;
> + case 'm': /* Colon separated: 00:01:02:03:04:05 */
> + case 'M': /* Contiguous: 000102030405 */
> + return mac_address_string(buf, end, ptr, spec, fmt);
> + case 'i': /*
> + * Formatted IP supported
> + * 4: 001.002.003.004
> + * 6: 0001:0203:...:0708
> + * 6c: 1::708
> + * 6c4: 1::1.2.3.4
> + */
> + case 'I': /* Contiguous: */
> + if (fmt[1] == '4' || fmt[1] == '6')
> + ip_addr_string(buf, end, ptr, spec, fmt);
> break;
> }
> spec.flags |= SMALL;
>
>
> --
> 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
--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com
^ permalink raw reply
* Re: [RFC] ipv6: Change %pI6 format to output compacted addresses?
From: Joe Perches @ 2009-08-13 18:10 UTC (permalink / raw)
To: Brian Haley; +Cc: Jens Rosenboom, Linux Network Developers, Chuck Lever
In-Reply-To: <4A843EF7.4010700@hp.com>
On Thu, 2009-08-13 at 12:27 -0400, Brian Haley wrote:
> Jens Rosenboom wrote:
> > Here is a new version that also
> > fixes
> >
> > - Leave %pi6 alone
> > - Don't compress a single :0:
> > - Do output 0
> > The results and also the remaining issues can be seen with the attached
> > test program, that also exposes a bug in glibc for v4-mapped addresses
> > from 0/16.
> > To fully conform to the cited draft, we would still have to implement
> > v4-mapped and also check whether a second run of zeros would be longer
> > than the first one, although the draft also suggests that operators
> > should avoid using this kind of addresses, so maybe this second issue
> > can be neglected.
>
> Yes, the "compress the most zeros" would be harder, and require two
> passes over the address. I had to cut corners somewhere :)
2 things.
First a question, then a compilable but untested patch.
The patch allows "%p6ic" for compressed and "%p6ic4" for compressed
with ipv4 last u32.
Can somebody tell me what I'm doing wrong when I link Jens' test?
cc -o test test_ipv6.c lib/vsprintf.o lib/ctype.o
lib/vsprintf.o: In function `global constructors keyed to
65535_0_simple_strtoul':
/home/joe/linux/linux-2.6/lib/vsprintf.c:1972: undefined reference to
`__gcov_init'
lib/vsprintf.o:(.data+0x28): undefined reference to `__gcov_merge_add'
collect2: ld returned 1 exit status
Now for the patch. Perhaps something like this (compiled, untested)
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 756ccaf..dd02842 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -630,7 +630,7 @@ static char *resource_string(char *buf, char *end, struct resource *res,
}
static char *mac_address_string(char *buf, char *end, u8 *addr,
- struct printf_spec spec)
+ struct printf_spec spec, const char *fmt)
{
char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */
char *p = mac_addr;
@@ -638,36 +638,128 @@ static char *mac_address_string(char *buf, char *end, u8 *addr,
for (i = 0; i < 6; i++) {
p = pack_hex_byte(p, addr[i]);
- if (!(spec.flags & SPECIAL) && i != 5)
+ if (!(fmt[0] == 'm') && i != 5)
*p++ = ':';
}
*p = '\0';
- spec.flags &= ~SPECIAL;
return string(buf, end, mac_addr, spec);
}
+typedef enum { DC_START, DC_MIDDLE, DC_DONE } ip6_colon_t;
+
+static char *ip6_compress_u16(char *p, u16 addr16, u16 addr16_next,
+ ip6_colon_t *colon, bool *needcolon)
+{
+ bool printhi;
+ u8 hi;
+ u8 lo;
+
+ if (addr16 == 0 && addr16_next == 0 && *colon == DC_START) {
+ *colon = DC_MIDDLE;
+ return p;
+ }
+ if (*colon == DC_MIDDLE) {
+ if (addr16 == 0)
+ return p;
+ *colon = DC_DONE;
+ *p++ = ':';
+ *p++ = ':';
+ } else if (*needcolon)
+ *p++ = ':';
+
+ printhi = false;
+ hi = addr16 >> 8;
+ lo = addr16 & 0xff;
+ if (hi) {
+ if (hi > 0x0f)
+ p = pack_hex_byte(p, hi);
+ else
+ *p++ = hex_asc_lo(hi);
+ printhi = true;
+ }
+ /*
+ * If we printed the high-order bits we must print the
+ * low-order ones, even if they're all zeros.
+ */
+ if (printhi || lo > 0x0f)
+ p = pack_hex_byte(p, lo);
+ else
+ *p++ = hex_asc_lo(lo);
+ *needcolon = true;
+
+ return p;
+}
+
+static char *ip6_compressed_string(char *buf, char *end, u8 *addr,
+ struct printf_spec spec, const char *fmt,
+ char *ip6_addr)
+{
+ char *p = ip6_addr;
+ int i;
+ bool needcolon = false;
+ u16 *addr16 = (u16 *)addr;
+ ip6_colon_t colon = DC_START;
+
+ if (fmt[3] == '4') { /* use :: and ipv4 */
+ for (i = 0; i < 6; i++) {
+ p = ip6_compress_u16(p, addr16[i], addr16[i+1],
+ &colon, &needcolon);
+ }
+ if (colon != DC_DONE) {
+ *p++ = ':';
+ *p++ = ':';
+ colon = DC_DONE;
+ }
+ addr += 6 * 2;
+ for (i = 0; i < 4; i++) {
+ p = put_dec_trunc(p, *addr++);
+ if (i != 3)
+ *p++ = '.';
+ }
+ } else {
+ for (i = 0; i < 7; i++) {
+ p = ip6_compress_u16(p, addr16[i], addr16[i+1],
+ &colon, &needcolon);
+ }
+ p = ip6_compress_u16(p, addr16[7], 0xff, &colon, &needcolon);
+ }
+
+ if (colon == DC_MIDDLE) {
+ *p++ = ':';
+ *p++ = ':';
+ }
+
+ *p = '\0';
+
+ return string(buf, end, ip6_addr, spec);
+}
+
static char *ip6_addr_string(char *buf, char *end, u8 *addr,
- struct printf_spec spec)
+ struct printf_spec spec, const char *fmt)
{
- char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */
+ char ip6_addr[7 * 4 + 7 + 4 * 4]; /* (7 * 4 hex digits) + 7 colons +
+ * ipv4 address, and trailing zero */
char *p = ip6_addr;
int i;
+ if (fmt[0] == 'i' && fmt[2] == 'c')
+ return ip6_compressed_string(buf, end, addr, spec, fmt,
+ ip6_addr);
+
for (i = 0; i < 8; i++) {
p = pack_hex_byte(p, addr[2 * i]);
p = pack_hex_byte(p, addr[2 * i + 1]);
- if (!(spec.flags & SPECIAL) && i != 7)
+ if (fmt[0] == 'i' && i != 7)
*p++ = ':';
}
*p = '\0';
- spec.flags &= ~SPECIAL;
return string(buf, end, ip6_addr, spec);
}
static char *ip4_addr_string(char *buf, char *end, u8 *addr,
- struct printf_spec spec)
+ struct printf_spec spec)
{
char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */
char temp[3]; /* hold each IP quad in reverse order */
@@ -683,11 +775,18 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr,
*p++ = '.';
}
*p = '\0';
- spec.flags &= ~SPECIAL;
return string(buf, end, ip4_addr, spec);
}
+static char *ip_addr_string(char *buf, char *end, u8 *addr,
+ struct printf_spec spec, const char *fmt)
+{
+ if (fmt[1] == '6')
+ return ip6_addr_string(buf, end, addr, spec, fmt);
+ return ip4_addr_string(buf, end, addr, spec);
+}
+
/*
* Show a '%p' thing. A kernel extension is that the '%p' is followed
* by an extra set of alphanumeric characters that are extended format
@@ -726,20 +825,19 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
return symbol_string(buf, end, ptr, spec, *fmt);
case 'R':
return resource_string(buf, end, ptr, spec);
- case 'm':
- spec.flags |= SPECIAL;
- /* Fallthrough */
- case 'M':
- return mac_address_string(buf, end, ptr, spec);
- case 'i':
- spec.flags |= SPECIAL;
- /* Fallthrough */
- case 'I':
- if (fmt[1] == '6')
- return ip6_addr_string(buf, end, ptr, spec);
- if (fmt[1] == '4')
- return ip4_addr_string(buf, end, ptr, spec);
- spec.flags &= ~SPECIAL;
+ case 'm': /* Colon separated: 00:01:02:03:04:05 */
+ case 'M': /* Contiguous: 000102030405 */
+ return mac_address_string(buf, end, ptr, spec, fmt);
+ case 'i': /*
+ * Formatted IP supported
+ * 4: 001.002.003.004
+ * 6: 0001:0203:...:0708
+ * 6c: 1::708
+ * 6c4: 1::1.2.3.4
+ */
+ case 'I': /* Contiguous: */
+ if (fmt[1] == '4' || fmt[1] == '6')
+ ip_addr_string(buf, end, ptr, spec, fmt);
break;
}
spec.flags |= SMALL;
^ permalink raw reply related
* Re: [PATCH] net/bridge: Add 'hairpin' port forwarding mode
From: Stephen Hemminger @ 2009-08-13 18:07 UTC (permalink / raw)
To: Fischer, Anna
Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
Paul Congdon (UC Davis), evb@yahoogroups.com,
bridge@lists.linux-foundation.org, davem@davemloft.net,
virtualization@lists.linux-foundation.org, kaber@trash.net,
Arnd Bergmann, Dickson, Mike (ISS Software), adobriyan@gmail.com,
bridge@osdl.org
In-Reply-To: <0199E0D51A61344794750DC57738F58E6D6B0C70D9@GVW1118EXC.americas.hpqcorp.net>
> diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
> index eb404dc..e486f1f 100644
> --- a/net/bridge/br_if.c
> +++ b/net/bridge/br_if.c
> @@ -256,6 +256,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
> p->path_cost = port_cost(dev);
> p->priority = 0x8000 >> BR_PORT_BITS;
> p->port_no = index;
> + p->flags = 0;
> br_init_port(p);
> p->state = BR_STATE_DISABLED;
> br_stp_port_timer_init(p);
Minor nit. this is unnecessary since the structure is allocated with kzalloc.
^ permalink raw reply
* Re: [PATCH 2/3] security: introducing security_request_module
From: Serge E. Hallyn @ 2009-08-13 17:54 UTC (permalink / raw)
To: Eric Paris
Cc: linux-kernel, selinux, netdev, linux-security-module, sds, davem,
shemminger, kees, morgan, casey, dwalsh
In-Reply-To: <1250177334.2182.88.camel@dhcp231-106.rdu.redhat.com>
Quoting Eric Paris (eparis@redhat.com):
> On Thu, 2009-08-13 at 09:03 -0500, Serge E. Hallyn wrote:
> > Quoting Eric Paris (eparis@redhat.com):
> > > Calling request_module() will trigger a userspace upcall which will load a
> > > new module into the kernel. This can be a dangerous event if the process
> > > able to trigger request_module() is able to control either the modprobe
> > > binary or the module binary. This patch adds a new security hook to
> > > request_module() which can be used by an LSM to control a processes ability
> > > to call request_module().
> >
> > Is there a specific case in which you'd want to deny this ability
> > from a real task?
>
> qemu and any network facing daemon are all programs I don't want to be
> able to even ask the kernel to load a module. Clearly you are right,
... What if the network facing daemon might want to use a kernel crypto
module? What if qemu needs the tun module loaded?
> that the best protection is done by controlling access to modprobe and
> the modules on disk (which we are working to fix vs what happened in the
> xen fb exploit I showed earlier) but stopping it from the other
> direction is, I feel, a useful defense in depth.
>
> If they can't get modprobe called, they can't take over the system
> directly, even if they did change a module or change modprobe. I agree
> it's not strong security as if they can change modprobe or modules they
> might be able to just wait until something else calls modprobe (next
> reboot maybe?) to take over the system. But I'd find it very
> interesting to know that a high threat target tried to do anything which
> attempted to load a module....
>
> -Eric
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" 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: [PATCH] libertas: name the network device wlan%d
From: Dan Williams @ 2009-08-13 17:28 UTC (permalink / raw)
To: Daniel Drake
Cc: netdev, Roel Kluin, John W. Linville, Daniel Mack, libertas-dev
In-Reply-To: <818423da0908122048p1fa69a2bnd570071f11336089@mail.gmail.com>
On Thu, 2009-08-13 at 09:33 +0545, Daniel Drake wrote:
> 2009/8/12 Dan Williams <dcbw@redhat.com>:
> > Daniel, is it a problem for you guys if the libertas wifi interface name
> > went from 'eth' -> 'wlan' ? Mesh name would be unchanged.
>
> I can't think of any problems.
In that case:
Acked-by: Dan Williams <dcbw@redhat.com>
^ 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