Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: s2io: fixing DBG_PRINT() macro ath9k: fix dma direction for map/unmap in ath_rx_tasklet net: dev_forward_skb should call nf_reset net sched: fix race in mirred device removal tun: avoid BUG, dump packet on GSO errors bonding: set device in RLB ARP packet handler wimax/i2400m: Add PID & VID for Intel WiMAX 6250 ipv6: Don't add routes to ipv6 disabled interfaces. net: Fix skb_copy_expand() handling of ->csum_start net: Fix corruption of skb csum field in pskb_expand_head() of net/core/skbuff.c macvtap: Limit packet queue length ixgbe/igb: catch invalid VF settings bnx2x: Advance a module version bnx2x: Protect statistics ramrod and sequence number bnx2x: Protect a SM state change wireless: use netif_rx_ni in ieee80211_send_layer2_update
This commit is contained in:
Коммит
a376bca610
|
@ -1062,6 +1062,10 @@ struct bnx2x {
|
|||
|
||||
/* used to synchronize stats collecting */
|
||||
int stats_state;
|
||||
|
||||
/* used for synchronization of concurrent threads statistics handling */
|
||||
spinlock_t stats_lock;
|
||||
|
||||
/* used by dmae command loader */
|
||||
struct dmae_command stats_dmae;
|
||||
int executer_idx;
|
||||
|
|
|
@ -57,8 +57,8 @@
|
|||
#include "bnx2x_init_ops.h"
|
||||
#include "bnx2x_dump.h"
|
||||
|
||||
#define DRV_MODULE_VERSION "1.52.53-1"
|
||||
#define DRV_MODULE_RELDATE "2010/18/04"
|
||||
#define DRV_MODULE_VERSION "1.52.53-2"
|
||||
#define DRV_MODULE_RELDATE "2010/21/07"
|
||||
#define BNX2X_BC_VER 0x040200
|
||||
|
||||
#include <linux/firmware.h>
|
||||
|
@ -3789,6 +3789,8 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
|
|||
struct eth_query_ramrod_data ramrod_data = {0};
|
||||
int i, rc;
|
||||
|
||||
spin_lock_bh(&bp->stats_lock);
|
||||
|
||||
ramrod_data.drv_counter = bp->stats_counter++;
|
||||
ramrod_data.collect_port = bp->port.pmf ? 1 : 0;
|
||||
for_each_queue(bp, i)
|
||||
|
@ -3802,6 +3804,8 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
|
|||
bp->spq_left++;
|
||||
bp->stats_pending = 1;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&bp->stats_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4367,6 +4371,14 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
|
|||
struct host_func_stats *fstats = bnx2x_sp(bp, func_stats);
|
||||
struct bnx2x_eth_stats *estats = &bp->eth_stats;
|
||||
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),
|
||||
&(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi),
|
||||
|
@ -4394,25 +4406,22 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
|
|||
u32 diff;
|
||||
|
||||
/* are storm stats valid? */
|
||||
if ((u16)(le16_to_cpu(xclient->stats_counter) + 1) !=
|
||||
bp->stats_counter) {
|
||||
if (le16_to_cpu(xclient->stats_counter) != cur_stats_counter) {
|
||||
DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm"
|
||||
" 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;
|
||||
}
|
||||
if ((u16)(le16_to_cpu(tclient->stats_counter) + 1) !=
|
||||
bp->stats_counter) {
|
||||
if (le16_to_cpu(tclient->stats_counter) != cur_stats_counter) {
|
||||
DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm"
|
||||
" 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;
|
||||
}
|
||||
if ((u16)(le16_to_cpu(uclient->stats_counter) + 1) !=
|
||||
bp->stats_counter) {
|
||||
if (le16_to_cpu(uclient->stats_counter) != cur_stats_counter) {
|
||||
DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm"
|
||||
" 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;
|
||||
}
|
||||
|
||||
|
@ -4849,16 +4858,18 @@ static const struct {
|
|||
|
||||
static 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))
|
||||
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;
|
||||
spin_unlock_bh(&bp->stats_lock);
|
||||
|
||||
/* Make sure the state has been "changed" */
|
||||
smp_wmb();
|
||||
bnx2x_stats_stm[state][event].action(bp);
|
||||
|
||||
if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
|
||||
DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
|
||||
|
@ -9908,6 +9919,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
|
|||
|
||||
mutex_init(&bp->port.phy_mutex);
|
||||
mutex_init(&bp->fw_mb_mutex);
|
||||
spin_lock_init(&bp->stats_lock);
|
||||
#ifdef BCM_CNIC
|
||||
mutex_init(&bp->cnic_mutex);
|
||||
#endif
|
||||
|
|
|
@ -822,7 +822,7 @@ static int rlb_initialize(struct bonding *bond)
|
|||
|
||||
/*initialize packet type*/
|
||||
pk_type->type = cpu_to_be16(ETH_P_ARP);
|
||||
pk_type->dev = NULL;
|
||||
pk_type->dev = bond->dev;
|
||||
pk_type->func = rlb_arp_recv;
|
||||
|
||||
/* register to receive ARPs */
|
||||
|
|
|
@ -1722,6 +1722,15 @@ static int __devinit igb_probe(struct pci_dev *pdev,
|
|||
u16 eeprom_apme_mask = IGB_EEPROM_APME;
|
||||
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);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -6492,6 +6492,15 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
|
|||
#endif
|
||||
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);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -499,7 +499,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
|
|||
.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);
|
||||
|
||||
|
@ -508,6 +508,12 @@ static void macvlan_setup(struct net_device *dev)
|
|||
dev->destructor = free_netdev;
|
||||
dev->header_ops = &macvlan_hard_header_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;
|
||||
}
|
||||
|
||||
|
@ -705,7 +711,6 @@ int macvlan_link_register(struct rtnl_link_ops *ops)
|
|||
/* common fields */
|
||||
ops->priv_size = sizeof(struct macvlan_dev);
|
||||
ops->get_tx_queues = macvlan_get_tx_queues;
|
||||
ops->setup = macvlan_setup;
|
||||
ops->validate = macvlan_validate;
|
||||
ops->maxtype = IFLA_MACVLAN_MAX;
|
||||
ops->policy = macvlan_policy;
|
||||
|
@ -719,6 +724,7 @@ EXPORT_SYMBOL_GPL(macvlan_link_register);
|
|||
|
||||
static struct rtnl_link_ops macvlan_link_ops = {
|
||||
.kind = "macvlan",
|
||||
.setup = macvlan_setup,
|
||||
.newlink = macvlan_newlink,
|
||||
.dellink = macvlan_dellink,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
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);
|
||||
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,
|
|||
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 = {
|
||||
.kind = "macvtap",
|
||||
.setup = macvtap_setup,
|
||||
.newlink = macvtap_newlink,
|
||||
.dellink = macvtap_dellink,
|
||||
};
|
||||
|
|
|
@ -65,7 +65,7 @@ static int debug_level = ERR_DBG;
|
|||
|
||||
/* DEBUG message print. */
|
||||
#define DBG_PRINT(dbg_level, fmt, args...) do { \
|
||||
if (dbg_level >= debug_level) \
|
||||
if (dbg_level <= debug_level) \
|
||||
pr_info(fmt, ##args); \
|
||||
} while (0)
|
||||
|
||||
|
|
|
@ -736,8 +736,18 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
|
|||
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
|
||||
else if (sinfo->gso_type & SKB_GSO_UDP)
|
||||
gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
|
||||
else
|
||||
BUG();
|
||||
else {
|
||||
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)
|
||||
gso.gso_type |= VIRTIO_NET_HDR_GSO_ECN;
|
||||
} else
|
||||
|
|
|
@ -152,6 +152,7 @@ enum {
|
|||
/* Device IDs */
|
||||
USB_DEVICE_ID_I6050 = 0x0186,
|
||||
USB_DEVICE_ID_I6050_2 = 0x0188,
|
||||
USB_DEVICE_ID_I6250 = 0x0187,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -491,6 +491,7 @@ int i2400mu_probe(struct usb_interface *iface,
|
|||
switch (id->idProduct) {
|
||||
case USB_DEVICE_ID_I6050:
|
||||
case USB_DEVICE_ID_I6050_2:
|
||||
case USB_DEVICE_ID_I6250:
|
||||
i2400mu->i6050 = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -739,6 +740,7 @@ static
|
|||
struct usb_device_id i2400mu_id_table[] = {
|
||||
{ USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) },
|
||||
{ USB_DEVICE(0x8086, USB_DEVICE_ID_I6050_2) },
|
||||
{ USB_DEVICE(0x8086, USB_DEVICE_ID_I6250) },
|
||||
{ USB_DEVICE(0x8086, 0x0181) },
|
||||
{ USB_DEVICE(0x8086, 0x1403) },
|
||||
{ USB_DEVICE(0x8086, 0x1405) },
|
||||
|
|
|
@ -844,9 +844,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
|||
int dma_type;
|
||||
|
||||
if (edma)
|
||||
dma_type = DMA_FROM_DEVICE;
|
||||
else
|
||||
dma_type = DMA_BIDIRECTIONAL;
|
||||
else
|
||||
dma_type = DMA_FROM_DEVICE;
|
||||
|
||||
qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
|
||||
spin_lock_bh(&sc->rx.rxbuflock);
|
||||
|
|
|
@ -67,6 +67,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,
|
||||
struct nlattr *tb[], struct nlattr *data[],
|
||||
int (*receive)(struct sk_buff *skb),
|
||||
|
|
|
@ -9,6 +9,7 @@ struct tcf_mirred {
|
|||
int tcfm_ifindex;
|
||||
int tcfm_ok_push;
|
||||
struct net_device *tcfm_dev;
|
||||
struct list_head tcfm_list;
|
||||
};
|
||||
#define to_mirred(pc) \
|
||||
container_of(pc, struct tcf_mirred, common)
|
||||
|
|
|
@ -1488,6 +1488,7 @@ static inline void net_timestamp_check(struct sk_buff *skb)
|
|||
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
skb_orphan(skb);
|
||||
nf_reset(skb);
|
||||
|
||||
if (!(dev->flags & IFF_UP) ||
|
||||
(skb->len > (dev->mtu + dev->hard_header_len))) {
|
||||
|
|
|
@ -843,7 +843,9 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
|
|||
skb->network_header += off;
|
||||
if (skb_mac_header_was_set(skb))
|
||||
skb->mac_header += off;
|
||||
skb->csum_start += nhead;
|
||||
/* Only adjust this if it actually is csum_start rather than csum */
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL)
|
||||
skb->csum_start += nhead;
|
||||
skb->cloned = 0;
|
||||
skb->hdr_len = 0;
|
||||
skb->nohdr = 0;
|
||||
|
@ -930,7 +932,8 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
|
|||
copy_skb_header(n, skb);
|
||||
|
||||
off = newheadroom - oldheadroom;
|
||||
n->csum_start += off;
|
||||
if (n->ip_summed == CHECKSUM_PARTIAL)
|
||||
n->csum_start += off;
|
||||
#ifdef NET_SKBUFF_DATA_USES_OFFSET
|
||||
n->transport_header += off;
|
||||
n->network_header += off;
|
||||
|
|
|
@ -1760,7 +1760,10 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
|
|||
|
||||
idev = ipv6_find_idev(dev);
|
||||
if (!idev)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOBUFS);
|
||||
|
||||
if (idev->cnf.disable_ipv6)
|
||||
return ERR_PTR(-EACCES);
|
||||
|
||||
/* Add default multicast route */
|
||||
addrconf_add_mroute(dev);
|
||||
|
@ -2129,8 +2132,9 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
|
|||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
if ((idev = addrconf_add_dev(dev)) == NULL)
|
||||
return -ENOBUFS;
|
||||
idev = addrconf_add_dev(dev);
|
||||
if (IS_ERR(idev))
|
||||
return PTR_ERR(idev);
|
||||
|
||||
scope = ipv6_addr_scope(pfx);
|
||||
|
||||
|
@ -2377,7 +2381,7 @@ static void addrconf_dev_config(struct net_device *dev)
|
|||
}
|
||||
|
||||
idev = addrconf_add_dev(dev);
|
||||
if (idev == NULL)
|
||||
if (IS_ERR(idev))
|
||||
return;
|
||||
|
||||
memset(&addr, 0, sizeof(struct in6_addr));
|
||||
|
@ -2468,7 +2472,7 @@ static void addrconf_ip6_tnl_config(struct net_device *dev)
|
|||
ASSERT_RTNL();
|
||||
|
||||
idev = addrconf_add_dev(dev);
|
||||
if (!idev) {
|
||||
if (IS_ERR(idev)) {
|
||||
printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -632,7 +632,7 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
|
|||
skb->dev = sta->sdata->dev;
|
||||
skb->protocol = eth_type_trans(skb, sta->sdata->dev);
|
||||
memset(skb->cb, 0, sizeof(skb->cb));
|
||||
netif_rx(skb);
|
||||
netif_rx_ni(skb);
|
||||
}
|
||||
|
||||
static void sta_apply_parameters(struct ieee80211_local *local,
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1];
|
||||
static u32 mirred_idx_gen;
|
||||
static DEFINE_RWLOCK(mirred_lock);
|
||||
static LIST_HEAD(mirred_list);
|
||||
|
||||
static struct tcf_hashinfo mirred_hash_info = {
|
||||
.htab = tcf_mirred_ht,
|
||||
|
@ -47,7 +48,9 @@ static inline int tcf_mirred_release(struct tcf_mirred *m, int bind)
|
|||
m->tcf_bindcnt--;
|
||||
m->tcf_refcnt--;
|
||||
if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) {
|
||||
dev_put(m->tcfm_dev);
|
||||
list_del(&m->tcfm_list);
|
||||
if (m->tcfm_dev)
|
||||
dev_put(m->tcfm_dev);
|
||||
tcf_hash_destroy(&m->common, &mirred_hash_info);
|
||||
return 1;
|
||||
}
|
||||
|
@ -134,8 +137,10 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est,
|
|||
m->tcfm_ok_push = ok_push;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -162,9 +167,14 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
|
|||
m->tcf_tm.lastuse = jiffies;
|
||||
|
||||
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 (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);
|
||||
goto out;
|
||||
}
|
||||
|
@ -232,6 +242,28 @@ nla_put_failure:
|
|||
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 = {
|
||||
.kind = "mirred",
|
||||
.hinfo = &mirred_hash_info,
|
||||
|
@ -252,12 +284,17 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
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");
|
||||
return tcf_register_action(&act_mirred_ops);
|
||||
}
|
||||
|
||||
static void __exit mirred_cleanup_module(void)
|
||||
{
|
||||
unregister_netdevice_notifier(&mirred_device_notifier);
|
||||
tcf_unregister_action(&act_mirred_ops);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче