Commit bb7e95c8 authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

Conflicts:
	drivers/net/bnx2x_main.c

Merge bnx2x bug fixes in by hand... :-/
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b8bc0421 5447080c
...@@ -863,6 +863,10 @@ struct bnx2x { ...@@ -863,6 +863,10 @@ struct bnx2x {
/* used to synchronize stats collecting */ /* used to synchronize stats collecting */
int stats_state; int stats_state;
/* used for synchronization of concurrent threads statistics handling */
spinlock_t stats_lock;
/* used by dmae command loader */ /* used by dmae command loader */
struct dmae_command stats_dmae; struct dmae_command stats_dmae;
int executer_idx; int executer_idx;
......
...@@ -6714,6 +6714,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) ...@@ -6714,6 +6714,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
mutex_init(&bp->port.phy_mutex); mutex_init(&bp->port.phy_mutex);
mutex_init(&bp->fw_mb_mutex); mutex_init(&bp->fw_mb_mutex);
spin_lock_init(&bp->stats_lock);
#ifdef BCM_CNIC #ifdef BCM_CNIC
mutex_init(&bp->cnic_mutex); mutex_init(&bp->cnic_mutex);
#endif #endif
......
...@@ -156,6 +156,8 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp) ...@@ -156,6 +156,8 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
struct eth_query_ramrod_data ramrod_data = {0}; struct eth_query_ramrod_data ramrod_data = {0};
int i, rc; int i, rc;
spin_lock_bh(&bp->stats_lock);
ramrod_data.drv_counter = bp->stats_counter++; ramrod_data.drv_counter = bp->stats_counter++;
ramrod_data.collect_port = bp->port.pmf ? 1 : 0; ramrod_data.collect_port = bp->port.pmf ? 1 : 0;
for_each_queue(bp, i) for_each_queue(bp, i)
...@@ -169,6 +171,8 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp) ...@@ -169,6 +171,8 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
bp->spq_left++; bp->spq_left++;
bp->stats_pending = 1; bp->stats_pending = 1;
} }
spin_unlock_bh(&bp->stats_lock);
} }
} }
...@@ -734,6 +738,14 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) ...@@ -734,6 +738,14 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
struct host_func_stats *fstats = bnx2x_sp(bp, func_stats); struct host_func_stats *fstats = bnx2x_sp(bp, func_stats);
struct bnx2x_eth_stats *estats = &bp->eth_stats; struct bnx2x_eth_stats *estats = &bp->eth_stats;
int i; int i;
u16 cur_stats_counter;
/* Make sure we use the value of the counter
* used for sending the last stats ramrod.
*/
spin_lock_bh(&bp->stats_lock);
cur_stats_counter = bp->stats_counter - 1;
spin_unlock_bh(&bp->stats_lock);
memcpy(&(fstats->total_bytes_received_hi), memcpy(&(fstats->total_bytes_received_hi),
&(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi), &(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi),
...@@ -761,25 +773,22 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) ...@@ -761,25 +773,22 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
u32 diff; u32 diff;
/* are storm stats valid? */ /* are storm stats valid? */
if ((u16)(le16_to_cpu(xclient->stats_counter) + 1) != if (le16_to_cpu(xclient->stats_counter) != cur_stats_counter) {
bp->stats_counter) {
DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm" DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm"
" xstorm counter (0x%x) != stats_counter (0x%x)\n", " xstorm counter (0x%x) != stats_counter (0x%x)\n",
i, xclient->stats_counter, bp->stats_counter); i, xclient->stats_counter, cur_stats_counter + 1);
return -1; return -1;
} }
if ((u16)(le16_to_cpu(tclient->stats_counter) + 1) != if (le16_to_cpu(tclient->stats_counter) != cur_stats_counter) {
bp->stats_counter) {
DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm" DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm"
" tstorm counter (0x%x) != stats_counter (0x%x)\n", " tstorm counter (0x%x) != stats_counter (0x%x)\n",
i, tclient->stats_counter, bp->stats_counter); i, tclient->stats_counter, cur_stats_counter + 1);
return -2; return -2;
} }
if ((u16)(le16_to_cpu(uclient->stats_counter) + 1) != if (le16_to_cpu(uclient->stats_counter) != cur_stats_counter) {
bp->stats_counter) {
DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm" DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm"
" ustorm counter (0x%x) != stats_counter (0x%x)\n", " ustorm counter (0x%x) != stats_counter (0x%x)\n",
i, uclient->stats_counter, bp->stats_counter); i, uclient->stats_counter, cur_stats_counter + 1);
return -4; return -4;
} }
...@@ -1216,16 +1225,18 @@ static const struct { ...@@ -1216,16 +1225,18 @@ static const struct {
void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
{ {
enum bnx2x_stats_state state = bp->stats_state; enum bnx2x_stats_state state;
if (unlikely(bp->panic)) if (unlikely(bp->panic))
return; return;
bnx2x_stats_stm[state][event].action(bp); /* Protect a state change flow */
spin_lock_bh(&bp->stats_lock);
state = bp->stats_state;
bp->stats_state = bnx2x_stats_stm[state][event].next_state; bp->stats_state = bnx2x_stats_stm[state][event].next_state;
spin_unlock_bh(&bp->stats_lock);
/* Make sure the state has been "changed" */ bnx2x_stats_stm[state][event].action(bp);
smp_wmb();
if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp)) if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n", DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
......
...@@ -815,7 +815,7 @@ static int rlb_initialize(struct bonding *bond) ...@@ -815,7 +815,7 @@ static int rlb_initialize(struct bonding *bond)
/*initialize packet type*/ /*initialize packet type*/
pk_type->type = cpu_to_be16(ETH_P_ARP); pk_type->type = cpu_to_be16(ETH_P_ARP);
pk_type->dev = NULL; pk_type->dev = bond->dev;
pk_type->func = rlb_arp_recv; pk_type->func = rlb_arp_recv;
/* register to receive ARPs */ /* register to receive ARPs */
......
...@@ -1722,6 +1722,15 @@ static int __devinit igb_probe(struct pci_dev *pdev, ...@@ -1722,6 +1722,15 @@ static int __devinit igb_probe(struct pci_dev *pdev,
u16 eeprom_apme_mask = IGB_EEPROM_APME; u16 eeprom_apme_mask = IGB_EEPROM_APME;
u32 part_num; u32 part_num;
/* Catch broken hardware that put the wrong VF device ID in
* the PCIe SR-IOV capability.
*/
if (pdev->is_virtfn) {
WARN(1, KERN_ERR "%s (%hx:%hx) should not be a VF!\n",
pci_name(pdev), pdev->vendor, pdev->device);
return -EINVAL;
}
err = pci_enable_device_mem(pdev); err = pci_enable_device_mem(pdev);
if (err) if (err)
return err; return err;
......
...@@ -6539,6 +6539,15 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ...@@ -6539,6 +6539,15 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
#endif #endif
u32 part_num, eec; u32 part_num, eec;
/* Catch broken hardware that put the wrong VF device ID in
* the PCIe SR-IOV capability.
*/
if (pdev->is_virtfn) {
WARN(1, KERN_ERR "%s (%hx:%hx) should not be a VF!\n",
pci_name(pdev), pdev->vendor, pdev->device);
return -EINVAL;
}
err = pci_enable_device_mem(pdev); err = pci_enable_device_mem(pdev);
if (err) if (err)
return err; return err;
......
...@@ -515,7 +515,7 @@ static const struct net_device_ops macvlan_netdev_ops = { ...@@ -515,7 +515,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
}; };
static void macvlan_setup(struct net_device *dev) void macvlan_common_setup(struct net_device *dev)
{ {
ether_setup(dev); ether_setup(dev);
...@@ -524,6 +524,12 @@ static void macvlan_setup(struct net_device *dev) ...@@ -524,6 +524,12 @@ static void macvlan_setup(struct net_device *dev)
dev->destructor = free_netdev; dev->destructor = free_netdev;
dev->header_ops = &macvlan_hard_header_ops, dev->header_ops = &macvlan_hard_header_ops,
dev->ethtool_ops = &macvlan_ethtool_ops; dev->ethtool_ops = &macvlan_ethtool_ops;
}
EXPORT_SYMBOL_GPL(macvlan_common_setup);
static void macvlan_setup(struct net_device *dev)
{
macvlan_common_setup(dev);
dev->tx_queue_len = 0; dev->tx_queue_len = 0;
} }
...@@ -735,7 +741,6 @@ int macvlan_link_register(struct rtnl_link_ops *ops) ...@@ -735,7 +741,6 @@ int macvlan_link_register(struct rtnl_link_ops *ops)
/* common fields */ /* common fields */
ops->priv_size = sizeof(struct macvlan_dev); ops->priv_size = sizeof(struct macvlan_dev);
ops->get_tx_queues = macvlan_get_tx_queues; ops->get_tx_queues = macvlan_get_tx_queues;
ops->setup = macvlan_setup;
ops->validate = macvlan_validate; ops->validate = macvlan_validate;
ops->maxtype = IFLA_MACVLAN_MAX; ops->maxtype = IFLA_MACVLAN_MAX;
ops->policy = macvlan_policy; ops->policy = macvlan_policy;
...@@ -749,6 +754,7 @@ EXPORT_SYMBOL_GPL(macvlan_link_register); ...@@ -749,6 +754,7 @@ EXPORT_SYMBOL_GPL(macvlan_link_register);
static struct rtnl_link_ops macvlan_link_ops = { static struct rtnl_link_ops macvlan_link_ops = {
.kind = "macvlan", .kind = "macvlan",
.setup = macvlan_setup,
.newlink = macvlan_newlink, .newlink = macvlan_newlink,
.dellink = macvlan_dellink, .dellink = macvlan_dellink,
}; };
......
...@@ -180,11 +180,18 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) ...@@ -180,11 +180,18 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb)
{ {
struct macvtap_queue *q = macvtap_get_queue(dev, skb); struct macvtap_queue *q = macvtap_get_queue(dev, skb);
if (!q) if (!q)
return -ENOLINK; goto drop;
if (skb_queue_len(&q->sk.sk_receive_queue) >= dev->tx_queue_len)
goto drop;
skb_queue_tail(&q->sk.sk_receive_queue, skb); skb_queue_tail(&q->sk.sk_receive_queue, skb);
wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND); wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND);
return 0; return NET_RX_SUCCESS;
drop:
kfree_skb(skb);
return NET_RX_DROP;
} }
/* /*
...@@ -235,8 +242,15 @@ static void macvtap_dellink(struct net_device *dev, ...@@ -235,8 +242,15 @@ static void macvtap_dellink(struct net_device *dev,
macvlan_dellink(dev, head); macvlan_dellink(dev, head);
} }
static void macvtap_setup(struct net_device *dev)
{
macvlan_common_setup(dev);
dev->tx_queue_len = TUN_READQ_SIZE;
}
static struct rtnl_link_ops macvtap_link_ops __read_mostly = { static struct rtnl_link_ops macvtap_link_ops __read_mostly = {
.kind = "macvtap", .kind = "macvtap",
.setup = macvtap_setup,
.newlink = macvtap_newlink, .newlink = macvtap_newlink,
.dellink = macvtap_dellink, .dellink = macvtap_dellink,
}; };
......
...@@ -65,7 +65,7 @@ static int debug_level = ERR_DBG; ...@@ -65,7 +65,7 @@ static int debug_level = ERR_DBG;
/* DEBUG message print. */ /* DEBUG message print. */
#define DBG_PRINT(dbg_level, fmt, args...) do { \ #define DBG_PRINT(dbg_level, fmt, args...) do { \
if (dbg_level >= debug_level) \ if (dbg_level <= debug_level) \
pr_info(fmt, ##args); \ pr_info(fmt, ##args); \
} while (0) } while (0)
......
...@@ -736,8 +736,18 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, ...@@ -736,8 +736,18 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
else if (sinfo->gso_type & SKB_GSO_UDP) else if (sinfo->gso_type & SKB_GSO_UDP)
gso.gso_type = VIRTIO_NET_HDR_GSO_UDP; gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
else else {
BUG(); printk(KERN_ERR "tun: unexpected GSO type: "
"0x%x, gso_size %d, hdr_len %d\n",
sinfo->gso_type, gso.gso_size,
gso.hdr_len);
print_hex_dump(KERN_ERR, "tun: ",
DUMP_PREFIX_NONE,
16, 1, skb->head,
min((int)gso.hdr_len, 64), true);
WARN_ON_ONCE(1);
return -EINVAL;
}
if (sinfo->gso_type & SKB_GSO_TCP_ECN) if (sinfo->gso_type & SKB_GSO_TCP_ECN)
gso.gso_type |= VIRTIO_NET_HDR_GSO_ECN; gso.gso_type |= VIRTIO_NET_HDR_GSO_ECN;
} else } else
......
...@@ -152,6 +152,7 @@ enum { ...@@ -152,6 +152,7 @@ enum {
/* Device IDs */ /* Device IDs */
USB_DEVICE_ID_I6050 = 0x0186, USB_DEVICE_ID_I6050 = 0x0186,
USB_DEVICE_ID_I6050_2 = 0x0188, USB_DEVICE_ID_I6050_2 = 0x0188,
USB_DEVICE_ID_I6250 = 0x0187,
}; };
......
...@@ -491,6 +491,7 @@ int i2400mu_probe(struct usb_interface *iface, ...@@ -491,6 +491,7 @@ int i2400mu_probe(struct usb_interface *iface,
switch (id->idProduct) { switch (id->idProduct) {
case USB_DEVICE_ID_I6050: case USB_DEVICE_ID_I6050:
case USB_DEVICE_ID_I6050_2: case USB_DEVICE_ID_I6050_2:
case USB_DEVICE_ID_I6250:
i2400mu->i6050 = 1; i2400mu->i6050 = 1;
break; break;
default: default:
...@@ -739,6 +740,7 @@ static ...@@ -739,6 +740,7 @@ static
struct usb_device_id i2400mu_id_table[] = { struct usb_device_id i2400mu_id_table[] = {
{ USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) }, { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) },
{ USB_DEVICE(0x8086, USB_DEVICE_ID_I6050_2) }, { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050_2) },
{ USB_DEVICE(0x8086, USB_DEVICE_ID_I6250) },
{ USB_DEVICE(0x8086, 0x0181) }, { USB_DEVICE(0x8086, 0x0181) },
{ USB_DEVICE(0x8086, 0x1403) }, { USB_DEVICE(0x8086, 0x1403) },
{ USB_DEVICE(0x8086, 0x1405) }, { USB_DEVICE(0x8086, 0x1405) },
......
...@@ -72,6 +72,8 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan, ...@@ -72,6 +72,8 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
} }
} }
extern void macvlan_common_setup(struct net_device *dev);
extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev, extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[], struct nlattr *tb[], struct nlattr *data[],
int (*receive)(struct sk_buff *skb), int (*receive)(struct sk_buff *skb),
......
...@@ -9,6 +9,7 @@ struct tcf_mirred { ...@@ -9,6 +9,7 @@ struct tcf_mirred {
int tcfm_ifindex; int tcfm_ifindex;
int tcfm_ok_push; int tcfm_ok_push;
struct net_device *tcfm_dev; struct net_device *tcfm_dev;
struct list_head tcfm_list;
}; };
#define to_mirred(pc) \ #define to_mirred(pc) \
container_of(pc, struct tcf_mirred, common) container_of(pc, struct tcf_mirred, common)
......
...@@ -1484,6 +1484,7 @@ static inline void net_timestamp_check(struct sk_buff *skb) ...@@ -1484,6 +1484,7 @@ static inline void net_timestamp_check(struct sk_buff *skb)
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
{ {
skb_orphan(skb); skb_orphan(skb);
nf_reset(skb);
if (!(dev->flags & IFF_UP) || if (!(dev->flags & IFF_UP) ||
(skb->len > (dev->mtu + dev->hard_header_len))) { (skb->len > (dev->mtu + dev->hard_header_len))) {
......
...@@ -843,6 +843,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, ...@@ -843,6 +843,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
skb->network_header += off; skb->network_header += off;
if (skb_mac_header_was_set(skb)) if (skb_mac_header_was_set(skb))
skb->mac_header += off; skb->mac_header += off;
/* Only adjust this if it actually is csum_start rather than csum */
if (skb->ip_summed == CHECKSUM_PARTIAL)
skb->csum_start += nhead; skb->csum_start += nhead;
skb->cloned = 0; skb->cloned = 0;
skb->hdr_len = 0; skb->hdr_len = 0;
...@@ -930,6 +932,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, ...@@ -930,6 +932,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
copy_skb_header(n, skb); copy_skb_header(n, skb);
off = newheadroom - oldheadroom; off = newheadroom - oldheadroom;
if (n->ip_summed == CHECKSUM_PARTIAL)
n->csum_start += off; n->csum_start += off;
#ifdef NET_SKBUFF_DATA_USES_OFFSET #ifdef NET_SKBUFF_DATA_USES_OFFSET
n->transport_header += off; n->transport_header += off;
......
...@@ -1763,7 +1763,10 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev) ...@@ -1763,7 +1763,10 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
idev = ipv6_find_idev(dev); idev = ipv6_find_idev(dev);
if (!idev) if (!idev)
return NULL; return ERR_PTR(-ENOBUFS);
if (idev->cnf.disable_ipv6)
return ERR_PTR(-EACCES);
/* Add default multicast route */ /* Add default multicast route */
addrconf_add_mroute(dev); addrconf_add_mroute(dev);
...@@ -2132,8 +2135,9 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, ...@@ -2132,8 +2135,9 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
if ((idev = addrconf_add_dev(dev)) == NULL) idev = addrconf_add_dev(dev);
return -ENOBUFS; if (IS_ERR(idev))
return PTR_ERR(idev);
scope = ipv6_addr_scope(pfx); scope = ipv6_addr_scope(pfx);
...@@ -2380,7 +2384,7 @@ static void addrconf_dev_config(struct net_device *dev) ...@@ -2380,7 +2384,7 @@ static void addrconf_dev_config(struct net_device *dev)
} }
idev = addrconf_add_dev(dev); idev = addrconf_add_dev(dev);
if (idev == NULL) if (IS_ERR(idev))
return; return;
memset(&addr, 0, sizeof(struct in6_addr)); memset(&addr, 0, sizeof(struct in6_addr));
...@@ -2471,7 +2475,7 @@ static void addrconf_ip6_tnl_config(struct net_device *dev) ...@@ -2471,7 +2475,7 @@ static void addrconf_ip6_tnl_config(struct net_device *dev)
ASSERT_RTNL(); ASSERT_RTNL();
idev = addrconf_add_dev(dev); idev = addrconf_add_dev(dev);
if (!idev) { if (IS_ERR(idev)) {
printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n"); printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n");
return; return;
} }
......
...@@ -632,7 +632,7 @@ static void ieee80211_send_layer2_update(struct sta_info *sta) ...@@ -632,7 +632,7 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
skb->dev = sta->sdata->dev; skb->dev = sta->sdata->dev;
skb->protocol = eth_type_trans(skb, sta->sdata->dev); skb->protocol = eth_type_trans(skb, sta->sdata->dev);
memset(skb->cb, 0, sizeof(skb->cb)); memset(skb->cb, 0, sizeof(skb->cb));
netif_rx(skb); netif_rx_ni(skb);
} }
static void sta_apply_parameters(struct ieee80211_local *local, static void sta_apply_parameters(struct ieee80211_local *local,
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1];
static u32 mirred_idx_gen; static u32 mirred_idx_gen;
static DEFINE_RWLOCK(mirred_lock); static DEFINE_RWLOCK(mirred_lock);
static LIST_HEAD(mirred_list);
static struct tcf_hashinfo mirred_hash_info = { static struct tcf_hashinfo mirred_hash_info = {
.htab = tcf_mirred_ht, .htab = tcf_mirred_ht,
...@@ -47,6 +48,8 @@ static inline int tcf_mirred_release(struct tcf_mirred *m, int bind) ...@@ -47,6 +48,8 @@ static inline int tcf_mirred_release(struct tcf_mirred *m, int bind)
m->tcf_bindcnt--; m->tcf_bindcnt--;
m->tcf_refcnt--; m->tcf_refcnt--;
if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) { if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) {
list_del(&m->tcfm_list);
if (m->tcfm_dev)
dev_put(m->tcfm_dev); dev_put(m->tcfm_dev);
tcf_hash_destroy(&m->common, &mirred_hash_info); tcf_hash_destroy(&m->common, &mirred_hash_info);
return 1; return 1;
...@@ -134,8 +137,10 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est, ...@@ -134,8 +137,10 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est,
m->tcfm_ok_push = ok_push; m->tcfm_ok_push = ok_push;
} }
spin_unlock_bh(&m->tcf_lock); spin_unlock_bh(&m->tcf_lock);
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED) {
list_add(&m->tcfm_list, &mirred_list);
tcf_hash_insert(pc, &mirred_hash_info); tcf_hash_insert(pc, &mirred_hash_info);
}
return ret; return ret;
} }
...@@ -164,9 +169,14 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, ...@@ -164,9 +169,14 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
m->tcf_bstats.packets++; m->tcf_bstats.packets++;
dev = m->tcfm_dev; dev = m->tcfm_dev;
if (!dev) {
printk_once(KERN_NOTICE "tc mirred: target device is gone\n");
goto out;
}
if (!(dev->flags & IFF_UP)) { if (!(dev->flags & IFF_UP)) {
if (net_ratelimit()) if (net_ratelimit())
pr_notice("tc mirred to Houston: device %s is gone!\n", pr_notice("tc mirred to Houston: device %s is down\n",
dev->name); dev->name);
goto out; goto out;
} }
...@@ -230,6 +240,28 @@ static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, i ...@@ -230,6 +240,28 @@ static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, i
return -1; return -1;
} }
static int mirred_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
struct tcf_mirred *m;
if (event == NETDEV_UNREGISTER)
list_for_each_entry(m, &mirred_list, tcfm_list) {
if (m->tcfm_dev == dev) {
dev_put(dev);
m->tcfm_dev = NULL;
}
}
return NOTIFY_DONE;
}
static struct notifier_block mirred_device_notifier = {
.notifier_call = mirred_device_event,
};
static struct tc_action_ops act_mirred_ops = { static struct tc_action_ops act_mirred_ops = {
.kind = "mirred", .kind = "mirred",
.hinfo = &mirred_hash_info, .hinfo = &mirred_hash_info,
...@@ -250,12 +282,17 @@ MODULE_LICENSE("GPL"); ...@@ -250,12 +282,17 @@ MODULE_LICENSE("GPL");
static int __init mirred_init_module(void) static int __init mirred_init_module(void)
{ {
int err = register_netdevice_notifier(&mirred_device_notifier);
if (err)
return err;
pr_info("Mirror/redirect action on\n"); pr_info("Mirror/redirect action on\n");
return tcf_register_action(&act_mirred_ops); return tcf_register_action(&act_mirred_ops);
} }
static void __exit mirred_cleanup_module(void) static void __exit mirred_cleanup_module(void)
{ {
unregister_netdevice_notifier(&mirred_device_notifier);
tcf_unregister_action(&act_mirred_ops); tcf_unregister_action(&act_mirred_ops);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment