#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/netpoll.h>
+#include <linux/rcupdate.h>
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> /* Note : will define WIRELESS_EXT */
#include <net/iw_handler.h>
#endif /* CONFIG_NET_RADIO */
#include <asm/current.h>
+#include <linux/vs_network.h>
/* This define, if set, will randomly drop a packet when congestion
* is more than moderate. It helps fairness in the multi-interface
*/
DEFINE_PER_CPU(struct softnet_data, softnet_data) = { 0, };
-#ifdef CONFIG_NET_FASTROUTE
-int netdev_fastroute;
-int netdev_fastroute_obstacles;
-#endif
-
#ifdef CONFIG_SYSFS
extern int netdev_sysfs_init(void);
extern int netdev_register_sysfs(struct net_device *);
int hash;
spin_lock_bh(&ptype_lock);
-#ifdef CONFIG_NET_FASTROUTE
- if (pt->af_packet_priv) {
- netdev_fastroute_obstacles++;
- dev_clear_fastroute(pt->dev);
- }
-#endif
if (pt->type == htons(ETH_P_ALL)) {
netdev_nit++;
list_add_rcu(&pt->list, &ptype_all);
list_for_each_entry(pt1, head, list) {
if (pt == pt1) {
-#ifdef CONFIG_NET_FASTROUTE
- if (pt->af_packet_priv)
- netdev_fastroute_obstacles--;
-#endif
list_del_rcu(&pt->list);
goto out;
}
return ret;
}
-#ifdef CONFIG_NET_FASTROUTE
-
-static void dev_do_clear_fastroute(struct net_device *dev)
-{
- if (dev->accept_fastpath) {
- int i;
-
- for (i = 0; i <= NETDEV_FASTROUTE_HMASK; i++) {
- struct dst_entry *dst;
-
- write_lock_irq(&dev->fastpath_lock);
- dst = dev->fastpath[i];
- dev->fastpath[i] = NULL;
- write_unlock_irq(&dev->fastpath_lock);
-
- dst_release(dst);
- }
- }
-}
-
-void dev_clear_fastroute(struct net_device *dev)
-{
- if (dev) {
- dev_do_clear_fastroute(dev);
- } else {
- read_lock(&dev_base_lock);
- for (dev = dev_base; dev; dev = dev->next)
- dev_do_clear_fastroute(dev);
- read_unlock(&dev_base_lock);
- }
-}
-#endif
-
/**
* dev_close - shutdown an interface.
* @dev: device to shutdown
*/
dev->flags &= ~IFF_UP;
-#ifdef CONFIG_NET_FASTROUTE
- dev_clear_fastroute(dev);
-#endif
/*
* Tell people we are down
return 0;
}
+#define HARD_TX_LOCK_BH(dev, cpu) { \
+ if ((dev->features & NETIF_F_LLTX) == 0) { \
+ spin_lock_bh(&dev->xmit_lock); \
+ dev->xmit_lock_owner = cpu; \
+ } \
+}
+
+#define HARD_TX_UNLOCK_BH(dev) { \
+ if ((dev->features & NETIF_F_LLTX) == 0) { \
+ dev->xmit_lock_owner = -1; \
+ spin_unlock_bh(&dev->xmit_lock); \
+ } \
+}
+
+static inline void qdisc_run(struct net_device *dev)
+{
+ while (!netif_queue_stopped(dev) &&
+ qdisc_restart(dev)<0)
+ /* NOTHING */;
+}
+
/**
* dev_queue_xmit - transmit a buffer
* @skb: buffer to transmit
if (skb_checksum_help(&skb, 0))
goto out_kfree_skb;
- /* Grab device queue */
- spin_lock_bh(&dev->queue_lock);
+ rcu_read_lock();
+ /* Updates of qdisc are serialized by queue_lock.
+ * The struct Qdisc which is pointed to by qdisc is now a
+ * rcu structure - it may be accessed without acquiring
+ * a lock (but the structure may be stale.) The freeing of the
+ * qdisc will be deferred until it's known that there are no
+ * more references to it.
+ *
+ * If the qdisc has an enqueue function, we still need to
+ * hold the queue_lock before calling it, since queue_lock
+ * also serializes access to the device queue.
+ */
+
q = dev->qdisc;
+ smp_read_barrier_depends();
+#ifdef CONFIG_NET_CLS_ACT
+ skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS);
+#endif
if (q->enqueue) {
+ /* Grab device queue */
+ spin_lock_bh(&dev->queue_lock);
+
rc = q->enqueue(skb, q);
qdisc_run(dev);
spin_unlock_bh(&dev->queue_lock);
+ rcu_read_unlock();
rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
goto out;
}
+ rcu_read_unlock();
/* The device has no queue. Common case for software devices:
loopback, all the sorts of tunnels...
Either shot noqueue qdisc, it is even simpler 8)
*/
if (dev->flags & IFF_UP) {
- int cpu = smp_processor_id();
+ int cpu = get_cpu();
if (dev->xmit_lock_owner != cpu) {
- /*
- * The spin_lock effectivly does a preempt lock, but
- * we are about to drop that...
- */
- preempt_disable();
- spin_unlock(&dev->queue_lock);
- spin_lock(&dev->xmit_lock);
- dev->xmit_lock_owner = cpu;
- preempt_enable();
+
+ HARD_TX_LOCK_BH(dev, cpu);
+ put_cpu();
if (!netif_queue_stopped(dev)) {
if (netdev_nit)
rc = 0;
if (!dev->hard_start_xmit(skb, dev)) {
- dev->xmit_lock_owner = -1;
- spin_unlock_bh(&dev->xmit_lock);
+ HARD_TX_UNLOCK_BH(dev);
goto out;
}
}
- dev->xmit_lock_owner = -1;
- spin_unlock_bh(&dev->xmit_lock);
+ HARD_TX_UNLOCK_BH(dev);
if (net_ratelimit())
printk(KERN_CRIT "Virtual device %s asks to "
"queue packet!\n", dev->name);
goto out_enetdown;
} else {
+ put_cpu();
/* Recursion is detected! It is possible,
* unfortunately */
if (net_ratelimit())
"%s, fix it urgently!\n", dev->name);
}
}
- spin_unlock_bh(&dev->queue_lock);
out_enetdown:
rc = -ENETDOWN;
out_kfree_skb:
return 0;
}
+
+#ifdef CONFIG_NET_CLS_ACT
+/* TODO: Maybe we should just force sch_ingress to be compiled in
+ * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
+ * a compare and 2 stores extra right now if we dont have it on
+ * but have CONFIG_NET_CLS_ACT
+ * NOTE: This doesnt stop any functionality; if you dont have
+ * the ingress scheduler, you just cant add policies on ingress.
+ *
+ */
+int ing_filter(struct sk_buff *skb)
+{
+ struct Qdisc *q;
+ struct net_device *dev = skb->dev;
+ int result = TC_ACT_OK;
+
+ if (dev->qdisc_ingress) {
+ __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd);
+ if (MAX_RED_LOOP < ttl++) {
+ printk("Redir loop detected Dropping packet (%s->%s)\n",
+ skb->input_dev?skb->input_dev->name:"??",skb->dev->name);
+ return TC_ACT_SHOT;
+ }
+
+ skb->tc_verd = SET_TC_RTTL(skb->tc_verd,ttl);
+
+ skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS);
+ if (NULL == skb->input_dev) {
+ skb->input_dev = skb->dev;
+ printk("ing_filter: fixed %s out %s\n",skb->input_dev->name,skb->dev->name);
+ }
+ spin_lock(&dev->ingress_lock);
+ if ((q = dev->qdisc_ingress) != NULL)
+ result = q->enqueue(skb, q);
+ spin_unlock(&dev->ingress_lock);
+
+ }
+
+ return result;
+}
+#endif
+
int netif_receive_skb(struct sk_buff *skb)
{
struct packet_type *ptype, *pt_prev;
__get_cpu_var(netdev_rx_stat).total++;
-#ifdef CONFIG_NET_FASTROUTE
- if (skb->pkt_type == PACKET_FASTROUTE) {
- __get_cpu_var(netdev_rx_stat).fastroute_deferred_out++;
- return dev_queue_xmit(skb);
- }
-#endif
-
skb->h.raw = skb->nh.raw = skb->data;
skb->mac_len = skb->nh.raw - skb->mac.raw;
pt_prev = NULL;
+#ifdef CONFIG_NET_CLS_ACT
+ if (skb->tc_verd & TC_NCLS) {
+ skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
+ rcu_read_lock();
+ goto ncls;
+ }
+ #endif
+
rcu_read_lock();
list_for_each_entry_rcu(ptype, &ptype_all, list) {
if (!ptype->dev || ptype->dev == skb->dev) {
}
}
+#ifdef CONFIG_NET_CLS_ACT
+ if (pt_prev) {
+ atomic_inc(&skb->users);
+ ret = pt_prev->func(skb, skb->dev, pt_prev);
+ pt_prev = NULL; /* noone else should process this after*/
+ } else {
+ skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
+ }
+
+ ret = ing_filter(skb);
+
+ if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) {
+ kfree_skb(skb);
+ goto out;
+ }
+
+ skb->tc_verd = 0;
+ncls:
+#endif
+
handle_diverter(skb);
if (__handle_bridge(skb, &pt_prev, &ret))
if ((dev->promiscuity += inc) == 0)
dev->flags &= ~IFF_PROMISC;
if (dev->flags ^ old_flags) {
-#ifdef CONFIG_NET_FASTROUTE
- if (dev->flags & IFF_PROMISC) {
- netdev_fastroute_obstacles++;
- dev_clear_fastroute(dev);
- } else
- netdev_fastroute_obstacles--;
-#endif
dev_mc_upload(dev);
printk(KERN_INFO "device %s %s promiscuous mode\n",
dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
spin_lock_init(&dev->queue_lock);
spin_lock_init(&dev->xmit_lock);
dev->xmit_lock_owner = -1;
-#ifdef CONFIG_NET_FASTROUTE
- dev->fastpath_lock = RW_LOCK_UNLOCKED;
+#ifdef CONFIG_NET_CLS_ACT
+ spin_lock_init(&dev->ingress_lock);
#endif
ret = alloc_divert_blk(dev);
while (atomic_read(&dev->refcnt) != 0) {
if (time_after(jiffies, rebroadcast_time + 1 * HZ)) {
rtnl_shlock();
- rtnl_exlock();
/* Rebroadcast unregister notification */
notifier_call_chain(&netdev_chain,
linkwatch_run_queue();
}
- rtnl_exunlock();
rtnl_shunlock();
rebroadcast_time = jiffies;
synchronize_net();
-#ifdef CONFIG_NET_FASTROUTE
- dev_clear_fastroute(dev);
-#endif
-
/* Shutdown queueing discipline. */
dev_shutdown(dev);
/* Finish processing unregister after unlock */
net_set_todo(dev);
+ synchronize_net();
+
dev_put(dev);
return 0;
}
EXPORT_SYMBOL(dev_remove_pack);
EXPORT_SYMBOL(dev_set_allmulti);
EXPORT_SYMBOL(dev_set_promiscuity);
+EXPORT_SYMBOL(dev_change_flags);
+EXPORT_SYMBOL(dev_set_mtu);
EXPORT_SYMBOL(free_netdev);
EXPORT_SYMBOL(netdev_boot_setup_check);
EXPORT_SYMBOL(netdev_set_master);
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
EXPORT_SYMBOL(br_handle_frame_hook);
#endif
-/* for 801q VLAN support */
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-EXPORT_SYMBOL(dev_change_flags);
-#endif
+
#ifdef CONFIG_KMOD
EXPORT_SYMBOL(dev_load);
#endif
EXPORT_SYMBOL(netdev_register_fc);
EXPORT_SYMBOL(netdev_unregister_fc);
#endif
-#ifdef CONFIG_NET_FASTROUTE
-EXPORT_SYMBOL(netdev_fastroute);
-EXPORT_SYMBOL(netdev_fastroute_obstacles);
+
+#ifdef CONFIG_NET_CLS_ACT
+EXPORT_SYMBOL(ing_filter);
#endif
+
EXPORT_PER_CPU_SYMBOL(softnet_data);