* Re: [PATCH] r8169: Fix rtl8169_rx_interrupt()
From: Eric Dumazet @ 2010-03-16 7:12 UTC (permalink / raw)
To: Sergey Senozhatsky
Cc: Oleg Nesterov, David Miller, Ingo Molnar, Francois Romieu,
Peter Zijlstra, netdev, linux-kernel
In-Reply-To: <20100316065015.GA3336@swordfish.minsk.epam.com>
Le mardi 16 mars 2010 à 08:50 +0200, Sergey Senozhatsky a écrit :
> Hello,
>
> Sure. Give me a couple of days. By the way, should I test against .34
> or .33?
>
It's an old bug anyway, so you can pick up whats is the best for you.
My personal pref would be current kernel.
To trigger the original condition (fifo overflow), you might flood your
machine from another one with small packets, for example using pktgen.
Thanks
^ permalink raw reply
* Re: [PATCH] r8169: Fix rtl8169_rx_interrupt()
From: Sergey Senozhatsky @ 2010-03-16 6:50 UTC (permalink / raw)
To: Eric Dumazet
Cc: Oleg Nesterov, David Miller, Ingo Molnar, Sergey Senozhatsky,
Francois Romieu, Peter Zijlstra, netdev, linux-kernel
In-Reply-To: <1268699602.2824.14.camel@edumazet-laptop>
[-- Attachment #1: Type: text/plain, Size: 3237 bytes --]
Hello,
Sure. Give me a couple of days. By the way, should I test against .34
or .33?
Sergey
On (03/16/10 01:33), Eric Dumazet wrote:
> Le lundi 15 mars 2010 à 22:01 +0100, Eric Dumazet a écrit :
>
> > Yes, this is wrong. In this context (process context, not softirq), we
> > should use netif_rx() or just drop frames if we are in reset phase.
> >
>
> Sergey,
>
> Here is a compiled but untested patch (I dont have the hardware), could
> you please test it ?
>
> Thanks
>
> [PATCH] r8169: Fix rtl8169_rx_interrupt()
>
> In case a reset is performed, rtl8169_rx_interrupt() is called from
> process context instead of softirq context. Special care must be taken
> to call appropriate network core services (netif_rx() instead of
> netif_receive_skb()). VLAN handling also corrected.
>
> Reported-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
> Diagnosed-by: Oleg Nesterov <oleg@redhat.com>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> ---
> diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
> index 9d3ebf3..d873639 100644
> --- a/drivers/net/r8169.c
> +++ b/drivers/net/r8169.c
> @@ -1038,14 +1038,14 @@ static void rtl8169_vlan_rx_register(struct net_device *dev,
> }
>
> static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
> - struct sk_buff *skb)
> + struct sk_buff *skb, int polling)
> {
> u32 opts2 = le32_to_cpu(desc->opts2);
> struct vlan_group *vlgrp = tp->vlgrp;
> int ret;
>
> if (vlgrp && (opts2 & RxVlanTag)) {
> - vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff));
> + __vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling);
> ret = 0;
> } else
> ret = -1;
> @@ -1062,7 +1062,7 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
> }
>
> static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
> - struct sk_buff *skb)
> + struct sk_buff *skb, int polling)
> {
> return -1;
> }
> @@ -4429,12 +4429,20 @@ out:
> return done;
> }
>
> +/*
> + * Warning : rtl8169_rx_interrupt() might be called :
> + * 1) from NAPI (softirq) context
> + * (polling = 1 : we should call netif_receive_skb())
> + * 2) from process context (rtl8169_reset_task())
> + * (polling = 0 : we must call netif_rx() instead)
> + */
> static int rtl8169_rx_interrupt(struct net_device *dev,
> struct rtl8169_private *tp,
> void __iomem *ioaddr, u32 budget)
> {
> unsigned int cur_rx, rx_left;
> unsigned int delta, count;
> + int polling = (budget != ~(u32)0) ? 1 : 0;
>
> cur_rx = tp->cur_rx;
> rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
> @@ -4496,8 +4504,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
> skb_put(skb, pkt_size);
> skb->protocol = eth_type_trans(skb, dev);
>
> - if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0)
> - netif_receive_skb(skb);
> + if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) {
> + if (likely(polling))
> + netif_receive_skb(skb);
> + else
> + netif_rx(skb);
> + }
>
> dev->stats.rx_bytes += pkt_size;
> dev->stats.rx_packets++;
>
>
[-- Attachment #2: Type: application/pgp-signature, Size: 316 bytes --]
^ permalink raw reply
* Re: [RFC PATCH net-2.6 0/3] ipv6 mcast: Introduce include/net/mld.h for MLD definitions.
From: YOSHIFUJI Hideaki @ 2010-03-16 5:31 UTC (permalink / raw)
To: YOSHIFUJI Hideaki; +Cc: davem, netdev
In-Reply-To: <201003160527.o2G5R4MQ010839@94.43.138.210.xn.2iij.net>
Oops, this should have 1/3 instead of 0/3 in subject...
(2010/03/16 14:27), YOSHIFUJI Hideaki wrote:
> Signed-off-by: YOSHIFUJI Hideaki<yoshfuji@linux-ipv6.org>
> ---
> include/net/mld.h | 75 +++++++++++++++++++++++++++++
> net/ipv6/mcast.c | 135 ++++++++++++++++-------------------------------------
> 2 files changed, 115 insertions(+), 95 deletions(-)
> create mode 100644 include/net/mld.h
--yoshfuji
^ permalink raw reply
* [RFC PATCH net-2.6 3/3] bridge br_multicast: IPv6 MLD support.
From: YOSHIFUJI Hideaki @ 2010-03-16 5:27 UTC (permalink / raw)
To: davem; +Cc: yoshfuji, netdev
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
net/bridge/Kconfig | 6 +-
net/bridge/br_multicast.c | 401 +++++++++++++++++++++++++++++++++++++++++++++
net/bridge/br_private.h | 3 +
3 files changed, 407 insertions(+), 3 deletions(-)
diff --git a/net/bridge/Kconfig b/net/bridge/Kconfig
index d115d5c..9190ae4 100644
--- a/net/bridge/Kconfig
+++ b/net/bridge/Kconfig
@@ -33,14 +33,14 @@ config BRIDGE
If unsure, say N.
config BRIDGE_IGMP_SNOOPING
- bool "IGMP snooping"
+ bool "IGMP/MLD snooping"
depends on BRIDGE
depends on INET
default y
---help---
If you say Y here, then the Ethernet bridge will be able selectively
- forward multicast traffic based on IGMP traffic received from each
- port.
+ forward multicast traffic based on IGMP/MLD traffic received from
+ each port.
Say N to exclude this support and reduce the binary size.
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index dad364b..067c23d 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -24,6 +24,8 @@
#include <linux/slab.h>
#include <linux/timer.h>
#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/mld.h>
#include "br_private.h"
@@ -32,6 +34,17 @@
.proto = htons(ETH_P_IP), \
}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#define IP6_BRIP(ip) (struct br_ip) { \
+ .u.ip6 = *ip, \
+ .proto = htons(ETH_P_IPV6), \
+ }
+static inline int ipv6_addr_is_mc_linklocal(const struct in6_addr *addr)
+{
+ return addr->s6_addr16[0] == htons(0xff02);
+}
+#endif
+
static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
{
if (a->proto != b->proto)
@@ -39,6 +52,10 @@ static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
switch (a->proto) {
case htons(ETH_P_IP):
return a->u.ip4 == b->u.ip4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case htons(ETH_P_IPV6):
+ return ipv6_addr_equal(&a->u.ip6, &b->u.ip6);
+#endif
}
return 0;
}
@@ -48,12 +65,24 @@ static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip)
return jhash_1word(mdb->secret, (u32)ip) & (mdb->max - 1);
}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static inline int __br_ip6_hash(struct net_bridge_mdb_htable *mdb,
+ const struct in6_addr *ip)
+{
+ return jhash2(ip->s6_addr32, 4, mdb->secret) & (mdb->max - 1);
+}
+#endif
+
static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb,
struct br_ip *ip)
{
switch (ip->proto) {
case htons(ETH_P_IP):
return __br_ip4_hash(mdb, ip->u.ip4);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case htons(ETH_P_IPV6):
+ return __br_ip6_hash(mdb, &ip->u.ip6);
+#endif
}
return 0;
}
@@ -78,6 +107,14 @@ static struct net_bridge_mdb_entry *br_mdb_ip4_get(
return __br_mdb_ip_get(mdb, &IP4_BRIP(dst), __br_ip4_hash(mdb, dst));
}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static struct net_bridge_mdb_entry *br_mdb_ip6_get(
+ struct net_bridge_mdb_htable *mdb, const struct in6_addr *dst)
+{
+ return __br_mdb_ip_get(mdb, &IP6_BRIP(dst), __br_ip6_hash(mdb, dst));
+}
+#endif
+
static struct net_bridge_mdb_entry *br_mdb_ip_get(
struct net_bridge_mdb_htable *mdb, struct br_ip *dst)
{
@@ -102,6 +139,11 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
case htons(ETH_P_IP):
ip.u.ip4 = ip_hdr(skb)->daddr;
break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case htons(ETH_P_IPV6):
+ ipv6_addr_copy(&ip.u.ip6, &ipv6_hdr(skb)->daddr);
+ break;
+#endif
default:
return NULL;
}
@@ -352,12 +394,95 @@ out:
return skb;
}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
+ struct in6_addr *group)
+{
+ struct sk_buff *skb;
+ struct ipv6hdr *ip6h;
+ struct mld_msg *mldq;
+ struct ethhdr *eth;
+ u8 *hopopt;
+ unsigned long interval;
+
+ skb = netdev_alloc_skb_ip_align(br->dev, sizeof(*eth) + sizeof(*ip6h) +
+ 8 + sizeof(*mldq));
+ if (!skb)
+ goto out;
+
+ skb->protocol = htons(ETH_P_IPV6);
+
+ /* Ethernet header */
+ skb_reset_mac_header(skb);
+ eth = eth_hdr(skb);
+
+ memcpy(eth->h_source, br->dev->dev_addr, 6);
+ ipv6_eth_mc_map(group, eth->h_dest);
+ eth->h_proto = htons(ETH_P_IPV6);
+ skb_put(skb, sizeof(*eth));
+
+ /* IPv6 header + HbH option */
+ skb_set_network_header(skb, skb->len);
+ ip6h = ipv6_hdr(skb);
+
+ *(__force __be32 *)ip6h = htonl(0x60000000);
+ ip6h->payload_len = 8 + sizeof(*mldq);
+ ip6h->nexthdr = IPPROTO_HOPOPTS;
+ ip6h->hop_limit = 1;
+ ipv6_addr_copy(&ip6h->saddr, &in6addr_any);
+ ipv6_addr_copy(&ip6h->daddr, &in6addr_linklocal_allnodes);
+ ipv6_addr_copy(&ip6h->daddr, group);
+
+ hopopt = (u8 *)(ip6h + 1);
+ hopopt[0] = IPPROTO_ICMPV6; /* next hdr */
+ hopopt[1] = 0; /* length of HbH */
+ hopopt[2] = IPV6_TLV_ROUTERALERT; /* Router Alert */
+ hopopt[3] = 2; /* Length of RA Option */
+ hopopt[4] = 0; /* Type = 0x0000 (MLD) */
+ hopopt[5] = 0;
+ hopopt[6] = IPV6_TLV_PAD0; /* Pad0 */
+ hopopt[7] = IPV6_TLV_PAD0; /* Pad0 */
+
+ skb_put(skb, sizeof(*ip6h) + 8);
+
+ /* ICMPv6 */
+ skb_set_transport_header(skb, skb->len);
+ mldq = (struct mld_msg *) icmp6_hdr(skb);
+
+ interval = ipv6_addr_any(group) ? br->multicast_last_member_interval :
+ br->multicast_query_response_interval;
+
+ mldq->mld_type = ICMPV6_MGM_QUERY;
+ mldq->mld_code = 0;
+ mldq->mld_cksum = 0;
+ mldq->mld_maxdelay = htons((u16)jiffies_to_msecs(interval));
+ mldq->mld_reserved = 0;
+ ipv6_addr_copy(&mldq->mld_mca, group);
+
+ /* checksum */
+ mldq->mld_cksum = csum_ipv6_magic(&in6addr_any, group,
+ sizeof(*mldq), IPPROTO_ICMPV6,
+ csum_partial(mldq,
+ sizeof(*mldq), 0));
+ skb_put(skb, sizeof(*mldq));
+
+ __skb_pull(skb, sizeof(*eth));
+
+out:
+ return skb;
+}
+#endif
+
static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
struct br_ip *addr)
{
switch (addr->proto) {
case htons(ETH_P_IP):
return br_ip4_multicast_alloc_query(br, addr->u.ip4);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case htons(ETH_P_IPV6):
+ return br_ip6_multicast_alloc_query(br, &addr->u.ip6);
+#endif
}
return NULL;
}
@@ -625,6 +750,17 @@ static int br_ip4_multicast_add_group(struct net_bridge *br,
return br_multicast_add_group(br, port, &IP4_BRIP(group));
}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int br_ip6_multicast_add_group(struct net_bridge *br,
+ struct net_bridge_port *port,
+ const struct in6_addr *group)
+{
+ if (ipv6_addr_is_mc_linklocal(group))
+ return 0;
+ return br_multicast_add_group(br, port, &IP6_BRIP(group));
+}
+#endif
+
static void br_multicast_router_expired(unsigned long data)
{
struct net_bridge_port *port = (void *)data;
@@ -675,6 +811,9 @@ static void br_multicast_send_query(struct net_bridge *br,
return;
__br_multicast_send_query(br, port, &IP4_BRIP(0));
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ __br_multicast_send_query(br, port, &IP6_BRIP(&in6addr_any));
+#endif
time = jiffies;
time += sent < br->multicast_startup_query_count ?
@@ -815,6 +954,65 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
return err;
}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int br_ip6_multicast_mld2_report(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct sk_buff *skb)
+{
+ struct icmp6hdr *icmp6h;
+ struct mld2_grec *grec;
+ int i;
+ int len;
+ int num;
+ int err = 0;
+
+ if (!pskb_may_pull(skb, sizeof(*icmp6h)))
+ return -EINVAL;
+
+ icmp6h = icmp6_hdr(skb);
+ num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
+ len = sizeof(*icmp6h);
+
+ for (i = 0; i < num; i++) {
+ __be16 *nsrcs, _nsrcs;
+
+ nsrcs = skb_header_pointer(skb,
+ len + offsetof(struct mld2_grec,
+ grec_mca),
+ sizeof(_nsrcs), &_nsrcs);
+ if (!nsrcs)
+ return -EINVAL;
+
+ len += sizeof(*grec) + sizeof(struct in6_addr) * (*nsrcs);
+ if (!pskb_may_pull(skb, len))
+ return -EINVAL;
+
+ grec = (struct mld2_grec *)(skb->data + len);
+ len += sizeof(struct in6_addr) * (*nsrcs);
+
+ /* We treat these as MLDv1 reports for now. */
+ switch (grec->grec_type) {
+ case MLD2_MODE_IS_INCLUDE:
+ case MLD2_MODE_IS_EXCLUDE:
+ case MLD2_CHANGE_TO_INCLUDE:
+ case MLD2_CHANGE_TO_EXCLUDE:
+ case MLD2_ALLOW_NEW_SOURCES:
+ case MLD2_BLOCK_OLD_SOURCES:
+ break;
+
+ default:
+ continue;
+ }
+
+ err = br_ip6_multicast_add_group(br, port, &grec->grec_mca);
+ if (!err)
+ break;
+ }
+
+ return err;
+}
+#endif
+
static void br_multicast_add_router(struct net_bridge *br,
struct net_bridge_port *port)
{
@@ -945,6 +1143,75 @@ out:
return err;
}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int br_ip6_multicast_query(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct sk_buff *skb)
+{
+ struct ipv6hdr *ip6h = ipv6_hdr(skb);
+ struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb);
+ struct net_bridge_mdb_entry *mp;
+ struct mld2_query *mld2q;
+ struct net_bridge_port_group *p, **pp;
+ unsigned long max_delay;
+ unsigned long now = jiffies;
+ struct in6_addr *group = NULL;
+ int err = 0;
+
+ spin_lock(&br->multicast_lock);
+ if (!netif_running(br->dev) ||
+ (port && port->state == BR_STATE_DISABLED))
+ goto out;
+
+ br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr));
+
+ if (skb->len == sizeof(*mld)) {
+ if (!pskb_may_pull(skb, sizeof(*mld))) {
+ err = -EINVAL;
+ goto out;
+ }
+ mld = (struct mld_msg *) icmp6_hdr(skb);
+ max_delay = msecs_to_jiffies(htons(mld->mld_maxdelay));
+ if (max_delay)
+ group = &mld->mld_mca;
+ } else if (skb->len >= sizeof(*mld2q)) {
+ if (!pskb_may_pull(skb, sizeof(*mld2q))) {
+ err = -EINVAL;
+ goto out;
+ }
+ mld2q = (struct mld2_query *)icmp6_hdr(skb);
+ if (!mld2q->mld2q_nsrcs)
+ group = &mld2q->mld2q_mca;
+ max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(mld2q->mld2q_mrc) : 1;
+ }
+
+ if (!group)
+ goto out;
+
+ mp = br_mdb_ip6_get(br->mdb, group);
+ if (!mp)
+ goto out;
+
+ max_delay *= br->multicast_last_member_count;
+ if (!hlist_unhashed(&mp->mglist) &&
+ (timer_pending(&mp->timer) ?
+ time_after(mp->timer.expires, now + max_delay) :
+ try_to_del_timer_sync(&mp->timer) >= 0))
+ mod_timer(&mp->timer, now + max_delay);
+
+ for (pp = &mp->ports; (p = *pp); pp = &p->next) {
+ if (timer_pending(&p->timer) ?
+ time_after(p->timer.expires, now + max_delay) :
+ try_to_del_timer_sync(&p->timer) >= 0)
+ mod_timer(&mp->timer, now + max_delay);
+ }
+
+out:
+ spin_unlock(&br->multicast_lock);
+ return err;
+}
+#endif
+
static void br_multicast_leave_group(struct net_bridge *br,
struct net_bridge_port *port,
struct br_ip *group)
@@ -1014,6 +1281,16 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
br_multicast_leave_group(br, port, &IP4_BRIP(group));
}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static void br_ip6_multicast_leave_group(struct net_bridge *br,
+ struct net_bridge_port *port,
+ const struct in6_addr *group)
+{
+ if (ipv6_addr_is_mc_linklocal(group))
+ return;
+ br_multicast_leave_group(br, port, &IP6_BRIP(group));
+}
+#endif
static int br_multicast_ipv4_rcv(struct net_bridge *br,
struct net_bridge_port *port,
@@ -1115,6 +1392,126 @@ err_out:
return err;
}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int br_multicast_ipv6_rcv(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct sk_buff *skb)
+{
+ struct sk_buff *skb2 = skb;
+ struct ipv6hdr *ip6h;
+ struct icmp6hdr *icmp6h;
+ u8 nexthdr;
+ unsigned len;
+ unsigned offset;
+ int err;
+
+ BR_INPUT_SKB_CB(skb)->igmp = 0;
+ BR_INPUT_SKB_CB(skb)->mrouters_only = 0;
+
+ if (!pskb_may_pull(skb, sizeof(*ip6h)))
+ return -EINVAL;
+
+ ip6h = ipv6_hdr(skb);
+
+ /*
+ * We're interested in MLD messages only.
+ * - Version is 6
+ * - MLD has always Router Alert hop-by-hop option
+ * - But we do not support jumbrograms.
+ */
+ if (ip6h->version != 6 ||
+ ip6h->nexthdr != IPPROTO_HOPOPTS ||
+ ip6h->payload_len == 0)
+ return 0;
+
+ len = ntohs(ip6h->payload_len);
+ if (skb->len < len)
+ return -EINVAL;
+
+ nexthdr = ip6h->nexthdr;
+ offset = ipv6_skip_exthdr(skb, sizeof(*ip6h), &nexthdr);
+
+ if (offset < 0 || nexthdr != IPPROTO_ICMPV6)
+ return 0;
+
+ /* Okay, we found ICMPv6 header */
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (!skb2)
+ return -ENOMEM;
+
+ len -= offset - skb_network_offset(skb2);
+
+ __skb_pull(skb2, offset);
+ skb_reset_transport_header(skb2);
+
+ err = -EINVAL;
+ if (!pskb_may_pull(skb2, sizeof(*icmp6h)))
+ goto out;
+
+ icmp6h = icmp6_hdr(skb2);
+
+ switch (icmp6h->icmp6_type) {
+ case ICMPV6_MGM_QUERY:
+ case ICMPV6_MGM_REPORT:
+ case ICMPV6_MGM_REDUCTION:
+ case ICMPV6_MLD2_REPORT:
+ break;
+ default:
+ err = 0;
+ goto out;
+ }
+
+ /* Okay, we found MLD message. Check further. */
+ if (skb2->len > len) {
+ err = pskb_trim_rcsum(skb2, len);
+ if (err)
+ goto out;
+ }
+
+ switch (skb2->ip_summed) {
+ case CHECKSUM_COMPLETE:
+ if (!csum_fold(skb2->csum))
+ break;
+ /*FALLTHROUGH*/
+ case CHECKSUM_NONE:
+ skb2->csum = 0;
+ if (skb_checksum_complete(skb2))
+ goto out;
+ }
+
+ err = 0;
+
+ BR_INPUT_SKB_CB(skb)->igmp = 1;
+
+ switch (icmp6h->icmp6_type) {
+ case ICMPV6_MGM_REPORT:
+ {
+ struct mld_msg *mld = (struct mld_msg *)icmp6h;
+ BR_INPUT_SKB_CB(skb2)->mrouters_only = 1;
+ err = br_ip6_multicast_add_group(br, port, &mld->mld_mca);
+ break;
+ }
+ case ICMPV6_MLD2_REPORT:
+ err = br_ip6_multicast_mld2_report(br, port, skb2);
+ break;
+ case ICMPV6_MGM_QUERY:
+ err = br_ip6_multicast_query(br, port, skb2);
+ break;
+ case ICMPV6_MGM_REDUCTION:
+ {
+ struct mld_msg *mld = (struct mld_msg *)icmp6h;
+ br_ip6_multicast_leave_group(br, port, &mld->mld_mca);
+ }
+ }
+
+out:
+ __skb_push(skb2, offset);
+ if (skb2 != skb)
+ kfree_skb(skb2);
+ return err;
+}
+#endif
+
int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
struct sk_buff *skb)
{
@@ -1124,6 +1521,10 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
switch (skb->protocol) {
case htons(ETH_P_IP):
return br_multicast_ipv4_rcv(br, port, skb);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case htons(ETH_P_IPV6):
+ return br_multicast_ipv6_rcv(br, port, skb);
+#endif
}
return 0;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 10e93bf..6f65675 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -49,6 +49,9 @@ struct br_ip
{
union {
__be32 ip4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct in6_addr ip6;
+#endif
} u;
__be16 proto;
};
--
1.5.6.5
^ permalink raw reply related
* [RFC PATCH net-2.6 2/3] bridge br_multicast: Make functions less ipv4 dependent.
From: YOSHIFUJI Hideaki @ 2010-03-16 5:27 UTC (permalink / raw)
To: davem; +Cc: yoshfuji, netdev
Introduce struct br_ip{} to store ip address and protocol
and make functions more generic so that we can support
both IPv4 and IPv6 with less pain.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
net/bridge/br_multicast.c | 176 +++++++++++++++++++++++++++++++--------------
net/bridge/br_private.h | 12 +++-
2 files changed, 133 insertions(+), 55 deletions(-)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index bbbd996..dad364b 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -27,28 +27,60 @@
#include "br_private.h"
-static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb, __be32 ip)
+#define IP4_BRIP(ip) (struct br_ip) { \
+ .u.ip4 = ip, \
+ .proto = htons(ETH_P_IP), \
+ }
+
+static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
+{
+ if (a->proto != b->proto)
+ return 0;
+ switch (a->proto) {
+ case htons(ETH_P_IP):
+ return a->u.ip4 == b->u.ip4;
+ }
+ return 0;
+}
+
+static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip)
{
return jhash_1word(mdb->secret, (u32)ip) & (mdb->max - 1);
}
+static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb,
+ struct br_ip *ip)
+{
+ switch (ip->proto) {
+ case htons(ETH_P_IP):
+ return __br_ip4_hash(mdb, ip->u.ip4);
+ }
+ return 0;
+}
+
static struct net_bridge_mdb_entry *__br_mdb_ip_get(
- struct net_bridge_mdb_htable *mdb, __be32 dst, int hash)
+ struct net_bridge_mdb_htable *mdb, struct br_ip *dst, int hash)
{
struct net_bridge_mdb_entry *mp;
struct hlist_node *p;
hlist_for_each_entry_rcu(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) {
- if (dst == mp->addr)
+ if (br_ip_equal(&mp->addr, dst))
return mp;
}
return NULL;
}
-static struct net_bridge_mdb_entry *br_mdb_ip_get(
+static struct net_bridge_mdb_entry *br_mdb_ip4_get(
struct net_bridge_mdb_htable *mdb, __be32 dst)
{
+ return __br_mdb_ip_get(mdb, &IP4_BRIP(dst), __br_ip4_hash(mdb, dst));
+}
+
+static struct net_bridge_mdb_entry *br_mdb_ip_get(
+ struct net_bridge_mdb_htable *mdb, struct br_ip *dst)
+{
return __br_mdb_ip_get(mdb, dst, br_ip_hash(mdb, dst));
}
@@ -56,18 +88,25 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
struct sk_buff *skb)
{
struct net_bridge_mdb_htable *mdb = br->mdb;
+ struct br_ip ip;
if (!mdb || br->multicast_disabled)
return NULL;
+ if (BR_INPUT_SKB_CB(skb)->igmp)
+ return NULL;
+
+ ip.proto = skb->protocol;
+
switch (skb->protocol) {
case htons(ETH_P_IP):
- if (BR_INPUT_SKB_CB(skb)->igmp)
- break;
- return br_mdb_ip_get(mdb, ip_hdr(skb)->daddr);
+ ip.u.ip4 = ip_hdr(skb)->daddr;
+ break;
+ default:
+ return NULL;
}
- return NULL;
+ return br_mdb_ip_get(mdb, &ip);
}
static void br_mdb_free(struct rcu_head *head)
@@ -94,7 +133,7 @@ static int br_mdb_copy(struct net_bridge_mdb_htable *new,
for (i = 0; i < old->max; i++)
hlist_for_each_entry(mp, p, &old->mhash[i], hlist[old->ver])
hlist_add_head(&mp->hlist[new->ver],
- &new->mhash[br_ip_hash(new, mp->addr)]);
+ &new->mhash[br_ip_hash(new, &mp->addr)]);
if (!elasticity)
return 0;
@@ -162,7 +201,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
struct net_bridge_port_group *p;
struct net_bridge_port_group **pp;
- mp = br_mdb_ip_get(mdb, pg->addr);
+ mp = br_mdb_ip_get(mdb, &pg->addr);
if (WARN_ON(!mp))
return;
@@ -248,8 +287,8 @@ out:
return 0;
}
-static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
- __be32 group)
+static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
+ __be32 group)
{
struct sk_buff *skb;
struct igmphdr *ih;
@@ -313,12 +352,22 @@ out:
return skb;
}
+static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
+ struct br_ip *addr)
+{
+ switch (addr->proto) {
+ case htons(ETH_P_IP):
+ return br_ip4_multicast_alloc_query(br, addr->u.ip4);
+ }
+ return NULL;
+}
+
static void br_multicast_send_group_query(struct net_bridge_mdb_entry *mp)
{
struct net_bridge *br = mp->br;
struct sk_buff *skb;
- skb = br_multicast_alloc_query(br, mp->addr);
+ skb = br_multicast_alloc_query(br, &mp->addr);
if (!skb)
goto timer;
@@ -352,7 +401,7 @@ static void br_multicast_send_port_group_query(struct net_bridge_port_group *pg)
struct net_bridge *br = port->br;
struct sk_buff *skb;
- skb = br_multicast_alloc_query(br, pg->addr);
+ skb = br_multicast_alloc_query(br, &pg->addr);
if (!skb)
goto timer;
@@ -382,8 +431,8 @@ out:
}
static struct net_bridge_mdb_entry *br_multicast_get_group(
- struct net_bridge *br, struct net_bridge_port *port, __be32 group,
- int hash)
+ struct net_bridge *br, struct net_bridge_port *port,
+ struct br_ip *group, int hash)
{
struct net_bridge_mdb_htable *mdb = br->mdb;
struct net_bridge_mdb_entry *mp;
@@ -395,9 +444,8 @@ static struct net_bridge_mdb_entry *br_multicast_get_group(
hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) {
count++;
- if (unlikely(group == mp->addr)) {
+ if (unlikely(br_ip_equal(group, &mp->addr)))
return mp;
- }
}
elasticity = 0;
@@ -462,7 +510,8 @@ err:
}
static struct net_bridge_mdb_entry *br_multicast_new_group(
- struct net_bridge *br, struct net_bridge_port *port, __be32 group)
+ struct net_bridge *br, struct net_bridge_port *port,
+ struct br_ip *group)
{
struct net_bridge_mdb_htable *mdb = br->mdb;
struct net_bridge_mdb_entry *mp;
@@ -495,7 +544,7 @@ rehash:
goto out;
mp->br = br;
- mp->addr = group;
+ mp->addr = *group;
setup_timer(&mp->timer, br_multicast_group_expired,
(unsigned long)mp);
setup_timer(&mp->query_timer, br_multicast_group_query_expired,
@@ -509,7 +558,8 @@ out:
}
static int br_multicast_add_group(struct net_bridge *br,
- struct net_bridge_port *port, __be32 group)
+ struct net_bridge_port *port,
+ struct br_ip *group)
{
struct net_bridge_mdb_entry *mp;
struct net_bridge_port_group *p;
@@ -517,9 +567,6 @@ static int br_multicast_add_group(struct net_bridge *br,
unsigned long now = jiffies;
int err;
- if (ipv4_is_local_multicast(group))
- return 0;
-
spin_lock(&br->multicast_lock);
if (!netif_running(br->dev) ||
(port && port->state == BR_STATE_DISABLED))
@@ -548,7 +595,7 @@ static int br_multicast_add_group(struct net_bridge *br,
if (unlikely(!p))
goto err;
- p->addr = group;
+ p->addr = *group;
p->port = port;
p->next = *pp;
hlist_add_head(&p->mglist, &port->mglist);
@@ -569,6 +616,15 @@ err:
return err;
}
+static int br_ip4_multicast_add_group(struct net_bridge *br,
+ struct net_bridge_port *port,
+ __be32 group)
+{
+ if (ipv4_is_local_multicast(group))
+ return 0;
+ return br_multicast_add_group(br, port, &IP4_BRIP(group));
+}
+
static void br_multicast_router_expired(unsigned long data)
{
struct net_bridge_port *port = (void *)data;
@@ -590,19 +646,15 @@ static void br_multicast_local_router_expired(unsigned long data)
{
}
-static void br_multicast_send_query(struct net_bridge *br,
- struct net_bridge_port *port, u32 sent)
+static void __br_multicast_send_query(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct br_ip *ip)
{
- unsigned long time;
struct sk_buff *skb;
- if (!netif_running(br->dev) || br->multicast_disabled ||
- timer_pending(&br->multicast_querier_timer))
- return;
-
- skb = br_multicast_alloc_query(br, 0);
+ skb = br_multicast_alloc_query(br, ip);
if (!skb)
- goto timer;
+ return;
if (port) {
__skb_push(skb, sizeof(struct ethhdr));
@@ -611,8 +663,19 @@ static void br_multicast_send_query(struct net_bridge *br,
dev_queue_xmit);
} else
netif_rx(skb);
+}
+
+static void br_multicast_send_query(struct net_bridge *br,
+ struct net_bridge_port *port, u32 sent)
+{
+ unsigned long time;
+
+ if (!netif_running(br->dev) || br->multicast_disabled ||
+ timer_pending(&br->multicast_querier_timer))
+ return;
+
+ __br_multicast_send_query(br, port, &IP4_BRIP(0));
-timer:
time = jiffies;
time += sent < br->multicast_startup_query_count ?
br->multicast_startup_query_interval :
@@ -697,9 +760,9 @@ void br_multicast_disable_port(struct net_bridge_port *port)
spin_unlock(&br->multicast_lock);
}
-static int br_multicast_igmp3_report(struct net_bridge *br,
- struct net_bridge_port *port,
- struct sk_buff *skb)
+static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct sk_buff *skb)
{
struct igmpv3_report *ih;
struct igmpv3_grec *grec;
@@ -744,7 +807,7 @@ static int br_multicast_igmp3_report(struct net_bridge *br,
continue;
}
- err = br_multicast_add_group(br, port, group);
+ err = br_ip4_multicast_add_group(br, port, group);
if (err)
break;
}
@@ -799,7 +862,7 @@ timer:
static void br_multicast_query_received(struct net_bridge *br,
struct net_bridge_port *port,
- __be32 saddr)
+ int saddr)
{
if (saddr)
mod_timer(&br->multicast_querier_timer,
@@ -810,9 +873,9 @@ static void br_multicast_query_received(struct net_bridge *br,
br_multicast_mark_router(br, port);
}
-static int br_multicast_query(struct net_bridge *br,
- struct net_bridge_port *port,
- struct sk_buff *skb)
+static int br_ip4_multicast_query(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
struct igmphdr *ih = igmp_hdr(skb);
@@ -830,7 +893,7 @@ static int br_multicast_query(struct net_bridge *br,
(port && port->state == BR_STATE_DISABLED))
goto out;
- br_multicast_query_received(br, port, iph->saddr);
+ br_multicast_query_received(br, port, !!iph->saddr);
group = ih->group;
@@ -858,7 +921,7 @@ static int br_multicast_query(struct net_bridge *br,
if (!group)
goto out;
- mp = br_mdb_ip_get(br->mdb, group);
+ mp = br_mdb_ip4_get(br->mdb, group);
if (!mp)
goto out;
@@ -884,7 +947,7 @@ out:
static void br_multicast_leave_group(struct net_bridge *br,
struct net_bridge_port *port,
- __be32 group)
+ struct br_ip *group)
{
struct net_bridge_mdb_htable *mdb;
struct net_bridge_mdb_entry *mp;
@@ -892,9 +955,6 @@ static void br_multicast_leave_group(struct net_bridge *br,
unsigned long now;
unsigned long time;
- if (ipv4_is_local_multicast(group))
- return;
-
spin_lock(&br->multicast_lock);
if (!netif_running(br->dev) ||
(port && port->state == BR_STATE_DISABLED) ||
@@ -945,6 +1005,16 @@ out:
spin_unlock(&br->multicast_lock);
}
+static void br_ip4_multicast_leave_group(struct net_bridge *br,
+ struct net_bridge_port *port,
+ __be32 group)
+{
+ if (ipv4_is_local_multicast(group))
+ return;
+ br_multicast_leave_group(br, port, &IP4_BRIP(group));
+}
+
+
static int br_multicast_ipv4_rcv(struct net_bridge *br,
struct net_bridge_port *port,
struct sk_buff *skb)
@@ -1024,16 +1094,16 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMPV2_HOST_MEMBERSHIP_REPORT:
BR_INPUT_SKB_CB(skb2)->mrouters_only = 1;
- err = br_multicast_add_group(br, port, ih->group);
+ err = br_ip4_multicast_add_group(br, port, ih->group);
break;
case IGMPV3_HOST_MEMBERSHIP_REPORT:
- err = br_multicast_igmp3_report(br, port, skb2);
+ err = br_ip4_multicast_igmp3_report(br, port, skb2);
break;
case IGMP_HOST_MEMBERSHIP_QUERY:
- err = br_multicast_query(br, port, skb2);
+ err = br_ip4_multicast_query(br, port, skb2);
break;
case IGMP_HOST_LEAVE_MESSAGE:
- br_multicast_leave_group(br, port, ih->group);
+ br_ip4_multicast_leave_group(br, port, ih->group);
break;
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 1cf2cef..10e93bf 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -45,6 +45,14 @@ struct mac_addr
unsigned char addr[6];
};
+struct br_ip
+{
+ union {
+ __be32 ip4;
+ } u;
+ __be16 proto;
+};
+
struct net_bridge_fdb_entry
{
struct hlist_node hlist;
@@ -64,7 +72,7 @@ struct net_bridge_port_group {
struct rcu_head rcu;
struct timer_list timer;
struct timer_list query_timer;
- __be32 addr;
+ struct br_ip addr;
u32 queries_sent;
};
@@ -77,7 +85,7 @@ struct net_bridge_mdb_entry
struct rcu_head rcu;
struct timer_list timer;
struct timer_list query_timer;
- __be32 addr;
+ struct br_ip addr;
u32 queries_sent;
};
--
1.5.6.5
^ permalink raw reply related
* [RFC PATCH net-2.6 0/3] ipv6 mcast: Introduce include/net/mld.h for MLD definitions.
From: YOSHIFUJI Hideaki @ 2010-03-16 5:27 UTC (permalink / raw)
To: davem; +Cc: yoshfuji, netdev
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
include/net/mld.h | 75 +++++++++++++++++++++++++++++
net/ipv6/mcast.c | 135 ++++++++++++++++-------------------------------------
2 files changed, 115 insertions(+), 95 deletions(-)
create mode 100644 include/net/mld.h
diff --git a/include/net/mld.h b/include/net/mld.h
new file mode 100644
index 0000000..ecc7553
--- /dev/null
+++ b/include/net/mld.h
@@ -0,0 +1,75 @@
+#ifndef LINUX_MLD_H
+#define LINUX_MLD_H
+
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+
+/* MLDv1 Query/Report/Done */
+struct mld_msg {
+ struct icmp6hdr mld_hdr;
+ struct in6_addr mld_mca;
+};
+
+#define mld_type mld_hdr.icmp6_type
+#define mld_code mld_hdr.icmp6_code
+#define mld_cksum mld_hdr.icmp6_cksum
+#define mld_maxdelay mld_hdr.icmp6_maxdelay
+#define mld_reserved mld_hdr.icmp6_dataun.un_data16[1]
+
+/* Multicast Listener Discovery version 2 headers */
+/* MLDv2 Report */
+struct mld2_grec {
+ __u8 grec_type;
+ __u8 grec_auxwords;
+ __be16 grec_nsrcs;
+ struct in6_addr grec_mca;
+ struct in6_addr grec_src[0];
+};
+
+struct mld2_report {
+ struct icmp6hdr mld2r_hdr;
+ struct mld2_grec mld2r_grec[0];
+};
+
+#define mld2r_type mld2r_hdr.icmp6_type
+#define mld2r_resv1 mld2r_hdr.icmp6_code
+#define mld2r_cksum mld2r_hdr.icmp6_cksum
+#define mld2r_resv2 mld2r_hdr.icmp6_dataun.un_data16[0]
+#define mld2r_ngrec mld2r_hdr.icmp6_dataun.un_data16[1]
+
+/* MLDv2 Query */
+struct mld2_query {
+ struct icmp6hdr mld2q_hdr;
+ struct in6_addr mld2q_mca;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 mld2q_qrv:3,
+ mld2q_suppress:1,
+ mld2q_resv2:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 mld2q_resv2:4,
+ mld2q_suppress:1,
+ mld2q_qrv:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 mld2q_qqic;
+ __be16 mld2q_nsrcs;
+ struct in6_addr mld2q_srcs[0];
+};
+
+#define mld2q_type mld2q_hdr.icmp6_type
+#define mld2q_code mld2q_hdr.icmp6_code
+#define mld2q_cksum mld2q_hdr.icmp6_cksum
+#define mld2q_mrc mld2q_hdr.icmp6_maxdelay
+#define mld2q_resv1 mld2q_hdr.icmp6_dataun.un_data16[1]
+
+/* Max Response Code */
+#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
+#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
+ ((value) < (thresh) ? (value) : \
+ ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
+ (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
+
+#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
+
+#endif
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index bcd9719..9f62278 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -43,6 +43,7 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <net/mld.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
@@ -70,54 +71,11 @@
#define MDBG(x)
#endif
-/*
- * These header formats should be in a separate include file, but icmpv6.h
- * doesn't have in6_addr defined in all cases, there is no __u128, and no
- * other files reference these.
- *
- * +-DLS 4/14/03
- */
-
-/* Multicast Listener Discovery version 2 headers */
-
-struct mld2_grec {
- __u8 grec_type;
- __u8 grec_auxwords;
- __be16 grec_nsrcs;
- struct in6_addr grec_mca;
- struct in6_addr grec_src[0];
-};
-
-struct mld2_report {
- __u8 type;
- __u8 resv1;
- __sum16 csum;
- __be16 resv2;
- __be16 ngrec;
- struct mld2_grec grec[0];
-};
-
-struct mld2_query {
- __u8 type;
- __u8 code;
- __sum16 csum;
- __be16 mrc;
- __be16 resv1;
- struct in6_addr mca;
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 qrv:3,
- suppress:1,
- resv2:4;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u8 resv2:4,
- suppress:1,
- qrv:3;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- __u8 qqic;
- __be16 nsrcs;
- struct in6_addr srcs[0];
+/* Ensure that we have struct in6_addr aligned on 32bit word. */
+static void *__mld2_query_bugs[] __attribute__((__unused__)) = {
+ BUILD_BUG_ON_NULL(offsetof(struct mld2_query, mld2q_srcs) % 4),
+ BUILD_BUG_ON_NULL(offsetof(struct mld2_report, mld2r_grec) % 4),
+ BUILD_BUG_ON_NULL(offsetof(struct mld2_grec, grec_mca) % 4)
};
static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT;
@@ -156,14 +114,6 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
((idev)->mc_v1_seen && \
time_before(jiffies, (idev)->mc_v1_seen)))
-#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
-#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
- ((value) < (thresh) ? (value) : \
- ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
- (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
-
-#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
-
#define IPV6_MLD_MAX_MSF 64
int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF;
@@ -1160,7 +1110,7 @@ int igmp6_event_query(struct sk_buff *skb)
struct in6_addr *group;
unsigned long max_delay;
struct inet6_dev *idev;
- struct icmp6hdr *hdr;
+ struct mld_msg *mld;
int group_type;
int mark = 0;
int len;
@@ -1181,8 +1131,8 @@ int igmp6_event_query(struct sk_buff *skb)
if (idev == NULL)
return 0;
- hdr = icmp6_hdr(skb);
- group = (struct in6_addr *) (hdr + 1);
+ mld = mld_msg(skb);
+ group = &mld->mld_mca;
group_type = ipv6_addr_type(group);
if (group_type != IPV6_ADDR_ANY &&
@@ -1196,7 +1146,7 @@ int igmp6_event_query(struct sk_buff *skb)
/* MLDv1 router present */
/* Translate milliseconds to jiffies */
- max_delay = (ntohs(hdr->icmp6_maxdelay)*HZ)/1000;
+ max_delay = (ntohs(mld->mld_maxdelay)*HZ)/1000;
switchback = (idev->mc_qrv + 1) * max_delay;
idev->mc_v1_seen = jiffies + switchback;
@@ -1215,14 +1165,14 @@ int igmp6_event_query(struct sk_buff *skb)
return -EINVAL;
}
mlh2 = (struct mld2_query *)skb_transport_header(skb);
- max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000;
+ max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000;
if (!max_delay)
max_delay = 1;
idev->mc_maxdelay = max_delay;
- if (mlh2->qrv)
- idev->mc_qrv = mlh2->qrv;
+ if (mlh2->mld2q_qrv)
+ idev->mc_qrv = mlh2->mld2q_qrv;
if (group_type == IPV6_ADDR_ANY) { /* general query */
- if (mlh2->nsrcs) {
+ if (mlh2->mld2q_nsrcs) {
in6_dev_put(idev);
return -EINVAL; /* no sources allowed */
}
@@ -1231,9 +1181,9 @@ int igmp6_event_query(struct sk_buff *skb)
return 0;
}
/* mark sources to include, if group & source-specific */
- if (mlh2->nsrcs != 0) {
+ if (mlh2->mld2q_nsrcs != 0) {
if (!pskb_may_pull(skb, srcs_offset +
- ntohs(mlh2->nsrcs) * sizeof(struct in6_addr))) {
+ ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr))) {
in6_dev_put(idev);
return -EINVAL;
}
@@ -1269,7 +1219,7 @@ int igmp6_event_query(struct sk_buff *skb)
ma->mca_flags &= ~MAF_GSQUERY;
}
if (!(ma->mca_flags & MAF_GSQUERY) ||
- mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs))
+ mld_marksources(ma, ntohs(mlh2->mld2q_nsrcs), mlh2->mld2q_srcs))
igmp6_group_queried(ma, max_delay);
spin_unlock_bh(&ma->mca_lock);
break;
@@ -1285,9 +1235,8 @@ int igmp6_event_query(struct sk_buff *skb)
int igmp6_event_report(struct sk_buff *skb)
{
struct ifmcaddr6 *ma;
- struct in6_addr *addrp;
struct inet6_dev *idev;
- struct icmp6hdr *hdr;
+ struct mld_msg *mld;
int addr_type;
/* Our own report looped back. Ignore it. */
@@ -1299,10 +1248,10 @@ int igmp6_event_report(struct sk_buff *skb)
skb->pkt_type != PACKET_BROADCAST)
return 0;
- if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
+ if (!pskb_may_pull(skb, sizeof(*mld) - sizeof(struct icmp6hdr)))
return -EINVAL;
- hdr = icmp6_hdr(skb);
+ mld = mld_msg(skb);
/* Drop reports with not link local source */
addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr);
@@ -1310,8 +1259,6 @@ int igmp6_event_report(struct sk_buff *skb)
!(addr_type&IPV6_ADDR_LINKLOCAL))
return -EINVAL;
- addrp = (struct in6_addr *) (hdr + 1);
-
idev = in6_dev_get(skb->dev);
if (idev == NULL)
return -ENODEV;
@@ -1322,7 +1269,7 @@ int igmp6_event_report(struct sk_buff *skb)
read_lock_bh(&idev->lock);
for (ma = idev->mc_list; ma; ma=ma->next) {
- if (ipv6_addr_equal(&ma->mca_addr, addrp)) {
+ if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) {
spin_lock(&ma->mca_lock);
if (del_timer(&ma->mca_timer))
atomic_dec(&ma->mca_refcnt);
@@ -1431,11 +1378,11 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data);
skb_put(skb, sizeof(*pmr));
pmr = (struct mld2_report *)skb_transport_header(skb);
- pmr->type = ICMPV6_MLD2_REPORT;
- pmr->resv1 = 0;
- pmr->csum = 0;
- pmr->resv2 = 0;
- pmr->ngrec = 0;
+ pmr->mld2r_type = ICMPV6_MLD2_REPORT;
+ pmr->mld2r_resv1 = 0;
+ pmr->mld2r_cksum = 0;
+ pmr->mld2r_resv2 = 0;
+ pmr->mld2r_ngrec = 0;
return skb;
}
@@ -1457,9 +1404,10 @@ static void mld_sendpack(struct sk_buff *skb)
mldlen = skb->tail - skb->transport_header;
pip6->payload_len = htons(payload_len);
- pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
- IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb),
- mldlen, 0));
+ pmr->mld2r_cksum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
+ IPPROTO_ICMPV6,
+ csum_partial(skb_transport_header(skb),
+ mldlen, 0));
dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
@@ -1520,7 +1468,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
pgr->grec_nsrcs = 0;
pgr->grec_mca = pmc->mca_addr; /* structure copy */
pmr = (struct mld2_report *)skb_transport_header(skb);
- pmr->ngrec = htons(ntohs(pmr->ngrec)+1);
+ pmr->mld2r_ngrec = htons(ntohs(pmr->mld2r_ngrec)+1);
*ppgr = pgr;
return skb;
}
@@ -1556,7 +1504,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
/* EX and TO_EX get a fresh packet, if needed */
if (truncate) {
- if (pmr && pmr->ngrec &&
+ if (pmr && pmr->mld2r_ngrec &&
AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) {
if (skb)
mld_sendpack(skb);
@@ -1769,9 +1717,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
struct sock *sk = net->ipv6.igmp_sk;
struct inet6_dev *idev;
struct sk_buff *skb;
- struct icmp6hdr *hdr;
+ struct mld_msg *hdr;
const struct in6_addr *snd_addr, *saddr;
- struct in6_addr *addrp;
struct in6_addr addr_buf;
int err, len, payload_len, full_len;
u8 ra[8] = { IPPROTO_ICMPV6, 0,
@@ -1819,16 +1766,14 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
- hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
- memset(hdr, 0, sizeof(struct icmp6hdr));
- hdr->icmp6_type = type;
+ hdr = (struct mld_msg *) skb_put(skb, sizeof(struct mld_msg));
+ memset(hdr, 0, sizeof(struct mld_msg));
+ hdr->mld_type = type;
+ ipv6_addr_copy(&hdr->mld_mca, addr);
- addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
- ipv6_addr_copy(addrp, addr);
-
- hdr->icmp6_cksum = csum_ipv6_magic(saddr, snd_addr, len,
- IPPROTO_ICMPV6,
- csum_partial(hdr, len, 0));
+ hdr->mld_cksum = csum_ipv6_magic(saddr, snd_addr, len,
+ IPPROTO_ICMPV6,
+ csum_partial(hdr, len, 0));
idev = in6_dev_get(skb->dev);
--
1.5.6.5
^ permalink raw reply related
* [PATCH net-2.6] bridge br_multicast: Fix handling of Max Response Code in IGMPv3 message.
From: YOSHIFUJI Hideaki @ 2010-03-16 5:27 UTC (permalink / raw)
To: davem; +Cc: yoshfuji, netdev
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
net/bridge/br_multicast.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 4095192..bbbd996 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -851,8 +851,8 @@ static int br_multicast_query(struct net_bridge *br,
if (ih3->nsrcs)
goto out;
- max_delay = ih3->code ? 1 :
- IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE);
+ max_delay = ih3->code ?
+ IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
}
if (!group)
--
1.5.6.5
^ permalink raw reply related
* [PATCH net-2.6] bridge br_multicast: Fix skb leakage in error path.
From: YOSHIFUJI Hideaki @ 2010-03-16 5:26 UTC (permalink / raw)
To: davem; +Cc: yoshfuji, netdev
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
net/bridge/br_multicast.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index fd96a8d..4095192 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -990,7 +990,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
err = pskb_trim_rcsum(skb2, len);
if (err)
- return err;
+ goto err_out;
}
len -= ip_hdrlen(skb2);
@@ -1012,7 +1012,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
case CHECKSUM_NONE:
skb2->csum = 0;
if (skb_checksum_complete(skb2))
- return -EINVAL;
+ goto out;
}
err = 0;
@@ -1039,6 +1039,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
out:
__skb_push(skb2, offset);
+err_out:
if (skb2 != skb)
kfree_skb(skb2);
return err;
--
1.5.6.5
^ permalink raw reply related
* Re: [PATCH] BUG: unable to handle kernel NULL pointer dereference at br_multicast_leave_group
From: David Miller @ 2010-03-16 3:38 UTC (permalink / raw)
To: herbert; +Cc: michael-dev, netdev
In-Reply-To: <20100316031005.GA17727@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Tue, 16 Mar 2010 11:10:05 +0800
> michael-dev@fami-braun.de wrote:
>>
>> I'm currently using linux-next and have been running into an OOPs which
>> I think might be caused by a patch you submitted on 2010-02-27.
>>
>> It's a linux-next kernel from 2010-03-12 on an x86 system and it
>> OOPs in the bridge module in br_mdp_ip_get (called by
>> br_multicast_leave_group) because the br->mdb is null.
>
> Thanks, there's actually another spot (the query handler) where
> the same thing can happen.
>
> Here's a patch to fix them both.
>
> bridge: Move NULL mdb check into br_mdb_ip_get
>
> Since all callers of br_mdb_ip_get need to check whether the
> hash table is NULL, this patch moves the check into the function.
>
> This fixes the two callers (query/leave handler) that didn't
> check it.
>
> Reported-by: Michael Braun <michael-dev@fami-braun.de>
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Applied, thanks Herbert.
^ permalink raw reply
* Re: [PATCH] BUG: unable to handle kernel NULL pointer dereference at br_multicast_leave_group
From: Herbert Xu @ 2010-03-16 3:10 UTC (permalink / raw)
To: michael-dev; +Cc: netdev, David S. Miller
In-Reply-To: <4B9C49E7.1080703@fami-braun.de>
michael-dev@fami-braun.de wrote:
>
> I'm currently using linux-next and have been running into an OOPs which
> I think might be caused by a patch you submitted on 2010-02-27.
>
> It's a linux-next kernel from 2010-03-12 on an x86 system and it
> OOPs in the bridge module in br_mdp_ip_get (called by
> br_multicast_leave_group) because the br->mdb is null.
Thanks, there's actually another spot (the query handler) where
the same thing can happen.
Here's a patch to fix them both.
bridge: Move NULL mdb check into br_mdb_ip_get
Since all callers of br_mdb_ip_get need to check whether the
hash table is NULL, this patch moves the check into the function.
This fixes the two callers (query/leave handler) that didn't
check it.
Reported-by: Michael Braun <michael-dev@fami-braun.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index fd96a8d..398221e 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -49,22 +49,23 @@ static struct net_bridge_mdb_entry *__br_mdb_ip_get(
static struct net_bridge_mdb_entry *br_mdb_ip_get(
struct net_bridge_mdb_htable *mdb, __be32 dst)
{
+ if (!mdb)
+ return NULL;
+
return __br_mdb_ip_get(mdb, dst, br_ip_hash(mdb, dst));
}
struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
struct sk_buff *skb)
{
- struct net_bridge_mdb_htable *mdb = br->mdb;
-
- if (!mdb || br->multicast_disabled)
+ if (br->multicast_disabled)
return NULL;
switch (skb->protocol) {
case htons(ETH_P_IP):
if (BR_INPUT_SKB_CB(skb)->igmp)
break;
- return br_mdb_ip_get(mdb, ip_hdr(skb)->daddr);
+ return br_mdb_ip_get(br->mdb, ip_hdr(skb)->daddr);
}
return NULL;
Thanks,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply related
* Re: [PATCH] BUG: unable to handle kernel NULL pointer dereference at br_pass_frame_up
From: Herbert Xu @ 2010-03-16 3:00 UTC (permalink / raw)
To: michael-dev, David S. Miller; +Cc: netdev
In-Reply-To: <4B9C4A2F.8040203@fami-braun.de>
michael-dev@fami-braun.de wrote:
>
> I'm currently using linux-next and have been running into an OOPs which
> I think might be caused by a patch submitted on 2010-02-27.
Thanks for the patch. Next time please add a changelog and a
Sign-off so that it can be immediately integrated.
I've done this for you now.
From: Michael Braun <michael-dev@fami-braun.de>
bridge: Fix br_forward crash in promiscuous mode
It's a linux-next kernel from 2010-03-12 on an x86 system and it
OOPs in the bridge module in br_pass_frame_up (called by
br_handle_frame_finish) because brdev cannot be dereferenced (its set to
a non-null value).
Adding some BUG_ON statements revealed that
BR_INPUT_SKB_CB(skb)->brdev == br-dev
(as set in br_handle_frame_finish first)
only holds until br_forward is called.
The next call to br_pass_frame_up then fails.
Digging deeper it seems that br_forward either frees the skb or passes
it to NF_HOOK which will in turn take care of freeing the skb. The same
is holds for br_pass_frame_ip. So it seems as if two independent skb
allocations are required. As far as I can see, commit
b33084be192ee1e347d98bb5c9e38a53d98d35e2 removed skb duplication and so
likely causes this crash. This crash does not happen on 2.6.33.
I've therefore modified br_forward the same way br_flood has been
modified so that the skb is not freed if skb0 is going to be used
and I can confirm that the attached patch resolves the issue for me.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index d61e6f7..8347916 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -19,6 +19,10 @@
#include <linux/netfilter_bridge.h>
#include "br_private.h"
+static int deliver_clone(struct net_bridge_port *prev, struct sk_buff *skb,
+ void (*__packet_hook)(const struct net_bridge_port *p,
+ struct sk_buff *skb));
+
/* Don't forward packets to originating port or forwarding diasabled */
static inline int should_deliver(const struct net_bridge_port *p,
const struct sk_buff *skb)
@@ -94,14 +98,18 @@ void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
}
/* called with rcu_read_lock */
-void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
+void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
{
if (should_deliver(to, skb)) {
- __br_forward(to, skb);
+ if (skb0)
+ deliver_clone(to, skb, __br_forward);
+ else
+ __br_forward(to, skb);
return;
}
- kfree_skb(skb);
+ if (!skb0)
+ kfree_skb(skb);
}
static int deliver_clone(struct net_bridge_port *prev, struct sk_buff *skb,
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 53b3985..08a72e6 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -90,7 +90,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
if (skb) {
if (dst)
- br_forward(dst->dst, skb);
+ br_forward(dst->dst, skb, skb2);
else
br_flood_forward(br, skb, skb2);
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index fef0384..bfb8feb 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -252,7 +252,7 @@ extern void br_deliver(const struct net_bridge_port *to,
struct sk_buff *skb);
extern int br_dev_queue_push_xmit(struct sk_buff *skb);
extern void br_forward(const struct net_bridge_port *to,
- struct sk_buff *skb);
+ struct sk_buff *skb, struct sk_buff *skb0);
extern int br_forward_finish(struct sk_buff *skb);
extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb);
extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply related
* Re: [Bridge] [PATCH] bridge: per-cpu packet statistics
From: Herbert Xu @ 2010-03-16 2:51 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: eric.dumazet, netdev, bridge, davem
In-Reply-To: <20100302092301.7ca9b368@nehalam>
Stephen Hemminger <shemminger@vyatta.com> wrote:
>
> No need, bridge has no queue!
OK, ignore my previous comment :)
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [Bridge] [PATCH] bridge: per-cpu packet statistics
From: Herbert Xu @ 2010-03-16 2:48 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: eric.dumazet, netdev, bridge, davem
In-Reply-To: <20100302092209.048f5682@nehalam>
Stephen Hemminger <shemminger@vyatta.com> wrote:
>
> Bridge is already using lockless transmit LLTX, so tx_lock is not touched.
LLTX doesn't actually buy you anything since you're still going
through a single qdisc. To get the full benefits of the per-cpu
counters you need to implement multiqueue support in the bridge.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH V2] ISDN: Add PCI ID for HFC-2S/4S Beronet Card PCIe
From: David Miller @ 2010-03-16 2:09 UTC (permalink / raw)
To: keil; +Cc: torvalds, lars.ellenberg, netdev, andreas, akpm, linux-kernel
In-Reply-To: <1268702879.31146@pingi>
From: Karsten Keil <keil@b1-systems.de>
Date: Mon, 15 Mar 2010 14:18:41 +0100
> From: Lars Ellenberg <lars.ellenberg@linbit.com>
>
> A few subdevice IDs seem to have been dropped when hfc_multi was
> included upstream, just compare the list at
> http://www.openvox.cn/viewvc/misdn/trunk/hfc_multi.c?revision=75&view=annotate#l175
> with the IDs in drivers/isdn/hardware/mISDN/hfcmulti.c
>
> Added PCIe 2 Port card and LED settings (same as PCI)
> Do not use <linux/pci_ids.h> /KKe
>
> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
> Signed-off-by: Karsten Keil <keil@b1-systems.de>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH] ISDN: Add PCI ID for HFC-2S/4S Beronet Card PCIe
From: David Miller @ 2010-03-16 2:06 UTC (permalink / raw)
To: keil; +Cc: torvalds, lars.ellenberg, netdev, andreas, akpm, linux-kernel
In-Reply-To: <201003160208.57232.keil@b1-systems.de>
From: Karsten Keil <keil@b1-systems.de>
Date: Tue, 16 Mar 2010 02:08:57 +0100
> Is here some plan to cleanup drivers for -next and remove IDs from pci_ids.h,
> or should it not changed for old entries ?
Leave things as they are for existing ones.
^ permalink raw reply
* Re: [PATCH] ISDN: Add PCI ID for HFC-2S/4S Beronet Card PCIe
From: Karsten Keil @ 2010-03-16 1:08 UTC (permalink / raw)
To: David Miller
Cc: torvalds, lars.ellenberg, netdev, andreas, akpm, linux-kernel
In-Reply-To: <20100315.160133.67908104.davem@davemloft.net>
On Dienstag, 16. März 2010 00:01:33 David Miller wrote:
> From: Karsten Keil <keil@b1-systems.de>
> Date: Mon, 15 Mar 2010 14:18:41 +0100
>
> > A few subdevice IDs seem to have been dropped when hfc_multi was
> > included upstream, just compare the list at
> > http://www.openvox.cn/viewvc/misdn/trunk/hfc_multi.c?revision=75&view=ann
> >otate#l175 with the IDs in drivers/isdn/hardware/mISDN/hfcmulti.c
> >
> > Added PCIe 2 Port card and LED settings (same as PCI) /KKe
> >
> > Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
> > Signed-off-by: Karsten Keil <keil@b1-systems.de>
>
> We don't add new defines to linux/pci_ids.h, it is deprecated.
> Simply add the device ID constants to the table.
Good policy, makes sense. Will send a new version.
May a check for adding defines to <linux/pci_ids> would help to enforce it.
>
> The only exception is the case where a device ID is used in
> more than one driver, but even that scenerio is heavily
> discouraged.
>
Is here some plan to cleanup drivers for -next and remove IDs from pci_ids.h,
or should it not changed for old entries ?
Karsten
^ permalink raw reply
* [PATCH] r8169: Fix rtl8169_rx_interrupt()
From: Eric Dumazet @ 2010-03-16 0:33 UTC (permalink / raw)
To: Oleg Nesterov, David Miller
Cc: Ingo Molnar, Sergey Senozhatsky, Francois Romieu, Peter Zijlstra,
netdev, linux-kernel
In-Reply-To: <1268686865.2824.4.camel@edumazet-laptop>
Le lundi 15 mars 2010 à 22:01 +0100, Eric Dumazet a écrit :
> Yes, this is wrong. In this context (process context, not softirq), we
> should use netif_rx() or just drop frames if we are in reset phase.
>
Sergey,
Here is a compiled but untested patch (I dont have the hardware), could
you please test it ?
Thanks
[PATCH] r8169: Fix rtl8169_rx_interrupt()
In case a reset is performed, rtl8169_rx_interrupt() is called from
process context instead of softirq context. Special care must be taken
to call appropriate network core services (netif_rx() instead of
netif_receive_skb()). VLAN handling also corrected.
Reported-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Diagnosed-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 9d3ebf3..d873639 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1038,14 +1038,14 @@ static void rtl8169_vlan_rx_register(struct net_device *dev,
}
static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
- struct sk_buff *skb)
+ struct sk_buff *skb, int polling)
{
u32 opts2 = le32_to_cpu(desc->opts2);
struct vlan_group *vlgrp = tp->vlgrp;
int ret;
if (vlgrp && (opts2 & RxVlanTag)) {
- vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff));
+ __vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling);
ret = 0;
} else
ret = -1;
@@ -1062,7 +1062,7 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
}
static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
- struct sk_buff *skb)
+ struct sk_buff *skb, int polling)
{
return -1;
}
@@ -4429,12 +4429,20 @@ out:
return done;
}
+/*
+ * Warning : rtl8169_rx_interrupt() might be called :
+ * 1) from NAPI (softirq) context
+ * (polling = 1 : we should call netif_receive_skb())
+ * 2) from process context (rtl8169_reset_task())
+ * (polling = 0 : we must call netif_rx() instead)
+ */
static int rtl8169_rx_interrupt(struct net_device *dev,
struct rtl8169_private *tp,
void __iomem *ioaddr, u32 budget)
{
unsigned int cur_rx, rx_left;
unsigned int delta, count;
+ int polling = (budget != ~(u32)0) ? 1 : 0;
cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
@@ -4496,8 +4504,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
- if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0)
- netif_receive_skb(skb);
+ if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) {
+ if (likely(polling))
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
+ }
dev->stats.rx_bytes += pkt_size;
dev->stats.rx_packets++;
^ permalink raw reply related
* Re: [1/3] gigaset: avoid registering CAPI driver more than once
From: Karsten Keil @ 2010-03-16 0:23 UTC (permalink / raw)
To: David Miller
Cc: tilman, netdev, linux-kernel, stable, isdn4linux, hjlipp,
i4ldeveloper
In-Reply-To: <20100315.142040.58983190.davem@davemloft.net>
On Montag, 15. März 2010 22:20:40 David Miller wrote:
> Karsten the way you reforward patches does not work.
>
> And I've told you about this last time you submitted ISDN patches.
>
> You don't add an extra "From: " line in the message body, so when the
> patch gets applied the author gets set to _you_ instead of the person
> who actually wrote the change.
>
Sorry about that.
>
> All you're doing is ACK'ing this person's work, so simply reply to the
> patch they posted and with your "Acked-by" line. This way patchwork
> and friends will figure out the rest when the patch gets integrated
> into the net-2.6 tree.
I tried to use my own patchwork which is feed by the
ISDN list to learn more about it, unfortunately it does not help for such
issues.
>
> By reposting the patches the way you are we're losing information.
>
> Add to this the fact that you never have the time to properly take
> care of ISDN patches, and when you do finally "get to it" you make all
> kinds of submission errors.
>
> This is not the first time either, it happens over and over again.
> It's incredibly frustrating, especially for me.
I can understand that.
> Please seriously consider handing ISDN maintainership over to someone
> who unlike you 1) has the time and the desire and 2) knows how to
> submit patches properly. Probably Tilman is the person who most meets
> these criteria based upon what I've seen.
>
> Meanwhile, I'm going to apply the original patches as posted by
> Tilman so that the proper authorship gets set.
Fair enough, thanks.
Karsten
- who had really a very bad day
^ permalink raw reply
* Re: [Regression] r8169: enable 64-bit DMA by default for PCI Express devices (v2)
From: Robert Hancock @ 2010-03-15 23:28 UTC (permalink / raw)
To: David Miller; +Cc: joern, torvalds, linux-kernel, netdev, romieu
In-Reply-To: <20100315.115748.13754030.davem@davemloft.net>
On Mon, Mar 15, 2010 at 12:57 PM, David Miller <davem@davemloft.net> wrote:
> From: Jörn Engel <joern@dublin.logfs.org>
> Date: Mon, 15 Mar 2010 16:10:41 +0100
>
>> Forgot to Cc: lkml.
>
> Actually, what you really need to CC: is netdev, added.
>> On Mon, 15 March 2010 16:08:06 +0100, J�rn Engel wrote:
>>>
>>> Hello Robert!
>>>
>>> Looks like 353176888386d9025062a12dcec08d49af10cf2c broke one of my
>>> machines. Reverting that patch fixes things again. Machine is
>>> running an x86_64 kernel. Lspci gives me this:
>>>
>>> 01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8101E/RTL8102E PCI Express Fast Ethernet controller (rev 02)
>>> Subsystem: ASRock Incorporation Device 8136
>>> Flags: bus master, fast devsel, latency 0, IRQ 26
>>> I/O ports at e800 [size=256]
>>> Memory at fdeff000 (64-bit, prefetchable) [size=4K]
>>> Memory at fdee0000 (64-bit, prefetchable) [size=64K]
>>> [virtual] Expansion ROM at fde00000 [disabled] [size=128K]
>>> Capabilities: [40] Power Management version 3
>>> Capabilities: [50] MSI: Enable+ Count=1/1 Maskable- 64bit+
>>> Capabilities: [70] Express Endpoint, MSI 01
>>> Capabilities: [ac] MSI-X: Enable- Count=2 Masked-
>>> Capabilities: [cc] Vital Product Data
>>> Capabilities: [100] Advanced Error Reporting
>>> Capabilities: [140] Virtual Channel <?>
>>> Capabilities: [160] Device Serial Number 08-00-00-00-ff-ff-00-00
>>> Kernel driver in use: r8169
>>>
>>> If you have any test patches to try, please send them my way. :)
>>>
>>> J�rn
>
What are the symptoms? Does setting use_dac=0 in the module options
for r8169 also resolve the problem?
Full dmesg and lspci -vv output might also be useful.
^ permalink raw reply
* net-next-2.6...
From: David Miller @ 2010-03-15 23:18 UTC (permalink / raw)
To: netdev
I intend to open up net-next-2.6 right after Linus pulls in
the next batch of bug fixes I send in via net-2.6
That submission should be either tonight or tomorrow some
time.
^ permalink raw reply
* Re: net-2.6 [Bug-Fix][dccp]: fix oops caused after failed initialisation
From: David Miller @ 2010-03-15 23:07 UTC (permalink / raw)
To: gerrit; +Cc: acme, netdev, dccp
In-Reply-To: <20100315061318.GA6110@gerrit.erg.abdn.ac.uk>
From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 15 Mar 2010 07:13:19 +0100
> dccp: fix panic caused by failed initialisation
>
> This fixes a kernel panic reported thanks to Andre Noll:
>
> if DCCP is compiled into the kernel and any out of the initialisation
> steps in net/dccp/proto.c:dccp_init() fail, a subsequent attempt to create
> a SOCK_DCCP socket will panic, since inet{,6}_create() are not prevented
> from creating DCCP sockets.
>
> This patch fixes the problem by propagating a failure in dccp_init() to
> dccp_v{4,6}_init_net(), and from there to dccp_v{4,6}_init(), so that the
> DCCP protocol is not made available if its initialisation fails.
>
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Applied, thanks Gerrit.
^ permalink raw reply
* Re: [patch] myri: remove dead code
From: David Miller @ 2010-03-15 23:06 UTC (permalink / raw)
To: gallatin; +Cc: error27, brice, kaber, netdev, kernel-janitors
In-Reply-To: <4B9E17BE.1080009@myri.com>
From: Andrew Gallatin <gallatin@myri.com>
Date: Mon, 15 Mar 2010 07:19:26 -0400
> Dan Carpenter wrote:
>> We can never reach the return statement.
>
> Agreed, thanks for pointing that out.
Applied, thanks everyone.
^ permalink raw reply
* Re: [PATCH 0/3] gigaset fixes for 2.6.34-rc1
From: David Miller @ 2010-03-15 23:06 UTC (permalink / raw)
To: tilman; +Cc: isdn, hjlipp, alan, isdn4linux, i4ldeveloper, netdev,
linux-kernel
In-Reply-To: <cover.1268580322.git.tilman@imap.cc>
From: Tilman Schmidt <tilman@imap.cc>
Date: Sun, 14 Mar 2010 23:58:05 +0100 (CET)
> following are three bugfix patches to the Gigaset driver which should
> still go into 2.6.34 if possible, and also into the 2.6.33 stable branch.
All applied, thanks Tilman.
^ permalink raw reply
* Re: [patch 5/5] obsolete config in kernel source: HSO_AUTOPM
From: David Miller @ 2010-03-15 23:06 UTC (permalink / raw)
To: akpm; +Cc: netdev, siccegge
In-Reply-To: <201003112207.o2BM7sbR013498@imap1.linux-foundation.org>
From: akpm@linux-foundation.org
Date: Thu, 11 Mar 2010 14:07:54 -0800
> From: Christoph Egger <siccegge@stud.informatik.uni-erlangen.de>
>
> CONFIG_HSO_AUTOPM is set by KConfig / set in the Kernel source, makefiles
> and won't be ever set this way, therefor simply removing the protected
> code.
>
> Signed-off-by: Christoph Egger <siccegge@stud.informatik.uni-erlangen.de>
> Cc: "David S. Miller" <davem@davemloft.net>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Applied.
^ permalink raw reply
* Re: [patch 4/5] obsolete config in kernel source: USE_INTERNAL_TIMER
From: David Miller @ 2010-03-15 23:05 UTC (permalink / raw)
To: akpm; +Cc: netdev, siccegge, roel.kluin
In-Reply-To: <201003112207.o2BM7rlU013495@imap1.linux-foundation.org>
From: akpm@linux-foundation.org
Date: Thu, 11 Mar 2010 14:07:52 -0800
> From: Christoph Egger <siccegge@stud.informatik.uni-erlangen.de>
>
> CONFIG_USE_INTERNAL_TIMER seems to be the remainings of some experiment.
> It is explicitely #undef-ed as not working, only referenced from one
> source file and rather aged.
>
> Hereby cleaning it from the kernel tree.
>
> Signed-off-by: Christoph Egger <siccegge@stud.informatik.uni-erlangen.de>
> Acked-by: Roel Kluin <roel.kluin@gmail.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Applied.
^ 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