* [PATCH] atm/iphase: rename fregt_t -> ffreg_t
From: Heiko Carstens @ 2013-02-08 10:19 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-kernel
We have conflicting type qualifiers for "freg_t" in s390's ptrace.h and the
iphase atm device driver, which causes the compile error below.
Unfortunately the s390 typedef can't be renamed, since it's a user visible api,
nor can I change the include order in s390 code to avoid the conflict.
So simply rename the iphase typedef to a new name. Fixes this compile error:
In file included from drivers/atm/iphase.c:66:0:
drivers/atm/iphase.h:639:25: error: conflicting type qualifiers for 'freg_t'
In file included from next/arch/s390/include/asm/ptrace.h:9:0,
from next/arch/s390/include/asm/lowcore.h:12,
from next/arch/s390/include/asm/thread_info.h:30,
from include/linux/thread_info.h:54,
from include/linux/preempt.h:9,
from include/linux/spinlock.h:50,
from include/linux/seqlock.h:29,
from include/linux/time.h:5,
from include/linux/stat.h:18,
from include/linux/module.h:10,
from drivers/atm/iphase.c:43:
next/arch/s390/include/uapi/asm/ptrace.h:197:3: note: previous declaration of 'freg_t' was here
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
---
drivers/atm/iphase.h | 146 +++++++++++++++++++++++++--------------------------
1 file changed, 73 insertions(+), 73 deletions(-)
diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h
index 6a0955e..53ecac5 100644
--- a/drivers/atm/iphase.h
+++ b/drivers/atm/iphase.h
@@ -636,82 +636,82 @@ struct rx_buf_desc {
#define SEG_BASE IPHASE5575_FRAG_CONTROL_REG_BASE
#define REASS_BASE IPHASE5575_REASS_CONTROL_REG_BASE
-typedef volatile u_int freg_t;
+typedef volatile u_int ffreg_t;
typedef u_int rreg_t;
typedef struct _ffredn_t {
- freg_t idlehead_high; /* Idle cell header (high) */
- freg_t idlehead_low; /* Idle cell header (low) */
- freg_t maxrate; /* Maximum rate */
- freg_t stparms; /* Traffic Management Parameters */
- freg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */
- freg_t rm_type; /* */
- u_int filler5[0x17 - 0x06];
- freg_t cmd_reg; /* Command register */
- u_int filler18[0x20 - 0x18];
- freg_t cbr_base; /* CBR Pointer Base */
- freg_t vbr_base; /* VBR Pointer Base */
- freg_t abr_base; /* ABR Pointer Base */
- freg_t ubr_base; /* UBR Pointer Base */
- u_int filler24;
- freg_t vbrwq_base; /* VBR Wait Queue Base */
- freg_t abrwq_base; /* ABR Wait Queue Base */
- freg_t ubrwq_base; /* UBR Wait Queue Base */
- freg_t vct_base; /* Main VC Table Base */
- freg_t vcte_base; /* Extended Main VC Table Base */
- u_int filler2a[0x2C - 0x2A];
- freg_t cbr_tab_beg; /* CBR Table Begin */
- freg_t cbr_tab_end; /* CBR Table End */
- freg_t cbr_pointer; /* CBR Pointer */
- u_int filler2f[0x30 - 0x2F];
- freg_t prq_st_adr; /* Packet Ready Queue Start Address */
- freg_t prq_ed_adr; /* Packet Ready Queue End Address */
- freg_t prq_rd_ptr; /* Packet Ready Queue read pointer */
- freg_t prq_wr_ptr; /* Packet Ready Queue write pointer */
- freg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/
- freg_t tcq_ed_adr; /* Transmit Complete Queue End Address */
- freg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */
- freg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/
- u_int filler38[0x40 - 0x38];
- freg_t queue_base; /* Base address for PRQ and TCQ */
- freg_t desc_base; /* Base address of descriptor table */
- u_int filler42[0x45 - 0x42];
- freg_t mode_reg_0; /* Mode register 0 */
- freg_t mode_reg_1; /* Mode register 1 */
- freg_t intr_status_reg;/* Interrupt Status register */
- freg_t mask_reg; /* Mask Register */
- freg_t cell_ctr_high1; /* Total cell transfer count (high) */
- freg_t cell_ctr_lo1; /* Total cell transfer count (low) */
- freg_t state_reg; /* Status register */
- u_int filler4c[0x58 - 0x4c];
- freg_t curr_desc_num; /* Contains the current descriptor num */
- freg_t next_desc; /* Next descriptor */
- freg_t next_vc; /* Next VC */
- u_int filler5b[0x5d - 0x5b];
- freg_t present_slot_cnt;/* Present slot count */
- u_int filler5e[0x6a - 0x5e];
- freg_t new_desc_num; /* New descriptor number */
- freg_t new_vc; /* New VC */
- freg_t sched_tbl_ptr; /* Schedule table pointer */
- freg_t vbrwq_wptr; /* VBR wait queue write pointer */
- freg_t vbrwq_rptr; /* VBR wait queue read pointer */
- freg_t abrwq_wptr; /* ABR wait queue write pointer */
- freg_t abrwq_rptr; /* ABR wait queue read pointer */
- freg_t ubrwq_wptr; /* UBR wait queue write pointer */
- freg_t ubrwq_rptr; /* UBR wait queue read pointer */
- freg_t cbr_vc; /* CBR VC */
- freg_t vbr_sb_vc; /* VBR SB VC */
- freg_t abr_sb_vc; /* ABR SB VC */
- freg_t ubr_sb_vc; /* UBR SB VC */
- freg_t vbr_next_link; /* VBR next link */
- freg_t abr_next_link; /* ABR next link */
- freg_t ubr_next_link; /* UBR next link */
- u_int filler7a[0x7c-0x7a];
- freg_t out_rate_head; /* Out of rate head */
- u_int filler7d[0xca-0x7d]; /* pad out to full address space */
- freg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */
- freg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */
- u_int fillercc[0x100-0xcc]; /* pad out to full address space */
+ ffreg_t idlehead_high; /* Idle cell header (high) */
+ ffreg_t idlehead_low; /* Idle cell header (low) */
+ ffreg_t maxrate; /* Maximum rate */
+ ffreg_t stparms; /* Traffic Management Parameters */
+ ffreg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */
+ ffreg_t rm_type; /* */
+ u_int filler5[0x17 - 0x06];
+ ffreg_t cmd_reg; /* Command register */
+ u_int filler18[0x20 - 0x18];
+ ffreg_t cbr_base; /* CBR Pointer Base */
+ ffreg_t vbr_base; /* VBR Pointer Base */
+ ffreg_t abr_base; /* ABR Pointer Base */
+ ffreg_t ubr_base; /* UBR Pointer Base */
+ u_int filler24;
+ ffreg_t vbrwq_base; /* VBR Wait Queue Base */
+ ffreg_t abrwq_base; /* ABR Wait Queue Base */
+ ffreg_t ubrwq_base; /* UBR Wait Queue Base */
+ ffreg_t vct_base; /* Main VC Table Base */
+ ffreg_t vcte_base; /* Extended Main VC Table Base */
+ u_int filler2a[0x2C - 0x2A];
+ ffreg_t cbr_tab_beg; /* CBR Table Begin */
+ ffreg_t cbr_tab_end; /* CBR Table End */
+ ffreg_t cbr_pointer; /* CBR Pointer */
+ u_int filler2f[0x30 - 0x2F];
+ ffreg_t prq_st_adr; /* Packet Ready Queue Start Address */
+ ffreg_t prq_ed_adr; /* Packet Ready Queue End Address */
+ ffreg_t prq_rd_ptr; /* Packet Ready Queue read pointer */
+ ffreg_t prq_wr_ptr; /* Packet Ready Queue write pointer */
+ ffreg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/
+ ffreg_t tcq_ed_adr; /* Transmit Complete Queue End Address */
+ ffreg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */
+ ffreg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/
+ u_int filler38[0x40 - 0x38];
+ ffreg_t queue_base; /* Base address for PRQ and TCQ */
+ ffreg_t desc_base; /* Base address of descriptor table */
+ u_int filler42[0x45 - 0x42];
+ ffreg_t mode_reg_0; /* Mode register 0 */
+ ffreg_t mode_reg_1; /* Mode register 1 */
+ ffreg_t intr_status_reg;/* Interrupt Status register */
+ ffreg_t mask_reg; /* Mask Register */
+ ffreg_t cell_ctr_high1; /* Total cell transfer count (high) */
+ ffreg_t cell_ctr_lo1; /* Total cell transfer count (low) */
+ ffreg_t state_reg; /* Status register */
+ u_int filler4c[0x58 - 0x4c];
+ ffreg_t curr_desc_num; /* Contains the current descriptor num */
+ ffreg_t next_desc; /* Next descriptor */
+ ffreg_t next_vc; /* Next VC */
+ u_int filler5b[0x5d - 0x5b];
+ ffreg_t present_slot_cnt;/* Present slot count */
+ u_int filler5e[0x6a - 0x5e];
+ ffreg_t new_desc_num; /* New descriptor number */
+ ffreg_t new_vc; /* New VC */
+ ffreg_t sched_tbl_ptr; /* Schedule table pointer */
+ ffreg_t vbrwq_wptr; /* VBR wait queue write pointer */
+ ffreg_t vbrwq_rptr; /* VBR wait queue read pointer */
+ ffreg_t abrwq_wptr; /* ABR wait queue write pointer */
+ ffreg_t abrwq_rptr; /* ABR wait queue read pointer */
+ ffreg_t ubrwq_wptr; /* UBR wait queue write pointer */
+ ffreg_t ubrwq_rptr; /* UBR wait queue read pointer */
+ ffreg_t cbr_vc; /* CBR VC */
+ ffreg_t vbr_sb_vc; /* VBR SB VC */
+ ffreg_t abr_sb_vc; /* ABR SB VC */
+ ffreg_t ubr_sb_vc; /* UBR SB VC */
+ ffreg_t vbr_next_link; /* VBR next link */
+ ffreg_t abr_next_link; /* ABR next link */
+ ffreg_t ubr_next_link; /* UBR next link */
+ u_int filler7a[0x7c-0x7a];
+ ffreg_t out_rate_head; /* Out of rate head */
+ u_int filler7d[0xca-0x7d]; /* pad out to full address space */
+ ffreg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */
+ ffreg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */
+ u_int fillercc[0x100-0xcc]; /* pad out to full address space */
} ffredn_t;
typedef struct _rfredn_t {
--
1.7.12.4
^ permalink raw reply related
* Re: Wifi basics documents
From: sl reddy @ 2013-02-08 9:53 UTC (permalink / raw)
To: Arend van Spriel
Cc: brcm80211-dev-list, Onteddu Slreddy, e1000-devel, netdev,
devicetree-discuss, linux-usb, linux-wireless, linux-kernel,
linux-can, wil6210, ath9k-devel
In-Reply-To: <5114B881.9000100@broadcom.com>
[-- Attachment #1.1: Type: text/plain, Size: 1815 bytes --]
Hi
Thanks for reply i referred that site (wireless.kernel.org) as you said
there is lot of information
but i am bit confused in getting right information because i am not
interested much about hardware architecture as of now
I need clear picture of software architecture
but in the website there is lot of information so bit confused where to
start
any successions will be helpful for me
Thanks & Regards
O S L Reddy
slreddy88@gmail.com
On Fri, Feb 8, 2013 at 2:04 PM, Arend van Spriel <arend@broadcom.com> wrote:
> On 02/08/2013 07:55 AM, Onteddu Slreddy wrote:
> > Hello All,
> >
> >
> > I recently joined this group the group.
> >
> > Can anybody suggest me places where I can get Documents which will
> explain
> > wifi Architecture in brief i would like to know details like
> >
> > In Linux for embedded systems:
> > What is the software architecture for wifi
> > What are each folders in kernel/net and kernel/drivers/net refer
> to
> > What is wpa_supplicant how to know which version I have to use
> > How to get familiar with words like nl802.11, mac802.11, wext,
> > copat-wireless, compatwireless-openmac
> > If I have to add a new chip driver what are the checklist points
> i
> > have to see
> >
> > My Quesitions may be basic kindly bare with me
> > If any body have self prepared documents that will be great help for me
>
> 802.11 is a IEEE standard that is freely available for download.
> Regarding Linux architecture and infrastructure there is a lot of
> information to be found on wireless.kernel.org.
>
> Regards,
> Arend
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless"
> in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
[-- Attachment #2: Type: text/plain, Size: 255 bytes --]
------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
[-- Attachment #3: Type: text/plain, Size: 257 bytes --]
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
^ permalink raw reply
* [PATCH net-next] net: sctp: sctp_auth_make_key_vector: use sctp_auth_create_key
From: Daniel Borkmann @ 2013-02-08 9:22 UTC (permalink / raw)
To: davem; +Cc: linux-sctp, netdev
In-Reply-To: <cover.1360314390.git.dborkman@redhat.com>
In sctp_auth_make_key_vector, we allocate a temporary sctp_auth_bytes
structure with kmalloc instead of the sctp_auth_create_key allocator.
Change this to sctp_auth_create_key as it is the case everywhere else,
so that we also can properly free it via sctp_auth_key_put. This makes
it easier for future code changes in the structure and allocator itself,
since a single API is consistently used for this purpose. Also, by
using sctp_auth_create_key we're doing sanity checks over the arguments.
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
---
net/sctp/auth.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/net/sctp/auth.c b/net/sctp/auth.c
index 94a12de..5ec7509 100644
--- a/net/sctp/auth.c
+++ b/net/sctp/auth.c
@@ -209,12 +209,10 @@ static struct sctp_auth_bytes *sctp_auth_make_key_vector(
len = random_len + hmacs_len + chunks_len;
- new = kmalloc(sizeof(struct sctp_auth_bytes) + len, gfp);
+ new = sctp_auth_create_key(len, gfp);
if (!new)
return NULL;
- new->len = len;
-
memcpy(new->data, random, random_len);
offset += random_len;
@@ -353,8 +351,8 @@ static struct sctp_auth_bytes *sctp_auth_asoc_create_secret(
secret = sctp_auth_asoc_set_secret(ep_key, first_vector, last_vector,
gfp);
out:
- kfree(local_key_vector);
- kfree(peer_key_vector);
+ sctp_auth_key_put(local_key_vector);
+ sctp_auth_key_put(peer_key_vector);
return secret;
}
--
1.7.11.7
^ permalink raw reply related
* Re: [PATCH RFC v2 1/2] net/802: Implement Multiple Registration Protocol (MRP)
From: Patrick McHardy @ 2013-02-08 8:37 UTC (permalink / raw)
To: David Ward; +Cc: netdev, Eric Dumazet
In-Reply-To: <1360295457-5245-2-git-send-email-david.ward@ll.mit.edu>
On Thu, Feb 07, 2013 at 10:50:55PM -0500, David Ward wrote:
> Initial implementation of the Multiple Registration Protocol (MRP)
> from IEEE 802.1Q-2011, based on the existing implementation of the
> Generic Attribute Registration Protocol (GARP).
>
> Signed-off-by: David Ward <david.ward@ll.mit.edu>
> +enum mrp_vecattr_event {
> + MRP_NEW,
> + MRP_JOIN_IN,
> + MRP_IN,
> + MRP_JOIN_MT,
> + MRP_MT,
> + MRP_LV,
> +};
> +static int mrp_pdu_append_event(struct mrp_applicant *app,
> + const struct mrp_attr *attr,
> + enum mrp_vecattr_event event)
> +{
...
> + switch (pos) {
> + case 0:
> + *events = event * 36;
> + break;
> + case 1:
> + *events += event * 6;
> + break;
> + case 2:
> + *events += event;
> + break;
> + default:
> + WARN_ON(1);
> + }
Could you define a MRT_VAEVENT_MAX or something and use that instead of the
magic values? Took me a bit to figure out their meaning.
> +static int mrp_pdu_parse_vecattr(struct mrp_applicant *app,
> + struct sk_buff *skb, int *offset)
> +{
...
> + while (valen > 0) {
> + if (skb_copy_bits(skb, *offset, &vaevents,
> + sizeof(vaevents)) < 0)
> + return -1;
> + *offset += sizeof(vaevents);
> +
> + /* Extract and process the first event. */
> + vaevent = vaevents / 36;
> + if (vaevent >= 6) {
Same here.
Other than that:
Acked-by: Patrick McHardy <kaber@trash.net>
for all patches.
^ permalink raw reply
* Re: Wifi basics documents
From: Arend van Spriel @ 2013-02-08 8:34 UTC (permalink / raw)
To: Onteddu Slreddy
Cc: netdev, linux-can, linux-kernel, e1000-devel, linux-usb,
linux-wireless, ath9k-devel, wil6210, brcm80211-dev-list,
devicetree-discuss
In-Reply-To: <CAHT=_ri0JBrbPfWJrzjYR4eNDDW9ygMkJSDU4vJXEfh_STLK9g@mail.gmail.com>
On 02/08/2013 07:55 AM, Onteddu Slreddy wrote:
> Hello All,
>
>
> I recently joined this group the group.
>
> Can anybody suggest me places where I can get Documents which will explain
> wifi Architecture in brief i would like to know details like
>
> In Linux for embedded systems:
> What is the software architecture for wifi
> What are each folders in kernel/net and kernel/drivers/net refer to
> What is wpa_supplicant how to know which version I have to use
> How to get familiar with words like nl802.11, mac802.11, wext,
> copat-wireless, compatwireless-openmac
> If I have to add a new chip driver what are the checklist points i
> have to see
>
> My Quesitions may be basic kindly bare with me
> If any body have self prepared documents that will be great help for me
802.11 is a IEEE standard that is freely available for download.
Regarding Linux architecture and infrastructure there is a lot of
information to be found on wireless.kernel.org.
Regards,
Arend
^ permalink raw reply
* [PATCH v2 1/1] eventfd: implementation of EFD_MASK flag
From: Martin Sustrik @ 2013-02-08 8:11 UTC (permalink / raw)
To: Alexander Viro, Andrew Morton, Sha Zhengju, linux-fsdevel,
linux-kernel
Cc: netdev, Martin Sustrik
When implementing network protocols in user space, one has to implement
fake user-space file descriptors to represent the sockets for the protocol.
While all the BSD socket API functionality for such descriptors may be faked as
well (myproto_send(), myproto_recv() etc.) this approach doesn't work for
polling (select, poll, epoll). And unfortunately, sockets that can't be polled
on allow only for building the simplest possible applications. Basically, you
can build a simple client, but once you want to implement a server handling
many sockets in parallel, you are stuck.
However, to do polling, real system-level file descriptor is needed,
not a fake one.
In theory, eventfd may be used for this purpose, except that it is well suited
only for signaling POLLIN. With some hacking it can be also used to signal
POLLOUT and POLLERR, but:
I. There's no way to signal POLLPRI, POLLHUP etc.
II. There's no way to signal arbitraty combination of POLL* flags. Most notably,
!POLLIN & !POLLOUT, which is a perfectly valid combination for a network
protocol (rx buffer is empty and tx buffer is full), cannot be signaled
using current implementation of eventfd.
This patch implements new EFD_MASK flag which attempts to solve this problem.
Additionally, when implementing network protocols in user space, there's a
need to associate user-space state with the each "socket". If eventfd object is
used as a reference to the socket, it should be possible to associate an opaque
pointer to user-space data with it.
The semantics of EFD_MASK are as follows:
eventfd(2):
If eventfd is created with EFD_MASK flag set, it is initialised in such a way
as to signal no events on the file descriptor when it is polled on. 'initval'
argument is ignored.
write(2):
User is allowed to write only buffers containing the following structure:
struct efd_mask {
short events;
union {
void *ptr;
uint32_t u32;
uint64_t u64;
};
};
The value of 'events' should be any combination of event flags as defined by
poll(2) function (POLLIN, POLLOUT, POLLERR, POLLHUP etc.) Specified events will
be signaled when polling (select, poll, epoll) on the eventfd is done later on.
ptr, u32 and u63 are opaque data that are not interpreted by eventfd object.
read(2):
User is allowed to read an efd_mask structure from the eventfd marked by
EFD_MASK. Returned value shall be the last one written to the eventfd.
select(2), poll(2) and similar:
When polling on the eventfd marked by EFD_MASK flag, all the events specified
in last written 'events' field shall be signaled.
Signed-off-by: Martin Sustrik <sustrik@250bpm.com>
---
v2 - Concerns raised by Andy Lutomirski addressed:
- uses fixed size (64 bits) opaque data in eventfd_mask instead of void*
- write returns EINVAL if invalid POLL flags are specified
---
fs/eventfd.c | 116 +++++++++++++++++++++++++++++++++++++----------
include/linux/eventfd.h | 3 +-
2 files changed, 94 insertions(+), 25 deletions(-)
diff --git a/fs/eventfd.c b/fs/eventfd.c
index 35470d9..bf83f6d87 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -2,6 +2,7 @@
* fs/eventfd.c
*
* Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
+ * Copyright (C) 2013 Martin Sustrik <sustrik@250bpm.com>
*
*/
@@ -22,18 +23,35 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#define EFD_MASK_VALID_EVENTS (POLLIN | POLLPRI | POLLOUT | POLLERR | POLLHUP)
+
+/* On x86-64 keep the same binary layout as on i386. */
+#ifdef __x86_64__
+#define EVENTFD_MASK_PACKED __packed
+#else
+#define EVENTFD_MASK_PACKED
+#endif
+
+struct eventfd_mask {
+ __u32 events;
+ __u64 data;
+} EVENTFD_MASK_PACKED;
+
struct eventfd_ctx {
struct kref kref;
wait_queue_head_t wqh;
- /*
- * Every time that a write(2) is performed on an eventfd, the
- * value of the __u64 being written is added to "count" and a
- * wakeup is performed on "wqh". A read(2) will return the "count"
- * value to userspace, and will reset "count" to zero. The kernel
- * side eventfd_signal() also, adds to the "count" counter and
- * issue a wakeup.
- */
- __u64 count;
+ union {
+ /*
+ * Every time that a write(2) is performed on an eventfd, the
+ * value of the __u64 being written is added to "count" and a
+ * wakeup is performed on "wqh". A read(2) will return the
+ * "count" value to userspace, and will reset "count" to zero.
+ * The kernel side eventfd_signal() also, adds to the "count"
+ * counter and issue a wakeup.
+ */
+ __u64 count;
+ struct eventfd_mask mask;
+ };
unsigned int flags;
};
@@ -55,6 +73,9 @@ __u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n)
{
unsigned long flags;
+ /* This function should never be used with eventfd in the mask mode. */
+ BUG_ON(ctx->flags & EFD_MASK);
+
spin_lock_irqsave(&ctx->wqh.lock, flags);
if (ULLONG_MAX - ctx->count < n)
n = ULLONG_MAX - ctx->count;
@@ -123,12 +144,16 @@ static unsigned int eventfd_poll(struct file *file, poll_table *wait)
poll_wait(file, &ctx->wqh, wait);
spin_lock_irqsave(&ctx->wqh.lock, flags);
- if (ctx->count > 0)
- events |= POLLIN;
- if (ctx->count == ULLONG_MAX)
- events |= POLLERR;
- if (ULLONG_MAX - 1 > ctx->count)
- events |= POLLOUT;
+ if (ctx->flags & EFD_MASK) {
+ events = ctx->mask.events;
+ } else {
+ if (ctx->count > 0)
+ events |= POLLIN;
+ if (ctx->count == ULLONG_MAX)
+ events |= POLLERR;
+ if (ULLONG_MAX - 1 > ctx->count)
+ events |= POLLOUT;
+ }
spin_unlock_irqrestore(&ctx->wqh.lock, flags);
return events;
@@ -158,6 +183,9 @@ int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_t *wait,
{
unsigned long flags;
+ /* This function should never be used with eventfd in the mask mode. */
+ BUG_ON(ctx->flags & EFD_MASK);
+
spin_lock_irqsave(&ctx->wqh.lock, flags);
eventfd_ctx_do_read(ctx, cnt);
__remove_wait_queue(&ctx->wqh, wait);
@@ -188,6 +216,9 @@ ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, __u64 *cnt)
ssize_t res;
DECLARE_WAITQUEUE(wait, current);
+ /* This function should never be used with eventfd in the mask mode. */
+ BUG_ON(ctx->flags & EFD_MASK);
+
spin_lock_irq(&ctx->wqh.lock);
*cnt = 0;
res = -EAGAIN;
@@ -230,13 +261,23 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
ssize_t res;
__u64 cnt;
- if (count < sizeof(cnt))
- return -EINVAL;
- res = eventfd_ctx_read(ctx, file->f_flags & O_NONBLOCK, &cnt);
- if (res < 0)
+ if (ctx->flags & EFD_MASK) {
+ spin_lock_irq(&ctx->wqh.lock);
+ if (count < sizeof(ctx->mask))
+ return -EINVAL;
+ res = copy_to_user(buf, &ctx->mask, sizeof(ctx->mask)) ?
+ -EFAULT : sizeof(ctx->mask);
+ spin_unlock_irq(&ctx->wqh.lock);
return res;
-
- return put_user(cnt, (__u64 __user *) buf) ? -EFAULT : sizeof(cnt);
+ } else {
+ if (count < sizeof(cnt))
+ return -EINVAL;
+ res = eventfd_ctx_read(ctx, file->f_flags & O_NONBLOCK, &cnt);
+ if (res < 0)
+ return res;
+ return put_user(cnt, (__u64 __user *) buf) ?
+ -EFAULT : sizeof(cnt);
+ }
}
static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count,
@@ -246,6 +287,23 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c
ssize_t res;
__u64 ucnt;
DECLARE_WAITQUEUE(wait, current);
+ struct eventfd_mask mask;
+
+ if (ctx->flags & EFD_MASK) {
+ if (count < sizeof(mask))
+ return -EINVAL;
+ if (copy_from_user(&mask, buf, sizeof(mask)))
+ return -EFAULT;
+ if (mask.events & ~EFD_MASK_VALID_EVENTS)
+ return -EINVAL;
+ spin_lock_irq(&ctx->wqh.lock);
+ memcpy(&ctx->mask, &mask, sizeof(ctx->mask));
+ if (waitqueue_active(&ctx->wqh))
+ wake_up_locked_poll(&ctx->wqh,
+ (unsigned long)ctx->mask.events);
+ spin_unlock_irq(&ctx->wqh.lock);
+ return sizeof(ctx->mask);
+ }
if (count < sizeof(ucnt))
return -EINVAL;
@@ -293,8 +351,13 @@ static int eventfd_show_fdinfo(struct seq_file *m, struct file *f)
int ret;
spin_lock_irq(&ctx->wqh.lock);
- ret = seq_printf(m, "eventfd-count: %16llx\n",
- (unsigned long long)ctx->count);
+ if (ctx->flags & EFD_MASK) {
+ ret = seq_printf(m, "eventfd-mask: %x\n",
+ (unsigned)ctx->mask.events);
+ } else {
+ ret = seq_printf(m, "eventfd-count: %16llx\n",
+ (unsigned long long)ctx->count);
+ }
spin_unlock_irq(&ctx->wqh.lock);
return ret;
@@ -412,7 +475,12 @@ struct file *eventfd_file_create(unsigned int count, int flags)
kref_init(&ctx->kref);
init_waitqueue_head(&ctx->wqh);
- ctx->count = count;
+ if (flags & EFD_MASK) {
+ ctx->mask.events = 0;
+ ctx->mask.data = 0;
+ } else {
+ ctx->count = count;
+ }
ctx->flags = flags;
file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx,
diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h
index 3c3ef19..b806d2b 100644
--- a/include/linux/eventfd.h
+++ b/include/linux/eventfd.h
@@ -20,11 +20,12 @@
* shared O_* flags.
*/
#define EFD_SEMAPHORE (1 << 0)
+#define EFD_MASK (1 << 1)
#define EFD_CLOEXEC O_CLOEXEC
#define EFD_NONBLOCK O_NONBLOCK
#define EFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
-#define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE)
+#define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE | EFD_MASK)
#ifdef CONFIG_EVENTFD
--
1.7.4.1
^ permalink raw reply related
* Re: [PATCH v2 0/4] XSA-39 CVE-2013-021[67]: Linux netback DoS via malicious guest ring.
From: Ian Campbell @ 2013-02-08 7:54 UTC (permalink / raw)
To: David Miller; +Cc: netdev@vger.kernel.org, xen-devel@lists.xen.org
In-Reply-To: <20130207.233107.1094455509765442729.davem@davemloft.net>
On Fri, 2013-02-08 at 04:31 +0000, David Miller wrote:
> Applied, please don't add stable CC:'s to networking patches, instead
> ask me to queue it up to my -stable todo pile instead.
Thanks & Ack.
> I don't like it when patches instantly be submitted to -stable when
> they hit Linus's tree, I'd rather it soak upstream for a week or two
> instead. That's why I do it this way.
Very reasonable.
Ian.
^ permalink raw reply
* Wifi basics documents
From: Onteddu Slreddy @ 2013-02-08 6:55 UTC (permalink / raw)
To: netdev, linux-can, linux-kernel, e1000-devel, linux-usb,
linux-wireless, ath9k-devel, wil6210, brcm80211-dev-list,
devicetree-discuss
[-- Attachment #1.1: Type: text/plain, Size: 792 bytes --]
Hello All,
I recently joined this group the group.
Can anybody suggest me places where I can get Documents which will explain
wifi Architecture in brief i would like to know details like
In Linux for embedded systems:
What is the software architecture for wifi
What are each folders in kernel/net and kernel/drivers/net refer to
What is wpa_supplicant how to know which version I have to use
How to get familiar with words like nl802.11, mac802.11, wext,
copat-wireless, compatwireless-openmac
If I have to add a new chip driver what are the checklist points i
have to see
My Quesitions may be basic kindly bare with me
If any body have self prepared documents that will be great help for me
Thanks & Regards
O S L Reddy
slreddy88@gmail.com
[-- Attachment #2: Type: text/plain, Size: 255 bytes --]
------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
[-- Attachment #3: Type: text/plain, Size: 257 bytes --]
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
^ permalink raw reply
* Re: [PATCH] net: usb: fix regression from 6509141f9c2ba74df6cc72ec35cd1865276ae3a4
From: David Miller @ 2013-02-08 6:52 UTC (permalink / raw)
To: dev; +Cc: netdev, cpuwolf
In-Reply-To: <1360289919-20409-1-git-send-email-dev@lynxeye.de>
From: Lucas Stach <dev@lynxeye.de>
Date: Fri, 8 Feb 2013 03:18:39 +0100
> The newly added flag NOARP was using an already defined value, which
> broke drivers using flag MULTI_PACKET.
>
> Signed-off-by: Lucas Stach <dev@lynxeye.de>
Applied, but I reworked your commit message like so:
net: usb: fix regression from FLAG_NOARP code
In commit 6509141f9c2ba74df6cc72ec35cd1865276ae3a4 ("usbnet: add new
flag FLAG_NOARP for usb net devices"), the newly added flag NOARP was
using an already defined value, which broke drivers using flag
MULTI_PACKET.
Signed-off-by: Lucas Stach <dev@lynxeye.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
References to commit IDs are ambiguous because a change can go
into multiple GIT trees. Therefore we don't reference them in
commit header lines, and when we reference them in the commit
body we postfix them with the commit header line of the
referenced commit (in parenthesis and quotes) in order to
eliminate the ambiguity.
Thanks.
^ permalink raw reply
* Re: [PATCH] l2tp: dont play with skb->truesize
From: David Miller @ 2013-02-08 6:50 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev, jchapman, bircoph
In-Reply-To: <1360281634.28557.71.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Thu, 07 Feb 2013 16:00:34 -0800
> From: Eric Dumazet <edumazet@google.com>
>
> Andrew Savchenko reported a DNS failure and we diagnosed that
> some UDP sockets were unable to send more packets because their
> sk_wmem_alloc was corrupted after a while (tx_queue column in
> following trace)
...
> Playing with skb->truesize is tricky, especially when
> skb is attached to a socket, as we can fool memory charging.
>
> Just remove this code, its not worth trying to be ultra
> precise in xmit path.
>
> Reported-by: Andrew Savchenko <bircoph@gmail.com>
> Tested-by: Andrew Savchenko <bircoph@gmail.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied and queued up for -stable, thanks.
^ permalink raw reply
* Re: [PATCH net-next] macvlan: add a salt to mc_hash()
From: Maciej Żenczykowski @ 2013-02-08 5:07 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1360291262.28557.89.camel@edumazet-glaptop>
Signed-off-by: Maciej Żenczykowski <maze@google.com>
On Thu, Feb 7, 2013 at 6:41 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> Some multicast addresses are common to all macvlans,
> so if a multicast message has a hash value collision, we
> have to deliver a copy to all macvlans, adding significant
> latency and possible packet drops if netdev_max_backlog
> limit is hit.
>
> Having a per macvlan hash function permits to reduce the
> impact of hash collisions.
>
> Suggested-by: Maciej Żenczykowski <maze@google.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> ---
> Should be applied after
> "macvlan: broadcast addr should be part of mc_filter"
>
> drivers/net/macvlan.c | 17 +++++++++++++----
> 1 file changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
> index ce7c926..e4b8078 100644
> --- a/drivers/net/macvlan.c
> +++ b/drivers/net/macvlan.c
> @@ -127,10 +127,18 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
> return vlan->receive(skb);
> }
>
> -static unsigned int mc_hash(const unsigned char *addr)
> +static u32 macvlan_hash_mix(const struct macvlan_dev *vlan)
> +{
> + return (u32)(((unsigned long)vlan) >> L1_CACHE_SHIFT);
> +}
> +
> +
> +static unsigned int mc_hash(const struct macvlan_dev *vlan,
> + const unsigned char *addr)
> {
> u32 val = __get_unaligned_cpu32(addr + 2);
>
> + val ^= macvlan_hash_mix(vlan);
> return hash_32(val, MACVLAN_MC_FILTER_BITS);
> }
>
> @@ -145,7 +153,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
> struct sk_buff *nskb;
> unsigned int i;
> int err;
> - unsigned int hash = mc_hash(eth->h_dest);
> + unsigned int hash;
>
> if (skb->protocol == htons(ETH_P_PAUSE))
> return;
> @@ -155,6 +163,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
> if (vlan->dev == src || !(vlan->mode & mode))
> continue;
>
> + hash = mc_hash(vlan, eth->h_dest);
> if (!test_bit(hash, vlan->mc_filter))
> continue;
> nskb = skb_clone(skb, GFP_ATOMIC);
> @@ -424,10 +433,10 @@ static void macvlan_set_mac_lists(struct net_device *dev)
>
> bitmap_zero(filter, MACVLAN_MC_FILTER_SZ);
> netdev_for_each_mc_addr(ha, dev) {
> - __set_bit(mc_hash(ha->addr), filter);
> + __set_bit(mc_hash(vlan, ha->addr), filter);
> }
>
> - __set_bit(mc_hash(dev->broadcast), filter);
> + __set_bit(mc_hash(vlan, dev->broadcast), filter);
>
> bitmap_copy(vlan->mc_filter, filter, MACVLAN_MC_FILTER_SZ);
> }
>
>
^ permalink raw reply
* Re: [PATCH v4 0/3] tg3: add support for Ethernet core in BCM4785
From: David Miller @ 2013-02-08 4:50 UTC (permalink / raw)
To: hauke; +Cc: mcarlson, mchan, nsujir, netdev, m
In-Reply-To: <1360251459-32384-1-git-send-email-hauke@hauke-m.de>
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Thu, 7 Feb 2013 16:37:36 +0100
> These patches are adding support for the Ethernet core found in the
> BCM4705/BCM4785 SoC.
>
> This is based on current master of davem/net-next.git.
Series applied to net-next, thanks.
^ permalink raw reply
* Re: [PATCH net-next] net: sctp: sctp_auth_make_key_vector: remove duplicate ntohs calls
From: David Miller @ 2013-02-08 4:45 UTC (permalink / raw)
To: dborkman; +Cc: vyasevich, linux-sctp, netdev
In-Reply-To: <c029f55f4d0bde790f77f62d623f4d1e387c4c0b.1360237025.git.dborkman@redhat.com>
From: Daniel Borkmann <dborkman@redhat.com>
Date: Thu, 7 Feb 2013 12:41:39 +0100
> Instead of calling 3 times ntohs(random->param_hdr.length), 2 times
> ntohs(hmacs->param_hdr.length), and 3 times ntohs(chunks->param_hdr.length)
> within the same function, we only call each once and store it in a
> variable.
>
> Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Applied.
^ permalink raw reply
* Re: [PATCH net 2/2] net: sctp: sctp_auth_key_put: use kzfree instead of kfree
From: David Miller @ 2013-02-08 4:45 UTC (permalink / raw)
To: dborkman; +Cc: vyasevich, netdev, linux-sctp
In-Reply-To: <8c764d916f21d56402a5b9a915ea31d927898da0.1360231701.git.dborkman@redhat.com>
From: Daniel Borkmann <dborkman@redhat.com>
Date: Thu, 7 Feb 2013 11:55:37 +0100
> For sensitive data like keying material, it is common practice to zero
> out keys before returning the memory back to the allocator. Thus, use
> kzfree instead of kfree.
>
> Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Applied and queued up for -stable.
^ permalink raw reply
* Re: [GIT net] Open vSwitch
From: David Miller @ 2013-02-08 4:39 UTC (permalink / raw)
To: jesse; +Cc: netdev, dev
In-Reply-To: <1360206896-43022-1-git-send-email-jesse@nicira.com>
From: Jesse Gross <jesse@nicira.com>
Date: Wed, 6 Feb 2013 19:14:55 -0800
> One bug fix for net/3.8 for a long standing problem that was reported a few
> times recently.
>
> The following changes since commit a49f0d1ea3ec94fc7cf33a7c36a16343b74bd565:
>
> Linux 3.8-rc1 (2012-12-21 17:19:00 -0800)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/jesse/openvswitch.git fixes
Pulled, thanks Jesse.
^ permalink raw reply
* Re: [PATCH v3 2/2 net-next] net: fec: fix spin_lock dead lock
From: David Miller @ 2013-02-08 4:37 UTC (permalink / raw)
To: Frank.Li; +Cc: lznuaa, linux-arm-kernel, netdev, shawn.guo, B38611, s.hauer
In-Reply-To: <1360198799-25173-2-git-send-email-Frank.Li@freescale.com>
From: Frank Li <Frank.Li@freescale.com>
Date: Thu, 7 Feb 2013 08:59:59 +0800
> =========================================================
> [ INFO: possible irq lock inversion dependency detected ]
> 3.8.0-rc5+ #82 Not tainted
> ---------------------------------------------------------
> swapper/0/0 just changed the state of lock:
> (&(&fep->hw_lock)->rlock){..-...}, at: [<8034e2f8>] fec_enet_start_xmit+0x48/0x 2cc
> but this lock took another, SOFTIRQ-unsafe lock in the past:
> (prepare_lock){+.+.+.}
>
> and interrupts could create inverse lock ordering between them.
> other info that might help us debug this:
> Possible interrupt unsafe locking scenario:
>
> CPU0 CPU1
> ---- ----
> lock(prepare_lock);
> local_irq_disable()
> lock(&(&fep->hw_lock)->rlock);
> lock(prepare_lock);
> <Interrupt>
> lock(&(&fep->hw_lock)->rlock);
>
> *** DEADLOCK ***
>
> Signed-off-by: Frank Li <Frank.Li@freescale.com>
Applied.
^ permalink raw reply
* Re: [PATCH v3 1/2 net-next] net: fec: correct fix method about miss init spinlock
From: David Miller @ 2013-02-08 4:36 UTC (permalink / raw)
To: Frank.Li; +Cc: lznuaa, linux-arm-kernel, netdev, shawn.guo, B38611, s.hauer
In-Reply-To: <1360198799-25173-1-git-send-email-Frank.Li@freescale.com>
From: Frank Li <Frank.Li@freescale.com>
Date: Thu, 7 Feb 2013 08:59:58 +0800
> Old method will cause init spinlock twice.
> New method will avoid init spinlock twice and fix miss init spinlock
> at fec_restart.
...
> Signed-off-by: Frank Li <Frank.Li@freescale.com>
Applied.
^ permalink raw reply
* Re: [PATCH]: fix phy_device_free memory leak
From: David Miller @ 2013-02-08 4:35 UTC (permalink / raw)
To: oss; +Cc: netdev
In-Reply-To: <201302070007.57434.oss@malat.biz>
From: Petr Malat <oss@malat.biz>
Date: Thu, 7 Feb 2013 00:07:57 +0100
> Hi,
> there is a memory leak in phy_device handling:
> phy_device_create() sets name of kobject using dev_set_name(), which allocates
> memory using kvasprintf(), but this memory isn't freed if the underlying
> device isn't registered properly, because kobject_cleanup() is not called in
> that case. This can happen (and actually is happening on our machines) if
> phy_device_register(), called by mdiobus_scan(), fails. I fixed this by the
> attached patch, so far it's working fine.
>
> Patch description:
> Name is freed by phy_device_free(). In the case a device is released trough
> kobject_cleanup()->device_release()->phy_device_release(), the name is set to
> NULL and it is not freed by phy_device_free(), because it will be freed later
> by kobject_cleanup().
>
> Please put me on CC, I'm not signed into the mailing list.
Please follow the directions in Documentation/SubmittingPatches, in
particular the part about providing a proper signoff.
Do not send an updated version of this patch as a reply to this thread,
instead create a completely new mailing list posting for that purpose.
Thanks.
^ permalink raw reply
* Re: [PATCH v2] mlx4_en: Fix BQL reset TX queue call point
From: David Miller @ 2013-02-08 4:34 UTC (permalink / raw)
To: amirv; +Cc: therbert, yevgenyp, netdev
In-Reply-To: <51134F33.1030007@mellanox.com>
From: Amir Vadai <amirv@mellanox.com>
Date: Thu, 7 Feb 2013 08:52:35 +0200
> On 06/02/2013 19:58, Tom Herbert wrote:
>> Fix issue in Mellanox driver related to BQL. netdev_tx_reset_queue
>> was not being called in certain situations where the device was
>> being start and stopped. Moved netdev_tx_reset_queue from the reset
>> device path to mlx4_en_free_tx_buf which is where the rings are
>> cleaned in a reset (specifically from device being stopped).
>>
>> Signed-off-by: Tom Herbert <therbert@google.com>
...
> Acked-By: Amir Vadai <amirv@mellanox.com>
Applied to net-next, thanks.
^ permalink raw reply
* Re: [PATCH v2 0/4] XSA-39 CVE-2013-021[67]: Linux netback DoS via malicious guest ring.
From: David Miller @ 2013-02-08 4:31 UTC (permalink / raw)
To: Ian.Campbell; +Cc: netdev, xen-devel
In-Reply-To: <1360230078.32479.41.camel@zakaz.uk.xensource.com>
From: Ian Campbell <Ian.Campbell@citrix.com>
Date: Thu, 7 Feb 2013 09:41:18 +0000
> The Xen netback implementation contains a couple of flaws which can
> allow a guest to cause a DoS in the backend domain, potentially
> affecting other domains in the system.
>
> CVE-2013-0216 is a failure to sanity check the ring producer/consumer
> pointers which can allow a guest to cause netback to loop for an
> extended period preventing other work from occurring.
>
> CVE-2013-0217 is a memory leak on an error path which is guest
> triggerable.
>
> The following series contains the fixes for these issues, as previously
> included in Xen Security Advisory 39:
> http://lists.xen.org/archives/html/xen-announce/2013-02/msg00001.html
>
> Changes in v2:
> - Typo and block comment format fixes
> - Added stable Cc
Applied, please don't add stable CC:'s to networking patches, instead
ask me to queue it up to my -stable todo pile instead.
I don't like it when patches instantly be submitted to -stable when
they hit Linus's tree, I'd rather it soak upstream for a week or two
instead. That's why I do it this way.
Thanks.
^ permalink raw reply
* Re: [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations
From: David Miller @ 2013-02-08 4:27 UTC (permalink / raw)
To: amirv; +Cc: ogerlitz, yanb, netdev
In-Reply-To: <1360239927-758-1-git-send-email-amirv@mellanox.com>
From: Amir Vadai <amirv@mellanox.com>
Date: Thu, 7 Feb 2013 14:25:18 +0200
> This series from Yan Burman adds support for unicast MAC address filtering and
> ndo FDB operations. It also includes some optimizations to loopback related
> decisions and checks in the TX/RX fast path and one cleanup, all in separate
> patches.
>
> Today, when adding macvlan devices, the NIC goes into promiscuous mode, since
> unicast MAC filtering is not supported. With these changes, macvlan devices can
> be added without the penalty of promiscuous mode.
>
> If for some reason adding a unicast address filter fails e.g as of missing space in
> the HW mac table, the device forces itself into promiscuous mode (and out of this
> forced state when enough space is available).
>
> Also, now it is possible to have bridge under multi-function configuration that include
> PF and VFs. In order to use bridge over PF/VFs, VM MAC fdb entries must be added e.g.
> using 'bridge fdb add' command.
Series applied, thanks.
^ permalink raw reply
* [PATCH RFC v2 1/2] net/802: Implement Multiple Registration Protocol (MRP)
From: David Ward @ 2013-02-08 3:50 UTC (permalink / raw)
To: netdev; +Cc: Patrick McHardy, Eric Dumazet, David Ward
In-Reply-To: <1360295457-5245-1-git-send-email-david.ward@ll.mit.edu>
Initial implementation of the Multiple Registration Protocol (MRP)
from IEEE 802.1Q-2011, based on the existing implementation of the
Generic Attribute Registration Protocol (GARP).
Signed-off-by: David Ward <david.ward@ll.mit.edu>
---
include/linux/netdevice.h | 2 +
include/net/mrp.h | 142 +++++++
net/802/Kconfig | 3 +
net/802/Makefile | 1 +
net/802/mrp.c | 889 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 1037 insertions(+), 0 deletions(-)
create mode 100644 include/net/mrp.h
create mode 100644 net/802/mrp.c
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ab2774e..25bd46f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1290,6 +1290,8 @@ struct net_device {
};
/* GARP */
struct garp_port __rcu *garp_port;
+ /* MRP */
+ struct mrp_port __rcu *mrp_port;
/* class/net/name entry */
struct device dev;
diff --git a/include/net/mrp.h b/include/net/mrp.h
new file mode 100644
index 0000000..69677d9
--- /dev/null
+++ b/include/net/mrp.h
@@ -0,0 +1,142 @@
+#ifndef _NET_MRP_H
+#define _NET_MRP_H
+
+#define MRP_END_MARK 0x0
+
+struct mrp_pdu_hdr {
+ u8 version;
+};
+
+struct mrp_msg_hdr {
+ u8 attrtype;
+ u8 attrlen;
+};
+
+struct mrp_vecattr_hdr {
+ __be16 lenflags;
+ unsigned char firstattrvalue[];
+#define MRP_VECATTR_HDR_LEN_MASK cpu_to_be16(0x1FFF)
+#define MRP_VECATTR_HDR_FLAG_LA cpu_to_be16(0x2000)
+};
+
+enum mrp_vecattr_event {
+ MRP_NEW,
+ MRP_JOIN_IN,
+ MRP_IN,
+ MRP_JOIN_MT,
+ MRP_MT,
+ MRP_LV,
+};
+
+struct mrp_skb_cb {
+ struct mrp_msg_hdr *mh;
+ struct mrp_vecattr_hdr *vah;
+ unsigned char attrvalue[];
+};
+
+static inline struct mrp_skb_cb *mrp_cb(struct sk_buff *skb)
+{
+ BUILD_BUG_ON(sizeof(struct mrp_skb_cb) >
+ FIELD_SIZEOF(struct sk_buff, cb));
+ return (struct mrp_skb_cb *)skb->cb;
+}
+
+enum mrp_applicant_state {
+ MRP_APPLICANT_INVALID,
+ MRP_APPLICANT_VO,
+ MRP_APPLICANT_VP,
+ MRP_APPLICANT_VN,
+ MRP_APPLICANT_AN,
+ MRP_APPLICANT_AA,
+ MRP_APPLICANT_QA,
+ MRP_APPLICANT_LA,
+ MRP_APPLICANT_AO,
+ MRP_APPLICANT_QO,
+ MRP_APPLICANT_AP,
+ MRP_APPLICANT_QP,
+ __MRP_APPLICANT_MAX
+};
+#define MRP_APPLICANT_MAX (__MRP_APPLICANT_MAX - 1)
+
+enum mrp_event {
+ MRP_EVENT_NEW,
+ MRP_EVENT_JOIN,
+ MRP_EVENT_LV,
+ MRP_EVENT_TX,
+ MRP_EVENT_R_NEW,
+ MRP_EVENT_R_JOIN_IN,
+ MRP_EVENT_R_IN,
+ MRP_EVENT_R_JOIN_MT,
+ MRP_EVENT_R_MT,
+ MRP_EVENT_R_LV,
+ MRP_EVENT_R_LA,
+ MRP_EVENT_REDECLARE,
+ MRP_EVENT_PERIODIC,
+ __MRP_EVENT_MAX
+};
+#define MRP_EVENT_MAX (__MRP_EVENT_MAX - 1)
+
+enum mrp_tx_action {
+ MRP_TX_ACTION_NONE,
+ MRP_TX_ACTION_S_NEW,
+ MRP_TX_ACTION_S_JOIN_IN,
+ MRP_TX_ACTION_S_JOIN_IN_OPTIONAL,
+ MRP_TX_ACTION_S_IN_OPTIONAL,
+ MRP_TX_ACTION_S_LV,
+};
+
+struct mrp_attr {
+ struct rb_node node;
+ enum mrp_applicant_state state;
+ u8 type;
+ u8 len;
+ unsigned char value[];
+};
+
+enum mrp_applications {
+ MRP_APPLICATION_MVRP,
+ __MRP_APPLICATION_MAX
+};
+#define MRP_APPLICATION_MAX (__MRP_APPLICATION_MAX - 1)
+
+struct mrp_application {
+ enum mrp_applications type;
+ unsigned int maxattr;
+ struct packet_type pkttype;
+ unsigned char group_address[ETH_ALEN];
+ u8 version;
+};
+
+struct mrp_applicant {
+ struct mrp_application *app;
+ struct net_device *dev;
+ struct timer_list join_timer;
+
+ spinlock_t lock;
+ struct sk_buff_head queue;
+ struct sk_buff *pdu;
+ struct rb_root mad;
+ struct rcu_head rcu;
+};
+
+struct mrp_port {
+ struct mrp_applicant __rcu *applicants[MRP_APPLICATION_MAX + 1];
+ struct rcu_head rcu;
+};
+
+extern int mrp_register_application(struct mrp_application *app);
+extern void mrp_unregister_application(struct mrp_application *app);
+
+extern int mrp_init_applicant(struct net_device *dev,
+ struct mrp_application *app);
+extern void mrp_uninit_applicant(struct net_device *dev,
+ struct mrp_application *app);
+
+extern int mrp_request_join(const struct net_device *dev,
+ const struct mrp_application *app,
+ const void *value, u8 len, u8 type);
+extern void mrp_request_leave(const struct net_device *dev,
+ const struct mrp_application *app,
+ const void *value, u8 len, u8 type);
+
+#endif /* _NET_MRP_H */
diff --git a/net/802/Kconfig b/net/802/Kconfig
index be33d27..80d4bf7 100644
--- a/net/802/Kconfig
+++ b/net/802/Kconfig
@@ -5,3 +5,6 @@ config STP
config GARP
tristate
select STP
+
+config MRP
+ tristate
diff --git a/net/802/Makefile b/net/802/Makefile
index a30d6e3..37e654d 100644
--- a/net/802/Makefile
+++ b/net/802/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_IPX) += p8022.o psnap.o p8023.o
obj-$(CONFIG_ATALK) += p8022.o psnap.o
obj-$(CONFIG_STP) += stp.o
obj-$(CONFIG_GARP) += garp.o
+obj-$(CONFIG_MRP) += mrp.o
diff --git a/net/802/mrp.c b/net/802/mrp.c
new file mode 100644
index 0000000..65aaa4e
--- /dev/null
+++ b/net/802/mrp.c
@@ -0,0 +1,889 @@
+/*
+ * IEEE 802.1Q Multiple Registration Protocol (MRP)
+ *
+ * Copyright (c) 2012 Massachusetts Institute of Technology
+ *
+ * Adapted from code in net/802/garp.c
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <net/mrp.h>
+#include <asm/unaligned.h>
+
+static unsigned int mrp_join_time __read_mostly = 200;
+module_param(mrp_join_time, uint, 0644);
+MODULE_PARM_DESC(mrp_join_time, "Join time in ms (default 200ms)");
+MODULE_LICENSE("GPL");
+
+static const u8
+mrp_applicant_state_table[MRP_APPLICANT_MAX + 1][MRP_EVENT_MAX + 1] = {
+ [MRP_APPLICANT_VO] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_VP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_VO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VO,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VO,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_VO,
+ },
+ [MRP_APPLICANT_VP] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_VP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_VO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VP,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VP,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_VP,
+ },
+ [MRP_APPLICANT_VN] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_VN,
+ [MRP_EVENT_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_TX] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VN,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VN,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_VN,
+ },
+ [MRP_APPLICANT_AN] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_AN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_AN,
+ [MRP_EVENT_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VN,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VN,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AN,
+ },
+ [MRP_APPLICANT_AA] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_AA,
+ [MRP_EVENT_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VP,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VP,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AA,
+ },
+ [MRP_APPLICANT_QA] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_QA,
+ [MRP_EVENT_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VP,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VP,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AA,
+ },
+ [MRP_APPLICANT_LA] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_AA,
+ [MRP_EVENT_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_TX] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_LA,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_LA,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_LA,
+ },
+ [MRP_APPLICANT_AO] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_AP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_AO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QO,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VO,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VO,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AO,
+ },
+ [MRP_APPLICANT_QO] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_QP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_QO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QO,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_QO,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QO,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_QO,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VO,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VO,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_QO,
+ },
+ [MRP_APPLICANT_AP] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_AP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_AO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QP,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VP,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VP,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AP,
+ },
+ [MRP_APPLICANT_QP] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_QP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_QO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QP,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_QP,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QP,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_QP,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VP,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VP,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AP,
+ },
+};
+
+static const u8
+mrp_tx_action_table[MRP_APPLICANT_MAX + 1] = {
+ [MRP_APPLICANT_VO] = MRP_TX_ACTION_S_IN_OPTIONAL,
+ [MRP_APPLICANT_VP] = MRP_TX_ACTION_S_JOIN_IN,
+ [MRP_APPLICANT_VN] = MRP_TX_ACTION_S_NEW,
+ [MRP_APPLICANT_AN] = MRP_TX_ACTION_S_NEW,
+ [MRP_APPLICANT_AA] = MRP_TX_ACTION_S_JOIN_IN,
+ [MRP_APPLICANT_QA] = MRP_TX_ACTION_S_JOIN_IN_OPTIONAL,
+ [MRP_APPLICANT_LA] = MRP_TX_ACTION_S_LV,
+ [MRP_APPLICANT_AO] = MRP_TX_ACTION_S_IN_OPTIONAL,
+ [MRP_APPLICANT_QO] = MRP_TX_ACTION_S_IN_OPTIONAL,
+ [MRP_APPLICANT_AP] = MRP_TX_ACTION_S_JOIN_IN,
+ [MRP_APPLICANT_QP] = MRP_TX_ACTION_S_IN_OPTIONAL,
+};
+
+static void mrp_attrvalue_inc(void *value, u8 len)
+{
+ u8 *v = (u8 *)value;
+
+ /* Add 1 to the last byte. If it becomes zero,
+ * go to the previous byte and repeat.
+ */
+ while (len > 0 && !++v[--len])
+ ;
+}
+
+static int mrp_attr_cmp(const struct mrp_attr *attr,
+ const void *value, u8 len, u8 type)
+{
+ if (attr->type != type)
+ return attr->type - type;
+ if (attr->len != len)
+ return attr->len - len;
+ return memcmp(attr->value, value, len);
+}
+
+static struct mrp_attr *mrp_attr_lookup(const struct mrp_applicant *app,
+ const void *value, u8 len, u8 type)
+{
+ struct rb_node *parent = app->mad.rb_node;
+ struct mrp_attr *attr;
+ int d;
+
+ while (parent) {
+ attr = rb_entry(parent, struct mrp_attr, node);
+ d = mrp_attr_cmp(attr, value, len, type);
+ if (d > 0)
+ parent = parent->rb_left;
+ else if (d < 0)
+ parent = parent->rb_right;
+ else
+ return attr;
+ }
+ return NULL;
+}
+
+static struct mrp_attr *mrp_attr_create(struct mrp_applicant *app,
+ const void *value, u8 len, u8 type)
+{
+ struct rb_node *parent = NULL, **p = &app->mad.rb_node;
+ struct mrp_attr *attr;
+ int d;
+
+ while (*p) {
+ parent = *p;
+ attr = rb_entry(parent, struct mrp_attr, node);
+ d = mrp_attr_cmp(attr, value, len, type);
+ if (d > 0)
+ p = &parent->rb_left;
+ else if (d < 0)
+ p = &parent->rb_right;
+ else {
+ /* The attribute already exists; re-use it. */
+ return attr;
+ }
+ }
+ attr = kmalloc(sizeof(*attr) + len, GFP_ATOMIC);
+ if (!attr)
+ return attr;
+ attr->state = MRP_APPLICANT_VO;
+ attr->type = type;
+ attr->len = len;
+ memcpy(attr->value, value, len);
+
+ rb_link_node(&attr->node, parent, p);
+ rb_insert_color(&attr->node, &app->mad);
+ return attr;
+}
+
+static void mrp_attr_destroy(struct mrp_applicant *app, struct mrp_attr *attr)
+{
+ rb_erase(&attr->node, &app->mad);
+ kfree(attr);
+}
+
+static int mrp_pdu_init(struct mrp_applicant *app)
+{
+ struct sk_buff *skb;
+ struct mrp_pdu_hdr *ph;
+
+ skb = alloc_skb(app->dev->mtu + LL_RESERVED_SPACE(app->dev),
+ GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ skb->dev = app->dev;
+ skb->protocol = app->app->pkttype.type;
+ skb_reserve(skb, LL_RESERVED_SPACE(app->dev));
+ skb_reset_network_header(skb);
+ skb_reset_transport_header(skb);
+
+ ph = (struct mrp_pdu_hdr *)__skb_put(skb, sizeof(*ph));
+ ph->version = app->app->version;
+
+ app->pdu = skb;
+ return 0;
+}
+
+static int mrp_pdu_append_end_mark(struct mrp_applicant *app)
+{
+ __be16 *endmark;
+
+ if (skb_tailroom(app->pdu) < sizeof(*endmark))
+ return -1;
+ endmark = (__be16 *)__skb_put(app->pdu, sizeof(*endmark));
+ put_unaligned(MRP_END_MARK, endmark);
+ return 0;
+}
+
+static void mrp_pdu_queue(struct mrp_applicant *app)
+{
+ if (!app->pdu)
+ return;
+
+ if (mrp_cb(app->pdu)->mh)
+ mrp_pdu_append_end_mark(app);
+ mrp_pdu_append_end_mark(app);
+
+ dev_hard_header(app->pdu, app->dev, ntohs(app->app->pkttype.type),
+ app->app->group_address, app->dev->dev_addr,
+ app->pdu->len);
+
+ skb_queue_tail(&app->queue, app->pdu);
+ app->pdu = NULL;
+}
+
+static void mrp_queue_xmit(struct mrp_applicant *app)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&app->queue)))
+ dev_queue_xmit(skb);
+}
+
+static int mrp_pdu_append_msg_hdr(struct mrp_applicant *app,
+ u8 attrtype, u8 attrlen)
+{
+ struct mrp_msg_hdr *mh;
+
+ if (mrp_cb(app->pdu)->mh) {
+ if (mrp_pdu_append_end_mark(app) < 0)
+ return -1;
+ mrp_cb(app->pdu)->mh = NULL;
+ mrp_cb(app->pdu)->vah = NULL;
+ }
+
+ if (skb_tailroom(app->pdu) < sizeof(*mh))
+ return -1;
+ mh = (struct mrp_msg_hdr *)__skb_put(app->pdu, sizeof(*mh));
+ mh->attrtype = attrtype;
+ mh->attrlen = attrlen;
+ mrp_cb(app->pdu)->mh = mh;
+ return 0;
+}
+
+static int mrp_pdu_append_vecattr_hdr(struct mrp_applicant *app,
+ const void *firstattrvalue, u8 attrlen)
+{
+ struct mrp_vecattr_hdr *vah;
+
+ if (skb_tailroom(app->pdu) < sizeof(*vah) + attrlen)
+ return -1;
+ vah = (struct mrp_vecattr_hdr *)__skb_put(app->pdu,
+ sizeof(*vah) + attrlen);
+ put_unaligned(0, &vah->lenflags);
+ memcpy(vah->firstattrvalue, firstattrvalue, attrlen);
+ mrp_cb(app->pdu)->vah = vah;
+ memcpy(mrp_cb(app->pdu)->attrvalue, firstattrvalue, attrlen);
+ return 0;
+}
+
+static int mrp_pdu_append_event(struct mrp_applicant *app,
+ const struct mrp_attr *attr,
+ enum mrp_vecattr_event event)
+{
+ u16 len, pos;
+ u8 *events;
+ int err;
+again:
+ if (!app->pdu) {
+ err = mrp_pdu_init(app);
+ if (err < 0)
+ return err;
+ }
+
+ /* If there is no Message header in the PDU, or the Message header is
+ * for a different attribute type, add an EndMark (if necessary) and a
+ * new Message header to the PDU.
+ */
+ if (!mrp_cb(app->pdu)->mh ||
+ mrp_cb(app->pdu)->mh->attrtype != attr->type ||
+ mrp_cb(app->pdu)->mh->attrlen != attr->len) {
+ if (mrp_pdu_append_msg_hdr(app, attr->type, attr->len) < 0)
+ goto queue;
+ }
+
+ /* If there is no VectorAttribute header for this Message in the PDU,
+ * or this attribute's value does not sequentially follow the previous
+ * attribute's value, add a new VectorAttribute header to the PDU.
+ */
+ if (!mrp_cb(app->pdu)->vah ||
+ memcmp(mrp_cb(app->pdu)->attrvalue, attr->value, attr->len)) {
+ if (mrp_pdu_append_vecattr_hdr(app, attr->value, attr->len) < 0)
+ goto queue;
+ }
+
+ len = be16_to_cpu(get_unaligned(&mrp_cb(app->pdu)->vah->lenflags));
+ pos = len % 3;
+
+ /* Events are packed into Vectors in the PDU, three to a byte. Add a
+ * byte to the end of the Vector if necessary.
+ */
+ if (!pos) {
+ if (skb_tailroom(app->pdu) < sizeof(u8))
+ goto queue;
+ events = (u8 *)__skb_put(app->pdu, sizeof(u8));
+ } else {
+ events = (u8 *)(skb_tail_pointer(app->pdu) - sizeof(u8));
+ }
+
+ switch (pos) {
+ case 0:
+ *events = event * 36;
+ break;
+ case 1:
+ *events += event * 6;
+ break;
+ case 2:
+ *events += event;
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ /* Increment the length of the VectorAttribute in the PDU, as well as
+ * the value of the next attribute that would continue its Vector.
+ */
+ put_unaligned(cpu_to_be16(++len), &mrp_cb(app->pdu)->vah->lenflags);
+ mrp_attrvalue_inc(mrp_cb(app->pdu)->attrvalue, attr->len);
+
+ return 0;
+
+queue:
+ mrp_pdu_queue(app);
+ goto again;
+}
+
+static void mrp_attr_event(struct mrp_applicant *app,
+ struct mrp_attr *attr, enum mrp_event event)
+{
+ enum mrp_applicant_state state;
+
+ state = mrp_applicant_state_table[attr->state][event];
+ if (state == MRP_APPLICANT_INVALID) {
+ WARN_ON(1);
+ return;
+ }
+
+ if (event == MRP_EVENT_TX) {
+ /* When appending the attribute fails, don't update its state
+ * in order to retry at the next TX event.
+ */
+
+ switch (mrp_tx_action_table[attr->state]) {
+ case MRP_TX_ACTION_NONE:
+ case MRP_TX_ACTION_S_JOIN_IN_OPTIONAL:
+ case MRP_TX_ACTION_S_IN_OPTIONAL:
+ break;
+ case MRP_TX_ACTION_S_NEW:
+ if (mrp_pdu_append_event(app, attr, MRP_NEW) < 0)
+ return;
+ break;
+ case MRP_TX_ACTION_S_JOIN_IN:
+ if (mrp_pdu_append_event(app, attr, MRP_JOIN_IN) < 0)
+ return;
+ break;
+ case MRP_TX_ACTION_S_LV:
+ if (mrp_pdu_append_event(app, attr, MRP_LV) < 0)
+ return;
+ /* As a pure applicant, sending a leave message
+ * implies that the attribute was unregistered and
+ * can be destroyed.
+ */
+ mrp_attr_destroy(app, attr);
+ return;
+ default:
+ WARN_ON(1);
+ }
+ }
+
+ attr->state = state;
+}
+
+int mrp_request_join(const struct net_device *dev,
+ const struct mrp_application *appl,
+ const void *value, u8 len, u8 type)
+{
+ struct mrp_port *port = rtnl_dereference(dev->mrp_port);
+ struct mrp_applicant *app = rtnl_dereference(
+ port->applicants[appl->type]);
+ struct mrp_attr *attr;
+
+ if (sizeof(struct mrp_skb_cb) + len >
+ FIELD_SIZEOF(struct sk_buff, cb))
+ return -ENOMEM;
+
+ spin_lock_bh(&app->lock);
+ attr = mrp_attr_create(app, value, len, type);
+ if (!attr) {
+ spin_unlock_bh(&app->lock);
+ return -ENOMEM;
+ }
+ mrp_attr_event(app, attr, MRP_EVENT_JOIN);
+ spin_unlock_bh(&app->lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mrp_request_join);
+
+void mrp_request_leave(const struct net_device *dev,
+ const struct mrp_application *appl,
+ const void *value, u8 len, u8 type)
+{
+ struct mrp_port *port = rtnl_dereference(dev->mrp_port);
+ struct mrp_applicant *app = rtnl_dereference(
+ port->applicants[appl->type]);
+ struct mrp_attr *attr;
+
+ if (sizeof(struct mrp_skb_cb) + len >
+ FIELD_SIZEOF(struct sk_buff, cb))
+ return;
+
+ spin_lock_bh(&app->lock);
+ attr = mrp_attr_lookup(app, value, len, type);
+ if (!attr) {
+ spin_unlock_bh(&app->lock);
+ return;
+ }
+ mrp_attr_event(app, attr, MRP_EVENT_LV);
+ spin_unlock_bh(&app->lock);
+}
+EXPORT_SYMBOL_GPL(mrp_request_leave);
+
+static void mrp_mad_event(struct mrp_applicant *app, enum mrp_event event)
+{
+ struct rb_node *node, *next;
+ struct mrp_attr *attr;
+
+ for (node = rb_first(&app->mad);
+ next = node ? rb_next(node) : NULL, node != NULL;
+ node = next) {
+ attr = rb_entry(node, struct mrp_attr, node);
+ mrp_attr_event(app, attr, event);
+ }
+}
+
+static void mrp_join_timer_arm(struct mrp_applicant *app)
+{
+ unsigned long delay;
+
+ delay = (u64)msecs_to_jiffies(mrp_join_time) * net_random() >> 32;
+ mod_timer(&app->join_timer, jiffies + delay);
+}
+
+static void mrp_join_timer(unsigned long data)
+{
+ struct mrp_applicant *app = (struct mrp_applicant *)data;
+
+ spin_lock(&app->lock);
+ mrp_mad_event(app, MRP_EVENT_TX);
+ mrp_pdu_queue(app);
+ spin_unlock(&app->lock);
+
+ mrp_queue_xmit(app);
+ mrp_join_timer_arm(app);
+}
+
+static int mrp_pdu_parse_end_mark(struct sk_buff *skb, int *offset)
+{
+ __be16 endmark;
+
+ if (skb_copy_bits(skb, *offset, &endmark, sizeof(endmark)) < 0)
+ return -1;
+ if (endmark == MRP_END_MARK) {
+ *offset += sizeof(endmark);
+ return -1;
+ }
+ return 0;
+}
+
+static void mrp_pdu_parse_vecattr_event(struct mrp_applicant *app,
+ struct sk_buff *skb,
+ enum mrp_vecattr_event vaevent)
+{
+ struct mrp_attr *attr;
+ enum mrp_event event;
+
+ attr = mrp_attr_lookup(app, mrp_cb(skb)->attrvalue,
+ mrp_cb(skb)->mh->attrlen,
+ mrp_cb(skb)->mh->attrtype);
+ if (attr == NULL)
+ return;
+
+ switch (vaevent) {
+ case MRP_NEW:
+ event = MRP_EVENT_R_NEW;
+ break;
+ case MRP_JOIN_IN:
+ event = MRP_EVENT_R_JOIN_IN;
+ break;
+ case MRP_IN:
+ event = MRP_EVENT_R_IN;
+ break;
+ case MRP_JOIN_MT:
+ event = MRP_EVENT_R_JOIN_MT;
+ break;
+ case MRP_MT:
+ event = MRP_EVENT_R_MT;
+ break;
+ case MRP_LV:
+ event = MRP_EVENT_R_LV;
+ break;
+ default:
+ return;
+ }
+
+ mrp_attr_event(app, attr, event);
+}
+
+static int mrp_pdu_parse_vecattr(struct mrp_applicant *app,
+ struct sk_buff *skb, int *offset)
+{
+ struct mrp_vecattr_hdr _vah;
+ u16 valen;
+ u8 vaevents, vaevent;
+
+ mrp_cb(skb)->vah = skb_header_pointer(skb, *offset, sizeof(_vah),
+ &_vah);
+ if (!mrp_cb(skb)->vah)
+ return -1;
+ *offset += sizeof(_vah);
+
+ if (get_unaligned(&mrp_cb(skb)->vah->lenflags) &
+ MRP_VECATTR_HDR_FLAG_LA)
+ mrp_mad_event(app, MRP_EVENT_R_LA);
+ valen = be16_to_cpu(get_unaligned(&mrp_cb(skb)->vah->lenflags) &
+ MRP_VECATTR_HDR_LEN_MASK);
+
+ /* The VectorAttribute structure in a PDU carries event information
+ * about one or more attributes having consecutive values. Only the
+ * value for the first attribute is contained in the structure. So
+ * we make a copy of that value, and then increment it each time we
+ * advance to the next event in its Vector.
+ */
+ if (sizeof(struct mrp_skb_cb) + mrp_cb(skb)->mh->attrlen >
+ FIELD_SIZEOF(struct sk_buff, cb))
+ return -1;
+ if (skb_copy_bits(skb, *offset, mrp_cb(skb)->attrvalue,
+ mrp_cb(skb)->mh->attrlen) < 0)
+ return -1;
+ *offset += mrp_cb(skb)->mh->attrlen;
+
+ /* In a VectorAttribute, the Vector contains events which are packed
+ * three to a byte. We process one byte of the Vector at a time.
+ */
+ while (valen > 0) {
+ if (skb_copy_bits(skb, *offset, &vaevents,
+ sizeof(vaevents)) < 0)
+ return -1;
+ *offset += sizeof(vaevents);
+
+ /* Extract and process the first event. */
+ vaevent = vaevents / 36;
+ if (vaevent >= 6) {
+ /* The byte is malformed; stop processing. */
+ return -1;
+ }
+ mrp_pdu_parse_vecattr_event(app, skb, vaevent);
+
+ /* If present, extract and process the second event. */
+ if (!--valen)
+ break;
+ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue,
+ mrp_cb(skb)->mh->attrlen);
+ vaevents %= 36;
+ vaevent = vaevents / 6;
+ mrp_pdu_parse_vecattr_event(app, skb, vaevent);
+
+ /* If present, extract and process the third event. */
+ if (!--valen)
+ break;
+ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue,
+ mrp_cb(skb)->mh->attrlen);
+ vaevents %= 6;
+ vaevent = vaevents;
+ mrp_pdu_parse_vecattr_event(app, skb, vaevent);
+ }
+ return 0;
+}
+
+static int mrp_pdu_parse_msg(struct mrp_applicant *app, struct sk_buff *skb,
+ int *offset)
+{
+ struct mrp_msg_hdr _mh;
+
+ mrp_cb(skb)->mh = skb_header_pointer(skb, *offset, sizeof(_mh), &_mh);
+ if (!mrp_cb(skb)->mh)
+ return -1;
+ *offset += sizeof(_mh);
+
+ if (mrp_cb(skb)->mh->attrtype == 0 ||
+ mrp_cb(skb)->mh->attrtype > app->app->maxattr ||
+ mrp_cb(skb)->mh->attrlen == 0)
+ return -1;
+
+ while (skb->len > *offset) {
+ if (mrp_pdu_parse_end_mark(skb, offset) < 0)
+ break;
+ if (mrp_pdu_parse_vecattr(app, skb, offset) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int mrp_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct mrp_application *appl = container_of(pt, struct mrp_application,
+ pkttype);
+ struct mrp_port *port;
+ struct mrp_applicant *app;
+ struct mrp_pdu_hdr _ph;
+ const struct mrp_pdu_hdr *ph;
+ int offset = skb_network_offset(skb);
+
+ /* If the interface is in promiscuous mode, drop the packet if
+ * it was unicast to another host.
+ */
+ if (unlikely(skb->pkt_type == PACKET_OTHERHOST))
+ goto out;
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (unlikely(!skb))
+ goto out;
+ port = rcu_dereference(dev->mrp_port);
+ if (unlikely(!port))
+ goto out;
+ app = rcu_dereference(port->applicants[appl->type]);
+ if (unlikely(!app))
+ goto out;
+
+ ph = skb_header_pointer(skb, offset, sizeof(_ph), &_ph);
+ if (!ph)
+ goto out;
+ offset += sizeof(_ph);
+
+ if (ph->version != app->app->version)
+ goto out;
+
+ spin_lock(&app->lock);
+ while (skb->len > offset) {
+ if (mrp_pdu_parse_end_mark(skb, &offset) < 0)
+ break;
+ if (mrp_pdu_parse_msg(app, skb, &offset) < 0)
+ break;
+ }
+ spin_unlock(&app->lock);
+out:
+ kfree_skb(skb);
+ return 0;
+}
+
+static int mrp_init_port(struct net_device *dev)
+{
+ struct mrp_port *port;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+ rcu_assign_pointer(dev->mrp_port, port);
+ return 0;
+}
+
+static void mrp_release_port(struct net_device *dev)
+{
+ struct mrp_port *port = rtnl_dereference(dev->mrp_port);
+ unsigned int i;
+
+ for (i = 0; i <= MRP_APPLICATION_MAX; i++) {
+ if (rtnl_dereference(port->applicants[i]))
+ return;
+ }
+ RCU_INIT_POINTER(dev->mrp_port, NULL);
+ kfree_rcu(port, rcu);
+}
+
+int mrp_init_applicant(struct net_device *dev, struct mrp_application *appl)
+{
+ struct mrp_applicant *app;
+ int err;
+
+ ASSERT_RTNL();
+
+ if (!rtnl_dereference(dev->mrp_port)) {
+ err = mrp_init_port(dev);
+ if (err < 0)
+ goto err1;
+ }
+
+ err = -ENOMEM;
+ app = kzalloc(sizeof(*app), GFP_KERNEL);
+ if (!app)
+ goto err2;
+
+ err = dev_mc_add(dev, appl->group_address);
+ if (err < 0)
+ goto err3;
+
+ app->dev = dev;
+ app->app = appl;
+ app->mad = RB_ROOT;
+ spin_lock_init(&app->lock);
+ skb_queue_head_init(&app->queue);
+ rcu_assign_pointer(dev->mrp_port->applicants[appl->type], app);
+ setup_timer(&app->join_timer, mrp_join_timer, (unsigned long)app);
+ mrp_join_timer_arm(app);
+ return 0;
+
+err3:
+ kfree(app);
+err2:
+ mrp_release_port(dev);
+err1:
+ return err;
+}
+EXPORT_SYMBOL_GPL(mrp_init_applicant);
+
+void mrp_uninit_applicant(struct net_device *dev, struct mrp_application *appl)
+{
+ struct mrp_port *port = rtnl_dereference(dev->mrp_port);
+ struct mrp_applicant *app = rtnl_dereference(
+ port->applicants[appl->type]);
+
+ ASSERT_RTNL();
+
+ RCU_INIT_POINTER(port->applicants[appl->type], NULL);
+
+ /* Delete timer and generate a final TX event to flush out
+ * all pending messages before the applicant is gone.
+ */
+ del_timer_sync(&app->join_timer);
+ mrp_mad_event(app, MRP_EVENT_TX);
+ mrp_pdu_queue(app);
+ mrp_queue_xmit(app);
+
+ dev_mc_del(dev, appl->group_address);
+ kfree_rcu(app, rcu);
+ mrp_release_port(dev);
+}
+EXPORT_SYMBOL_GPL(mrp_uninit_applicant);
+
+int mrp_register_application(struct mrp_application *appl)
+{
+ appl->pkttype.func = mrp_rcv;
+ dev_add_pack(&appl->pkttype);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mrp_register_application);
+
+void mrp_unregister_application(struct mrp_application *appl)
+{
+ dev_remove_pack(&appl->pkttype);
+}
+EXPORT_SYMBOL_GPL(mrp_unregister_application);
--
1.7.1
^ permalink raw reply related
* [PATCH RFC v2 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011)
From: David Ward @ 2013-02-08 3:50 UTC (permalink / raw)
To: netdev; +Cc: Patrick McHardy, Eric Dumazet, David Ward
v2: Use skb_header_pointer() as suggested by Eric Duzamet.
The Linux kernel currently implements the GARP VLAN Registration
Protocol (GVRP) from IEEE 802.1Q-1998 (applicant-only participant).
When the GVRP flag is set for a VLAN interface on a Linux host, the
host advertises its membership in the VLAN to the attached bridge/
switch, so that it is not necessary to manually configure the bridge/
switch port to participate in the VLAN.
GVRP has been superseded by the Multiple VLAN Registration Protocol
(MVRP) in IEEE 802.1Q-2011, which addresses scalability concerns about
the earlier protocol. The following patches add support for MVRP to
the Linux kernel and iproute2 utility. They are based largely off of
the existing implementation of GVRP, but have been modified for the
new PDU structure and state machine.
Please let me know if you have any comments. This implementation was
tested with two Juniper EX4200 switches and found to work as expected.
If you have access to other switches that implement MVRP, I would of
course welcome additional testing.
Signed-off-by: David Ward <david.ward@ll.mit.edu>
David Ward (2):
net/802: Implement Multiple Registration Protocol (MRP)
net/8021q: Implement Multiple VLAN Registration Protocol (MVRP)
include/linux/netdevice.h | 2 +
include/net/mrp.h | 142 +++++++
include/uapi/linux/if_ether.h | 1 +
include/uapi/linux/if_vlan.h | 1 +
net/802/Kconfig | 3 +
net/802/Makefile | 1 +
net/802/mrp.c | 889 +++++++++++++++++++++++++++++++++++++++++
net/8021q/Kconfig | 11 +
net/8021q/Makefile | 1 +
net/8021q/vlan.c | 27 +-
net/8021q/vlan.h | 16 +
net/8021q/vlan_dev.c | 12 +-
net/8021q/vlan_mvrp.c | 72 ++++
net/8021q/vlan_netlink.c | 2 +-
14 files changed, 1173 insertions(+), 7 deletions(-)
create mode 100644 include/net/mrp.h
create mode 100644 net/802/mrp.c
create mode 100644 net/8021q/vlan_mvrp.c
^ permalink raw reply
* [PATCH RFC v2 iproute2] iplink_vlan: Add flag for Multiple VLAN Registration Protocol (MVRP)
From: David Ward @ 2013-02-08 3:50 UTC (permalink / raw)
To: netdev; +Cc: Patrick McHardy, Eric Dumazet, David Ward
In-Reply-To: <1360295457-5245-1-git-send-email-david.ward@ll.mit.edu>
Signed-off-by: David Ward <david.ward@ll.mit.edu>
---
include/linux/if_vlan.h | 1 +
ip/iplink_vlan.c | 12 +++++++++++-
2 files changed, 12 insertions(+), 1 deletions(-)
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 3be1ca6..24ae007 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -34,6 +34,7 @@ enum vlan_flags {
VLAN_FLAG_REORDER_HDR = 0x1,
VLAN_FLAG_GVRP = 0x2,
VLAN_FLAG_LOOSE_BINDING = 0x4,
+ VLAN_FLAG_MVRP = 0x8,
};
enum vlan_name_types {
diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c
index 97af8d6..4d155b6 100644
--- a/ip/iplink_vlan.c
+++ b/ip/iplink_vlan.c
@@ -26,7 +26,7 @@ static void explain(void)
"\n"
"VLANID := 0-4095\n"
"FLAG-LIST := [ FLAG-LIST ] FLAG\n"
- "FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ]\n"
+ "FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ] [ mvrp { on | off } ]\n"
" [ loose_binding { on | off } ]\n"
"QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n"
"QOS-MAPPING := FROM:TO\n"
@@ -103,6 +103,15 @@ static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
flags.flags &= ~VLAN_FLAG_GVRP;
else
return on_off("gvrp");
+ } else if (matches(*argv, "mvrp") == 0) {
+ NEXT_ARG();
+ flags.mask |= VLAN_FLAG_MVRP;
+ if (strcmp(*argv, "on") == 0)
+ flags.flags |= VLAN_FLAG_MVRP;
+ else if (strcmp(*argv, "off") == 0)
+ flags.flags &= ~VLAN_FLAG_MVRP;
+ else
+ return on_off("mvrp");
} else if (matches(*argv, "loose_binding") == 0) {
NEXT_ARG();
flags.mask |= VLAN_FLAG_LOOSE_BINDING;
@@ -166,6 +175,7 @@ static void vlan_print_flags(FILE *fp, __u32 flags)
}
_PF(REORDER_HDR);
_PF(GVRP);
+ _PF(MVRP);
_PF(LOOSE_BINDING);
#undef _PF
if (flags)
--
1.7.1
^ permalink raw reply related
* [PATCH RFC v2 2/2] net/8021q: Implement Multiple VLAN Registration Protocol (MVRP)
From: David Ward @ 2013-02-08 3:50 UTC (permalink / raw)
To: netdev; +Cc: Patrick McHardy, Eric Dumazet, David Ward
In-Reply-To: <1360295457-5245-1-git-send-email-david.ward@ll.mit.edu>
Initial implementation of the Multiple VLAN Registration Protocol
(MVRP) from IEEE 802.1Q-2011, based on the existing implementation
of the GARP VLAN Registration Protocol (GVRP).
Signed-off-by: David Ward <david.ward@ll.mit.edu>
---
include/uapi/linux/if_ether.h | 1 +
include/uapi/linux/if_vlan.h | 1 +
net/8021q/Kconfig | 11 ++++++
net/8021q/Makefile | 1 +
net/8021q/vlan.c | 27 ++++++++++++---
net/8021q/vlan.h | 16 +++++++++
net/8021q/vlan_dev.c | 12 ++++++-
net/8021q/vlan_mvrp.c | 72 +++++++++++++++++++++++++++++++++++++++++
net/8021q/vlan_netlink.c | 2 +-
9 files changed, 136 insertions(+), 7 deletions(-)
create mode 100644 net/8021q/vlan_mvrp.c
diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index 67fb87c..798032d 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -83,6 +83,7 @@
#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */
#define ETH_P_TIPC 0x88CA /* TIPC */
#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
+#define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */
#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
#define ETH_P_TDLS 0x890D /* TDLS */
diff --git a/include/uapi/linux/if_vlan.h b/include/uapi/linux/if_vlan.h
index 0744f8e..7e5e6b3 100644
--- a/include/uapi/linux/if_vlan.h
+++ b/include/uapi/linux/if_vlan.h
@@ -34,6 +34,7 @@ enum vlan_flags {
VLAN_FLAG_REORDER_HDR = 0x1,
VLAN_FLAG_GVRP = 0x2,
VLAN_FLAG_LOOSE_BINDING = 0x4,
+ VLAN_FLAG_MVRP = 0x8,
};
enum vlan_name_types {
diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig
index fa073a5..8f7517d 100644
--- a/net/8021q/Kconfig
+++ b/net/8021q/Kconfig
@@ -27,3 +27,14 @@ config VLAN_8021Q_GVRP
automatic propagation of registered VLANs to switches.
If unsure, say N.
+
+config VLAN_8021Q_MVRP
+ bool "MVRP (Multiple VLAN Registration Protocol) support"
+ depends on VLAN_8021Q
+ select MRP
+ help
+ Select this to enable MVRP end-system support. MVRP is used for
+ automatic propagation of registered VLANs to switches; it
+ supersedes GVRP and is not backwards-compatible.
+
+ If unsure, say N.
diff --git a/net/8021q/Makefile b/net/8021q/Makefile
index 9f4f174..7bc8db0 100644
--- a/net/8021q/Makefile
+++ b/net/8021q/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_VLAN_8021Q) += 8021q.o
8021q-y := vlan.o vlan_dev.o vlan_netlink.o
8021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o
+8021q-$(CONFIG_VLAN_8021Q_MVRP) += vlan_mvrp.o
8021q-$(CONFIG_PROC_FS) += vlanproc.o
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index addc578..a187144 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -95,6 +95,8 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
grp->nr_vlan_devs--;
+ if (vlan->flags & VLAN_FLAG_MVRP)
+ vlan_mvrp_request_leave(dev);
if (vlan->flags & VLAN_FLAG_GVRP)
vlan_gvrp_request_leave(dev);
@@ -107,8 +109,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
netdev_upper_dev_unlink(real_dev, dev);
- if (grp->nr_vlan_devs == 0)
+ if (grp->nr_vlan_devs == 0) {
+ vlan_mvrp_uninit_applicant(real_dev);
vlan_gvrp_uninit_applicant(real_dev);
+ }
/* Get rid of the vlan's reference to real_dev */
dev_put(real_dev);
@@ -151,15 +155,18 @@ int register_vlan_dev(struct net_device *dev)
err = vlan_gvrp_init_applicant(real_dev);
if (err < 0)
goto out_vid_del;
+ err = vlan_mvrp_init_applicant(real_dev);
+ if (err < 0)
+ goto out_uninit_gvrp;
}
err = vlan_group_prealloc_vid(grp, vlan_id);
if (err < 0)
- goto out_uninit_applicant;
+ goto out_uninit_mvrp;
err = netdev_upper_dev_link(real_dev, dev);
if (err)
- goto out_uninit_applicant;
+ goto out_uninit_mvrp;
err = register_netdevice(dev);
if (err < 0)
@@ -181,7 +188,10 @@ int register_vlan_dev(struct net_device *dev)
out_upper_dev_unlink:
netdev_upper_dev_unlink(real_dev, dev);
-out_uninit_applicant:
+out_uninit_mvrp:
+ if (grp->nr_vlan_devs == 0)
+ vlan_mvrp_uninit_applicant(real_dev);
+out_uninit_gvrp:
if (grp->nr_vlan_devs == 0)
vlan_gvrp_uninit_applicant(real_dev);
out_vid_del:
@@ -655,13 +665,19 @@ static int __init vlan_proto_init(void)
if (err < 0)
goto err3;
- err = vlan_netlink_init();
+ err = vlan_mvrp_init();
if (err < 0)
goto err4;
+ err = vlan_netlink_init();
+ if (err < 0)
+ goto err5;
+
vlan_ioctl_set(vlan_ioctl_handler);
return 0;
+err5:
+ vlan_mvrp_uninit();
err4:
vlan_gvrp_uninit();
err3:
@@ -682,6 +698,7 @@ static void __exit vlan_cleanup_module(void)
unregister_pernet_subsys(&vlan_net_ops);
rcu_barrier(); /* Wait for completion of call_rcu()'s */
+ vlan_mvrp_uninit();
vlan_gvrp_uninit();
}
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index a4886d9..670f1e8 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -171,6 +171,22 @@ static inline int vlan_gvrp_init(void) { return 0; }
static inline void vlan_gvrp_uninit(void) {}
#endif
+#ifdef CONFIG_VLAN_8021Q_MVRP
+extern int vlan_mvrp_request_join(const struct net_device *dev);
+extern void vlan_mvrp_request_leave(const struct net_device *dev);
+extern int vlan_mvrp_init_applicant(struct net_device *dev);
+extern void vlan_mvrp_uninit_applicant(struct net_device *dev);
+extern int vlan_mvrp_init(void);
+extern void vlan_mvrp_uninit(void);
+#else
+static inline int vlan_mvrp_request_join(const struct net_device *dev) { return 0; }
+static inline void vlan_mvrp_request_leave(const struct net_device *dev) {}
+static inline int vlan_mvrp_init_applicant(struct net_device *dev) { return 0; }
+static inline void vlan_mvrp_uninit_applicant(struct net_device *dev) {}
+static inline int vlan_mvrp_init(void) { return 0; }
+static inline void vlan_mvrp_uninit(void) {}
+#endif
+
extern const char vlan_fullname[];
extern const char vlan_version[];
extern int vlan_netlink_init(void);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 09f9108..34df5b3 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -261,7 +261,7 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
u32 old_flags = vlan->flags;
if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
- VLAN_FLAG_LOOSE_BINDING))
+ VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP))
return -EINVAL;
vlan->flags = (old_flags & ~mask) | (flags & mask);
@@ -272,6 +272,13 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
else
vlan_gvrp_request_leave(dev);
}
+
+ if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_MVRP) {
+ if (vlan->flags & VLAN_FLAG_MVRP)
+ vlan_mvrp_request_join(dev);
+ else
+ vlan_mvrp_request_leave(dev);
+ }
return 0;
}
@@ -312,6 +319,9 @@ static int vlan_dev_open(struct net_device *dev)
if (vlan->flags & VLAN_FLAG_GVRP)
vlan_gvrp_request_join(dev);
+ if (vlan->flags & VLAN_FLAG_MVRP)
+ vlan_mvrp_request_join(dev);
+
if (netif_carrier_ok(real_dev))
netif_carrier_on(dev);
return 0;
diff --git a/net/8021q/vlan_mvrp.c b/net/8021q/vlan_mvrp.c
new file mode 100644
index 0000000..d9ec1d5
--- /dev/null
+++ b/net/8021q/vlan_mvrp.c
@@ -0,0 +1,72 @@
+/*
+ * IEEE 802.1Q Multiple VLAN Registration Protocol (MVRP)
+ *
+ * Copyright (c) 2012 Massachusetts Institute of Technology
+ *
+ * Adapted from code in net/8021q/vlan_gvrp.c
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <net/mrp.h>
+#include "vlan.h"
+
+#define MRP_MVRP_ADDRESS { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x21 }
+
+enum mvrp_attributes {
+ MVRP_ATTR_INVALID,
+ MVRP_ATTR_VID,
+ __MVRP_ATTR_MAX
+};
+#define MVRP_ATTR_MAX (__MVRP_ATTR_MAX - 1)
+
+static struct mrp_application vlan_mrp_app __read_mostly = {
+ .type = MRP_APPLICATION_MVRP,
+ .maxattr = MVRP_ATTR_MAX,
+ .pkttype.type = htons(ETH_P_MVRP),
+ .group_address = MRP_MVRP_ADDRESS,
+ .version = 0,
+};
+
+int vlan_mvrp_request_join(const struct net_device *dev)
+{
+ const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+ __be16 vlan_id = htons(vlan->vlan_id);
+
+ return mrp_request_join(vlan->real_dev, &vlan_mrp_app,
+ &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
+}
+
+void vlan_mvrp_request_leave(const struct net_device *dev)
+{
+ const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+ __be16 vlan_id = htons(vlan->vlan_id);
+
+ mrp_request_leave(vlan->real_dev, &vlan_mrp_app,
+ &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
+}
+
+int vlan_mvrp_init_applicant(struct net_device *dev)
+{
+ return mrp_init_applicant(dev, &vlan_mrp_app);
+}
+
+void vlan_mvrp_uninit_applicant(struct net_device *dev)
+{
+ mrp_uninit_applicant(dev, &vlan_mrp_app);
+}
+
+int __init vlan_mvrp_init(void)
+{
+ return mrp_register_application(&vlan_mrp_app);
+}
+
+void vlan_mvrp_uninit(void)
+{
+ mrp_unregister_application(&vlan_mrp_app);
+}
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index 708c80e..1789658 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -62,7 +62,7 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
flags = nla_data(data[IFLA_VLAN_FLAGS]);
if ((flags->flags & flags->mask) &
~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
- VLAN_FLAG_LOOSE_BINDING))
+ VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP))
return -EINVAL;
}
--
1.7.1
^ permalink raw reply related
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