* [patch net-next-2.6 0/8] mostly bonding rx path changes
From: Jiri Pirko @ 2011-03-05 10:29 UTC (permalink / raw)
To: netdev
Cc: davem, shemminger, kaber, fubar, eric.dumazet, nicolas.2p.debian,
andy
This patchset focuses mainly bonding rx path changes.
Depends on "fcoe: correct checking for bonding"
Jiri Pirko (8):
af_packet: use skb->skb_iif instead of orig_dev->ifindex
bonding: register slave pointer for rx_handler
net: get rid of multiple bond-related netdevice->priv_flags
bonding: wrap slave state work
bonding: get rid of IFF_SLAVE_INACTIVE netdev->priv_flag
bonding: move processing of recv handlers into handle_frame()
net: introduce rx_handler results and logic around that
net: get rid of orig_dev parameter of packet handlers
drivers/block/aoe/aoenet.c | 2 +-
drivers/net/bonding/bond_3ad.c | 31 +-----
drivers/net/bonding/bond_3ad.h | 4 +-
drivers/net/bonding/bond_alb.c | 46 ++------
drivers/net/bonding/bond_alb.h | 1 -
drivers/net/bonding/bond_main.c | 217 ++++++++++++-------------------------
drivers/net/bonding/bond_sysfs.c | 20 +---
drivers/net/bonding/bonding.h | 64 ++++++-----
drivers/net/hamradio/bpqether.c | 4 +-
drivers/net/macvlan.c | 11 +-
drivers/net/pppoe.c | 4 +-
drivers/net/wan/hdlc.c | 2 +-
drivers/net/wan/lapbether.c | 2 +-
drivers/scsi/fcoe/fcoe.c | 12 +--
include/linux/if.h | 23 ++---
include/linux/netdevice.h | 12 ++-
include/linux/skbuff.h | 5 +-
include/net/ax25.h | 3 +-
include/net/datalink.h | 2 +-
include/net/ip.h | 2 +-
include/net/ipv6.h | 3 +-
include/net/irda/irda.h | 3 +-
include/net/llc.h | 8 +-
include/net/p8022.h | 3 +-
include/net/psnap.h | 3 +-
include/net/x25.h | 2 +-
net/802/p8022.c | 3 +-
net/802/psnap.c | 7 +-
net/802/stp.c | 2 +-
net/8021q/vlan.h | 2 +-
net/8021q/vlan_dev.c | 2 +-
net/appletalk/aarp.c | 2 +-
net/appletalk/ddp.c | 6 +-
net/ax25/ax25_in.c | 2 +-
net/batman-adv/hard-interface.c | 6 +-
net/bridge/br_input.c | 25 +++--
net/bridge/br_private.h | 2 +-
net/caif/caif_dev.c | 2 +-
net/can/af_can.c | 2 +-
net/core/dev.c | 45 ++++----
net/core/skbuff.c | 1 -
net/decnet/af_decnet.c | 2 +-
net/decnet/dn_route.c | 2 +-
net/dsa/tag_dsa.c | 2 +-
net/dsa/tag_edsa.c | 2 +-
net/dsa/tag_trailer.c | 2 +-
net/econet/af_econet.c | 2 +-
net/ieee802154/af_ieee802154.c | 2 +-
net/ipv4/arp.c | 2 +-
net/ipv4/ip_input.c | 2 +-
net/ipv4/ipconfig.c | 13 ++-
net/ipv6/ip6_input.c | 3 +-
net/ipx/af_ipx.c | 3 +-
net/irda/irlap_frame.c | 2 +-
net/llc/llc_core.c | 3 +-
net/llc/llc_input.c | 8 +-
net/packet/af_packet.c | 10 +-
net/phonet/af_phonet.c | 3 +-
net/tipc/eth_media.c | 2 +-
net/x25/x25_dev.c | 2 +-
60 files changed, 268 insertions(+), 397 deletions(-)
--
1.7.4
^ permalink raw reply
* [patch net-next-2.6 3/8] net: get rid of multiple bond-related netdevice->priv_flags
From: Jiri Pirko @ 2011-03-05 10:29 UTC (permalink / raw)
To: netdev
Cc: davem, shemminger, kaber, fubar, eric.dumazet, nicolas.2p.debian,
andy
In-Reply-To: <1299320969-7951-1-git-send-email-jpirko@redhat.com>
Now when bond-related code is moved from net/core/dev.c into bonding
code, multiple priv_flags are not needed anymore. So toss them out.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/bonding/bond_main.c | 33 ++++++++++++++-------------------
drivers/net/bonding/bond_sysfs.c | 8 --------
drivers/net/bonding/bonding.h | 24 +-----------------------
include/linux/if.h | 22 +++++++++-------------
4 files changed, 24 insertions(+), 63 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 1c19368..7923184 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1471,20 +1471,20 @@ static void bond_setup_by_slave(struct net_device *bond_dev,
* ARP on active-backup slaves with arp_validate enabled.
*/
static bool bond_should_deliver_exact_match(struct sk_buff *skb,
- struct net_device *slave_dev,
- struct net_device *bond_dev)
+ struct slave *slave,
+ struct bonding *bond)
{
- if (slave_dev->priv_flags & IFF_SLAVE_INACTIVE) {
- if (slave_dev->priv_flags & IFF_SLAVE_NEEDARP &&
+ if (slave->dev->priv_flags & IFF_SLAVE_INACTIVE) {
+ if (slave_do_arp_validate(bond, slave) &&
skb->protocol == __cpu_to_be16(ETH_P_ARP))
return false;
- if (bond_dev->priv_flags & IFF_MASTER_ALB &&
+ if (bond->params.mode == BOND_MODE_ALB &&
skb->pkt_type != PACKET_BROADCAST &&
skb->pkt_type != PACKET_MULTICAST)
return false;
- if (bond_dev->priv_flags & IFF_MASTER_8023AD &&
+ if (bond->params.mode == BOND_MODE_8023AD &&
skb->protocol == __cpu_to_be16(ETH_P_SLOW))
return false;
@@ -1497,6 +1497,7 @@ static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
{
struct slave *slave;
struct net_device *bond_dev;
+ struct bonding *bond;
skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(!skb))
@@ -1507,17 +1508,19 @@ static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
if (unlikely(!bond_dev))
return skb;
- if (bond_dev->priv_flags & IFF_MASTER_ARPMON)
+ bond = netdev_priv(bond_dev);
+
+ if (bond->params.arp_interval)
slave->dev->last_rx = jiffies;
- if (bond_should_deliver_exact_match(skb, slave->dev, bond_dev)) {
+ if (bond_should_deliver_exact_match(skb, slave, bond)) {
skb->deliver_no_wcard = 1;
return skb;
}
skb->dev = bond_dev;
- if (bond_dev->priv_flags & IFF_MASTER_ALB &&
+ if (bond->params.mode == BOND_MODE_ALB &&
bond_dev->priv_flags & IFF_BRIDGE_PORT &&
skb->pkt_type == PACKET_HOST) {
u16 *dest = (u16 *) eth_hdr(skb)->h_dest;
@@ -2128,9 +2131,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
dev_set_mtu(slave_dev, slave->original_mtu);
- slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
- IFF_SLAVE_INACTIVE | IFF_BONDING |
- IFF_SLAVE_NEEDARP);
+ slave_dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_BONDING);
kfree(slave);
@@ -2241,8 +2242,7 @@ static int bond_release_all(struct net_device *bond_dev)
dev_set_mac_address(slave_dev, &addr);
}
- slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
- IFF_SLAVE_INACTIVE);
+ slave_dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
kfree(slave);
@@ -4718,11 +4718,9 @@ void bond_set_mode_ops(struct bonding *bond, int mode)
case BOND_MODE_BROADCAST:
break;
case BOND_MODE_8023AD:
- bond_set_master_3ad_flags(bond);
bond_set_xmit_hash_policy(bond);
break;
case BOND_MODE_ALB:
- bond_set_master_alb_flags(bond);
/* FALLTHRU */
case BOND_MODE_TLB:
break;
@@ -4813,9 +4811,6 @@ static void bond_setup(struct net_device *bond_dev)
bond_dev->priv_flags |= IFF_BONDING;
bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
- if (bond->params.arp_interval)
- bond_dev->priv_flags |= IFF_MASTER_ARPMON;
-
/* At first, we block adding VLANs. That's the only way to
* prevent problems that occur when adding VLANs over an
* empty bond. The block will be removed once non-challenged
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 72bb0f6..05e0ae5 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -322,11 +322,6 @@ static ssize_t bonding_store_mode(struct device *d,
ret = -EINVAL;
goto out;
}
- if (bond->params.mode == BOND_MODE_8023AD)
- bond_unset_master_3ad_flags(bond);
-
- if (bond->params.mode == BOND_MODE_ALB)
- bond_unset_master_alb_flags(bond);
bond->params.mode = new_value;
bond_set_mode_ops(bond, bond->params.mode);
@@ -527,8 +522,6 @@ static ssize_t bonding_store_arp_interval(struct device *d,
pr_info("%s: Setting ARP monitoring interval to %d.\n",
bond->dev->name, new_value);
bond->params.arp_interval = new_value;
- if (bond->params.arp_interval)
- bond->dev->priv_flags |= IFF_MASTER_ARPMON;
if (bond->params.miimon) {
pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n",
bond->dev->name, bond->dev->name);
@@ -1004,7 +997,6 @@ static ssize_t bonding_store_miimon(struct device *d,
pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
bond->dev->name);
bond->params.arp_interval = 0;
- bond->dev->priv_flags &= ~IFF_MASTER_ARPMON;
if (bond->params.arp_validate) {
bond_unregister_arp(bond);
bond->params.arp_validate =
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 1aac5cd..ddee62f 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -354,34 +354,12 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave)
slave->state = BOND_STATE_BACKUP;
if (!bond->params.all_slaves_active)
slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
- if (slave_do_arp_validate(bond, slave))
- slave->dev->priv_flags |= IFF_SLAVE_NEEDARP;
}
static inline void bond_set_slave_active_flags(struct slave *slave)
{
slave->state = BOND_STATE_ACTIVE;
- slave->dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_SLAVE_NEEDARP);
-}
-
-static inline void bond_set_master_3ad_flags(struct bonding *bond)
-{
- bond->dev->priv_flags |= IFF_MASTER_8023AD;
-}
-
-static inline void bond_unset_master_3ad_flags(struct bonding *bond)
-{
- bond->dev->priv_flags &= ~IFF_MASTER_8023AD;
-}
-
-static inline void bond_set_master_alb_flags(struct bonding *bond)
-{
- bond->dev->priv_flags |= IFF_MASTER_ALB;
-}
-
-static inline void bond_unset_master_alb_flags(struct bonding *bond)
-{
- bond->dev->priv_flags &= ~IFF_MASTER_ALB;
+ slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
}
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
diff --git a/include/linux/if.h b/include/linux/if.h
index 3bc63e6..2fdd47a 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -60,21 +60,17 @@
#define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */
#define IFF_EBRIDGE 0x2 /* Ethernet bridging device. */
#define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */
-#define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */
-#define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */
-#define IFF_BONDING 0x20 /* bonding master or slave */
-#define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */
-#define IFF_ISATAP 0x80 /* ISATAP interface (RFC4214) */
-#define IFF_MASTER_ARPMON 0x100 /* bonding master, ARP mon in use */
-#define IFF_WAN_HDLC 0x200 /* WAN HDLC device */
-#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to
+#define IFF_BONDING 0x8 /* bonding master or slave */
+#define IFF_ISATAP 0x10 /* ISATAP interface (RFC4214) */
+#define IFF_WAN_HDLC 0x20 /* WAN HDLC device */
+#define IFF_XMIT_DST_RELEASE 0x40 /* dev_hard_start_xmit() is allowed to
* release skb->dst
*/
-#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */
-#define IFF_DISABLE_NETPOLL 0x1000 /* disable netpoll at run-time */
-#define IFF_MACVLAN_PORT 0x2000 /* device used as macvlan port */
-#define IFF_BRIDGE_PORT 0x4000 /* device used as bridge port */
-#define IFF_OVS_DATAPATH 0x8000 /* device used as Open vSwitch
+#define IFF_DONT_BRIDGE 0x80 /* disallow bridging this ether dev */
+#define IFF_DISABLE_NETPOLL 0x100 /* disable netpoll at run-time */
+#define IFF_MACVLAN_PORT 0x200 /* device used as macvlan port */
+#define IFF_BRIDGE_PORT 0x400 /* device used as bridge port */
+#define IFF_OVS_DATAPATH 0x800 /* device used as Open vSwitch
* datapath port */
#define IF_GET_IFACE 0x0001 /* for querying only */
--
1.7.4
^ permalink raw reply related
* [patch net-next-2.6 4/8] bonding: wrap slave state work
From: Jiri Pirko @ 2011-03-05 10:29 UTC (permalink / raw)
To: netdev
Cc: davem, shemminger, kaber, fubar, eric.dumazet, nicolas.2p.debian,
andy
In-Reply-To: <1299320969-7951-1-git-send-email-jpirko@redhat.com>
transfers slave->state into slave->backup (that it's going to transfer
into bitfield. Introduce wrapper inlines to do the work with it.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/bonding/bond_3ad.c | 2 +-
drivers/net/bonding/bond_main.c | 36 ++++++++++++++++++------------------
drivers/net/bonding/bond_sysfs.c | 2 +-
drivers/net/bonding/bonding.h | 31 ++++++++++++++++++++++++++-----
4 files changed, 46 insertions(+), 25 deletions(-)
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 1024ae1..047af0b 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -246,7 +246,7 @@ static inline void __enable_port(struct port *port)
*/
static inline int __port_is_enabled(struct port *port)
{
- return port->slave->state == BOND_STATE_ACTIVE;
+ return bond_is_active_slave(port->slave);
}
/**
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 7923184..62020a7 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1872,7 +1872,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
break;
case BOND_MODE_TLB:
case BOND_MODE_ALB:
- new_slave->state = BOND_STATE_ACTIVE;
+ bond_set_active_slave(new_slave);
bond_set_slave_inactive_flags(new_slave);
bond_select_active_slave(bond);
break;
@@ -1880,7 +1880,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
pr_debug("This slave is always active in trunk mode\n");
/* always active in trunk mode */
- new_slave->state = BOND_STATE_ACTIVE;
+ bond_set_active_slave(new_slave);
/* In trunking mode there is little meaning to curr_active_slave
* anyway (it holds no special properties of the bond device),
@@ -1918,7 +1918,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
pr_info("%s: enslaving %s as a%s interface with a%s link.\n",
bond_dev->name, slave_dev->name,
- new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup",
+ bond_is_active_slave(new_slave) ? "n active" : " backup",
new_slave->link != BOND_LINK_DOWN ? "n up" : " down");
/* enslave is successful */
@@ -2016,7 +2016,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
pr_info("%s: releasing %s interface %s\n",
bond_dev->name,
- (slave->state == BOND_STATE_ACTIVE) ? "active" : "backup",
+ bond_is_active_slave(slave) ? "active" : "backup",
slave_dev->name);
oldcurrent = bond->curr_active_slave;
@@ -2357,7 +2357,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
res = 0;
strcpy(info->slave_name, slave->dev->name);
info->link = slave->link;
- info->state = slave->state;
+ info->state = bond_slave_state(slave);
info->link_failure_count = slave->link_failure_count;
break;
}
@@ -2396,7 +2396,7 @@ static int bond_miimon_inspect(struct bonding *bond)
bond->dev->name,
(bond->params.mode ==
BOND_MODE_ACTIVEBACKUP) ?
- ((slave->state == BOND_STATE_ACTIVE) ?
+ (bond_is_active_slave(slave) ?
"active " : "backup ") : "",
slave->dev->name,
bond->params.downdelay * bond->params.miimon);
@@ -2487,13 +2487,13 @@ static void bond_miimon_commit(struct bonding *bond)
if (bond->params.mode == BOND_MODE_8023AD) {
/* prevent it from being the active one */
- slave->state = BOND_STATE_BACKUP;
+ bond_set_backup_slave(slave);
} else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
/* make it immediately active */
- slave->state = BOND_STATE_ACTIVE;
+ bond_set_active_slave(slave);
} else if (slave != bond->primary_slave) {
/* prevent it from being the active one */
- slave->state = BOND_STATE_BACKUP;
+ bond_set_backup_slave(slave);
}
bond_update_speed_duplex(slave);
@@ -2871,7 +2871,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
memcpy(&tip, arp_ptr, 4);
pr_debug("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n",
- bond->dev->name, slave->dev->name, slave->state,
+ bond->dev->name, slave->dev->name, bond_slave_state(slave),
bond->params.arp_validate, slave_do_arp_validate(bond, slave),
&sip, &tip);
@@ -2883,7 +2883,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
* the active, through one switch, the router, then the other
* switch before reaching the backup.
*/
- if (slave->state == BOND_STATE_ACTIVE)
+ if (bond_is_active_slave(slave))
bond_validate_arp(bond, slave, sip, tip);
else
bond_validate_arp(bond, slave, tip, sip);
@@ -2945,7 +2945,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
slave->dev->last_rx + delta_in_ticks)) {
slave->link = BOND_LINK_UP;
- slave->state = BOND_STATE_ACTIVE;
+ bond_set_active_slave(slave);
/* primary_slave has no meaning in round-robin
* mode. the window of a slave being up and
@@ -2978,7 +2978,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
slave->dev->last_rx + 2 * delta_in_ticks)) {
slave->link = BOND_LINK_DOWN;
- slave->state = BOND_STATE_BACKUP;
+ bond_set_backup_slave(slave);
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
@@ -3072,7 +3072,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
* gives each slave a chance to tx/rx traffic
* before being taken out
*/
- if (slave->state == BOND_STATE_BACKUP &&
+ if (!bond_is_active_slave(slave) &&
!bond->current_arp_slave &&
!time_in_range(jiffies,
slave_last_rx(bond, slave) - delta_in_ticks,
@@ -3089,7 +3089,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
* the bond has an IP address)
*/
trans_start = dev_trans_start(slave->dev);
- if ((slave->state == BOND_STATE_ACTIVE) &&
+ if (bond_is_active_slave(slave) &&
(!time_in_range(jiffies,
trans_start - delta_in_ticks,
trans_start + 2 * delta_in_ticks) ||
@@ -4446,7 +4446,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
bond_for_each_slave_from(bond, slave, i, start_at) {
if (IS_UP(slave->dev) &&
(slave->link == BOND_LINK_UP) &&
- (slave->state == BOND_STATE_ACTIVE)) {
+ bond_is_active_slave(slave)) {
res = bond_dev_queue_xmit(bond, skb, slave->dev);
break;
}
@@ -4523,7 +4523,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
bond_for_each_slave_from(bond, slave, i, start_at) {
if (IS_UP(slave->dev) &&
(slave->link == BOND_LINK_UP) &&
- (slave->state == BOND_STATE_ACTIVE)) {
+ bond_is_active_slave(slave)) {
res = bond_dev_queue_xmit(bond, skb, slave->dev);
break;
}
@@ -4564,7 +4564,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
bond_for_each_slave_from(bond, slave, i, start_at) {
if (IS_UP(slave->dev) &&
(slave->link == BOND_LINK_UP) &&
- (slave->state == BOND_STATE_ACTIVE)) {
+ bond_is_active_slave(slave)) {
if (tx_dev) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
if (!skb2) {
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 05e0ae5..344d23f 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -1579,7 +1579,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
}
bond_for_each_slave(bond, slave, i) {
- if (slave->state == BOND_STATE_BACKUP) {
+ if (!bond_is_active_slave(slave)) {
if (new_value)
slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
else
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index ddee62f..8a3718b 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -53,7 +53,7 @@
(((slave)->dev->flags & IFF_UP) && \
netif_running((slave)->dev) && \
((slave)->link == BOND_LINK_UP) && \
- ((slave)->state == BOND_STATE_ACTIVE))
+ bond_is_active_slave(slave))
#define USES_PRIMARY(mode) \
@@ -190,7 +190,8 @@ struct slave {
unsigned long last_arp_rx;
s8 link; /* one of BOND_LINK_XXXX */
s8 new_link;
- s8 state; /* one of BOND_STATE_XXXX */
+ u8 backup; /* indicates backup slave. Value corresponds with
+ BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
u32 original_mtu;
u32 link_failure_count;
u8 perm_hwaddr[ETH_ALEN];
@@ -302,6 +303,26 @@ static inline bool bond_is_lb(const struct bonding *bond)
bond->params.mode == BOND_MODE_ALB);
}
+static inline void bond_set_active_slave(struct slave *slave)
+{
+ slave->backup = 0;
+}
+
+static inline void bond_set_backup_slave(struct slave *slave)
+{
+ slave->backup = 1;
+}
+
+static inline int bond_slave_state(struct slave *slave)
+{
+ return slave->backup;
+}
+
+static inline bool bond_is_active_slave(struct slave *slave)
+{
+ return !bond_slave_state(slave);
+}
+
#define BOND_PRI_RESELECT_ALWAYS 0
#define BOND_PRI_RESELECT_BETTER 1
#define BOND_PRI_RESELECT_FAILURE 2
@@ -319,7 +340,7 @@ static inline bool bond_is_lb(const struct bonding *bond)
static inline int slave_do_arp_validate(struct bonding *bond,
struct slave *slave)
{
- return bond->params.arp_validate & (1 << slave->state);
+ return bond->params.arp_validate & (1 << bond_slave_state(slave));
}
static inline unsigned long slave_last_rx(struct bonding *bond,
@@ -351,14 +372,14 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave)
{
struct bonding *bond = netdev_priv(slave->dev->master);
if (!bond_is_lb(bond))
- slave->state = BOND_STATE_BACKUP;
+ bond_set_backup_slave(slave);
if (!bond->params.all_slaves_active)
slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
}
static inline void bond_set_slave_active_flags(struct slave *slave)
{
- slave->state = BOND_STATE_ACTIVE;
+ bond_set_active_slave(slave);
slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
}
--
1.7.4
^ permalink raw reply related
* [patch net-next-2.6 5/8] bonding: get rid of IFF_SLAVE_INACTIVE netdev->priv_flag
From: Jiri Pirko @ 2011-03-05 10:29 UTC (permalink / raw)
To: netdev
Cc: davem, shemminger, kaber, fubar, eric.dumazet, nicolas.2p.debian,
andy
In-Reply-To: <1299320969-7951-1-git-send-email-jpirko@redhat.com>
Since bond-related code was moved from net/core/dev.c into bonding,
IFF_SLAVE_INACTIVE is no longer needed. Replace is with flag "inactive"
stored in slave structure
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/bonding/bond_main.c | 6 ++----
drivers/net/bonding/bond_sysfs.c | 4 ++--
drivers/net/bonding/bonding.h | 14 ++++++++++----
include/linux/if.h | 19 +++++++++----------
4 files changed, 23 insertions(+), 20 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 62020a7..dbe182c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1474,7 +1474,7 @@ static bool bond_should_deliver_exact_match(struct sk_buff *skb,
struct slave *slave,
struct bonding *bond)
{
- if (slave->dev->priv_flags & IFF_SLAVE_INACTIVE) {
+ if (bond_is_slave_inactive(slave)) {
if (slave_do_arp_validate(bond, slave) &&
skb->protocol == __cpu_to_be16(ETH_P_ARP))
return false;
@@ -2131,7 +2131,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
dev_set_mtu(slave_dev, slave->original_mtu);
- slave_dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_BONDING);
+ slave_dev->priv_flags &= ~IFF_BONDING;
kfree(slave);
@@ -2242,8 +2242,6 @@ static int bond_release_all(struct net_device *bond_dev)
dev_set_mac_address(slave_dev, &addr);
}
- slave_dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
-
kfree(slave);
/* re-acquire the lock before getting the next slave */
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 344d23f..5161183 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -1581,9 +1581,9 @@ static ssize_t bonding_store_slaves_active(struct device *d,
bond_for_each_slave(bond, slave, i) {
if (!bond_is_active_slave(slave)) {
if (new_value)
- slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
+ slave->inactive = 0;
else
- slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+ slave->inactive = 1;
}
}
out:
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 8a3718b..8f78166 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -190,8 +190,9 @@ struct slave {
unsigned long last_arp_rx;
s8 link; /* one of BOND_LINK_XXXX */
s8 new_link;
- u8 backup; /* indicates backup slave. Value corresponds with
- BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
+ u8 backup:1, /* indicates backup slave. Value corresponds with
+ BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
+ inactive:1; /* indicates inactive slave */
u32 original_mtu;
u32 link_failure_count;
u8 perm_hwaddr[ETH_ALEN];
@@ -374,13 +375,18 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave)
if (!bond_is_lb(bond))
bond_set_backup_slave(slave);
if (!bond->params.all_slaves_active)
- slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+ slave->inactive = 1;
}
static inline void bond_set_slave_active_flags(struct slave *slave)
{
bond_set_active_slave(slave);
- slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
+ slave->inactive = 0;
+}
+
+static inline bool bond_is_slave_inactive(struct slave *slave)
+{
+ return slave->inactive;
}
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
diff --git a/include/linux/if.h b/include/linux/if.h
index 2fdd47a..0da7991 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -59,18 +59,17 @@
/* Private (from user) interface flags (netdevice->priv_flags). */
#define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */
#define IFF_EBRIDGE 0x2 /* Ethernet bridging device. */
-#define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */
-#define IFF_BONDING 0x8 /* bonding master or slave */
-#define IFF_ISATAP 0x10 /* ISATAP interface (RFC4214) */
-#define IFF_WAN_HDLC 0x20 /* WAN HDLC device */
-#define IFF_XMIT_DST_RELEASE 0x40 /* dev_hard_start_xmit() is allowed to
+#define IFF_BONDING 0x4 /* bonding master or slave */
+#define IFF_ISATAP 0x8 /* ISATAP interface (RFC4214) */
+#define IFF_WAN_HDLC 0x10 /* WAN HDLC device */
+#define IFF_XMIT_DST_RELEASE 0x20 /* dev_hard_start_xmit() is allowed to
* release skb->dst
*/
-#define IFF_DONT_BRIDGE 0x80 /* disallow bridging this ether dev */
-#define IFF_DISABLE_NETPOLL 0x100 /* disable netpoll at run-time */
-#define IFF_MACVLAN_PORT 0x200 /* device used as macvlan port */
-#define IFF_BRIDGE_PORT 0x400 /* device used as bridge port */
-#define IFF_OVS_DATAPATH 0x800 /* device used as Open vSwitch
+#define IFF_DONT_BRIDGE 0x40 /* disallow bridging this ether dev */
+#define IFF_DISABLE_NETPOLL 0x80 /* disable netpoll at run-time */
+#define IFF_MACVLAN_PORT 0x100 /* device used as macvlan port */
+#define IFF_BRIDGE_PORT 0x200 /* device used as bridge port */
+#define IFF_OVS_DATAPATH 0x400 /* device used as Open vSwitch
* datapath port */
#define IF_GET_IFACE 0x0001 /* for querying only */
--
1.7.4
^ permalink raw reply related
* [patch net-next-2.6 6/8] bonding: move processing of recv handlers into handle_frame()
From: Jiri Pirko @ 2011-03-05 10:29 UTC (permalink / raw)
To: netdev
Cc: davem, shemminger, kaber, fubar, eric.dumazet, nicolas.2p.debian,
andy
In-Reply-To: <1299320969-7951-1-git-send-email-jpirko@redhat.com>
Since now when bonding uses rx_handler, all traffic going into bond
device goes thru bond_handle_frame. So there's no need to go back into
bonding code later via ptype handlers. This patch converts
original ptype handlers into "bonding receive probes". These functions
are called from bond_handle_frame and they are registered per-mode.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/bonding/bond_3ad.c | 29 ++--------
drivers/net/bonding/bond_3ad.h | 4 +-
drivers/net/bonding/bond_alb.c | 46 ++++-----------
drivers/net/bonding/bond_alb.h | 1 -
drivers/net/bonding/bond_main.c | 121 +++++++------------------------------
drivers/net/bonding/bond_sysfs.c | 6 --
drivers/net/bonding/bonding.h | 4 +-
7 files changed, 43 insertions(+), 168 deletions(-)
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 047af0b..194aaf7 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2461,35 +2461,16 @@ out:
return NETDEV_TX_OK;
}
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev)
+void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
+ struct slave *slave)
{
- struct bonding *bond = netdev_priv(dev);
- struct slave *slave = NULL;
- int ret = NET_RX_DROP;
-
- if (!(dev->flags & IFF_MASTER))
- goto out;
-
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (!skb)
- goto out;
+ if (skb->protocol != PKT_TYPE_LACPDU)
+ return;
if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
- goto out;
+ return;
read_lock(&bond->lock);
- slave = bond_get_slave_by_dev(netdev_priv(dev), orig_dev);
- if (!slave)
- goto out_unlock;
-
bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len);
-
- ret = NET_RX_SUCCESS;
-
-out_unlock:
read_unlock(&bond->lock);
-out:
- dev_kfree_skb(skb);
-
- return ret;
}
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 2c46a154..56a88ff 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -258,7 +258,6 @@ struct ad_bond_info {
* requested
*/
struct timer_list ad_timer;
- struct packet_type ad_pkt_type;
};
struct ad_slave_info {
@@ -279,7 +278,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave);
void bond_3ad_handle_link_change(struct slave *slave, char link);
int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev);
+void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
+ struct slave *slave);
int bond_3ad_set_carrier(struct bonding *bond);
#endif //__BOND_3AD_H__
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 9bc5de3..96d28f9 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -308,49 +308,33 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
_unlock_rx_hashtbl(bond);
}
-static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype, struct net_device *orig_dev)
+static void rlb_arp_recv(struct sk_buff *skb, struct bonding *bond,
+ struct slave *slave)
{
- struct bonding *bond;
- struct arp_pkt *arp = (struct arp_pkt *)skb->data;
- int res = NET_RX_DROP;
+ struct arp_pkt *arp;
- while (bond_dev->priv_flags & IFF_802_1Q_VLAN)
- bond_dev = vlan_dev_real_dev(bond_dev);
-
- if (!(bond_dev->priv_flags & IFF_BONDING) ||
- !(bond_dev->flags & IFF_MASTER))
- goto out;
+ if (skb->protocol != cpu_to_be16(ETH_P_ARP))
+ return;
+ arp = (struct arp_pkt *) skb->data;
if (!arp) {
pr_debug("Packet has no ARP data\n");
- goto out;
+ return;
}
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (!skb)
- goto out;
-
- if (!pskb_may_pull(skb, arp_hdr_len(bond_dev)))
- goto out;
+ if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
+ return;
if (skb->len < sizeof(struct arp_pkt)) {
pr_debug("Packet is too small to be an ARP\n");
- goto out;
+ return;
}
if (arp->op_code == htons(ARPOP_REPLY)) {
/* update rx hash table for this ARP */
- bond = netdev_priv(bond_dev);
rlb_update_entry_from_arp(bond, arp);
pr_debug("Server received an ARP Reply from client\n");
}
-
- res = NET_RX_SUCCESS;
-
-out:
- dev_kfree_skb(skb);
-
- return res;
}
/* Caller must hold bond lock for read */
@@ -759,7 +743,6 @@ static void rlb_init_table_entry(struct rlb_client_info *entry)
static int rlb_initialize(struct bonding *bond)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
- struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type);
struct rlb_client_info *new_hashtbl;
int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info);
int i;
@@ -784,13 +767,8 @@ static int rlb_initialize(struct bonding *bond)
_unlock_rx_hashtbl(bond);
- /*initialize packet type*/
- pk_type->type = cpu_to_be16(ETH_P_ARP);
- pk_type->dev = bond->dev;
- pk_type->func = rlb_arp_recv;
-
/* register to receive ARPs */
- dev_add_pack(pk_type);
+ bond->recv_probe = rlb_arp_recv;
return 0;
}
@@ -799,8 +777,6 @@ static void rlb_deinitialize(struct bonding *bond)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
- dev_remove_pack(&(bond_info->rlb_pkt_type));
-
_lock_rx_hashtbl(bond);
kfree(bond_info->rx_hashtbl);
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 118c28a..6605e9e 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -130,7 +130,6 @@ struct alb_bond_info {
int lp_counter;
/* -------- rlb parameters -------- */
int rlb_enabled;
- struct packet_type rlb_pkt_type;
struct rlb_client_info *rx_hashtbl; /* Receive hash table */
spinlock_t rx_hashtbl_lock;
u32 rx_hashtbl_head;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index dbe182c..8ba7faa 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1467,27 +1467,17 @@ static void bond_setup_by_slave(struct net_device *bond_dev,
}
/* On bonding slaves other than the currently active slave, suppress
- * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
- * ARP on active-backup slaves with arp_validate enabled.
+ * duplicates except for alb non-mcast/bcast.
*/
static bool bond_should_deliver_exact_match(struct sk_buff *skb,
struct slave *slave,
struct bonding *bond)
{
if (bond_is_slave_inactive(slave)) {
- if (slave_do_arp_validate(bond, slave) &&
- skb->protocol == __cpu_to_be16(ETH_P_ARP))
- return false;
-
if (bond->params.mode == BOND_MODE_ALB &&
skb->pkt_type != PACKET_BROADCAST &&
skb->pkt_type != PACKET_MULTICAST)
- return false;
-
- if (bond->params.mode == BOND_MODE_8023AD &&
- skb->protocol == __cpu_to_be16(ETH_P_SLOW))
return false;
-
return true;
}
return false;
@@ -1513,6 +1503,15 @@ static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
if (bond->params.arp_interval)
slave->dev->last_rx = jiffies;
+ if (bond->recv_probe) {
+ struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
+
+ if (likely(nskb)) {
+ bond->recv_probe(nskb, bond, slave);
+ dev_kfree_skb(nskb);
+ }
+ }
+
if (bond_should_deliver_exact_match(skb, slave, bond)) {
skb->deliver_no_wcard = 1;
return skb;
@@ -2813,48 +2812,26 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
}
}
-static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static void bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
+ struct slave *slave)
{
struct arphdr *arp;
- struct slave *slave;
- struct bonding *bond;
unsigned char *arp_ptr;
__be32 sip, tip;
- if (dev->priv_flags & IFF_802_1Q_VLAN) {
- /*
- * When using VLANS and bonding, dev and oriv_dev may be
- * incorrect if the physical interface supports VLAN
- * acceleration. With this change ARP validation now
- * works for hosts only reachable on the VLAN interface.
- */
- dev = vlan_dev_real_dev(dev);
- orig_dev = dev_get_by_index_rcu(dev_net(skb->dev),skb->skb_iif);
- }
-
- if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
- goto out;
+ if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
+ return;
- bond = netdev_priv(dev);
read_lock(&bond->lock);
- pr_debug("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
- bond->dev->name, skb->dev ? skb->dev->name : "NULL",
- orig_dev ? orig_dev->name : "NULL");
+ pr_debug("bond_arp_rcv: bond %s skb->dev %s\n",
+ bond->dev->name, skb->dev->name);
- slave = bond_get_slave_by_dev(bond, orig_dev);
- if (!slave || !slave_do_arp_validate(bond, slave))
- goto out_unlock;
-
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (!skb)
- goto out_unlock;
-
- if (!pskb_may_pull(skb, arp_hdr_len(dev)))
+ if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
goto out_unlock;
arp = arp_hdr(skb);
- if (arp->ar_hln != dev->addr_len ||
+ if (arp->ar_hln != bond->dev->addr_len ||
skb->pkt_type == PACKET_OTHERHOST ||
skb->pkt_type == PACKET_LOOPBACK ||
arp->ar_hrd != htons(ARPHRD_ETHER) ||
@@ -2863,9 +2840,9 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
goto out_unlock;
arp_ptr = (unsigned char *)(arp + 1);
- arp_ptr += dev->addr_len;
+ arp_ptr += bond->dev->addr_len;
memcpy(&sip, arp_ptr, 4);
- arp_ptr += 4 + dev->addr_len;
+ arp_ptr += 4 + bond->dev->addr_len;
memcpy(&tip, arp_ptr, 4);
pr_debug("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n",
@@ -2888,9 +2865,6 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
out_unlock:
read_unlock(&bond->lock);
-out:
- dev_kfree_skb(skb);
- return NET_RX_SUCCESS;
}
/*
@@ -3782,48 +3756,6 @@ static struct notifier_block bond_inetaddr_notifier = {
.notifier_call = bond_inetaddr_event,
};
-/*-------------------------- Packet type handling ---------------------------*/
-
-/* register to receive lacpdus on a bond */
-static void bond_register_lacpdu(struct bonding *bond)
-{
- struct packet_type *pk_type = &(BOND_AD_INFO(bond).ad_pkt_type);
-
- /* initialize packet type */
- pk_type->type = PKT_TYPE_LACPDU;
- pk_type->dev = bond->dev;
- pk_type->func = bond_3ad_lacpdu_recv;
-
- dev_add_pack(pk_type);
-}
-
-/* unregister to receive lacpdus on a bond */
-static void bond_unregister_lacpdu(struct bonding *bond)
-{
- dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type));
-}
-
-void bond_register_arp(struct bonding *bond)
-{
- struct packet_type *pt = &bond->arp_mon_pt;
-
- if (pt->type)
- return;
-
- pt->type = htons(ETH_P_ARP);
- pt->dev = bond->dev;
- pt->func = bond_arp_rcv;
- dev_add_pack(pt);
-}
-
-void bond_unregister_arp(struct bonding *bond)
-{
- struct packet_type *pt = &bond->arp_mon_pt;
-
- dev_remove_pack(pt);
- pt->type = 0;
-}
-
/*---------------------------- Hashing Policies -----------------------------*/
/*
@@ -3917,14 +3849,14 @@ static int bond_open(struct net_device *bond_dev)
queue_delayed_work(bond->wq, &bond->arp_work, 0);
if (bond->params.arp_validate)
- bond_register_arp(bond);
+ bond->recv_probe = bond_arp_rcv;
}
if (bond->params.mode == BOND_MODE_8023AD) {
INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler);
queue_delayed_work(bond->wq, &bond->ad_work, 0);
/* register to receive LACPDUs */
- bond_register_lacpdu(bond);
+ bond->recv_probe = bond_3ad_lacpdu_recv;
bond_3ad_initiate_agg_selection(bond, 1);
}
@@ -3935,14 +3867,6 @@ static int bond_close(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- if (bond->params.mode == BOND_MODE_8023AD) {
- /* Unregister the receive of LACPDUs */
- bond_unregister_lacpdu(bond);
- }
-
- if (bond->params.arp_validate)
- bond_unregister_arp(bond);
-
write_lock_bh(&bond->lock);
bond->send_grat_arp = 0;
@@ -3982,6 +3906,7 @@ static int bond_close(struct net_device *bond_dev)
*/
bond_alb_deinitialize(bond);
}
+ bond->recv_probe = NULL;
return 0;
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 5161183..6804efe 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -419,11 +419,6 @@ static ssize_t bonding_store_arp_validate(struct device *d,
bond->dev->name, arp_validate_tbl[new_value].modename,
new_value);
- if (!bond->params.arp_validate && new_value)
- bond_register_arp(bond);
- else if (bond->params.arp_validate && !new_value)
- bond_unregister_arp(bond);
-
bond->params.arp_validate = new_value;
return count;
@@ -998,7 +993,6 @@ static ssize_t bonding_store_miimon(struct device *d,
bond->dev->name);
bond->params.arp_interval = 0;
if (bond->params.arp_validate) {
- bond_unregister_arp(bond);
bond->params.arp_validate =
BOND_ARP_VALIDATE_NONE;
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 8f78166..75a1308 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -228,6 +228,8 @@ struct bonding {
struct slave *primary_slave;
bool force_primary;
s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
+ void (*recv_probe)(struct sk_buff *, struct bonding *,
+ struct slave *);
rwlock_t lock;
rwlock_t curr_slave_lock;
s8 kill_timers;
@@ -406,8 +408,6 @@ void bond_set_mode_ops(struct bonding *bond, int mode);
int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl);
void bond_select_active_slave(struct bonding *bond);
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
-void bond_register_arp(struct bonding *);
-void bond_unregister_arp(struct bonding *);
void bond_create_debugfs(void);
void bond_destroy_debugfs(void);
void bond_debug_register(struct bonding *bond);
--
1.7.4
^ permalink raw reply related
* [patch net-next-2.6 7/8] net: introduce rx_handler results and logic around that
From: Jiri Pirko @ 2011-03-05 10:29 UTC (permalink / raw)
To: netdev
Cc: davem, shemminger, kaber, fubar, eric.dumazet, nicolas.2p.debian,
andy
In-Reply-To: <1299320969-7951-1-git-send-email-jpirko@redhat.com>
This patch allows rx_handlers to better signalize what to do next to
it's caller. That makes skb->deliver_no_wcard no longer needed.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/bonding/bond_main.c | 20 +++++++++++---------
drivers/net/macvlan.c | 11 ++++++-----
include/linux/netdevice.h | 9 ++++++++-
include/linux/skbuff.h | 5 +----
net/bridge/br_input.c | 25 +++++++++++++++----------
net/bridge/br_private.h | 2 +-
net/core/dev.c | 19 ++++++++++++-------
7 files changed, 54 insertions(+), 37 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 8ba7faa..ab56190 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1483,20 +1483,23 @@ static bool bond_should_deliver_exact_match(struct sk_buff *skb,
return false;
}
-static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
+static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
{
+ struct sk_buff *skb = *pskb;
struct slave *slave;
struct net_device *bond_dev;
struct bonding *bond;
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (unlikely(!skb))
- return NULL;
-
slave = bond_slave_get_rcu(skb->dev);
bond_dev = ACCESS_ONCE(slave->dev->master);
if (unlikely(!bond_dev))
- return skb;
+ return RX_HANDLER_PASS;
+
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return RX_HANDLER_CONSUMED;
+
+ *pskb = skb;
bond = netdev_priv(bond_dev);
@@ -1513,8 +1516,7 @@ static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
}
if (bond_should_deliver_exact_match(skb, slave, bond)) {
- skb->deliver_no_wcard = 1;
- return skb;
+ return RX_HANDLER_EXACT;
}
skb->dev = bond_dev;
@@ -1527,7 +1529,7 @@ static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
memcpy(dest, bond_dev->dev_addr, ETH_ALEN);
}
- return skb;
+ return RX_HANDLER_ANOTHER;
}
/* enslave device <slave> to bond device <master> */
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 6ed577b..ead9a8f 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -152,9 +152,10 @@ static void macvlan_broadcast(struct sk_buff *skb,
}
/* called under rcu_read_lock() from netif_receive_skb */
-static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
{
struct macvlan_port *port;
+ struct sk_buff *skb = *pskb;
const struct ethhdr *eth = eth_hdr(skb);
const struct macvlan_dev *vlan;
const struct macvlan_dev *src;
@@ -184,7 +185,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
*/
macvlan_broadcast(skb, port, src->dev,
MACVLAN_MODE_VEPA);
- return skb;
+ return RX_HANDLER_PASS;
}
if (port->passthru)
@@ -192,12 +193,12 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
else
vlan = macvlan_hash_lookup(port, eth->h_dest);
if (vlan == NULL)
- return skb;
+ return RX_HANDLER_PASS;
dev = vlan->dev;
if (unlikely(!(dev->flags & IFF_UP))) {
kfree_skb(skb);
- return NULL;
+ return RX_HANDLER_CONSUMED;
}
len = skb->len + ETH_HLEN;
skb = skb_share_check(skb, GFP_ATOMIC);
@@ -211,7 +212,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
out:
macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0);
- return NULL;
+ return RX_HANDLER_CONSUMED;
}
static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 8be4056..ff386a4 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -390,7 +390,14 @@ enum gro_result {
};
typedef enum gro_result gro_result_t;
-typedef struct sk_buff *rx_handler_func_t(struct sk_buff *skb);
+enum rx_handler_result {
+ RX_HANDLER_CONSUMED,
+ RX_HANDLER_ANOTHER,
+ RX_HANDLER_EXACT,
+ RX_HANDLER_PASS,
+};
+typedef enum rx_handler_result rx_handler_result_t;
+typedef rx_handler_result_t rx_handler_func_t(struct sk_buff **pskb);
extern void __napi_schedule(struct napi_struct *n);
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 31f02d0..24cfa62 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -388,10 +388,7 @@ struct sk_buff {
kmemcheck_bitfield_begin(flags2);
__u16 queue_mapping:16;
#ifdef CONFIG_IPV6_NDISC_NODETYPE
- __u8 ndisc_nodetype:2,
- deliver_no_wcard:1;
-#else
- __u8 deliver_no_wcard:1;
+ __u8 ndisc_nodetype:2;
#endif
__u8 ooo_okay:1;
kmemcheck_bitfield_end(flags2);
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 88e4aa9..e216079 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -139,21 +139,22 @@ static inline int is_link_local(const unsigned char *dest)
* Return NULL if skb is handled
* note: already called with rcu_read_lock
*/
-struct sk_buff *br_handle_frame(struct sk_buff *skb)
+rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
{
struct net_bridge_port *p;
+ struct sk_buff *skb = *pskb;
const unsigned char *dest = eth_hdr(skb)->h_dest;
br_should_route_hook_t *rhook;
if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
- return skb;
+ return RX_HANDLER_PASS;
if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
goto drop;
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
- return NULL;
+ return RX_HANDLER_CONSUMED;
p = br_port_get_rcu(skb->dev);
@@ -167,10 +168,12 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb)
goto forward;
if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
- NULL, br_handle_local_finish))
- return NULL; /* frame consumed by filter */
- else
- return skb; /* continue processing */
+ NULL, br_handle_local_finish)) {
+ return RX_HANDLER_CONSUMED; /* consumed by filter */
+ } else {
+ *pskb = skb;
+ return RX_HANDLER_PASS; /* continue processing */
+ }
}
forward:
@@ -178,8 +181,10 @@ forward:
case BR_STATE_FORWARDING:
rhook = rcu_dereference(br_should_route_hook);
if (rhook) {
- if ((*rhook)(skb))
- return skb;
+ if ((*rhook)(skb)) {
+ *pskb = skb;
+ return RX_HANDLER_PASS;
+ }
dest = eth_hdr(skb)->h_dest;
}
/* fall through */
@@ -194,5 +199,5 @@ forward:
drop:
kfree_skb(skb);
}
- return NULL;
+ return RX_HANDLER_CONSUMED;
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f7afc36..19e2f46 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -379,7 +379,7 @@ extern void br_features_recompute(struct net_bridge *br);
/* br_input.c */
extern int br_handle_frame_finish(struct sk_buff *skb);
-extern struct sk_buff *br_handle_frame(struct sk_buff *skb);
+extern rx_handler_result_t br_handle_frame(struct sk_buff **pskb);
/* br_ioctl.c */
extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
diff --git a/net/core/dev.c b/net/core/dev.c
index 9f66de9..58daddb 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3121,6 +3121,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
rx_handler_func_t *rx_handler;
struct net_device *orig_dev;
struct net_device *null_or_dev;
+ bool deliver_exact = false;
int ret = NET_RX_DROP;
__be16 type;
@@ -3173,18 +3174,22 @@ ncls:
rx_handler = rcu_dereference(skb->dev->rx_handler);
if (rx_handler) {
- struct net_device *prev_dev;
-
if (pt_prev) {
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = NULL;
}
- prev_dev = skb->dev;
- skb = rx_handler(skb);
- if (!skb)
+ switch (rx_handler(&skb)) {
+ case RX_HANDLER_CONSUMED:
goto out;
- if (skb->dev != prev_dev)
+ case RX_HANDLER_ANOTHER:
goto another_round;
+ case RX_HANDLER_EXACT:
+ deliver_exact = true;
+ case RX_HANDLER_PASS:
+ break;
+ default:
+ BUG();
+ }
}
if (vlan_tx_tag_present(skb)) {
@@ -3202,7 +3207,7 @@ ncls:
vlan_on_bond_hook(skb);
/* deliver only exact match when indicated */
- null_or_dev = skb->deliver_no_wcard ? skb->dev : NULL;
+ null_or_dev = deliver_exact ? skb->dev : NULL;
type = skb->protocol;
list_for_each_entry_rcu(ptype,
--
1.7.4
^ permalink raw reply related
* [patch net-next-2.6 8/8] net: get rid of orig_dev parameter of packet handlers
From: Jiri Pirko @ 2011-03-05 10:29 UTC (permalink / raw)
To: netdev
Cc: davem, shemminger, kaber, fubar, eric.dumazet, nicolas.2p.debian,
andy
In-Reply-To: <1299320969-7951-1-git-send-email-jpirko@redhat.com>
Since orig_dev was used in af_packet (where it was replaced) and by
bonding ptype handlers (which are no longer with us) only, orig_dev
parameter is no longer needed -> toss it out
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/block/aoe/aoenet.c | 2 +-
drivers/net/hamradio/bpqether.c | 4 ++--
drivers/net/pppoe.c | 4 ++--
drivers/net/wan/hdlc.c | 2 +-
drivers/net/wan/lapbether.c | 2 +-
drivers/scsi/fcoe/fcoe.c | 12 ++++--------
include/linux/netdevice.h | 3 +--
include/net/ax25.h | 3 ++-
include/net/datalink.h | 2 +-
include/net/ip.h | 2 +-
include/net/ipv6.h | 3 +--
include/net/irda/irda.h | 3 +--
include/net/llc.h | 8 +++-----
include/net/p8022.h | 3 +--
include/net/psnap.h | 3 +--
include/net/x25.h | 2 +-
net/802/p8022.c | 3 +--
net/802/psnap.c | 7 +++----
net/802/stp.c | 2 +-
net/8021q/vlan.h | 2 +-
net/8021q/vlan_dev.c | 2 +-
net/appletalk/aarp.c | 2 +-
net/appletalk/ddp.c | 6 +++---
net/ax25/ax25_in.c | 2 +-
net/batman-adv/hard-interface.c | 6 ++----
net/caif/caif_dev.c | 2 +-
net/can/af_can.c | 2 +-
net/core/dev.c | 26 ++++++++++++--------------
net/core/skbuff.c | 1 -
net/decnet/af_decnet.c | 2 +-
net/decnet/dn_route.c | 2 +-
net/dsa/tag_dsa.c | 2 +-
net/dsa/tag_edsa.c | 2 +-
net/dsa/tag_trailer.c | 2 +-
net/econet/af_econet.c | 2 +-
net/ieee802154/af_ieee802154.c | 2 +-
net/ipv4/arp.c | 2 +-
net/ipv4/ip_input.c | 2 +-
net/ipv4/ipconfig.c | 13 ++++++++-----
net/ipv6/ip6_input.c | 3 ++-
net/ipx/af_ipx.c | 3 ++-
net/irda/irlap_frame.c | 2 +-
net/llc/llc_core.c | 3 +--
net/llc/llc_input.c | 8 ++++----
net/packet/af_packet.c | 6 +++---
net/phonet/af_phonet.c | 3 +--
net/tipc/eth_media.c | 2 +-
net/x25/x25_dev.c | 2 +-
48 files changed, 85 insertions(+), 99 deletions(-)
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index 4d3bc0d..c12e14b 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -99,7 +99,7 @@ aoenet_xmit(struct sk_buff_head *queue)
* (1) len doesn't include the header by default. I want this.
*/
static int
-aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev)
+aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt)
{
struct aoe_hdr *h;
u32 n;
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 8931168..f17ca33 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -95,7 +95,7 @@ static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
static char bpq_eth_addr[6];
-static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
+static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
static int bpq_device_event(struct notifier_block *, unsigned long, void *);
static struct packet_type bpq_packet_type __read_mostly = {
@@ -177,7 +177,7 @@ static inline int dev_is_ethdev(struct net_device *dev)
/*
* Receive an AX.25 frame via an ethernet interface.
*/
-static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
+static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
{
int len;
char * ptr;
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 78c0e3c..b99cdaa 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -419,7 +419,7 @@ abort_kfree:
*
***********************************************************************/
static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct pppoe_hdr *ph;
struct pppox_sock *po;
@@ -467,7 +467,7 @@ out:
*
***********************************************************************/
static int pppoe_disc_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct pppoe_hdr *ph;
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index 5d4bb61..0ac4f27 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -53,7 +53,7 @@ int hdlc_change_mtu(struct net_device *dev, int new_mtu)
}
static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *p, struct net_device *orig_dev)
+ struct packet_type *p)
{
struct hdlc_device *hdlc = dev_to_hdlc(dev);
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 7f5bb91..993d71a 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -86,7 +86,7 @@ static __inline__ int dev_is_ethdev(struct net_device *dev)
/*
* Receive a LAPB frame via an ethernet interface.
*/
-static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
+static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
{
int len, err;
struct lapbethdev *lapbeth;
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 3becc6a..d7442b6 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -70,7 +70,7 @@ DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu);
static int fcoe_reset(struct Scsi_Host *);
static int fcoe_xmit(struct fc_lport *, struct fc_frame *);
static int fcoe_rcv(struct sk_buff *, struct net_device *,
- struct packet_type *, struct net_device *);
+ struct packet_type *);
static int fcoe_percpu_receive_thread(void *);
static void fcoe_clean_pending_queue(struct fc_lport *);
static void fcoe_percpu_clean(struct fc_lport *);
@@ -88,7 +88,7 @@ static struct fcoe_interface
*fcoe_hostlist_lookup_port(const struct net_device *);
static int fcoe_fip_recv(struct sk_buff *, struct net_device *,
- struct packet_type *, struct net_device *);
+ struct packet_type *);
static void fcoe_fip_send(struct fcoe_ctlr *, struct sk_buff *);
static void fcoe_update_src_mac(struct fc_lport *, u8 *);
@@ -465,14 +465,11 @@ static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
* @skb: The receive skb
* @netdev: The associated net device
* @ptype: The packet_type structure which was used to register this handler
- * @orig_dev: The original net_device the the skb was received on.
- * (in case dev is a bond)
*
* Returns: 0 for success
*/
static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev,
- struct packet_type *ptype,
- struct net_device *orig_dev)
+ struct packet_type *ptype)
{
struct fcoe_interface *fcoe;
@@ -1228,7 +1225,6 @@ static int fcoe_cpu_callback(struct notifier_block *nfb,
* @skb: The received packet
* @netdev: The net device that the packet was received on
* @ptype: The packet type context
- * @olddev: The last device net device
*
* This routine is called by NET_RX_SOFTIRQ. It receives a packet, builds a
* FC frame and passes the frame to libfc.
@@ -1236,7 +1232,7 @@ static int fcoe_cpu_callback(struct notifier_block *nfb,
* Returns: 0 for success
*/
int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
- struct packet_type *ptype, struct net_device *olddev)
+ struct packet_type *ptype)
{
struct fc_lport *lport;
struct fcoe_rcv_info *fr;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ff386a4..48a9638 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1456,8 +1456,7 @@ struct packet_type {
struct net_device *dev; /* NULL is wildcarded here */
int (*func) (struct sk_buff *,
struct net_device *,
- struct packet_type *,
- struct net_device *);
+ struct packet_type *);
struct sk_buff *(*gso_segment)(struct sk_buff *skb,
u32 features);
int (*gso_send_check)(struct sk_buff *skb);
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 206d222..fcbe6d8 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -362,7 +362,8 @@ extern int ax25_protocol_is_registered(unsigned int);
/* ax25_in.c */
extern int ax25_rx_iframe(ax25_cb *, struct sk_buff *);
-extern int ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
+extern int ax25_kiss_rcv(struct sk_buff *, struct net_device *,
+ struct packet_type *);
/* ax25_ip.c */
extern int ax25_hard_header(struct sk_buff *, struct net_device *,
diff --git a/include/net/datalink.h b/include/net/datalink.h
index deb7ca7..5797ba3 100644
--- a/include/net/datalink.h
+++ b/include/net/datalink.h
@@ -9,7 +9,7 @@ struct datalink_proto {
unsigned short header_length;
int (*rcvfunc)(struct sk_buff *, struct net_device *,
- struct packet_type *, struct net_device *);
+ struct packet_type *);
int (*request)(struct datalink_proto *, struct sk_buff *,
unsigned char *);
struct list_head node;
diff --git a/include/net/ip.h b/include/net/ip.h
index a4f6311..3b04c24 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -94,7 +94,7 @@ extern int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
__be32 saddr, __be32 daddr,
struct ip_options *opt);
extern int ip_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev);
+ struct packet_type *pt);
extern int ip_local_deliver(struct sk_buff *skb);
extern int ip_mr_input(struct sk_buff *skb);
extern int ip_output(struct sk_buff *skb);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index d6d077d..990f90b 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -470,8 +470,7 @@ static __inline__ void ipv6_select_ident(struct frag_hdr *fhdr)
extern int ipv6_rcv(struct sk_buff *skb,
struct net_device *dev,
- struct packet_type *pt,
- struct net_device *orig_dev);
+ struct packet_type *pt);
extern int ip6_rcv_finish(struct sk_buff *skb);
diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h
index 3bed61d..2c6e25d 100644
--- a/include/net/irda/irda.h
+++ b/include/net/irda/irda.h
@@ -125,7 +125,6 @@ extern int irda_nl_register(void);
extern void irda_nl_unregister(void);
extern int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype,
- struct net_device *orig_dev);
+ struct packet_type *ptype);
#endif /* NET_IRDA_H */
diff --git a/include/net/llc.h b/include/net/llc.h
index 5503b74..73bfea5 100644
--- a/include/net/llc.h
+++ b/include/net/llc.h
@@ -58,8 +58,7 @@ struct llc_sap {
atomic_t refcnt;
int (*rcv_func)(struct sk_buff *skb,
struct net_device *dev,
- struct packet_type *pt,
- struct net_device *orig_dev);
+ struct packet_type *pt);
struct llc_addr laddr;
struct list_head node;
spinlock_t sk_lock;
@@ -96,7 +95,7 @@ extern struct list_head llc_sap_list;
extern spinlock_t llc_sap_list_lock;
extern int llc_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev);
+ struct packet_type *pt);
extern int llc_mac_hdr_init(struct sk_buff *skb,
const unsigned char *sa, const unsigned char *da);
@@ -110,8 +109,7 @@ extern void llc_set_station_handler(void (*handler)(struct sk_buff *skb));
extern struct llc_sap *llc_sap_open(unsigned char lsap,
int (*rcv)(struct sk_buff *skb,
struct net_device *dev,
- struct packet_type *pt,
- struct net_device *orig_dev));
+ struct packet_type *pt));
static inline void llc_sap_hold(struct llc_sap *sap)
{
atomic_inc(&sap->refcnt);
diff --git a/include/net/p8022.h b/include/net/p8022.h
index 42e9fac..6d878ae 100644
--- a/include/net/p8022.h
+++ b/include/net/p8022.h
@@ -4,8 +4,7 @@ extern struct datalink_proto *
register_8022_client(unsigned char type,
int (*func)(struct sk_buff *skb,
struct net_device *dev,
- struct packet_type *pt,
- struct net_device *orig_dev));
+ struct packet_type *pt));
extern void unregister_8022_client(struct datalink_proto *proto);
extern struct datalink_proto *make_8023_client(void);
diff --git a/include/net/psnap.h b/include/net/psnap.h
index fe456c2..604bf4b 100644
--- a/include/net/psnap.h
+++ b/include/net/psnap.h
@@ -4,8 +4,7 @@
extern struct datalink_proto *
register_snap_client(const unsigned char *desc,
int (*rcvfunc)(struct sk_buff *, struct net_device *,
- struct packet_type *,
- struct net_device *orig_dev));
+ struct packet_type *));
extern void unregister_snap_client(struct datalink_proto *proto);
#endif
diff --git a/include/net/x25.h b/include/net/x25.h
index a06119a..3f1c0df2 100644
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -202,7 +202,7 @@ extern void x25_kill_by_neigh(struct x25_neigh *);
/* x25_dev.c */
extern void x25_send_frame(struct sk_buff *, struct x25_neigh *);
-extern int x25_lapb_receive_frame(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
+extern int x25_lapb_receive_frame(struct sk_buff *, struct net_device *, struct packet_type *);
extern void x25_establish_link(struct x25_neigh *);
extern void x25_terminate_link(struct x25_neigh *);
diff --git a/net/802/p8022.c b/net/802/p8022.c
index 7f353c4..4ab1339 100644
--- a/net/802/p8022.c
+++ b/net/802/p8022.c
@@ -36,8 +36,7 @@ static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb,
struct datalink_proto *register_8022_client(unsigned char type,
int (*func)(struct sk_buff *skb,
struct net_device *dev,
- struct packet_type *pt,
- struct net_device *orig_dev))
+ struct packet_type *pt))
{
struct datalink_proto *proto;
diff --git a/net/802/psnap.c b/net/802/psnap.c
index 21cde8f..e74b48e 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -47,7 +47,7 @@ static struct datalink_proto *find_snap_client(const unsigned char *desc)
* A SNAP packet has arrived
*/
static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
int rc = 1;
struct datalink_proto *proto;
@@ -64,7 +64,7 @@ static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
/* Pass the frame on. */
skb->transport_header += 5;
skb_pull_rcsum(skb, 5);
- rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev);
+ rc = proto->rcvfunc(skb, dev, &snap_packet_type);
}
rcu_read_unlock();
@@ -126,8 +126,7 @@ module_exit(snap_exit);
struct datalink_proto *register_snap_client(const unsigned char *desc,
int (*rcvfunc)(struct sk_buff *,
struct net_device *,
- struct packet_type *,
- struct net_device *))
+ struct packet_type *))
{
struct datalink_proto *proto = NULL;
diff --git a/net/802/stp.c b/net/802/stp.c
index 978c30b..dec1f88 100644
--- a/net/802/stp.c
+++ b/net/802/stp.c
@@ -30,7 +30,7 @@ static DEFINE_MUTEX(stp_proto_mutex);
/* Called under rcu_read_lock from LLC */
static int stp_pdu_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
const struct ethhdr *eh = eth_hdr(skb);
const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 5687c9b..6f8941e 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -76,7 +76,7 @@ static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
/* found in vlan_dev.c */
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev);
+ struct packet_type *ptype);
void vlan_dev_set_ingress_priority(const struct net_device *dev,
u32 skb_prio, u16 vlan_prio);
int vlan_dev_set_egress_priority(const struct net_device *dev,
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index be73753..6e396b9 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -138,7 +138,7 @@ static inline void vlan_set_encap_proto(struct sk_buff *skb,
*
*/
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev)
+ struct packet_type *ptype)
{
struct vlan_hdr *vhdr;
struct vlan_pcpu_stats *rx_stats;
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
index 50dce79..996f366 100644
--- a/net/appletalk/aarp.c
+++ b/net/appletalk/aarp.c
@@ -715,7 +715,7 @@ static void __aarp_resolved(struct aarp_entry **list, struct aarp_entry *a,
* frame. We currently only support Ethernet.
*/
static int aarp_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct elapaarp *ea = aarp_hdr(skb);
int hash, ret = 0;
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index c410b93..61b4983 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1425,7 +1425,7 @@ drop:
* layer. [ie ARPHRD_ETHERTALK]
*/
static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct ddpehdr *ddp;
struct sock *sock;
@@ -1522,7 +1522,7 @@ out:
* header and append a long one.
*/
static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
if (!net_eq(dev_net(dev), &init_net))
goto freeit;
@@ -1568,7 +1568,7 @@ static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
}
skb_reset_transport_header(skb);
- return atalk_rcv(skb, dev, pt, orig_dev);
+ return atalk_rcv(skb, dev, pt);
freeit:
kfree_skb(skb);
return 0;
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
index 9bb7765..f6f94e6 100644
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -436,7 +436,7 @@ free:
* Receive an AX.25 frame via a SLIP interface.
*/
int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev)
+ struct packet_type *ptype)
{
skb_orphan(skb);
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index f2131f4..08579b0 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -37,8 +37,7 @@ static DEFINE_SPINLOCK(if_list_lock);
static int batman_skb_recv(struct sk_buff *skb,
struct net_device *dev,
- struct packet_type *ptype,
- struct net_device *orig_dev);
+ struct packet_type *ptype);
static void hardif_free_rcu(struct rcu_head *rcu)
{
@@ -556,8 +555,7 @@ out:
/* receive a packet with the batman ethertype coming on a hard
* interface */
static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype,
- struct net_device *orig_dev)
+ struct packet_type *ptype)
{
struct bat_priv *bat_priv;
struct batman_packet *batman_packet;
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index a42a408..9f016f0 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -165,7 +165,7 @@ static int modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
* On error, returns non-zero and releases the skb.
*/
static int receive(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pkttype, struct net_device *orig_dev)
+ struct packet_type *pkttype)
{
struct net *net;
struct cfpkt *pkt;
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 702be5a..ad32de5 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -616,7 +616,7 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
}
static int can_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct dev_rcv_lists *d;
struct can_frame *cf = (struct can_frame *)skb->data;
diff --git a/net/core/dev.c b/net/core/dev.c
index 58daddb..c71bd18 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1534,11 +1534,10 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
EXPORT_SYMBOL_GPL(dev_forward_skb);
static inline int deliver_skb(struct sk_buff *skb,
- struct packet_type *pt_prev,
- struct net_device *orig_dev)
+ struct packet_type *pt_prev)
{
atomic_inc(&skb->users);
- return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
+ return pt_prev->func(skb, skb->dev, pt_prev);
}
/*
@@ -1561,7 +1560,7 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
(ptype->af_packet_priv == NULL ||
(struct sock *)ptype->af_packet_priv != skb->sk)) {
if (pt_prev) {
- deliver_skb(skb2, pt_prev, skb->dev);
+ deliver_skb(skb2, pt_prev);
pt_prev = ptype;
continue;
}
@@ -1594,7 +1593,7 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
}
}
if (pt_prev)
- pt_prev->func(skb2, skb->dev, pt_prev, skb->dev);
+ pt_prev->func(skb2, skb->dev, pt_prev);
rcu_read_unlock();
}
@@ -3025,8 +3024,7 @@ static int ing_filter(struct sk_buff *skb, struct netdev_queue *rxq)
}
static inline struct sk_buff *handle_ing(struct sk_buff *skb,
- struct packet_type **pt_prev,
- int *ret, struct net_device *orig_dev)
+ struct packet_type **pt_prev, int *ret)
{
struct netdev_queue *rxq = rcu_dereference(skb->dev->ingress_queue);
@@ -3034,7 +3032,7 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,
goto out;
if (*pt_prev) {
- *ret = deliver_skb(skb, *pt_prev, orig_dev);
+ *ret = deliver_skb(skb, *pt_prev);
*pt_prev = NULL;
}
@@ -3160,13 +3158,13 @@ another_round:
list_for_each_entry_rcu(ptype, &ptype_all, list) {
if (!ptype->dev || ptype->dev == skb->dev) {
if (pt_prev)
- ret = deliver_skb(skb, pt_prev, orig_dev);
+ ret = deliver_skb(skb, pt_prev);
pt_prev = ptype;
}
}
#ifdef CONFIG_NET_CLS_ACT
- skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
+ skb = handle_ing(skb, &pt_prev, &ret);
if (!skb)
goto out;
ncls:
@@ -3175,7 +3173,7 @@ ncls:
rx_handler = rcu_dereference(skb->dev->rx_handler);
if (rx_handler) {
if (pt_prev) {
- ret = deliver_skb(skb, pt_prev, orig_dev);
+ ret = deliver_skb(skb, pt_prev);
pt_prev = NULL;
}
switch (rx_handler(&skb)) {
@@ -3194,7 +3192,7 @@ ncls:
if (vlan_tx_tag_present(skb)) {
if (pt_prev) {
- ret = deliver_skb(skb, pt_prev, orig_dev);
+ ret = deliver_skb(skb, pt_prev);
pt_prev = NULL;
}
if (vlan_hwaccel_do_receive(&skb)) {
@@ -3216,13 +3214,13 @@ ncls:
(ptype->dev == null_or_dev || ptype->dev == skb->dev ||
ptype->dev == orig_dev)) {
if (pt_prev)
- ret = deliver_skb(skb, pt_prev, orig_dev);
+ ret = deliver_skb(skb, pt_prev);
pt_prev = ptype;
}
}
if (pt_prev) {
- ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
+ ret = pt_prev->func(skb, skb->dev, pt_prev);
} else {
atomic_long_inc(&skb->dev->rx_dropped);
kfree_skb(skb);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 1eb526a..801dd08 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -523,7 +523,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->ip_summed = old->ip_summed;
skb_copy_queue_mapping(new, old);
new->priority = old->priority;
- new->deliver_no_wcard = old->deliver_no_wcard;
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
new->ipvs_property = old->ipvs_property;
#endif
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 2af15b1..1421721 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -2106,7 +2106,7 @@ static struct notifier_block dn_dev_notifier = {
.notifier_call = dn_device_event,
};
-extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
+extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
static struct packet_type dn_dix_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_DNA_RT),
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 484fdbf..20abc79 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -588,7 +588,7 @@ static int dn_route_ptp_hello(struct sk_buff *skb)
return NET_RX_SUCCESS;
}
-int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
struct dn_skb_cb *cb;
unsigned char flags = 0;
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 98dfe80..56b686e 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -77,7 +77,7 @@ out_free:
}
static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index 6f38332..474a955 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -90,7 +90,7 @@ out_free:
}
static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index d6d7d0a..f8f36ad 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -67,7 +67,7 @@ netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)
}
static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 0c28263..edeea09 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -1052,7 +1052,7 @@ release:
* Receive an Econet frame from a device.
*/
-static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
struct ec_framehdr *hdr;
struct sock *sk = NULL;
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c
index 6df6ecf..68d5bce 100644
--- a/net/ieee802154/af_ieee802154.c
+++ b/net/ieee802154/af_ieee802154.c
@@ -299,7 +299,7 @@ static const struct net_proto_family ieee802154_family_ops = {
};
static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
if (!netif_running(dev))
return -ENODEV;
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index fa9988d..53a8f14 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -974,7 +974,7 @@ static void parp_redo(struct sk_buff *skb)
*/
static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct arphdr *arp;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index d7b2b09..639b69b 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -372,7 +372,7 @@ drop:
/*
* Main IP Receive routine.
*/
-int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
struct iphdr *iph;
u32 len;
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 2b09775..5669509 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -438,7 +438,8 @@ static int __init ic_defaults(void)
#ifdef IPCONFIG_RARP
-static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
+static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt);
static struct packet_type rarp_packet_type __initdata = {
.type = cpu_to_be16(ETH_P_RARP),
@@ -458,8 +459,8 @@ static inline void __init ic_rarp_cleanup(void)
/*
* Process received RARP packet.
*/
-static int __init
-ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static int __init ic_rarp_recv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt)
{
struct arphdr *rarp;
unsigned char *rarp_ptr;
@@ -600,7 +601,8 @@ struct bootp_pkt { /* BOOTP packet format */
#define DHCPRELEASE 7
#define DHCPINFORM 8
-static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
+static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev
+ struct packet_type *pt);
static struct packet_type bootp_packet_type __initdata = {
.type = cpu_to_be16(ETH_P_IP),
@@ -893,7 +895,8 @@ static void __init ic_do_bootp_ext(u8 *ext)
/*
* Receive BOOTP reply.
*/
-static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt)
{
struct bootp_pkt *b;
struct iphdr *h;
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index a83e920..dd72591 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -55,7 +55,8 @@ inline int ip6_rcv_finish( struct sk_buff *skb)
return dst_input(skb);
}
-int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+int ipv6_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt)
{
struct ipv6hdr *hdr;
u32 pkt_len;
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index da3d21c..614e207 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -1665,7 +1665,8 @@ static unsigned int ipx_datagram_poll(struct file *file, struct socket *sock,
return rc;
}
-static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static int ipx_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt)
{
/* NULL here for pt means the packet was looped back */
struct ipx_interface *intrfc;
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 688222c..7850321 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -1306,7 +1306,7 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
* Jean II
*/
int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev)
+ struct packet_type *ptype)
{
struct irlap_info info;
struct irlap_cb *self;
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c
index 2bb0ddf..dfeda38 100644
--- a/net/llc/llc_core.c
+++ b/net/llc/llc_core.c
@@ -91,8 +91,7 @@ struct llc_sap *llc_sap_find(unsigned char sap_value)
struct llc_sap *llc_sap_open(unsigned char lsap,
int (*func)(struct sk_buff *skb,
struct net_device *dev,
- struct packet_type *pt,
- struct net_device *orig_dev))
+ struct packet_type *pt))
{
struct llc_sap *sap = NULL;
diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c
index 058f1e9..d884e23 100644
--- a/net/llc/llc_input.c
+++ b/net/llc/llc_input.c
@@ -143,13 +143,13 @@ static inline int llc_fixup_skb(struct sk_buff *skb)
* data now), it queues this frame in the connection's backlog.
*/
int llc_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct llc_sap *sap;
struct llc_pdu_sn *pdu;
int dest;
int (*rcv)(struct sk_buff *, struct net_device *,
- struct packet_type *, struct net_device *);
+ struct packet_type *);
if (!net_eq(dev_net(dev), &init_net))
goto drop;
@@ -184,14 +184,14 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
dest = llc_pdu_type(skb);
if (unlikely(!dest || !llc_type_handlers[dest - 1])) {
if (rcv)
- rcv(skb, dev, pt, orig_dev);
+ rcv(skb, dev, pt);
else
kfree_skb(skb);
} else {
if (rcv) {
struct sk_buff *cskb = skb_clone(skb, GFP_ATOMIC);
if (cskb)
- rcv(cskb, dev, pt, orig_dev);
+ rcv(cskb, dev, pt);
}
llc_type_handlers[dest - 1](sap, skb);
}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index b34294e..85e2493 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -350,7 +350,7 @@ static const struct proto_ops packet_ops;
static const struct proto_ops packet_ops_spkt;
static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct sock *sk;
struct sockaddr_pkt *spkt;
@@ -557,7 +557,7 @@ static inline unsigned int run_filter(const struct sk_buff *skb,
*/
static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct sock *sk;
struct sockaddr_ll *sll;
@@ -667,7 +667,7 @@ drop:
}
static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct sock *sk;
struct packet_sock *po;
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index 30cc676..2fb5bf2 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -372,8 +372,7 @@ static int send_reset_indications(struct sk_buff *rskb)
* On error, returns non-zero and releases the skb.
*/
static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pkttype,
- struct net_device *orig_dev)
+ struct packet_type *pkttype)
{
struct net *net = dev_net(dev);
struct phonethdr *ph;
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index b69092e..21c8fe4 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -100,7 +100,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
*/
static int recv_msg(struct sk_buff *buf, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+ struct packet_type *pt)
{
struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv;
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index 9005f6d..4b049ec 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -92,7 +92,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
}
int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev)
+ struct packet_type *ptype)
{
struct sk_buff *nskb;
struct x25_neigh *nb;
--
1.7.4
^ permalink raw reply related
* Re: [patch net-next-2.6 0/8] mostly bonding rx path changes
From: Jiri Pirko @ 2011-03-05 10:30 UTC (permalink / raw)
To: netdev
Cc: davem, shemminger, kaber, fubar, eric.dumazet, nicolas.2p.debian,
andy
In-Reply-To: <1299313794-5218-1-git-send-email-jpirko@redhat.com>
Resubmitted with more text. Sorry for annoyance :(
Sat, Mar 05, 2011 at 09:29:46AM CET, jpirko@redhat.com wrote:
>This patchset focuses mainly bonding rx path changes.
>
>Depends on "fcoe: correct checking for bonding"
>
>Jiri Pirko (8):
> af_packet: use skb->skb_iif instead of orig_dev->ifindex
> bonding: register slave pointer for rx_handler
> net: get rid of multiple bond-related netdevice->priv_flags
> bonding: wrap slave state work
> bonding: get rid of IFF_SLAVE_INACTIVE netdev->priv_flag
> bonding: move processing of recv handlers into handle_frame()
> net: introduce rx_handler results and logic around that
> net: get rid of orig_dev parameter of packet handlers
>
> drivers/block/aoe/aoenet.c | 2 +-
> drivers/net/bonding/bond_3ad.c | 31 +-----
> drivers/net/bonding/bond_3ad.h | 4 +-
> drivers/net/bonding/bond_alb.c | 46 ++------
> drivers/net/bonding/bond_alb.h | 1 -
> drivers/net/bonding/bond_main.c | 217 ++++++++++++-------------------------
> drivers/net/bonding/bond_sysfs.c | 20 +---
> drivers/net/bonding/bonding.h | 64 ++++++-----
> drivers/net/hamradio/bpqether.c | 4 +-
> drivers/net/macvlan.c | 11 +-
> drivers/net/pppoe.c | 4 +-
> drivers/net/wan/hdlc.c | 2 +-
> drivers/net/wan/lapbether.c | 2 +-
> drivers/scsi/fcoe/fcoe.c | 12 +--
> include/linux/if.h | 23 ++---
> include/linux/netdevice.h | 12 ++-
> include/linux/skbuff.h | 5 +-
> include/net/ax25.h | 3 +-
> include/net/datalink.h | 2 +-
> include/net/ip.h | 2 +-
> include/net/ipv6.h | 3 +-
> include/net/irda/irda.h | 3 +-
> include/net/llc.h | 8 +-
> include/net/p8022.h | 3 +-
> include/net/psnap.h | 3 +-
> include/net/x25.h | 2 +-
> net/802/p8022.c | 3 +-
> net/802/psnap.c | 7 +-
> net/802/stp.c | 2 +-
> net/8021q/vlan.h | 2 +-
> net/8021q/vlan_dev.c | 2 +-
> net/appletalk/aarp.c | 2 +-
> net/appletalk/ddp.c | 6 +-
> net/ax25/ax25_in.c | 2 +-
> net/batman-adv/hard-interface.c | 6 +-
> net/bridge/br_input.c | 25 +++--
> net/bridge/br_private.h | 2 +-
> net/caif/caif_dev.c | 2 +-
> net/can/af_can.c | 2 +-
> net/core/dev.c | 45 ++++----
> net/core/skbuff.c | 1 -
> net/decnet/af_decnet.c | 2 +-
> net/decnet/dn_route.c | 2 +-
> net/dsa/tag_dsa.c | 2 +-
> net/dsa/tag_edsa.c | 2 +-
> net/dsa/tag_trailer.c | 2 +-
> net/econet/af_econet.c | 2 +-
> net/ieee802154/af_ieee802154.c | 2 +-
> net/ipv4/arp.c | 2 +-
> net/ipv4/ip_input.c | 2 +-
> net/ipv4/ipconfig.c | 13 ++-
> net/ipv6/ip6_input.c | 3 +-
> net/ipx/af_ipx.c | 3 +-
> net/irda/irlap_frame.c | 2 +-
> net/llc/llc_core.c | 3 +-
> net/llc/llc_input.c | 8 +-
> net/packet/af_packet.c | 10 +-
> net/phonet/af_phonet.c | 3 +-
> net/tipc/eth_media.c | 2 +-
> net/x25/x25_dev.c | 2 +-
> 60 files changed, 268 insertions(+), 397 deletions(-)
>
>--
>1.7.4
>
^ permalink raw reply
* Re: [RFC PATCH] net/core: fix skb handling on netif serves for both bridge and vlan
From: Jiri Pirko @ 2011-03-05 10:36 UTC (permalink / raw)
To: Xiaotian Feng
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet, Tom Herbert
In-Reply-To: <1299149713-18740-1-git-send-email-dfeng@redhat.com>
Thu, Mar 03, 2011 at 11:55:13AM CET, dfeng@redhat.com wrote:
>Consider network topology as follows:
>
>eth0 eth1
> |_____|
> |
> bond0 --- br0
> |
> vlan0 --- br1
>
>bond0 serves for both br0 and vlan0, if a vlan tagged packet was sent
>to br1 through bond0, bridge handling code is seeing the packet on bond0
>and handing it off to my "legacy" bridge before vlan_tx_tag_present
>and vlan_hwaccel_do_receive even haven't a chance to look at it.
>
>Moving the vlan_tx_tag_present before bridge/macvlan handling code could
>cure this.
Wouldn't this break "eth0 - br0 - br0.5"?
>
>Signed-off-by: Xiaotian Feng <dfeng@redhat.com>
>Cc: "David S. Miller" <davem@davemloft.net>
>Cc: Eric Dumazet <eric.dumazet@gmail.com>
>Cc: Tom Herbert <therbert@google.com>
>---
> net/core/dev.c | 20 ++++++++++----------
> 1 files changed, 10 insertions(+), 10 deletions(-)
>
>diff --git a/net/core/dev.c b/net/core/dev.c
>index 8ae6631..d2d12c2 100644
>--- a/net/core/dev.c
>+++ b/net/core/dev.c
>@@ -3079,27 +3079,27 @@ static int __netif_receive_skb(struct sk_buff *skb)
> ncls:
> #endif
>
>- /* Handle special case of bridge or macvlan */
>- rx_handler = rcu_dereference(skb->dev->rx_handler);
>- if (rx_handler) {
>+ if (vlan_tx_tag_present(skb)) {
> if (pt_prev) {
> ret = deliver_skb(skb, pt_prev, orig_dev);
> pt_prev = NULL;
> }
>- skb = rx_handler(skb);
>- if (!skb)
>+ if (vlan_hwaccel_do_receive(&skb)) {
>+ ret = __netif_receive_skb(skb);
>+ goto out;
>+ } else if (unlikely(!skb))
> goto out;
> }
>
>- if (vlan_tx_tag_present(skb)) {
>+ /* Handle special case of bridge or macvlan */
>+ rx_handler = rcu_dereference(skb->dev->rx_handler);
>+ if (rx_handler) {
> if (pt_prev) {
> ret = deliver_skb(skb, pt_prev, orig_dev);
> pt_prev = NULL;
> }
>- if (vlan_hwaccel_do_receive(&skb)) {
>- ret = __netif_receive_skb(skb);
>- goto out;
>- } else if (unlikely(!skb))
>+ skb = rx_handler(skb);
>+ if (!skb)
> goto out;
> }
>
>--
>1.7.1
>
>--
>To unsubscribe from this list: send the line "unsubscribe netdev" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: 2.6.37 regression: adding main interface to a bridge breaks vlan interface RX
From: chriss @ 2011-03-05 10:53 UTC (permalink / raw)
To: netdev
In-Reply-To: <20110304224130.GA13718@electric-eye.fr.zoreil.com>
Francois Romieu <romieu <at> fr.zoreil.com> writes:
>
> chriss <mail_to_chriss <at> gmx.net> :
> [...]
> > I hope i'm doing it right. i checked out the
> > 'git://git.kernel.org/pub/scm/linux/kernel/git/sfr/linux-next.git'
> >
> > and will try to apply the patch you provided. please correct me if i'm wrong.
> > I will report back.
>
> I have tested it against davem's -next somewhere along -rc5 but it should be
> fine as well.
>
My hat gows of to you kindly sir! Everything works as expected. im looking
forward to see this patch in the stable releases.
thank you very much
//chriss
^ permalink raw reply
* Re: tun routing is broken
From: Valdis.Kletnieks @ 2011-03-05 11:48 UTC (permalink / raw)
To: David Miller
Cc: jslaby, jirislaby, linux-kernel, akpm, mm-commits, netdev, maxk
In-Reply-To: <20110305.001022.183044112.davem@davemloft.net>
[-- Attachment #1: Type: text/plain, Size: 623 bytes --]
On Sat, 05 Mar 2011 00:10:22 PST, David Miller said:
> --------------------
> ipv4: Fix __ip_dev_find() to use ifa_local instead of ifa_address.
>
> Reported-by: Stephen Hemminger <shemminger@vyatta.com>
> Reported-by: Julian Anastasov <ja@ssi.bg>
> Signed-off-by: David S. Miller <davem@davemloft.net>
> ---
> net/ipv4/devinet.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
> index 9038928..ff53860 100644
> --- a/net/ipv4/devinet.c
> +++ b/net/ipv4/devinet.c
Confirming this fixes the problem I reported with IPv4 over PPP as well, thanks.
[-- Attachment #2: Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply
* pull request: batman-adv 2011-03-05
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r
Hi,
I was asked to submit following pull request for net-next-2.6/linux-2.6.39. It
contains Marek's hard work (and of course related work by other people) to
remove the orig_hash (aka the batman-adv private "big kernel lock").
There are also smaller cleanups by Marek, Jesper Juhl and Linus Luessing which
remove some unused variables, includes and irritating naming schemes.
thanks,
Sven
The following changes since commit 3878f1f075470990d9c2418b53f31694e774f743:
batman-adv: Disallow originator addressing within mesh layer (2011-02-11 23:30:33 +0100)
are available in the git repository at:
git://git.open-mesh.org/ecsv/linux-merge.git batman-adv/next
Jesper Juhl (1):
batman-adv: Remove two duplicate includes.
Linus Lüssing (4):
batman-adv: Make bat_priv->curr_gw an rcu protected pointer
batman-adv: Increase orig_node refcount before releasing rcu read lock
batman-adv: Fix possible buffer overflow in softif neigh list output
batman-adv: Remove unused hdr_size variable in route_unicast_packet()
Marek Lindner (21):
batman-adv: protect neighbor nodes with reference counters
batman-adv: convert neighbor list to hlist
batman-adv: protect neighbor list with rcu locks
batman-adv: free neighbors when an interface is deactivated
batman-adv: protect neigh_nodes used outside of rcu_locks with refcounting
batman-adv: protect each hash row with rcu locks
batman-adv: protect originator nodes with reference counters
batman-adv: protect ogm counter arrays with spinlock
batman-adv: Correct rcu refcounting for neigh_node
batman-adv: Correct rcu refcounting for gw_node
batman-adv: Correct rcu refcounting for softif_neigh
batman-adv: Correct rcu refcounting for batman_if
batman-adv: protect bit operations to count OGMs with spinlock
batman-adv: make broadcast seqno operations atomic
batman-adv: separate ethernet comparing calls from hash functions
batman-adv: remove extra layer between hash and hash element - hash bucket
batman-adv: Correct rcu refcounting for orig_node
batman-adv: increase refcount in create_neighbor to be consistent
batman-adv: remove orig_hash spinlock
batman-adv: rename global if_list to hardif_list
batman-adv: rename batman_if struct to hard_iface
Simon Wunderlich (1):
batman-adv: protect bonding with rcu locks
Sven Eckelmann (1):
batman-adv: Disallow regular interface as mesh device
net/batman-adv/aggregation.c | 8 +-
net/batman-adv/aggregation.h | 4 +-
net/batman-adv/bat_sysfs.c | 51 +-
net/batman-adv/gateway_client.c | 140 ++++--
net/batman-adv/hard-interface.c | 407 ++++++++--------
net/batman-adv/hard-interface.h | 15 +-
net/batman-adv/hash.c | 26 +-
net/batman-adv/hash.h | 112 ++---
net/batman-adv/icmp_socket.c | 40 +-
net/batman-adv/main.c | 13 +-
net/batman-adv/main.h | 12 +-
net/batman-adv/originator.c | 252 ++++++----
net/batman-adv/originator.h | 50 ++-
net/batman-adv/routing.c | 983 +++++++++++++++++++++---------------
net/batman-adv/routing.h | 25 +-
net/batman-adv/send.c | 103 ++--
net/batman-adv/send.h | 8 +-
net/batman-adv/soft-interface.c | 74 ++--
net/batman-adv/soft-interface.h | 3 +-
net/batman-adv/translation-table.c | 205 +++++---
net/batman-adv/types.h | 48 +-
net/batman-adv/unicast.c | 93 ++--
net/batman-adv/unicast.h | 2 +-
net/batman-adv/vis.c | 192 ++++---
24 files changed, 1634 insertions(+), 1232 deletions(-)
^ permalink raw reply
* [PATCH 01/28] batman-adv: Remove two duplicate includes.
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r, Marek Lindner,
Jesper Juhl
In-Reply-To: <1299328122-21468-1-git-send-email-sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
From: Jesper Juhl <jj-IYz4IdjRLj0sV2N9l4h3zg@public.gmane.org>
Remove duplicate inclusion of "send.h" and "routing.h" from
net/batman-adv/soft-interface.c
Signed-off-by: Jesper Juhl <jj-IYz4IdjRLj0sV2N9l4h3zg@public.gmane.org>
Signed-off-by: Sven Eckelmann <sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
---
net/batman-adv/soft-interface.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index bd088f8..7e37077 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -29,14 +29,12 @@
#include "hash.h"
#include "gateway_common.h"
#include "gateway_client.h"
-#include "send.h"
#include "bat_sysfs.h"
#include <linux/slab.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include "unicast.h"
-#include "routing.h"
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
--
1.7.2.3
^ permalink raw reply related
* [PATCH 02/28] batman-adv: protect neighbor nodes with reference counters
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
From: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
---
net/batman-adv/originator.c | 20 +++++++++++++++-----
net/batman-adv/originator.h | 8 +++++---
net/batman-adv/routing.c | 7 +++++++
net/batman-adv/types.h | 1 +
4 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 54863c9..b1b1773 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -59,9 +59,18 @@ err:
return 0;
}
-struct neigh_node *
-create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
- uint8_t *neigh, struct batman_if *if_incoming)
+void neigh_node_free_ref(struct kref *refcount)
+{
+ struct neigh_node *neigh_node;
+
+ neigh_node = container_of(refcount, struct neigh_node, refcount);
+ kfree(neigh_node);
+}
+
+struct neigh_node *create_neighbor(struct orig_node *orig_node,
+ struct orig_node *orig_neigh_node,
+ uint8_t *neigh,
+ struct batman_if *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct neigh_node *neigh_node;
@@ -78,6 +87,7 @@ create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
memcpy(neigh_node->addr, neigh, ETH_ALEN);
neigh_node->orig_node = orig_neigh_node;
neigh_node->if_incoming = if_incoming;
+ kref_init(&neigh_node->refcount);
list_add_tail(&neigh_node->list, &orig_node->neigh_list);
return neigh_node;
@@ -95,7 +105,7 @@ static void free_orig_node(void *data, void *arg)
neigh_node = list_entry(list_pos, struct neigh_node, list);
list_del(list_pos);
- kfree(neigh_node);
+ kref_put(&neigh_node->refcount, neigh_node_free_ref);
}
frag_list_free(&orig_node->frag_list);
@@ -216,7 +226,7 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
neigh_purged = true;
list_del(list_pos);
- kfree(neigh_node);
+ kref_put(&neigh_node->refcount, neigh_node_free_ref);
} else {
if ((!*best_neigh_node) ||
(neigh_node->tq_avg > (*best_neigh_node)->tq_avg))
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 8019fbd..88e5c60 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -26,9 +26,11 @@ int originator_init(struct bat_priv *bat_priv);
void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv);
struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
-struct neigh_node *
-create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
- uint8_t *neigh, struct batman_if *if_incoming);
+struct neigh_node *create_neighbor(struct orig_node *orig_node,
+ struct orig_node *orig_neigh_node,
+ uint8_t *neigh,
+ struct batman_if *if_incoming);
+void neigh_node_free_ref(struct kref *refcount);
int orig_seq_print_text(struct seq_file *seq, void *offset);
int orig_hash_add_if(struct batman_if *batman_if, int max_if_num);
int orig_hash_del_if(struct batman_if *batman_if, int max_if_num);
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 8274140..36351d3 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -89,6 +89,8 @@ static void update_route(struct bat_priv *bat_priv,
struct neigh_node *neigh_node,
unsigned char *hna_buff, int hna_buff_len)
{
+ struct neigh_node *neigh_node_tmp;
+
/* route deleted */
if ((orig_node->router) && (!neigh_node)) {
@@ -115,7 +117,12 @@ static void update_route(struct bat_priv *bat_priv,
orig_node->router->addr);
}
+ if (neigh_node)
+ kref_get(&neigh_node->refcount);
+ neigh_node_tmp = orig_node->router;
orig_node->router = neigh_node;
+ if (neigh_node_tmp)
+ kref_put(&neigh_node_tmp->refcount, neigh_node_free_ref);
}
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 7270405..f9217d5 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -115,6 +115,7 @@ struct neigh_node {
struct neigh_node *next_bond_candidate;
unsigned long last_valid;
unsigned long real_bits[NUM_WORDS];
+ struct kref refcount;
struct orig_node *orig_node;
struct batman_if *if_incoming;
};
--
1.7.2.3
^ permalink raw reply related
* [PATCH 03/28] batman-adv: convert neighbor list to hlist
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
From: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
---
net/batman-adv/originator.c | 30 +++++++++++++++---------------
net/batman-adv/routing.c | 29 ++++++++++++++++++-----------
net/batman-adv/types.h | 4 ++--
3 files changed, 35 insertions(+), 28 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index b1b1773..68b04e7 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -82,29 +82,28 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
if (!neigh_node)
return NULL;
- INIT_LIST_HEAD(&neigh_node->list);
+ INIT_HLIST_NODE(&neigh_node->list);
memcpy(neigh_node->addr, neigh, ETH_ALEN);
neigh_node->orig_node = orig_neigh_node;
neigh_node->if_incoming = if_incoming;
kref_init(&neigh_node->refcount);
- list_add_tail(&neigh_node->list, &orig_node->neigh_list);
+ hlist_add_head(&neigh_node->list, &orig_node->neigh_list);
return neigh_node;
}
static void free_orig_node(void *data, void *arg)
{
- struct list_head *list_pos, *list_pos_tmp;
+ struct hlist_node *node, *node_tmp;
struct neigh_node *neigh_node;
struct orig_node *orig_node = (struct orig_node *)data;
struct bat_priv *bat_priv = (struct bat_priv *)arg;
/* for all neighbors towards this originator ... */
- list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
- neigh_node = list_entry(list_pos, struct neigh_node, list);
-
- list_del(list_pos);
+ hlist_for_each_entry_safe(neigh_node, node, node_tmp,
+ &orig_node->neigh_list, list) {
+ hlist_del(&neigh_node->list);
kref_put(&neigh_node->refcount, neigh_node_free_ref);
}
@@ -151,7 +150,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
if (!orig_node)
return NULL;
- INIT_LIST_HEAD(&orig_node->neigh_list);
+ INIT_HLIST_HEAD(&orig_node->neigh_list);
memcpy(orig_node->orig, addr, ETH_ALEN);
orig_node->router = NULL;
@@ -195,15 +194,15 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
struct orig_node *orig_node,
struct neigh_node **best_neigh_node)
{
- struct list_head *list_pos, *list_pos_tmp;
+ struct hlist_node *node, *node_tmp;
struct neigh_node *neigh_node;
bool neigh_purged = false;
*best_neigh_node = NULL;
/* for all neighbors towards this originator ... */
- list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
- neigh_node = list_entry(list_pos, struct neigh_node, list);
+ hlist_for_each_entry_safe(neigh_node, node, node_tmp,
+ &orig_node->neigh_list, list) {
if ((time_after(jiffies,
neigh_node->last_valid + PURGE_TIMEOUT * HZ)) ||
@@ -225,7 +224,8 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
(neigh_node->last_valid / HZ));
neigh_purged = true;
- list_del(list_pos);
+
+ hlist_del(&neigh_node->list);
kref_put(&neigh_node->refcount, neigh_node_free_ref);
} else {
if ((!*best_neigh_node) ||
@@ -328,7 +328,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
struct net_device *net_dev = (struct net_device *)seq->private;
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hashtable_t *hash = bat_priv->orig_hash;
- struct hlist_node *walk;
+ struct hlist_node *walk, *node;
struct hlist_head *head;
struct element_t *bucket;
struct orig_node *orig_node;
@@ -384,8 +384,8 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
neigh_node->addr,
neigh_node->if_incoming->net_dev->name);
- list_for_each_entry(neigh_node, &orig_node->neigh_list,
- list) {
+ hlist_for_each_entry(neigh_node, node,
+ &orig_node->neigh_list, list) {
seq_printf(seq, " %pM (%3i)", neigh_node->addr,
neigh_node->tq_avg);
}
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 36351d3..e8379ba 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -149,12 +149,12 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
+ struct hlist_node *node;
unsigned char total_count;
if (orig_node == orig_neigh_node) {
- list_for_each_entry(tmp_neigh_node,
- &orig_node->neigh_list,
- list) {
+ hlist_for_each_entry(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
if (compare_orig(tmp_neigh_node->addr,
orig_neigh_node->orig) &&
@@ -174,8 +174,8 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
neigh_node->last_valid = jiffies;
} else {
/* find packet count of corresponding one hop neighbor */
- list_for_each_entry(tmp_neigh_node,
- &orig_neigh_node->neigh_list, list) {
+ hlist_for_each_entry(tmp_neigh_node, node,
+ &orig_neigh_node->neigh_list, list) {
if (compare_orig(tmp_neigh_node->addr,
orig_neigh_node->orig) &&
@@ -260,12 +260,14 @@ static void update_orig(struct bat_priv *bat_priv,
char is_duplicate)
{
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
+ struct hlist_node *node;
int tmp_hna_buff_len;
bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
"Searching and updating originator entry of received packet\n");
- list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
+ hlist_for_each_entry(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
(tmp_neigh_node->if_incoming == if_incoming)) {
neigh_node = tmp_neigh_node;
@@ -391,6 +393,7 @@ static char count_real_packets(struct ethhdr *ethhdr,
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct orig_node *orig_node;
struct neigh_node *tmp_neigh_node;
+ struct hlist_node *node;
char is_duplicate = 0;
int32_t seq_diff;
int need_update = 0;
@@ -407,7 +410,8 @@ static char count_real_packets(struct ethhdr *ethhdr,
&orig_node->batman_seqno_reset))
return -1;
- list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
+ hlist_for_each_entry(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
orig_node->last_real_seqno,
@@ -457,6 +461,7 @@ void update_bonding_candidates(struct orig_node *orig_node)
int candidates;
int interference_candidate;
int best_tq;
+ struct hlist_node *node, *node2;
struct neigh_node *tmp_neigh_node, *tmp_neigh_node2;
struct neigh_node *first_candidate, *last_candidate;
@@ -476,13 +481,15 @@ void update_bonding_candidates(struct orig_node *orig_node)
* as "bonding partner" */
/* first, zero the list */
- list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
+ hlist_for_each_entry(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
tmp_neigh_node->next_bond_candidate = NULL;
}
first_candidate = NULL;
last_candidate = NULL;
- list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
+ hlist_for_each_entry(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
/* only consider if it has the same primary address ... */
if (memcmp(orig_node->orig,
@@ -499,8 +506,8 @@ void update_bonding_candidates(struct orig_node *orig_node)
* select this candidate because of possible interference. */
interference_candidate = 0;
- list_for_each_entry(tmp_neigh_node2,
- &orig_node->neigh_list, list) {
+ hlist_for_each_entry(tmp_neigh_node2, node2,
+ &orig_node->neigh_list, list) {
if (tmp_neigh_node2 == tmp_neigh_node)
continue;
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index f9217d5..779c5c3 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -83,7 +83,7 @@ struct orig_node {
uint8_t last_ttl;
unsigned long bcast_bits[NUM_WORDS];
uint32_t last_bcast_seqno;
- struct list_head neigh_list;
+ struct hlist_head neigh_list;
struct list_head frag_list;
unsigned long last_frag_packet;
struct {
@@ -105,7 +105,7 @@ struct gw_node {
* @last_valid: when last packet via this neighbor was received
*/
struct neigh_node {
- struct list_head list;
+ struct hlist_node list;
uint8_t addr[ETH_ALEN];
uint8_t real_packet_count;
uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE];
--
1.7.2.3
^ permalink raw reply related
* [PATCH 04/28] batman-adv: protect neighbor list with rcu locks
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
From: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
---
net/batman-adv/originator.c | 35 ++++++++++++++++++++++++++++-------
net/batman-adv/routing.c | 41 +++++++++++++++++++++++++++--------------
net/batman-adv/types.h | 2 ++
3 files changed, 57 insertions(+), 21 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 68b04e7..6cb9af3 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -67,6 +67,14 @@ void neigh_node_free_ref(struct kref *refcount)
kfree(neigh_node);
}
+static void neigh_node_free_rcu(struct rcu_head *rcu)
+{
+ struct neigh_node *neigh_node;
+
+ neigh_node = container_of(rcu, struct neigh_node, rcu);
+ kref_put(&neigh_node->refcount, neigh_node_free_ref);
+}
+
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
uint8_t *neigh,
@@ -89,7 +97,9 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
neigh_node->if_incoming = if_incoming;
kref_init(&neigh_node->refcount);
- hlist_add_head(&neigh_node->list, &orig_node->neigh_list);
+ spin_lock_bh(&orig_node->neigh_list_lock);
+ hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
+ spin_unlock_bh(&orig_node->neigh_list_lock);
return neigh_node;
}
@@ -100,13 +110,17 @@ static void free_orig_node(void *data, void *arg)
struct orig_node *orig_node = (struct orig_node *)data;
struct bat_priv *bat_priv = (struct bat_priv *)arg;
+ spin_lock_bh(&orig_node->neigh_list_lock);
+
/* for all neighbors towards this originator ... */
hlist_for_each_entry_safe(neigh_node, node, node_tmp,
&orig_node->neigh_list, list) {
- hlist_del(&neigh_node->list);
- kref_put(&neigh_node->refcount, neigh_node_free_ref);
+ hlist_del_rcu(&neigh_node->list);
+ call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
}
+ spin_unlock_bh(&orig_node->neigh_list_lock);
+
frag_list_free(&orig_node->frag_list);
hna_global_del_orig(bat_priv, orig_node, "originator timed out");
@@ -151,6 +165,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
return NULL;
INIT_HLIST_HEAD(&orig_node->neigh_list);
+ spin_lock_init(&orig_node->neigh_list_lock);
memcpy(orig_node->orig, addr, ETH_ALEN);
orig_node->router = NULL;
@@ -200,6 +215,8 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
*best_neigh_node = NULL;
+ spin_lock_bh(&orig_node->neigh_list_lock);
+
/* for all neighbors towards this originator ... */
hlist_for_each_entry_safe(neigh_node, node, node_tmp,
&orig_node->neigh_list, list) {
@@ -225,14 +242,16 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
neigh_purged = true;
- hlist_del(&neigh_node->list);
- kref_put(&neigh_node->refcount, neigh_node_free_ref);
+ hlist_del_rcu(&neigh_node->list);
+ call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
} else {
if ((!*best_neigh_node) ||
(neigh_node->tq_avg > (*best_neigh_node)->tq_avg))
*best_neigh_node = neigh_node;
}
}
+
+ spin_unlock_bh(&orig_node->neigh_list_lock);
return neigh_purged;
}
@@ -384,11 +403,13 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
neigh_node->addr,
neigh_node->if_incoming->net_dev->name);
- hlist_for_each_entry(neigh_node, node,
- &orig_node->neigh_list, list) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(neigh_node, node,
+ &orig_node->neigh_list, list) {
seq_printf(seq, " %pM (%3i)", neigh_node->addr,
neigh_node->tq_avg);
}
+ rcu_read_unlock();
seq_printf(seq, "\n");
batman_count++;
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index e8379ba..97f3216 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -153,14 +153,16 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
unsigned char total_count;
if (orig_node == orig_neigh_node) {
- hlist_for_each_entry(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
if (compare_orig(tmp_neigh_node->addr,
orig_neigh_node->orig) &&
(tmp_neigh_node->if_incoming == if_incoming))
neigh_node = tmp_neigh_node;
}
+ rcu_read_unlock();
if (!neigh_node)
neigh_node = create_neighbor(orig_node,
@@ -174,14 +176,16 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
neigh_node->last_valid = jiffies;
} else {
/* find packet count of corresponding one hop neighbor */
- hlist_for_each_entry(tmp_neigh_node, node,
- &orig_neigh_node->neigh_list, list) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_node, node,
+ &orig_neigh_node->neigh_list, list) {
if (compare_orig(tmp_neigh_node->addr,
orig_neigh_node->orig) &&
(tmp_neigh_node->if_incoming == if_incoming))
neigh_node = tmp_neigh_node;
}
+ rcu_read_unlock();
if (!neigh_node)
neigh_node = create_neighbor(orig_neigh_node,
@@ -266,8 +270,9 @@ static void update_orig(struct bat_priv *bat_priv,
bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
"Searching and updating originator entry of received packet\n");
- hlist_for_each_entry(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
(tmp_neigh_node->if_incoming == if_incoming)) {
neigh_node = tmp_neigh_node;
@@ -282,6 +287,7 @@ static void update_orig(struct bat_priv *bat_priv,
tmp_neigh_node->tq_avg =
ring_buffer_avg(tmp_neigh_node->tq_recv);
}
+ rcu_read_unlock();
if (!neigh_node) {
struct orig_node *orig_tmp;
@@ -410,8 +416,9 @@ static char count_real_packets(struct ethhdr *ethhdr,
&orig_node->batman_seqno_reset))
return -1;
- hlist_for_each_entry(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
orig_node->last_real_seqno,
@@ -431,6 +438,7 @@ static char count_real_packets(struct ethhdr *ethhdr,
tmp_neigh_node->real_packet_count =
bit_packet_count(tmp_neigh_node->real_bits);
}
+ rcu_read_unlock();
if (need_update) {
bat_dbg(DBG_BATMAN, bat_priv,
@@ -481,15 +489,19 @@ void update_bonding_candidates(struct orig_node *orig_node)
* as "bonding partner" */
/* first, zero the list */
- hlist_for_each_entry(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
tmp_neigh_node->next_bond_candidate = NULL;
}
+ rcu_read_unlock();
first_candidate = NULL;
last_candidate = NULL;
- hlist_for_each_entry(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
/* only consider if it has the same primary address ... */
if (memcmp(orig_node->orig,
@@ -506,8 +518,8 @@ void update_bonding_candidates(struct orig_node *orig_node)
* select this candidate because of possible interference. */
interference_candidate = 0;
- hlist_for_each_entry(tmp_neigh_node2, node2,
- &orig_node->neigh_list, list) {
+ hlist_for_each_entry_rcu(tmp_neigh_node2, node2,
+ &orig_node->neigh_list, list) {
if (tmp_neigh_node2 == tmp_neigh_node)
continue;
@@ -541,6 +553,7 @@ void update_bonding_candidates(struct orig_node *orig_node)
candidates++;
}
+ rcu_read_unlock();
if (candidates > 0) {
first_candidate->next_bond_candidate = last_candidate;
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 779c5c3..d4fa727 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -85,6 +85,7 @@ struct orig_node {
uint32_t last_bcast_seqno;
struct hlist_head neigh_list;
struct list_head frag_list;
+ spinlock_t neigh_list_lock; /* protects neighbor list */
unsigned long last_frag_packet;
struct {
uint8_t candidates;
@@ -116,6 +117,7 @@ struct neigh_node {
unsigned long last_valid;
unsigned long real_bits[NUM_WORDS];
struct kref refcount;
+ struct rcu_head rcu;
struct orig_node *orig_node;
struct batman_if *if_incoming;
};
--
1.7.2.3
^ permalink raw reply related
* [PATCH 05/28] batman-adv: free neighbors when an interface is deactivated
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
From: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
hardif_disable_interface() calls purge_orig_ref() to immediately free
all neighbors associated with the interface that is going down.
purge_orig_neighbors() checked if the interface status is IF_INACTIVE
which is set to IF_NOT_IN_USE shortly before calling purge_orig_ref().
Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
---
net/batman-adv/originator.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 6cb9af3..899d494 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -224,10 +224,15 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
if ((time_after(jiffies,
neigh_node->last_valid + PURGE_TIMEOUT * HZ)) ||
(neigh_node->if_incoming->if_status == IF_INACTIVE) ||
+ (neigh_node->if_incoming->if_status == IF_NOT_IN_USE) ||
(neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) {
- if (neigh_node->if_incoming->if_status ==
- IF_TO_BE_REMOVED)
+ if ((neigh_node->if_incoming->if_status ==
+ IF_INACTIVE) ||
+ (neigh_node->if_incoming->if_status ==
+ IF_NOT_IN_USE) ||
+ (neigh_node->if_incoming->if_status ==
+ IF_TO_BE_REMOVED))
bat_dbg(DBG_BATMAN, bat_priv,
"neighbor purge: originator %pM, "
"neighbor: %pM, iface: %s\n",
--
1.7.2.3
^ permalink raw reply related
* [PATCH 06/28] batman-adv: protect neigh_nodes used outside of rcu_locks with refcounting
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
From: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
---
net/batman-adv/routing.c | 40 +++++++++++++++++++++++++++++++---------
1 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 97f3216..c15e6c1 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -151,6 +151,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
struct hlist_node *node;
unsigned char total_count;
+ int ret = 0;
if (orig_node == orig_neigh_node) {
rcu_read_lock();
@@ -162,7 +163,6 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
(tmp_neigh_node->if_incoming == if_incoming))
neigh_node = tmp_neigh_node;
}
- rcu_read_unlock();
if (!neigh_node)
neigh_node = create_neighbor(orig_node,
@@ -171,7 +171,10 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
if_incoming);
/* create_neighbor failed, return 0 */
if (!neigh_node)
- return 0;
+ goto unlock;
+
+ kref_get(&neigh_node->refcount);
+ rcu_read_unlock();
neigh_node->last_valid = jiffies;
} else {
@@ -185,7 +188,6 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
(tmp_neigh_node->if_incoming == if_incoming))
neigh_node = tmp_neigh_node;
}
- rcu_read_unlock();
if (!neigh_node)
neigh_node = create_neighbor(orig_neigh_node,
@@ -194,7 +196,10 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
if_incoming);
/* create_neighbor failed, return 0 */
if (!neigh_node)
- return 0;
+ goto unlock;
+
+ kref_get(&neigh_node->refcount);
+ rcu_read_unlock();
}
orig_node->last_valid = jiffies;
@@ -250,9 +255,16 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
/* if link has the minimum required transmission quality
* consider it bidirectional */
if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
- return 1;
+ ret = 1;
- return 0;
+ goto out;
+
+unlock:
+ rcu_read_unlock();
+out:
+ if (neigh_node)
+ kref_put(&neigh_node->refcount, neigh_node_free_ref);
+ return ret;
}
static void update_orig(struct bat_priv *bat_priv,
@@ -287,23 +299,25 @@ static void update_orig(struct bat_priv *bat_priv,
tmp_neigh_node->tq_avg =
ring_buffer_avg(tmp_neigh_node->tq_recv);
}
- rcu_read_unlock();
if (!neigh_node) {
struct orig_node *orig_tmp;
orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);
if (!orig_tmp)
- return;
+ goto unlock;
neigh_node = create_neighbor(orig_node, orig_tmp,
ethhdr->h_source, if_incoming);
if (!neigh_node)
- return;
+ goto unlock;
} else
bat_dbg(DBG_BATMAN, bat_priv,
"Updating existing last-hop neighbor of originator\n");
+ kref_get(&neigh_node->refcount);
+ rcu_read_unlock();
+
orig_node->flags = batman_packet->flags;
neigh_node->last_valid = jiffies;
@@ -357,6 +371,14 @@ update_gw:
(atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) &&
(atomic_read(&bat_priv->gw_sel_class) > 2))
gw_check_election(bat_priv, orig_node);
+
+ goto out;
+
+unlock:
+ rcu_read_unlock();
+out:
+ if (neigh_node)
+ kref_put(&neigh_node->refcount, neigh_node_free_ref);
}
/* checks whether the host restarted and is in the protection time.
--
1.7.2.3
^ permalink raw reply related
* [PATCH 11/28] batman-adv: Correct rcu refcounting for neigh_node
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
From: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
It might be possible that 2 threads access the same data in the same
rcu grace period. The first thread calls call_rcu() to decrement the
refcount and free the data while the second thread increases the
refcount to use the data. To avoid this race condition all refcount
operations have to be atomic.
Reported-by: Sven Eckelmann <sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
---
net/batman-adv/icmp_socket.c | 27 +++-
net/batman-adv/originator.c | 26 +---
net/batman-adv/originator.h | 3 +-
net/batman-adv/routing.c | 338 +++++++++++++++++++++++++++--------------
net/batman-adv/types.h | 3 +-
net/batman-adv/unicast.c | 57 +++++---
net/batman-adv/vis.c | 33 ++++-
7 files changed, 313 insertions(+), 174 deletions(-)
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
index 8e0cd8a..7fa5bb8 100644
--- a/net/batman-adv/icmp_socket.c
+++ b/net/batman-adv/icmp_socket.c
@@ -156,7 +156,8 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
struct sk_buff *skb;
struct icmp_packet_rr *icmp_packet;
- struct orig_node *orig_node;
+ struct orig_node *orig_node = NULL;
+ struct neigh_node *neigh_node = NULL;
struct batman_if *batman_if;
size_t packet_len = sizeof(struct icmp_packet);
uint8_t dstaddr[ETH_ALEN];
@@ -224,17 +225,25 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
compare_orig, choose_orig,
icmp_packet->dst));
- rcu_read_unlock();
if (!orig_node)
goto unlock;
- if (!orig_node->router)
+ kref_get(&orig_node->refcount);
+ neigh_node = orig_node->router;
+
+ if (!neigh_node)
+ goto unlock;
+
+ if (!atomic_inc_not_zero(&neigh_node->refcount)) {
+ neigh_node = NULL;
goto unlock;
+ }
+
+ rcu_read_unlock();
batman_if = orig_node->router->if_incoming;
memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
-
spin_unlock_bh(&bat_priv->orig_hash_lock);
if (!batman_if)
@@ -247,14 +256,14 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
if (packet_len == sizeof(struct icmp_packet_rr))
- memcpy(icmp_packet->rr, batman_if->net_dev->dev_addr, ETH_ALEN);
-
+ memcpy(icmp_packet->rr,
+ batman_if->net_dev->dev_addr, ETH_ALEN);
send_skb_packet(skb, batman_if, dstaddr);
-
goto out;
unlock:
+ rcu_read_unlock();
spin_unlock_bh(&bat_priv->orig_hash_lock);
dst_unreach:
icmp_packet->msg_type = DESTINATION_UNREACHABLE;
@@ -262,6 +271,10 @@ dst_unreach:
free_skb:
kfree_skb(skb);
out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (orig_node)
+ kref_put(&orig_node->refcount, orig_node_free_ref);
return len;
}
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index a85eadc..61299da 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -59,28 +59,18 @@ err:
return 0;
}
-void neigh_node_free_ref(struct kref *refcount)
-{
- struct neigh_node *neigh_node;
-
- neigh_node = container_of(refcount, struct neigh_node, refcount);
- kfree(neigh_node);
-}
-
static void neigh_node_free_rcu(struct rcu_head *rcu)
{
struct neigh_node *neigh_node;
neigh_node = container_of(rcu, struct neigh_node, rcu);
- kref_put(&neigh_node->refcount, neigh_node_free_ref);
+ kfree(neigh_node);
}
-void neigh_node_free_rcu_bond(struct rcu_head *rcu)
+void neigh_node_free_ref(struct neigh_node *neigh_node)
{
- struct neigh_node *neigh_node;
-
- neigh_node = container_of(rcu, struct neigh_node, rcu_bond);
- kref_put(&neigh_node->refcount, neigh_node_free_ref);
+ if (atomic_dec_and_test(&neigh_node->refcount))
+ call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
}
struct neigh_node *create_neighbor(struct orig_node *orig_node,
@@ -104,7 +94,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
memcpy(neigh_node->addr, neigh, ETH_ALEN);
neigh_node->orig_node = orig_neigh_node;
neigh_node->if_incoming = if_incoming;
- kref_init(&neigh_node->refcount);
+ atomic_set(&neigh_node->refcount, 1);
spin_lock_bh(&orig_node->neigh_list_lock);
hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
@@ -126,14 +116,14 @@ void orig_node_free_ref(struct kref *refcount)
list_for_each_entry_safe(neigh_node, tmp_neigh_node,
&orig_node->bond_list, bonding_list) {
list_del_rcu(&neigh_node->bonding_list);
- call_rcu(&neigh_node->rcu_bond, neigh_node_free_rcu_bond);
+ neigh_node_free_ref(neigh_node);
}
/* for all neighbors towards this originator ... */
hlist_for_each_entry_safe(neigh_node, node, node_tmp,
&orig_node->neigh_list, list) {
hlist_del_rcu(&neigh_node->list);
- call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
+ neigh_node_free_ref(neigh_node);
}
spin_unlock_bh(&orig_node->neigh_list_lock);
@@ -315,7 +305,7 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
hlist_del_rcu(&neigh_node->list);
bonding_candidate_del(orig_node, neigh_node);
- call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
+ neigh_node_free_ref(neigh_node);
} else {
if ((!*best_neigh_node) ||
(neigh_node->tq_avg > (*best_neigh_node)->tq_avg))
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 360dfd1..84d96e2 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -26,13 +26,12 @@ int originator_init(struct bat_priv *bat_priv);
void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv);
void orig_node_free_ref(struct kref *refcount);
-void neigh_node_free_rcu_bond(struct rcu_head *rcu);
struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
uint8_t *neigh,
struct batman_if *if_incoming);
-void neigh_node_free_ref(struct kref *refcount);
+void neigh_node_free_ref(struct neigh_node *neigh_node);
int orig_seq_print_text(struct seq_file *seq, void *offset);
int orig_hash_add_if(struct batman_if *batman_if, int max_if_num);
int orig_hash_del_if(struct batman_if *batman_if, int max_if_num);
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 1ad14da..9185666 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -121,12 +121,12 @@ static void update_route(struct bat_priv *bat_priv,
orig_node->router->addr);
}
- if (neigh_node)
- kref_get(&neigh_node->refcount);
+ if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount))
+ neigh_node = NULL;
neigh_node_tmp = orig_node->router;
orig_node->router = neigh_node;
if (neigh_node_tmp)
- kref_put(&neigh_node_tmp->refcount, neigh_node_free_ref);
+ neigh_node_free_ref(neigh_node_tmp);
}
@@ -177,7 +177,11 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
if (!neigh_node)
goto unlock;
- kref_get(&neigh_node->refcount);
+ if (!atomic_inc_not_zero(&neigh_node->refcount)) {
+ neigh_node = NULL;
+ goto unlock;
+ }
+
rcu_read_unlock();
neigh_node->last_valid = jiffies;
@@ -202,7 +206,11 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
if (!neigh_node)
goto unlock;
- kref_get(&neigh_node->refcount);
+ if (!atomic_inc_not_zero(&neigh_node->refcount)) {
+ neigh_node = NULL;
+ goto unlock;
+ }
+
rcu_read_unlock();
}
@@ -267,7 +275,7 @@ unlock:
rcu_read_unlock();
out:
if (neigh_node)
- kref_put(&neigh_node->refcount, neigh_node_free_ref);
+ neigh_node_free_ref(neigh_node);
return ret;
}
@@ -280,8 +288,8 @@ void bonding_candidate_del(struct orig_node *orig_node,
goto out;
list_del_rcu(&neigh_node->bonding_list);
- call_rcu(&neigh_node->rcu_bond, neigh_node_free_rcu_bond);
INIT_LIST_HEAD(&neigh_node->bonding_list);
+ neigh_node_free_ref(neigh_node);
atomic_dec(&orig_node->bond_candidates);
out:
@@ -342,8 +350,10 @@ static void bonding_candidate_add(struct orig_node *orig_node,
if (!list_empty(&neigh_node->bonding_list))
goto out;
+ if (!atomic_inc_not_zero(&neigh_node->refcount))
+ goto out;
+
list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list);
- kref_get(&neigh_node->refcount);
atomic_inc(&orig_node->bond_candidates);
goto out;
@@ -387,7 +397,10 @@ static void update_orig(struct bat_priv *bat_priv,
hlist_for_each_entry_rcu(tmp_neigh_node, node,
&orig_node->neigh_list, list) {
if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
- (tmp_neigh_node->if_incoming == if_incoming)) {
+ (tmp_neigh_node->if_incoming == if_incoming) &&
+ atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
neigh_node = tmp_neigh_node;
continue;
}
@@ -414,11 +427,15 @@ static void update_orig(struct bat_priv *bat_priv,
kref_put(&orig_tmp->refcount, orig_node_free_ref);
if (!neigh_node)
goto unlock;
+
+ if (!atomic_inc_not_zero(&neigh_node->refcount)) {
+ neigh_node = NULL;
+ goto unlock;
+ }
} else
bat_dbg(DBG_BATMAN, bat_priv,
"Updating existing last-hop neighbor of originator\n");
- kref_get(&neigh_node->refcount);
rcu_read_unlock();
orig_node->flags = batman_packet->flags;
@@ -495,7 +512,7 @@ unlock:
rcu_read_unlock();
out:
if (neigh_node)
- kref_put(&neigh_node->refcount, neigh_node_free_ref);
+ neigh_node_free_ref(neigh_node);
}
/* checks whether the host restarted and is in the protection time.
@@ -870,22 +887,23 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if)
static int recv_my_icmp_packet(struct bat_priv *bat_priv,
struct sk_buff *skb, size_t icmp_len)
{
- struct orig_node *orig_node;
+ struct orig_node *orig_node = NULL;
+ struct neigh_node *neigh_node = NULL;
struct icmp_packet_rr *icmp_packet;
struct batman_if *batman_if;
- int ret;
uint8_t dstaddr[ETH_ALEN];
+ int ret = NET_RX_DROP;
icmp_packet = (struct icmp_packet_rr *)skb->data;
/* add data to device queue */
if (icmp_packet->msg_type != ECHO_REQUEST) {
bat_socket_receive_packet(icmp_packet, icmp_len);
- return NET_RX_DROP;
+ goto out;
}
if (!bat_priv->primary_if)
- return NET_RX_DROP;
+ goto out;
/* answer echo request (ping) */
/* get routing information */
@@ -894,46 +912,65 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
compare_orig, choose_orig,
icmp_packet->orig));
- rcu_read_unlock();
- ret = NET_RX_DROP;
- if ((orig_node) && (orig_node->router)) {
+ if (!orig_node)
+ goto unlock;
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
- spin_unlock_bh(&bat_priv->orig_hash_lock);
+ kref_get(&orig_node->refcount);
+ neigh_node = orig_node->router;
- /* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
- return NET_RX_DROP;
+ if (!neigh_node)
+ goto unlock;
- icmp_packet = (struct icmp_packet_rr *)skb->data;
+ if (!atomic_inc_not_zero(&neigh_node->refcount)) {
+ neigh_node = NULL;
+ goto unlock;
+ }
- memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
- memcpy(icmp_packet->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
- icmp_packet->msg_type = ECHO_REPLY;
- icmp_packet->ttl = TTL;
+ rcu_read_unlock();
- send_skb_packet(skb, batman_if, dstaddr);
- ret = NET_RX_SUCCESS;
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->router->if_incoming;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
- } else
- spin_unlock_bh(&bat_priv->orig_hash_lock);
+ /* create a copy of the skb, if needed, to modify it. */
+ if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
+ goto out;
+ icmp_packet = (struct icmp_packet_rr *)skb->data;
+
+ memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
+ memcpy(icmp_packet->orig,
+ bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ icmp_packet->msg_type = ECHO_REPLY;
+ icmp_packet->ttl = TTL;
+
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
+ goto out;
+
+unlock:
+ rcu_read_unlock();
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (orig_node)
+ kref_put(&orig_node->refcount, orig_node_free_ref);
return ret;
}
static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
struct sk_buff *skb)
{
- struct orig_node *orig_node;
+ struct orig_node *orig_node = NULL;
+ struct neigh_node *neigh_node = NULL;
struct icmp_packet *icmp_packet;
struct batman_if *batman_if;
- int ret;
uint8_t dstaddr[ETH_ALEN];
+ int ret = NET_RX_DROP;
icmp_packet = (struct icmp_packet *)skb->data;
@@ -942,11 +979,11 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
pr_debug("Warning - can't forward icmp packet from %pM to "
"%pM: ttl exceeded\n", icmp_packet->orig,
icmp_packet->dst);
- return NET_RX_DROP;
+ goto out;
}
if (!bat_priv->primary_if)
- return NET_RX_DROP;
+ goto out;
/* get routing information */
spin_lock_bh(&bat_priv->orig_hash_lock);
@@ -954,35 +991,53 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
orig_node = ((struct orig_node *)
hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
icmp_packet->orig));
- rcu_read_unlock();
- ret = NET_RX_DROP;
- if ((orig_node) && (orig_node->router)) {
+ if (!orig_node)
+ goto unlock;
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
- spin_unlock_bh(&bat_priv->orig_hash_lock);
+ kref_get(&orig_node->refcount);
+ neigh_node = orig_node->router;
- /* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
- return NET_RX_DROP;
+ if (!neigh_node)
+ goto unlock;
+
+ if (!atomic_inc_not_zero(&neigh_node->refcount)) {
+ neigh_node = NULL;
+ goto unlock;
+ }
- icmp_packet = (struct icmp_packet *) skb->data;
+ rcu_read_unlock();
- memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
- memcpy(icmp_packet->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
- icmp_packet->msg_type = TTL_EXCEEDED;
- icmp_packet->ttl = TTL;
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->router->if_incoming;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
- send_skb_packet(skb, batman_if, dstaddr);
- ret = NET_RX_SUCCESS;
+ /* create a copy of the skb, if needed, to modify it. */
+ if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
+ goto out;
- } else
- spin_unlock_bh(&bat_priv->orig_hash_lock);
+ icmp_packet = (struct icmp_packet *)skb->data;
+
+ memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
+ memcpy(icmp_packet->orig,
+ bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ icmp_packet->msg_type = TTL_EXCEEDED;
+ icmp_packet->ttl = TTL;
+
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
+ goto out;
+unlock:
+ rcu_read_unlock();
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (orig_node)
+ kref_put(&orig_node->refcount, orig_node_free_ref);
return ret;
}
@@ -992,11 +1047,12 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct icmp_packet_rr *icmp_packet;
struct ethhdr *ethhdr;
- struct orig_node *orig_node;
+ struct orig_node *orig_node = NULL;
+ struct neigh_node *neigh_node = NULL;
struct batman_if *batman_if;
int hdr_size = sizeof(struct icmp_packet);
- int ret;
uint8_t dstaddr[ETH_ALEN];
+ int ret = NET_RX_DROP;
/**
* we truncate all incoming icmp packets if they don't match our size
@@ -1006,21 +1062,21 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
/* drop packet if it has not necessary minimum size */
if (unlikely(!pskb_may_pull(skb, hdr_size)))
- return NET_RX_DROP;
+ goto out;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with unicast indication but broadcast recipient */
if (is_broadcast_ether_addr(ethhdr->h_dest))
- return NET_RX_DROP;
+ goto out;
/* packet with broadcast sender address */
if (is_broadcast_ether_addr(ethhdr->h_source))
- return NET_RX_DROP;
+ goto out;
/* not for me */
if (!is_my_mac(ethhdr->h_dest))
- return NET_RX_DROP;
+ goto out;
icmp_packet = (struct icmp_packet_rr *)skb->data;
@@ -1040,40 +1096,56 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
if (icmp_packet->ttl < 2)
return recv_icmp_ttl_exceeded(bat_priv, skb);
- ret = NET_RX_DROP;
-
/* get routing information */
spin_lock_bh(&bat_priv->orig_hash_lock);
rcu_read_lock();
orig_node = ((struct orig_node *)
hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
icmp_packet->dst));
- rcu_read_unlock();
+ if (!orig_node)
+ goto unlock;
- if ((orig_node) && (orig_node->router)) {
+ kref_get(&orig_node->refcount);
+ neigh_node = orig_node->router;
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
- spin_unlock_bh(&bat_priv->orig_hash_lock);
+ if (!neigh_node)
+ goto unlock;
- /* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
- return NET_RX_DROP;
+ if (!atomic_inc_not_zero(&neigh_node->refcount)) {
+ neigh_node = NULL;
+ goto unlock;
+ }
+
+ rcu_read_unlock();
- icmp_packet = (struct icmp_packet_rr *)skb->data;
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->router->if_incoming;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
- /* decrement ttl */
- icmp_packet->ttl--;
+ /* create a copy of the skb, if needed, to modify it. */
+ if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
+ goto out;
- /* route it */
- send_skb_packet(skb, batman_if, dstaddr);
- ret = NET_RX_SUCCESS;
+ icmp_packet = (struct icmp_packet_rr *)skb->data;
- } else
- spin_unlock_bh(&bat_priv->orig_hash_lock);
+ /* decrement ttl */
+ icmp_packet->ttl--;
+ /* route it */
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
+ goto out;
+
+unlock:
+ rcu_read_unlock();
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (orig_node)
+ kref_put(&orig_node->refcount, orig_node_free_ref);
return ret;
}
@@ -1104,12 +1176,11 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
/* select default router to output */
router = orig_node->router;
router_orig = orig_node->router->orig_node;
- if (!router_orig) {
+ if (!router_orig || !atomic_inc_not_zero(&router->refcount)) {
rcu_read_unlock();
return NULL;
}
-
if ((!recv_if) && (!bonding_enabled))
goto return_router;
@@ -1142,6 +1213,7 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
* is is not on the interface where the packet came
* in. */
+ neigh_node_free_ref(router);
first_candidate = NULL;
router = NULL;
@@ -1154,16 +1226,23 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
if (!first_candidate)
first_candidate = tmp_neigh_node;
/* recv_if == NULL on the first node. */
- if (tmp_neigh_node->if_incoming != recv_if) {
+ if (tmp_neigh_node->if_incoming != recv_if &&
+ atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
router = tmp_neigh_node;
break;
}
}
/* use the first candidate if nothing was found. */
- if (!router)
+ if (!router && first_candidate &&
+ atomic_inc_not_zero(&first_candidate->refcount))
router = first_candidate;
+ if (!router) {
+ rcu_read_unlock();
+ return NULL;
+ }
+
/* selected should point to the next element
* after the current router */
spin_lock_bh(&primary_orig_node->neigh_list_lock);
@@ -1184,21 +1263,34 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
first_candidate = tmp_neigh_node;
/* recv_if == NULL on the first node. */
- if (tmp_neigh_node->if_incoming != recv_if)
- /* if we don't have a router yet
- * or this one is better, choose it. */
- if ((!router) ||
- (tmp_neigh_node->tq_avg > router->tq_avg)) {
- router = tmp_neigh_node;
- }
+ if (tmp_neigh_node->if_incoming == recv_if)
+ continue;
+
+ if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
+ continue;
+
+ /* if we don't have a router yet
+ * or this one is better, choose it. */
+ if ((!router) ||
+ (tmp_neigh_node->tq_avg > router->tq_avg)) {
+ /* decrement refcount of
+ * previously selected router */
+ if (router)
+ neigh_node_free_ref(router);
+
+ router = tmp_neigh_node;
+ atomic_inc_not_zero(&router->refcount);
+ }
+
+ neigh_node_free_ref(tmp_neigh_node);
}
/* use the first candidate if nothing was found. */
- if (!router)
+ if (!router && first_candidate &&
+ atomic_inc_not_zero(&first_candidate->refcount))
router = first_candidate;
}
return_router:
- kref_get(&router->refcount);
rcu_read_unlock();
return router;
}
@@ -1232,13 +1324,13 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
int hdr_size)
{
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
- struct orig_node *orig_node;
- struct neigh_node *router;
+ struct orig_node *orig_node = NULL;
+ struct neigh_node *neigh_node = NULL;
struct batman_if *batman_if;
uint8_t dstaddr[ETH_ALEN];
struct unicast_packet *unicast_packet;
struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
- int ret;
+ int ret = NET_RX_DROP;
struct sk_buff *new_skb;
unicast_packet = (struct unicast_packet *)skb->data;
@@ -1248,7 +1340,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
pr_debug("Warning - can't forward unicast packet from %pM to "
"%pM: ttl exceeded\n", ethhdr->h_source,
unicast_packet->dest);
- return NET_RX_DROP;
+ goto out;
}
/* get routing information */
@@ -1257,27 +1349,29 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
orig_node = ((struct orig_node *)
hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
unicast_packet->dest));
+ if (!orig_node)
+ goto unlock;
+
+ kref_get(&orig_node->refcount);
rcu_read_unlock();
/* find_router() increases neigh_nodes refcount if found. */
- router = find_router(bat_priv, orig_node, recv_if);
+ neigh_node = find_router(bat_priv, orig_node, recv_if);
- if (!router) {
+ if (!neigh_node) {
spin_unlock_bh(&bat_priv->orig_hash_lock);
- return NET_RX_DROP;
+ goto out;
}
/* don't lock while sending the packets ... we therefore
* copy the required data before sending */
-
- batman_if = router->if_incoming;
- memcpy(dstaddr, router->addr, ETH_ALEN);
-
+ batman_if = neigh_node->if_incoming;
+ memcpy(dstaddr, neigh_node->addr, ETH_ALEN);
spin_unlock_bh(&bat_priv->orig_hash_lock);
/* create a copy of the skb, if needed, to modify it. */
if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
- return NET_RX_DROP;
+ goto out;
unicast_packet = (struct unicast_packet *)skb->data;
@@ -1293,11 +1387,13 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
ret = frag_reassemble_skb(skb, bat_priv, &new_skb);
if (ret == NET_RX_DROP)
- return NET_RX_DROP;
+ goto out;
/* packet was buffered for late merge */
- if (!new_skb)
- return NET_RX_SUCCESS;
+ if (!new_skb) {
+ ret = NET_RX_SUCCESS;
+ goto out;
+ }
skb = new_skb;
unicast_packet = (struct unicast_packet *)skb->data;
@@ -1308,8 +1404,18 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
/* route it */
send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
+ goto out;
- return NET_RX_SUCCESS;
+unlock:
+ rcu_read_unlock();
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (orig_node)
+ kref_put(&orig_node->refcount, orig_node_free_ref);
+ return ret;
}
int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 1f833f0..084604a 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -117,9 +117,8 @@ struct neigh_node {
struct list_head bonding_list;
unsigned long last_valid;
unsigned long real_bits[NUM_WORDS];
- struct kref refcount;
+ atomic_t refcount;
struct rcu_head rcu;
- struct rcu_head rcu_bond;
struct orig_node *orig_node;
struct batman_if *if_incoming;
};
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 00bfeaf..7ca994c 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -285,38 +285,42 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
struct unicast_packet *unicast_packet;
struct orig_node *orig_node = NULL;
struct batman_if *batman_if;
- struct neigh_node *router;
+ struct neigh_node *neigh_node;
int data_len = skb->len;
uint8_t dstaddr[6];
+ int ret = 1;
spin_lock_bh(&bat_priv->orig_hash_lock);
/* get routing information */
if (is_multicast_ether_addr(ethhdr->h_dest))
orig_node = (struct orig_node *)gw_get_selected(bat_priv);
+ if (orig_node) {
+ kref_get(&orig_node->refcount);
+ goto find_router;
+ }
- /* check for hna host */
- if (!orig_node)
- orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+ /* check for hna host - increases orig_node refcount */
+ orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+find_router:
/* find_router() increases neigh_nodes refcount if found. */
- router = find_router(bat_priv, orig_node, NULL);
+ neigh_node = find_router(bat_priv, orig_node, NULL);
- if (!router)
+ if (!neigh_node)
goto unlock;
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
- batman_if = router->if_incoming;
- memcpy(dstaddr, router->addr, ETH_ALEN);
-
- spin_unlock_bh(&bat_priv->orig_hash_lock);
-
- if (batman_if->if_status != IF_ACTIVE)
- goto dropped;
+ if (neigh_node->if_incoming->if_status != IF_ACTIVE)
+ goto unlock;
if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0)
- goto dropped;
+ goto unlock;
+
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = neigh_node->if_incoming;
+ memcpy(dstaddr, neigh_node->addr, ETH_ALEN);
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
unicast_packet = (struct unicast_packet *)skb->data;
@@ -330,18 +334,25 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
if (atomic_read(&bat_priv->fragmentation) &&
data_len + sizeof(struct unicast_packet) >
- batman_if->net_dev->mtu) {
+ batman_if->net_dev->mtu) {
/* send frag skb decreases ttl */
unicast_packet->ttl++;
- return frag_send_skb(skb, bat_priv, batman_if,
- dstaddr);
+ ret = frag_send_skb(skb, bat_priv, batman_if, dstaddr);
+ goto out;
}
+
send_skb_packet(skb, batman_if, dstaddr);
- return 0;
+ ret = 0;
+ goto out;
unlock:
spin_unlock_bh(&bat_priv->orig_hash_lock);
-dropped:
- kfree_skb(skb);
- return 1;
+out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (orig_node)
+ kref_put(&orig_node->refcount, orig_node_free_ref);
+ if (ret == 1)
+ kfree_skb(skb);
+ return ret;
}
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index 8092ead..9832d8f 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -764,21 +764,35 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
struct vis_info *info)
{
struct orig_node *orig_node;
+ struct neigh_node *neigh_node = NULL;
struct sk_buff *skb;
struct vis_packet *packet;
struct batman_if *batman_if;
uint8_t dstaddr[ETH_ALEN];
- spin_lock_bh(&bat_priv->orig_hash_lock);
packet = (struct vis_packet *)info->skb_packet->data;
+
+ spin_lock_bh(&bat_priv->orig_hash_lock);
rcu_read_lock();
orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
compare_orig, choose_orig,
packet->target_orig));
- rcu_read_unlock();
- if ((!orig_node) || (!orig_node->router))
- goto out;
+ if (!orig_node)
+ goto unlock;
+
+ kref_get(&orig_node->refcount);
+ neigh_node = orig_node->router;
+
+ if (!neigh_node)
+ goto unlock;
+
+ if (!atomic_inc_not_zero(&neigh_node->refcount)) {
+ neigh_node = NULL;
+ goto unlock;
+ }
+
+ rcu_read_unlock();
/* don't lock while sending the packets ... we therefore
* copy the required data before sending */
@@ -790,10 +804,17 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
if (skb)
send_skb_packet(skb, batman_if, dstaddr);
- return;
+ goto out;
-out:
+unlock:
+ rcu_read_unlock();
spin_unlock_bh(&bat_priv->orig_hash_lock);
+out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (orig_node)
+ kref_put(&orig_node->refcount, orig_node_free_ref);
+ return;
}
/* only send one vis packet. called from send_vis_packets() */
--
1.7.2.3
^ permalink raw reply related
* [PATCH 19/28] batman-adv: Fix possible buffer overflow in softif neigh list output
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r, Marek Lindner,
Linus Lüssing
In-Reply-To: <1299328122-21468-1-git-send-email-sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
From: Linus Lüssing <linus.luessing-8gDhuhu/iIQ@public.gmane.org>
When printing the soft interface table the number of entries in the
softif neigh list are first being counted and a fitting buffer
allocated. After that the softif neigh list gets locked again and
the buffer printed - which has the following two issues:
For one thing, the softif neigh list might have grown when reacquiring
the rcu lock, which results in writing outside of the allocated buffer.
Furthermore 31 Bytes are not enough for printing an entry with a vid
of more than 2 digits.
The manual buffering is unnecessary, we can safely print to the seq
directly during the rcu_read_lock().
Signed-off-by: Linus Lüssing <linus.luessing-8gDhuhu/iIQ@public.gmane.org>
Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
---
net/batman-adv/soft-interface.c | 22 +---------------------
1 files changed, 1 insertions(+), 21 deletions(-)
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 152beaa..c30ccd6 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -171,8 +171,6 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct softif_neigh *softif_neigh;
struct hlist_node *node;
- size_t buf_size, pos;
- char *buff;
if (!bat_priv->primary_if) {
return seq_printf(seq, "BATMAN mesh %s disabled - "
@@ -182,33 +180,15 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
- buf_size = 1;
- /* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */
rcu_read_lock();
hlist_for_each_entry_rcu(softif_neigh, node,
&bat_priv->softif_neigh_list, list)
- buf_size += 30;
- rcu_read_unlock();
-
- buff = kmalloc(buf_size, GFP_ATOMIC);
- if (!buff)
- return -ENOMEM;
-
- buff[0] = '\0';
- pos = 0;
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(softif_neigh, node,
- &bat_priv->softif_neigh_list, list) {
- pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n",
+ seq_printf(seq, "%s %pM (vid: %d)\n",
bat_priv->softif_neigh == softif_neigh
? "=>" : " ", softif_neigh->addr,
softif_neigh->vid);
- }
rcu_read_unlock();
- seq_printf(seq, "%s", buff);
- kfree(buff);
return 0;
}
--
1.7.2.3
^ permalink raw reply related
* [PATCH 07/28] batman-adv: protect each hash row with rcu locks
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem; +Cc: netdev, b.a.t.m.a.n, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven@narfation.org>
From: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
net/batman-adv/hash.c | 34 ++++++++++++----
net/batman-adv/hash.h | 73 ++++++++++++++++++++++++------------
net/batman-adv/icmp_socket.c | 2 +
net/batman-adv/originator.c | 27 ++++++++++---
net/batman-adv/routing.c | 16 +++++++-
net/batman-adv/translation-table.c | 14 +++++++
net/batman-adv/unicast.c | 2 +
net/batman-adv/vis.c | 18 +++++++--
8 files changed, 141 insertions(+), 45 deletions(-)
diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c
index fa26939..0265366 100644
--- a/net/batman-adv/hash.c
+++ b/net/batman-adv/hash.c
@@ -27,13 +27,16 @@ static void hash_init(struct hashtable_t *hash)
{
int i;
- for (i = 0 ; i < hash->size; i++)
+ for (i = 0 ; i < hash->size; i++) {
INIT_HLIST_HEAD(&hash->table[i]);
+ spin_lock_init(&hash->list_locks[i]);
+ }
}
/* free only the hashtable and the hash itself. */
void hash_destroy(struct hashtable_t *hash)
{
+ kfree(hash->list_locks);
kfree(hash->table);
kfree(hash);
}
@@ -43,20 +46,33 @@ struct hashtable_t *hash_new(int size)
{
struct hashtable_t *hash;
- hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC);
-
+ hash = kmalloc(sizeof(struct hashtable_t), GFP_ATOMIC);
if (!hash)
return NULL;
- hash->size = size;
hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC);
+ if (!hash->table)
+ goto free_hash;
- if (!hash->table) {
- kfree(hash);
- return NULL;
- }
+ hash->list_locks = kmalloc(sizeof(spinlock_t) * size, GFP_ATOMIC);
+ if (!hash->list_locks)
+ goto free_table;
+ hash->size = size;
hash_init(hash);
-
return hash;
+
+free_table:
+ kfree(hash->table);
+free_hash:
+ kfree(hash);
+ return NULL;
+}
+
+void bucket_free_rcu(struct rcu_head *rcu)
+{
+ struct element_t *bucket;
+
+ bucket = container_of(rcu, struct element_t, rcu);
+ kfree(bucket);
}
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h
index eae2440..3c48c6b 100644
--- a/net/batman-adv/hash.h
+++ b/net/batman-adv/hash.h
@@ -39,10 +39,12 @@ typedef void (*hashdata_free_cb)(void *, void *);
struct element_t {
void *data; /* pointer to the data */
struct hlist_node hlist; /* bucket list pointer */
+ struct rcu_head rcu;
};
struct hashtable_t {
- struct hlist_head *table; /* the hashtable itself, with the buckets */
+ struct hlist_head *table; /* the hashtable itself with the buckets */
+ spinlock_t *list_locks; /* spinlock for each hash list entry */
int size; /* size of hashtable */
};
@@ -52,6 +54,8 @@ struct hashtable_t *hash_new(int size);
/* free only the hashtable and the hash itself. */
void hash_destroy(struct hashtable_t *hash);
+void bucket_free_rcu(struct rcu_head *rcu);
+
/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
* called to remove the elements inside of the hash. if you don't remove the
* elements, memory might be leaked. */
@@ -61,19 +65,22 @@ static inline void hash_delete(struct hashtable_t *hash,
struct hlist_head *head;
struct hlist_node *walk, *safe;
struct element_t *bucket;
+ spinlock_t *list_lock; /* spinlock to protect write access */
int i;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
- hlist_for_each_safe(walk, safe, head) {
- bucket = hlist_entry(walk, struct element_t, hlist);
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
if (free_cb)
free_cb(bucket->data, arg);
- hlist_del(walk);
- kfree(bucket);
+ hlist_del_rcu(walk);
+ call_rcu(&bucket->rcu, bucket_free_rcu);
}
+ spin_unlock_bh(list_lock);
}
hash_destroy(hash);
@@ -88,29 +95,39 @@ static inline int hash_add(struct hashtable_t *hash,
struct hlist_head *head;
struct hlist_node *walk, *safe;
struct element_t *bucket;
+ spinlock_t *list_lock; /* spinlock to protect write access */
if (!hash)
- return -1;
+ goto err;
index = choose(data, hash->size);
head = &hash->table[index];
+ list_lock = &hash->list_locks[index];
- hlist_for_each_safe(walk, safe, head) {
- bucket = hlist_entry(walk, struct element_t, hlist);
+ rcu_read_lock();
+ hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
if (compare(bucket->data, data))
- return -1;
+ goto err_unlock;
}
+ rcu_read_unlock();
/* no duplicate found in list, add new element */
bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC);
-
if (!bucket)
- return -1;
+ goto err;
bucket->data = data;
- hlist_add_head(&bucket->hlist, head);
+
+ spin_lock_bh(list_lock);
+ hlist_add_head_rcu(&bucket->hlist, head);
+ spin_unlock_bh(list_lock);
return 0;
+
+err_unlock:
+ rcu_read_unlock();
+err:
+ return -1;
}
/* removes data from hash, if found. returns pointer do data on success, so you
@@ -125,25 +142,31 @@ static inline void *hash_remove(struct hashtable_t *hash,
struct hlist_node *walk;
struct element_t *bucket;
struct hlist_head *head;
- void *data_save;
+ void *data_save = NULL;
index = choose(data, hash->size);
head = &hash->table[index];
+ spin_lock_bh(&hash->list_locks[index]);
hlist_for_each_entry(bucket, walk, head, hlist) {
if (compare(bucket->data, data)) {
data_save = bucket->data;
- hlist_del(walk);
- kfree(bucket);
- return data_save;
+ hlist_del_rcu(walk);
+ call_rcu(&bucket->rcu, bucket_free_rcu);
+ break;
}
}
+ spin_unlock_bh(&hash->list_locks[index]);
- return NULL;
+ return data_save;
}
-/* finds data, based on the key in keydata. returns the found data on success,
- * or NULL on error */
+/**
+ * finds data, based on the key in keydata. returns the found data on success,
+ * or NULL on error
+ *
+ * caller must lock with rcu_read_lock() / rcu_read_unlock()
+ **/
static inline void *hash_find(struct hashtable_t *hash,
hashdata_compare_cb compare,
hashdata_choose_cb choose, void *keydata)
@@ -152,6 +175,7 @@ static inline void *hash_find(struct hashtable_t *hash,
struct hlist_head *head;
struct hlist_node *walk;
struct element_t *bucket;
+ void *bucket_data = NULL;
if (!hash)
return NULL;
@@ -159,13 +183,14 @@ static inline void *hash_find(struct hashtable_t *hash,
index = choose(keydata , hash->size);
head = &hash->table[index];
- hlist_for_each(walk, head) {
- bucket = hlist_entry(walk, struct element_t, hlist);
- if (compare(bucket->data, keydata))
- return bucket->data;
+ hlist_for_each_entry(bucket, walk, head, hlist) {
+ if (compare(bucket->data, keydata)) {
+ bucket_data = bucket->data;
+ break;
+ }
}
- return NULL;
+ return bucket_data;
}
#endif /* _NET_BATMAN_ADV_HASH_H_ */
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
index 319a7cc..8e0cd8a 100644
--- a/net/batman-adv/icmp_socket.c
+++ b/net/batman-adv/icmp_socket.c
@@ -220,9 +220,11 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
goto dst_unreach;
spin_lock_bh(&bat_priv->orig_hash_lock);
+ rcu_read_lock();
orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
compare_orig, choose_orig,
icmp_packet->dst));
+ rcu_read_unlock();
if (!orig_node)
goto unlock;
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 899d494..5c32314 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -150,9 +150,11 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
int size;
int hash_added;
+ rcu_read_lock();
orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
compare_orig, choose_orig,
addr));
+ rcu_read_unlock();
if (orig_node)
return orig_node;
@@ -294,6 +296,7 @@ static void _purge_orig(struct bat_priv *bat_priv)
struct hlist_node *walk, *safe;
struct hlist_head *head;
struct element_t *bucket;
+ spinlock_t *list_lock; /* spinlock to protect write access */
struct orig_node *orig_node;
int i;
@@ -305,22 +308,26 @@ static void _purge_orig(struct bat_priv *bat_priv)
/* for all origins... */
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+ spin_lock_bh(list_lock);
hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
orig_node = bucket->data;
if (purge_orig_node(bat_priv, orig_node)) {
if (orig_node->gw_flags)
gw_node_delete(bat_priv, orig_node);
- hlist_del(walk);
- kfree(bucket);
+ hlist_del_rcu(walk);
+ call_rcu(&bucket->rcu, bucket_free_rcu);
free_orig_node(orig_node, bat_priv);
+ continue;
}
if (time_after(jiffies, orig_node->last_frag_packet +
msecs_to_jiffies(FRAG_TIMEOUT)))
frag_list_free(&orig_node->frag_list);
}
+ spin_unlock_bh(list_lock);
}
spin_unlock_bh(&bat_priv->orig_hash_lock);
@@ -387,7 +394,8 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
orig_node = bucket->data;
if (!orig_node->router)
@@ -408,17 +416,16 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
neigh_node->addr,
neigh_node->if_incoming->net_dev->name);
- rcu_read_lock();
hlist_for_each_entry_rcu(neigh_node, node,
&orig_node->neigh_list, list) {
seq_printf(seq, " %pM (%3i)", neigh_node->addr,
neigh_node->tq_avg);
}
- rcu_read_unlock();
seq_printf(seq, "\n");
batman_count++;
}
+ rcu_read_unlock();
}
spin_unlock_bh(&bat_priv->orig_hash_lock);
@@ -476,18 +483,21 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
orig_node = bucket->data;
if (orig_node_add_if(orig_node, max_if_num) == -1)
goto err;
}
+ rcu_read_unlock();
}
spin_unlock_bh(&bat_priv->orig_hash_lock);
return 0;
err:
+ rcu_read_unlock();
spin_unlock_bh(&bat_priv->orig_hash_lock);
return -ENOMEM;
}
@@ -562,7 +572,8 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
orig_node = bucket->data;
ret = orig_node_del_if(orig_node, max_if_num,
@@ -571,6 +582,7 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
if (ret == -1)
goto err;
}
+ rcu_read_unlock();
}
/* renumber remaining batman interfaces _inside_ of orig_hash_lock */
@@ -595,6 +607,7 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
return 0;
err:
+ rcu_read_unlock();
spin_unlock_bh(&bat_priv->orig_hash_lock);
return -ENOMEM;
}
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index c15e6c1..32ae04e 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -52,7 +52,8 @@ void slide_own_bcast_window(struct batman_if *batman_if)
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
orig_node = bucket->data;
word_index = batman_if->if_num * NUM_WORDS;
word = &(orig_node->bcast_own[word_index]);
@@ -61,6 +62,7 @@ void slide_own_bcast_window(struct batman_if *batman_if)
orig_node->bcast_own_sum[batman_if->if_num] =
bit_packet_count(word);
}
+ rcu_read_unlock();
}
spin_unlock_bh(&bat_priv->orig_hash_lock);
@@ -873,9 +875,11 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
/* answer echo request (ping) */
/* get routing information */
spin_lock_bh(&bat_priv->orig_hash_lock);
+ rcu_read_lock();
orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
compare_orig, choose_orig,
icmp_packet->orig));
+ rcu_read_unlock();
ret = NET_RX_DROP;
if ((orig_node) && (orig_node->router)) {
@@ -931,9 +935,11 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
/* get routing information */
spin_lock_bh(&bat_priv->orig_hash_lock);
+ rcu_read_lock();
orig_node = ((struct orig_node *)
hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
icmp_packet->orig));
+ rcu_read_unlock();
ret = NET_RX_DROP;
if ((orig_node) && (orig_node->router)) {
@@ -1023,9 +1029,11 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
/* get routing information */
spin_lock_bh(&bat_priv->orig_hash_lock);
+ rcu_read_lock();
orig_node = ((struct orig_node *)
hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
icmp_packet->dst));
+ rcu_read_unlock();
if ((orig_node) && (orig_node->router)) {
@@ -1094,9 +1102,11 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
router_orig->orig, ETH_ALEN) == 0) {
primary_orig_node = router_orig;
} else {
+ rcu_read_lock();
primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig,
choose_orig,
router_orig->primary_addr);
+ rcu_read_unlock();
if (!primary_orig_node)
return orig_node->router;
@@ -1199,9 +1209,11 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
/* get routing information */
spin_lock_bh(&bat_priv->orig_hash_lock);
+ rcu_read_lock();
orig_node = ((struct orig_node *)
hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
unicast_packet->dest));
+ rcu_read_unlock();
router = find_router(bat_priv, orig_node, recv_if);
@@ -1345,9 +1357,11 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if)
return NET_RX_DROP;
spin_lock_bh(&bat_priv->orig_hash_lock);
+ rcu_read_lock();
orig_node = ((struct orig_node *)
hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
bcast_packet->orig));
+ rcu_read_unlock();
if (!orig_node) {
spin_unlock_bh(&bat_priv->orig_hash_lock);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 7fb6726..b25e4b3 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -60,10 +60,12 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr)
int required_bytes;
spin_lock_bh(&bat_priv->hna_lhash_lock);
+ rcu_read_lock();
hna_local_entry =
((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash,
compare_orig, choose_orig,
addr));
+ rcu_read_unlock();
spin_unlock_bh(&bat_priv->hna_lhash_lock);
if (hna_local_entry) {
@@ -116,9 +118,11 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr)
/* remove address from global hash if present */
spin_lock_bh(&bat_priv->hna_ghash_lock);
+ rcu_read_lock();
hna_global_entry = ((struct hna_global_entry *)
hash_find(bat_priv->hna_global_hash,
compare_orig, choose_orig, addr));
+ rcu_read_unlock();
if (hna_global_entry)
_hna_global_del_orig(bat_priv, hna_global_entry,
@@ -252,9 +256,11 @@ void hna_local_remove(struct bat_priv *bat_priv,
spin_lock_bh(&bat_priv->hna_lhash_lock);
+ rcu_read_lock();
hna_local_entry = (struct hna_local_entry *)
hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig,
addr);
+ rcu_read_unlock();
if (hna_local_entry)
hna_local_del(bat_priv, hna_local_entry, message);
@@ -334,9 +340,11 @@ void hna_global_add_orig(struct bat_priv *bat_priv,
spin_lock_bh(&bat_priv->hna_ghash_lock);
hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
+ rcu_read_lock();
hna_global_entry = (struct hna_global_entry *)
hash_find(bat_priv->hna_global_hash, compare_orig,
choose_orig, hna_ptr);
+ rcu_read_unlock();
if (!hna_global_entry) {
spin_unlock_bh(&bat_priv->hna_ghash_lock);
@@ -368,9 +376,11 @@ void hna_global_add_orig(struct bat_priv *bat_priv,
spin_lock_bh(&bat_priv->hna_lhash_lock);
hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
+ rcu_read_lock();
hna_local_entry = (struct hna_local_entry *)
hash_find(bat_priv->hna_local_hash, compare_orig,
choose_orig, hna_ptr);
+ rcu_read_unlock();
if (hna_local_entry)
hna_local_del(bat_priv, hna_local_entry,
@@ -483,9 +493,11 @@ void hna_global_del_orig(struct bat_priv *bat_priv,
while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) {
hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN);
+ rcu_read_lock();
hna_global_entry = (struct hna_global_entry *)
hash_find(bat_priv->hna_global_hash, compare_orig,
choose_orig, hna_ptr);
+ rcu_read_unlock();
if ((hna_global_entry) &&
(hna_global_entry->orig_node == orig_node))
@@ -521,9 +533,11 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr)
struct hna_global_entry *hna_global_entry;
spin_lock_bh(&bat_priv->hna_ghash_lock);
+ rcu_read_lock();
hna_global_entry = (struct hna_global_entry *)
hash_find(bat_priv->hna_global_hash,
compare_orig, choose_orig, addr);
+ rcu_read_unlock();
spin_unlock_bh(&bat_priv->hna_ghash_lock);
if (!hna_global_entry)
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 1b5e761..4687027 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -179,9 +179,11 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
*new_skb = NULL;
spin_lock_bh(&bat_priv->orig_hash_lock);
+ rcu_read_lock();
orig_node = ((struct orig_node *)
hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
unicast_packet->orig));
+ rcu_read_unlock();
if (!orig_node) {
pr_debug("couldn't find originator in orig_hash\n");
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index a77b773..8092ead 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -380,8 +380,10 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
sizeof(struct vis_packet));
memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN);
+ rcu_read_lock();
old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
&search_elem);
+ rcu_read_unlock();
kfree_skb(search_elem.skb_packet);
if (old_info) {
@@ -540,7 +542,8 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
orig_node = bucket->data;
if ((orig_node) && (orig_node->router) &&
(orig_node->flags & VIS_SERVER) &&
@@ -550,6 +553,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
ETH_ALEN);
}
}
+ rcu_read_unlock();
}
return best_tq;
@@ -605,7 +609,8 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
orig_node = bucket->data;
neigh_node = orig_node->router;
@@ -632,10 +637,12 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
packet->entries++;
if (vis_packet_full(info)) {
+ rcu_read_unlock();
spin_unlock_bh(&bat_priv->orig_hash_lock);
return 0;
}
}
+ rcu_read_unlock();
}
spin_unlock_bh(&bat_priv->orig_hash_lock);
@@ -721,7 +728,8 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
orig_node = bucket->data;
/* if it's a vis server and reachable, send it. */
@@ -746,7 +754,7 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
spin_lock_bh(&bat_priv->orig_hash_lock);
}
-
+ rcu_read_unlock();
}
spin_unlock_bh(&bat_priv->orig_hash_lock);
@@ -763,9 +771,11 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
spin_lock_bh(&bat_priv->orig_hash_lock);
packet = (struct vis_packet *)info->skb_packet->data;
+ rcu_read_lock();
orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
compare_orig, choose_orig,
packet->target_orig));
+ rcu_read_unlock();
if ((!orig_node) || (!orig_node->router))
goto out;
--
1.7.2.3
^ permalink raw reply related
* [PATCH 08/28] batman-adv: protect originator nodes with reference counters
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem; +Cc: netdev, b.a.t.m.a.n, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven@narfation.org>
From: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
net/batman-adv/originator.c | 61 ++++++++++++++++++++++++++++++++++++------
net/batman-adv/originator.h | 1 +
net/batman-adv/routing.c | 33 ++++++++++++++++-------
net/batman-adv/types.h | 2 +
4 files changed, 78 insertions(+), 19 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 5c32314..fcdb0b7 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -103,12 +103,13 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
return neigh_node;
}
-static void free_orig_node(void *data, void *arg)
+void orig_node_free_ref(struct kref *refcount)
{
struct hlist_node *node, *node_tmp;
struct neigh_node *neigh_node;
- struct orig_node *orig_node = (struct orig_node *)data;
- struct bat_priv *bat_priv = (struct bat_priv *)arg;
+ struct orig_node *orig_node;
+
+ orig_node = container_of(refcount, struct orig_node, refcount);
spin_lock_bh(&orig_node->neigh_list_lock);
@@ -122,7 +123,8 @@ static void free_orig_node(void *data, void *arg)
spin_unlock_bh(&orig_node->neigh_list_lock);
frag_list_free(&orig_node->frag_list);
- hna_global_del_orig(bat_priv, orig_node, "originator timed out");
+ hna_global_del_orig(orig_node->bat_priv, orig_node,
+ "originator timed out");
kfree(orig_node->bcast_own);
kfree(orig_node->bcast_own_sum);
@@ -131,17 +133,53 @@ static void free_orig_node(void *data, void *arg)
void originator_free(struct bat_priv *bat_priv)
{
- if (!bat_priv->orig_hash)
+ struct hashtable_t *hash = bat_priv->orig_hash;
+ struct hlist_node *walk, *safe;
+ struct hlist_head *head;
+ struct element_t *bucket;
+ spinlock_t *list_lock; /* spinlock to protect write access */
+ struct orig_node *orig_node;
+ int i;
+
+ if (!hash)
return;
cancel_delayed_work_sync(&bat_priv->orig_work);
spin_lock_bh(&bat_priv->orig_hash_lock);
- hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv);
bat_priv->orig_hash = NULL;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
+ orig_node = bucket->data;
+
+ hlist_del_rcu(walk);
+ call_rcu(&bucket->rcu, bucket_free_rcu);
+ kref_put(&orig_node->refcount, orig_node_free_ref);
+ }
+ spin_unlock_bh(list_lock);
+ }
+
+ hash_destroy(hash);
spin_unlock_bh(&bat_priv->orig_hash_lock);
}
+static void bucket_free_orig_rcu(struct rcu_head *rcu)
+{
+ struct element_t *bucket;
+ struct orig_node *orig_node;
+
+ bucket = container_of(rcu, struct element_t, rcu);
+ orig_node = bucket->data;
+
+ kref_put(&orig_node->refcount, orig_node_free_ref);
+ kfree(bucket);
+}
+
/* this function finds or creates an originator entry for the given
* address if it does not exits */
struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
@@ -156,8 +194,10 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
addr));
rcu_read_unlock();
- if (orig_node)
+ if (orig_node) {
+ kref_get(&orig_node->refcount);
return orig_node;
+ }
bat_dbg(DBG_BATMAN, bat_priv,
"Creating new originator: %pM\n", addr);
@@ -168,7 +208,9 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
INIT_HLIST_HEAD(&orig_node->neigh_list);
spin_lock_init(&orig_node->neigh_list_lock);
+ kref_init(&orig_node->refcount);
+ orig_node->bat_priv = bat_priv;
memcpy(orig_node->orig, addr, ETH_ALEN);
orig_node->router = NULL;
orig_node->hna_buff = NULL;
@@ -197,6 +239,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
if (hash_added < 0)
goto free_bcast_own_sum;
+ /* extra reference for return */
+ kref_get(&orig_node->refcount);
return orig_node;
free_bcast_own_sum:
kfree(orig_node->bcast_own_sum);
@@ -318,8 +362,7 @@ static void _purge_orig(struct bat_priv *bat_priv)
if (orig_node->gw_flags)
gw_node_delete(bat_priv, orig_node);
hlist_del_rcu(walk);
- call_rcu(&bucket->rcu, bucket_free_rcu);
- free_orig_node(orig_node, bat_priv);
+ call_rcu(&bucket->rcu, bucket_free_orig_rcu);
continue;
}
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 88e5c60..edc64dc 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -25,6 +25,7 @@
int originator_init(struct bat_priv *bat_priv);
void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv);
+void orig_node_free_ref(struct kref *refcount);
struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 32ae04e..1c31a0e 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -311,6 +311,8 @@ static void update_orig(struct bat_priv *bat_priv,
neigh_node = create_neighbor(orig_node, orig_tmp,
ethhdr->h_source, if_incoming);
+
+ kref_put(&orig_tmp->refcount, orig_node_free_ref);
if (!neigh_node)
goto unlock;
} else
@@ -438,7 +440,7 @@ static char count_real_packets(struct ethhdr *ethhdr,
/* signalize caller that the packet is to be dropped. */
if (window_protected(bat_priv, seq_diff,
&orig_node->batman_seqno_reset))
- return -1;
+ goto err;
rcu_read_lock();
hlist_for_each_entry_rcu(tmp_neigh_node, node,
@@ -471,7 +473,12 @@ static char count_real_packets(struct ethhdr *ethhdr,
orig_node->last_real_seqno = batman_packet->seqno;
}
+ kref_put(&orig_node->refcount, orig_node_free_ref);
return is_duplicate;
+
+err:
+ kref_put(&orig_node->refcount, orig_node_free_ref);
+ return -1;
}
/* copy primary address for bonding */
@@ -686,7 +693,6 @@ void receive_bat_packet(struct ethhdr *ethhdr,
int offset;
orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
-
if (!orig_neigh_node)
return;
@@ -707,6 +713,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
"originator packet from myself (via neighbor)\n");
+ kref_put(&orig_neigh_node->refcount, orig_node_free_ref);
return;
}
@@ -727,13 +734,13 @@ void receive_bat_packet(struct ethhdr *ethhdr,
bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: packet within seqno protection time "
"(sender: %pM)\n", ethhdr->h_source);
- return;
+ goto out;
}
if (batman_packet->tq == 0) {
bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: originator packet with tq equal 0\n");
- return;
+ goto out;
}
/* avoid temporary routing loops */
@@ -747,7 +754,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: ignoring all rebroadcast packets that "
"may make me loop (sender: %pM)\n", ethhdr->h_source);
- return;
+ goto out;
}
/* if sender is a direct neighbor the sender mac equals
@@ -756,14 +763,14 @@ void receive_bat_packet(struct ethhdr *ethhdr,
orig_node :
get_orig_node(bat_priv, ethhdr->h_source));
if (!orig_neigh_node)
- return;
+ goto out_neigh;
/* drop packet if sender is not a direct neighbor and if we
* don't route towards it */
if (!is_single_hop_neigh && (!orig_neigh_node->router)) {
bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: OGM via unknown neighbor!\n");
- return;
+ goto out_neigh;
}
is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
@@ -790,26 +797,32 @@ void receive_bat_packet(struct ethhdr *ethhdr,
bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
"rebroadcast neighbor packet with direct link flag\n");
- return;
+ goto out_neigh;
}
/* multihop originator */
if (!is_bidirectional) {
bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: not received via bidirectional link\n");
- return;
+ goto out_neigh;
}
if (is_duplicate) {
bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: duplicate packet received\n");
- return;
+ goto out_neigh;
}
bat_dbg(DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
schedule_forward_packet(orig_node, ethhdr, batman_packet,
0, hna_buff_len, if_incoming);
+
+out_neigh:
+ if (!is_single_hop_neigh)
+ kref_put(&orig_neigh_node->refcount, orig_node_free_ref);
+out:
+ kref_put(&orig_node->refcount, orig_node_free_ref);
}
int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if)
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index d4fa727..ca4d42d 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -86,6 +86,8 @@ struct orig_node {
struct hlist_head neigh_list;
struct list_head frag_list;
spinlock_t neigh_list_lock; /* protects neighbor list */
+ struct kref refcount;
+ struct bat_priv *bat_priv;
unsigned long last_frag_packet;
struct {
uint8_t candidates;
--
1.7.2.3
^ permalink raw reply related
* [PATCH 09/28] batman-adv: protect ogm counter arrays with spinlock
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem; +Cc: netdev, b.a.t.m.a.n, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven@narfation.org>
From: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
net/batman-adv/originator.c | 11 +++++++++--
net/batman-adv/routing.c | 27 +++++++++++++++++++++++----
net/batman-adv/types.h | 1 +
3 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index fcdb0b7..71dfc24 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -207,6 +207,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
return NULL;
INIT_HLIST_HEAD(&orig_node->neigh_list);
+ spin_lock_init(&orig_node->ogm_cnt_lock);
spin_lock_init(&orig_node->neigh_list_lock);
kref_init(&orig_node->refcount);
@@ -517,7 +518,7 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
struct hlist_head *head;
struct element_t *bucket;
struct orig_node *orig_node;
- int i;
+ int i, ret;
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num */
@@ -530,7 +531,11 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
orig_node = bucket->data;
- if (orig_node_add_if(orig_node, max_if_num) == -1)
+ spin_lock_bh(&orig_node->ogm_cnt_lock);
+ ret = orig_node_add_if(orig_node, max_if_num);
+ spin_unlock_bh(&orig_node->ogm_cnt_lock);
+
+ if (ret == -1)
goto err;
}
rcu_read_unlock();
@@ -619,8 +624,10 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
orig_node = bucket->data;
+ spin_lock_bh(&orig_node->ogm_cnt_lock);
ret = orig_node_del_if(orig_node, max_if_num,
batman_if->if_num);
+ spin_unlock_bh(&orig_node->ogm_cnt_lock);
if (ret == -1)
goto err;
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 1c31a0e..7627ebe 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -55,12 +55,14 @@ void slide_own_bcast_window(struct batman_if *batman_if)
rcu_read_lock();
hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
orig_node = bucket->data;
+ spin_lock_bh(&orig_node->ogm_cnt_lock);
word_index = batman_if->if_num * NUM_WORDS;
word = &(orig_node->bcast_own[word_index]);
bit_get_packet(bat_priv, word, 1, 0);
orig_node->bcast_own_sum[batman_if->if_num] =
bit_packet_count(word);
+ spin_unlock_bh(&orig_node->ogm_cnt_lock);
}
rcu_read_unlock();
}
@@ -278,8 +280,10 @@ static void update_orig(struct bat_priv *bat_priv,
char is_duplicate)
{
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
+ struct orig_node *orig_node_tmp;
struct hlist_node *node;
int tmp_hna_buff_len;
+ uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
"Searching and updating originator entry of received packet\n");
@@ -351,10 +355,22 @@ static void update_orig(struct bat_priv *bat_priv,
/* if the TQ is the same and the link not more symetric we
* won't consider it either */
if ((orig_node->router) &&
- ((neigh_node->tq_avg == orig_node->router->tq_avg) &&
- (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num]
- >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num])))
- goto update_hna;
+ (neigh_node->tq_avg == orig_node->router->tq_avg)) {
+ orig_node_tmp = orig_node->router->orig_node;
+ spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
+ bcast_own_sum_orig =
+ orig_node_tmp->bcast_own_sum[if_incoming->if_num];
+ spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
+
+ orig_node_tmp = neigh_node->orig_node;
+ spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
+ bcast_own_sum_neigh =
+ orig_node_tmp->bcast_own_sum[if_incoming->if_num];
+ spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
+
+ if (bcast_own_sum_orig >= bcast_own_sum_neigh)
+ goto update_hna;
+ }
update_routes(bat_priv, orig_node, neigh_node,
hna_buff, tmp_hna_buff_len);
@@ -705,10 +721,13 @@ void receive_bat_packet(struct ethhdr *ethhdr,
batman_packet->orig) &&
(batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
offset = if_incoming->if_num * NUM_WORDS;
+
+ spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
word = &(orig_neigh_node->bcast_own[offset]);
bit_mark(word, 0);
orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
bit_packet_count(word);
+ spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
}
bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index ca4d42d..ff70afc 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -89,6 +89,7 @@ struct orig_node {
struct kref refcount;
struct bat_priv *bat_priv;
unsigned long last_frag_packet;
+ spinlock_t ogm_cnt_lock; /* protects ogm counter */
struct {
uint8_t candidates;
struct neigh_node *selected;
--
1.7.2.3
^ permalink raw reply related
* [PATCH 10/28] batman-adv: protect bonding with rcu locks
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem; +Cc: netdev, b.a.t.m.a.n, Simon Wunderlich, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven@narfation.org>
From: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
bonding / alternating candidates need to be secured by rcu locks
as well. This patch therefore converts the bonding list
from a plain pointer list to a rcu securable lists and references
the bonding candidates.
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
net/batman-adv/hard-interface.c | 2 +-
net/batman-adv/originator.c | 25 +++-
net/batman-adv/originator.h | 1 +
net/batman-adv/routing.c | 313 ++++++++++++++++++++-------------------
net/batman-adv/routing.h | 6 +-
net/batman-adv/types.h | 9 +-
net/batman-adv/unicast.c | 2 +-
7 files changed, 195 insertions(+), 163 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index f2131f4..e2b001a 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -271,7 +271,7 @@ static void hardif_activate_interface(struct batman_if *batman_if)
static void hardif_deactivate_interface(struct batman_if *batman_if)
{
if ((batman_if->if_status != IF_ACTIVE) &&
- (batman_if->if_status != IF_TO_BE_ACTIVATED))
+ (batman_if->if_status != IF_TO_BE_ACTIVATED))
return;
batman_if->if_status = IF_INACTIVE;
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 71dfc24..a85eadc 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -75,6 +75,14 @@ static void neigh_node_free_rcu(struct rcu_head *rcu)
kref_put(&neigh_node->refcount, neigh_node_free_ref);
}
+void neigh_node_free_rcu_bond(struct rcu_head *rcu)
+{
+ struct neigh_node *neigh_node;
+
+ neigh_node = container_of(rcu, struct neigh_node, rcu_bond);
+ kref_put(&neigh_node->refcount, neigh_node_free_ref);
+}
+
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
uint8_t *neigh,
@@ -91,6 +99,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
return NULL;
INIT_HLIST_NODE(&neigh_node->list);
+ INIT_LIST_HEAD(&neigh_node->bonding_list);
memcpy(neigh_node->addr, neigh, ETH_ALEN);
neigh_node->orig_node = orig_neigh_node;
@@ -106,13 +115,20 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
void orig_node_free_ref(struct kref *refcount)
{
struct hlist_node *node, *node_tmp;
- struct neigh_node *neigh_node;
+ struct neigh_node *neigh_node, *tmp_neigh_node;
struct orig_node *orig_node;
orig_node = container_of(refcount, struct orig_node, refcount);
spin_lock_bh(&orig_node->neigh_list_lock);
+ /* for all bonding members ... */
+ list_for_each_entry_safe(neigh_node, tmp_neigh_node,
+ &orig_node->bond_list, bonding_list) {
+ list_del_rcu(&neigh_node->bonding_list);
+ call_rcu(&neigh_node->rcu_bond, neigh_node_free_rcu_bond);
+ }
+
/* for all neighbors towards this originator ... */
hlist_for_each_entry_safe(neigh_node, node, node_tmp,
&orig_node->neigh_list, list) {
@@ -207,6 +223,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
return NULL;
INIT_HLIST_HEAD(&orig_node->neigh_list);
+ INIT_LIST_HEAD(&orig_node->bond_list);
spin_lock_init(&orig_node->ogm_cnt_lock);
spin_lock_init(&orig_node->neigh_list_lock);
kref_init(&orig_node->refcount);
@@ -220,6 +237,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
orig_node->batman_seqno_reset = jiffies - 1
- msecs_to_jiffies(RESET_PROTECTION_MS);
+ atomic_set(&orig_node->bond_candidates, 0);
+
size = bat_priv->num_ifaces * sizeof(unsigned long) * NUM_WORDS;
orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
@@ -295,6 +314,7 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
neigh_purged = true;
hlist_del_rcu(&neigh_node->list);
+ bonding_candidate_del(orig_node, neigh_node);
call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
} else {
if ((!*best_neigh_node) ||
@@ -326,9 +346,6 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
best_neigh_node,
orig_node->hna_buff,
orig_node->hna_buff_len);
- /* update bonding candidates, we could have lost
- * some candidates. */
- update_bonding_candidates(orig_node);
}
}
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index edc64dc..360dfd1 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -26,6 +26,7 @@ int originator_init(struct bat_priv *bat_priv);
void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv);
void orig_node_free_ref(struct kref *refcount);
+void neigh_node_free_rcu_bond(struct rcu_head *rcu);
struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 7627ebe..1ad14da 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -271,6 +271,101 @@ out:
return ret;
}
+/* caller must hold the neigh_list_lock */
+void bonding_candidate_del(struct orig_node *orig_node,
+ struct neigh_node *neigh_node)
+{
+ /* this neighbor is not part of our candidate list */
+ if (list_empty(&neigh_node->bonding_list))
+ goto out;
+
+ list_del_rcu(&neigh_node->bonding_list);
+ call_rcu(&neigh_node->rcu_bond, neigh_node_free_rcu_bond);
+ INIT_LIST_HEAD(&neigh_node->bonding_list);
+ atomic_dec(&orig_node->bond_candidates);
+
+out:
+ return;
+}
+
+static void bonding_candidate_add(struct orig_node *orig_node,
+ struct neigh_node *neigh_node)
+{
+ struct hlist_node *node;
+ struct neigh_node *tmp_neigh_node;
+ uint8_t best_tq, interference_candidate = 0;
+
+ spin_lock_bh(&orig_node->neigh_list_lock);
+
+ /* only consider if it has the same primary address ... */
+ if (!compare_orig(orig_node->orig,
+ neigh_node->orig_node->primary_addr))
+ goto candidate_del;
+
+ if (!orig_node->router)
+ goto candidate_del;
+
+ best_tq = orig_node->router->tq_avg;
+
+ /* ... and is good enough to be considered */
+ if (neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD)
+ goto candidate_del;
+
+ /**
+ * check if we have another candidate with the same mac address or
+ * interface. If we do, we won't select this candidate because of
+ * possible interference.
+ */
+ hlist_for_each_entry_rcu(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
+
+ if (tmp_neigh_node == neigh_node)
+ continue;
+
+ /* we only care if the other candidate is even
+ * considered as candidate. */
+ if (list_empty(&tmp_neigh_node->bonding_list))
+ continue;
+
+ if ((neigh_node->if_incoming == tmp_neigh_node->if_incoming) ||
+ (compare_orig(neigh_node->addr, tmp_neigh_node->addr))) {
+ interference_candidate = 1;
+ break;
+ }
+ }
+
+ /* don't care further if it is an interference candidate */
+ if (interference_candidate)
+ goto candidate_del;
+
+ /* this neighbor already is part of our candidate list */
+ if (!list_empty(&neigh_node->bonding_list))
+ goto out;
+
+ list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list);
+ kref_get(&neigh_node->refcount);
+ atomic_inc(&orig_node->bond_candidates);
+ goto out;
+
+candidate_del:
+ bonding_candidate_del(orig_node, neigh_node);
+
+out:
+ spin_unlock_bh(&orig_node->neigh_list_lock);
+ return;
+}
+
+/* copy primary address for bonding */
+static void bonding_save_primary(struct orig_node *orig_node,
+ struct orig_node *orig_neigh_node,
+ struct batman_packet *batman_packet)
+{
+ if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
+ return;
+
+ memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN);
+}
+
static void update_orig(struct bat_priv *bat_priv,
struct orig_node *orig_node,
struct ethhdr *ethhdr,
@@ -339,6 +434,8 @@ static void update_orig(struct bat_priv *bat_priv,
neigh_node->last_ttl = batman_packet->ttl;
}
+ bonding_candidate_add(orig_node, neigh_node);
+
tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ?
batman_packet->num_hna * ETH_ALEN : hna_buff_len);
@@ -497,123 +594,10 @@ err:
return -1;
}
-/* copy primary address for bonding */
-static void mark_bonding_address(struct orig_node *orig_node,
- struct orig_node *orig_neigh_node,
- struct batman_packet *batman_packet)
-
-{
- if (batman_packet->flags & PRIMARIES_FIRST_HOP)
- memcpy(orig_neigh_node->primary_addr,
- orig_node->orig, ETH_ALEN);
-
- return;
-}
-
-/* mark possible bond.candidates in the neighbor list */
-void update_bonding_candidates(struct orig_node *orig_node)
-{
- int candidates;
- int interference_candidate;
- int best_tq;
- struct hlist_node *node, *node2;
- struct neigh_node *tmp_neigh_node, *tmp_neigh_node2;
- struct neigh_node *first_candidate, *last_candidate;
-
- /* update the candidates for this originator */
- if (!orig_node->router) {
- orig_node->bond.candidates = 0;
- return;
- }
-
- best_tq = orig_node->router->tq_avg;
-
- /* update bond.candidates */
-
- candidates = 0;
-
- /* mark other nodes which also received "PRIMARIES FIRST HOP" packets
- * as "bonding partner" */
-
- /* first, zero the list */
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
- tmp_neigh_node->next_bond_candidate = NULL;
- }
- rcu_read_unlock();
-
- first_candidate = NULL;
- last_candidate = NULL;
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
-
- /* only consider if it has the same primary address ... */
- if (memcmp(orig_node->orig,
- tmp_neigh_node->orig_node->primary_addr,
- ETH_ALEN) != 0)
- continue;
-
- /* ... and is good enough to be considered */
- if (tmp_neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD)
- continue;
-
- /* check if we have another candidate with the same
- * mac address or interface. If we do, we won't
- * select this candidate because of possible interference. */
-
- interference_candidate = 0;
- hlist_for_each_entry_rcu(tmp_neigh_node2, node2,
- &orig_node->neigh_list, list) {
-
- if (tmp_neigh_node2 == tmp_neigh_node)
- continue;
-
- /* we only care if the other candidate is even
- * considered as candidate. */
- if (!tmp_neigh_node2->next_bond_candidate)
- continue;
-
-
- if ((tmp_neigh_node->if_incoming ==
- tmp_neigh_node2->if_incoming)
- || (memcmp(tmp_neigh_node->addr,
- tmp_neigh_node2->addr, ETH_ALEN) == 0)) {
-
- interference_candidate = 1;
- break;
- }
- }
- /* don't care further if it is an interference candidate */
- if (interference_candidate)
- continue;
-
- if (!first_candidate) {
- first_candidate = tmp_neigh_node;
- tmp_neigh_node->next_bond_candidate = first_candidate;
- } else
- tmp_neigh_node->next_bond_candidate = last_candidate;
-
- last_candidate = tmp_neigh_node;
-
- candidates++;
- }
- rcu_read_unlock();
-
- if (candidates > 0) {
- first_candidate->next_bond_candidate = last_candidate;
- orig_node->bond.selected = first_candidate;
- }
-
- orig_node->bond.candidates = candidates;
-}
-
void receive_bat_packet(struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- unsigned char *hna_buff, int hna_buff_len,
- struct batman_if *if_incoming)
+ struct batman_packet *batman_packet,
+ unsigned char *hna_buff, int hna_buff_len,
+ struct batman_if *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct batman_if *batman_if;
@@ -795,6 +779,8 @@ void receive_bat_packet(struct ethhdr *ethhdr,
is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
batman_packet, if_incoming);
+ bonding_save_primary(orig_node, orig_neigh_node, batman_packet);
+
/* update ranking if it is not a duplicate or has the same
* seqno and similar ttl as the non-duplicate */
if (is_bidirectional &&
@@ -804,9 +790,6 @@ void receive_bat_packet(struct ethhdr *ethhdr,
update_orig(bat_priv, orig_node, ethhdr, batman_packet,
if_incoming, hna_buff, hna_buff_len, is_duplicate);
- mark_bonding_address(orig_node, orig_neigh_node, batman_packet);
- update_bonding_candidates(orig_node);
-
/* is single hop (direct) neighbor */
if (is_single_hop_neigh) {
@@ -1095,14 +1078,15 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
}
/* find a suitable router for this originator, and use
- * bonding if possible. */
+ * bonding if possible. increases the found neighbors
+ * refcount.*/
struct neigh_node *find_router(struct bat_priv *bat_priv,
struct orig_node *orig_node,
struct batman_if *recv_if)
{
struct orig_node *primary_orig_node;
struct orig_node *router_orig;
- struct neigh_node *router, *first_candidate, *best_router;
+ struct neigh_node *router, *first_candidate, *tmp_neigh_node;
static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
int bonding_enabled;
@@ -1114,18 +1098,25 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
/* without bonding, the first node should
* always choose the default router. */
-
bonding_enabled = atomic_read(&bat_priv->bonding);
- if ((!recv_if) && (!bonding_enabled))
- return orig_node->router;
-
+ rcu_read_lock();
+ /* select default router to output */
+ router = orig_node->router;
router_orig = orig_node->router->orig_node;
+ if (!router_orig) {
+ rcu_read_unlock();
+ return NULL;
+ }
+
+
+ if ((!recv_if) && (!bonding_enabled))
+ goto return_router;
/* if we have something in the primary_addr, we can search
* for a potential bonding candidate. */
if (memcmp(router_orig->primary_addr, zero_mac, ETH_ALEN) == 0)
- return orig_node->router;
+ goto return_router;
/* find the orig_node which has the primary interface. might
* even be the same as our router_orig in many cases */
@@ -1134,60 +1125,81 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
router_orig->orig, ETH_ALEN) == 0) {
primary_orig_node = router_orig;
} else {
- rcu_read_lock();
primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig,
choose_orig,
router_orig->primary_addr);
- rcu_read_unlock();
-
if (!primary_orig_node)
- return orig_node->router;
+ goto return_router;
}
/* with less than 2 candidates, we can't do any
* bonding and prefer the original router. */
-
- if (primary_orig_node->bond.candidates < 2)
- return orig_node->router;
+ if (atomic_read(&primary_orig_node->bond_candidates) < 2)
+ goto return_router;
/* all nodes between should choose a candidate which
* is is not on the interface where the packet came
* in. */
- first_candidate = primary_orig_node->bond.selected;
- router = first_candidate;
+
+ first_candidate = NULL;
+ router = NULL;
if (bonding_enabled) {
/* in the bonding case, send the packets in a round
* robin fashion over the remaining interfaces. */
- do {
+
+ list_for_each_entry_rcu(tmp_neigh_node,
+ &primary_orig_node->bond_list, bonding_list) {
+ if (!first_candidate)
+ first_candidate = tmp_neigh_node;
/* recv_if == NULL on the first node. */
- if (router->if_incoming != recv_if)
+ if (tmp_neigh_node->if_incoming != recv_if) {
+ router = tmp_neigh_node;
break;
+ }
+ }
- router = router->next_bond_candidate;
- } while (router != first_candidate);
+ /* use the first candidate if nothing was found. */
+ if (!router)
+ router = first_candidate;
- primary_orig_node->bond.selected = router->next_bond_candidate;
+ /* selected should point to the next element
+ * after the current router */
+ spin_lock_bh(&primary_orig_node->neigh_list_lock);
+ /* this is a list_move(), which unfortunately
+ * does not exist as rcu version */
+ list_del_rcu(&primary_orig_node->bond_list);
+ list_add_rcu(&primary_orig_node->bond_list,
+ &router->bonding_list);
+ spin_unlock_bh(&primary_orig_node->neigh_list_lock);
} else {
/* if bonding is disabled, use the best of the
* remaining candidates which are not using
* this interface. */
- best_router = first_candidate;
+ list_for_each_entry_rcu(tmp_neigh_node,
+ &primary_orig_node->bond_list, bonding_list) {
+ if (!first_candidate)
+ first_candidate = tmp_neigh_node;
- do {
/* recv_if == NULL on the first node. */
- if ((router->if_incoming != recv_if) &&
- (router->tq_avg > best_router->tq_avg))
- best_router = router;
-
- router = router->next_bond_candidate;
- } while (router != first_candidate);
+ if (tmp_neigh_node->if_incoming != recv_if)
+ /* if we don't have a router yet
+ * or this one is better, choose it. */
+ if ((!router) ||
+ (tmp_neigh_node->tq_avg > router->tq_avg)) {
+ router = tmp_neigh_node;
+ }
+ }
- router = best_router;
+ /* use the first candidate if nothing was found. */
+ if (!router)
+ router = first_candidate;
}
-
+return_router:
+ kref_get(&router->refcount);
+ rcu_read_unlock();
return router;
}
@@ -1247,6 +1259,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
unicast_packet->dest));
rcu_read_unlock();
+ /* find_router() increases neigh_nodes refcount if found. */
router = find_router(bat_priv, orig_node, recv_if);
if (!router) {
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
index a09d16f..e2a9872 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -39,7 +39,9 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if);
int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if);
int recv_bat_packet(struct sk_buff *skb, struct batman_if *recv_if);
struct neigh_node *find_router(struct bat_priv *bat_priv,
- struct orig_node *orig_node, struct batman_if *recv_if);
-void update_bonding_candidates(struct orig_node *orig_node);
+ struct orig_node *orig_node,
+ struct batman_if *recv_if);
+void bonding_candidate_del(struct orig_node *orig_node,
+ struct neigh_node *neigh_node);
#endif /* _NET_BATMAN_ADV_ROUTING_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index ff70afc..1f833f0 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -90,10 +90,8 @@ struct orig_node {
struct bat_priv *bat_priv;
unsigned long last_frag_packet;
spinlock_t ogm_cnt_lock; /* protects ogm counter */
- struct {
- uint8_t candidates;
- struct neigh_node *selected;
- } bond;
+ atomic_t bond_candidates;
+ struct list_head bond_list;
};
struct gw_node {
@@ -116,11 +114,12 @@ struct neigh_node {
uint8_t tq_index;
uint8_t tq_avg;
uint8_t last_ttl;
- struct neigh_node *next_bond_candidate;
+ struct list_head bonding_list;
unsigned long last_valid;
unsigned long real_bits[NUM_WORDS];
struct kref refcount;
struct rcu_head rcu;
+ struct rcu_head rcu_bond;
struct orig_node *orig_node;
struct batman_if *if_incoming;
};
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 4687027..00bfeaf 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -299,6 +299,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
if (!orig_node)
orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+ /* find_router() increases neigh_nodes refcount if found. */
router = find_router(bat_priv, orig_node, NULL);
if (!router)
@@ -306,7 +307,6 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
/* don't lock while sending the packets ... we therefore
* copy the required data before sending */
-
batman_if = router->if_incoming;
memcpy(dstaddr, router->addr, ETH_ALEN);
--
1.7.2.3
^ permalink raw reply related
* [PATCH 12/28] batman-adv: Correct rcu refcounting for gw_node
From: Sven Eckelmann @ 2011-03-05 12:28 UTC (permalink / raw)
To: davem; +Cc: netdev, b.a.t.m.a.n, Marek Lindner
In-Reply-To: <1299328122-21468-1-git-send-email-sven@narfation.org>
From: Marek Lindner <lindner_marek@yahoo.de>
It might be possible that 2 threads access the same data in the same
rcu grace period. The first thread calls call_rcu() to decrement the
refcount and free the data while the second thread increases the
refcount to use the data. To avoid this race condition all refcount
operations have to be atomic.
Reported-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
net/batman-adv/gateway_client.c | 37 ++++++++++++++++---------------------
net/batman-adv/types.h | 2 +-
2 files changed, 17 insertions(+), 22 deletions(-)
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 429a013..517e001 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -28,20 +28,18 @@
#include <linux/udp.h>
#include <linux/if_vlan.h>
-static void gw_node_free_ref(struct kref *refcount)
+static void gw_node_free_rcu(struct rcu_head *rcu)
{
struct gw_node *gw_node;
- gw_node = container_of(refcount, struct gw_node, refcount);
+ gw_node = container_of(rcu, struct gw_node, rcu);
kfree(gw_node);
}
-static void gw_node_free_rcu(struct rcu_head *rcu)
+static void gw_node_free_ref(struct gw_node *gw_node)
{
- struct gw_node *gw_node;
-
- gw_node = container_of(rcu, struct gw_node, rcu);
- kref_put(&gw_node->refcount, gw_node_free_ref);
+ if (atomic_dec_and_test(&gw_node->refcount))
+ call_rcu(&gw_node->rcu, gw_node_free_rcu);
}
void *gw_get_selected(struct bat_priv *bat_priv)
@@ -61,25 +59,26 @@ void gw_deselect(struct bat_priv *bat_priv)
bat_priv->curr_gw = NULL;
if (gw_node)
- kref_put(&gw_node->refcount, gw_node_free_ref);
+ gw_node_free_ref(gw_node);
}
-static struct gw_node *gw_select(struct bat_priv *bat_priv,
- struct gw_node *new_gw_node)
+static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
{
struct gw_node *curr_gw_node = bat_priv->curr_gw;
- if (new_gw_node)
- kref_get(&new_gw_node->refcount);
+ if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
+ new_gw_node = NULL;
bat_priv->curr_gw = new_gw_node;
- return curr_gw_node;
+
+ if (curr_gw_node)
+ gw_node_free_ref(curr_gw_node);
}
void gw_election(struct bat_priv *bat_priv)
{
struct hlist_node *node;
- struct gw_node *gw_node, *curr_gw_tmp = NULL, *old_gw_node = NULL;
+ struct gw_node *gw_node, *curr_gw_tmp = NULL;
uint8_t max_tq = 0;
uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
int down, up;
@@ -174,14 +173,10 @@ void gw_election(struct bat_priv *bat_priv)
curr_gw_tmp->orig_node->gw_flags,
curr_gw_tmp->orig_node->router->tq_avg);
- old_gw_node = gw_select(bat_priv, curr_gw_tmp);
+ gw_select(bat_priv, curr_gw_tmp);
}
rcu_read_unlock();
-
- /* the kfree() has to be outside of the rcu lock */
- if (old_gw_node)
- kref_put(&old_gw_node->refcount, gw_node_free_ref);
}
void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
@@ -242,7 +237,7 @@ static void gw_node_add(struct bat_priv *bat_priv,
memset(gw_node, 0, sizeof(struct gw_node));
INIT_HLIST_NODE(&gw_node->list);
gw_node->orig_node = orig_node;
- kref_init(&gw_node->refcount);
+ atomic_set(&gw_node->refcount, 1);
spin_lock_bh(&bat_priv->gw_list_lock);
hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list);
@@ -325,7 +320,7 @@ void gw_node_purge(struct bat_priv *bat_priv)
gw_deselect(bat_priv);
hlist_del_rcu(&gw_node->list);
- call_rcu(&gw_node->rcu, gw_node_free_rcu);
+ gw_node_free_ref(gw_node);
}
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 084604a..cfbeb45 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -98,7 +98,7 @@ struct gw_node {
struct hlist_node list;
struct orig_node *orig_node;
unsigned long deleted;
- struct kref refcount;
+ atomic_t refcount;
struct rcu_head rcu;
};
--
1.7.2.3
^ 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