mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
bitkeeper revision 1.89 (3e58aeffGldVBDUrCPQ3AX0iBm4OYw)
Many files: Ripped out lots from code from Xen's network transmit path, pending a new scheduler. devinit.c: Rename: xen-2.4.16/net/sch_generic.c -> xen-2.4.16/net/devinit.c sch_generic.c: Rename: BitKeeper/deleted/.del-sch_generic.c~c8d7d9959cc80952 -> xen-2.4.16/net/sch_generic.c .del-sch_generic.c~c8d7d9959cc80952: Delete: xen-2.4.16/net/sch_generic.c .del-utils.c~e7553afc72d1b648: Delete: xen-2.4.16/net/utils.c .del-pkt_sched.h~e13e384d6b974c61: Delete: xen-2.4.16/include/xeno/pkt_sched.h
This commit is contained in:
1 parent
ef170179d0
commit
0dc9ba5c3a
18 files changed
+1293
-2809
No files matched your search
@@ -260,7 +260,6 @@
|
||||
3ddb79c0MOVXq8qZDQRGb6z64_xAwg xen-2.4.16/include/xeno/pci_ids.h
|
||||
3e54c38dlSCVdyVM4PKcrSfzLLxWUQ xen-2.4.16/include/xeno/perfc.h
|
||||
3e54c38de9SUSYSAwxDf_DwkpAnQFA xen-2.4.16/include/xeno/perfc_defn.h
|
||||
3ddb79c2byJwwNNkiES__A9H4Cvc4g xen-2.4.16/include/xeno/pkt_sched.h
|
||||
3ddb79c04nQVR3EYM5L4zxDV_MCo1g xen-2.4.16/include/xeno/prefetch.h
|
||||
3e4540ccU1sgCx8seIMGlahmMfv7yQ xen-2.4.16/include/xeno/reboot.h
|
||||
3ddb79c0LzqqS0LhAQ50ekgj4oGl7Q xen-2.4.16/include/xeno/sched.h
|
||||
@@ -279,10 +278,9 @@
|
||||
3ddb79c4YQCQ6r0xNLLu0jfbM7pVmA xen-2.4.16/net/Makefile
|
||||
3ddb79c4AkfDkTCw0comx4L8wsUOMg xen-2.4.16/net/dev.c
|
||||
3ddb79c4x1L_soh8b-r_1jQW_37Icw xen-2.4.16/net/dev_mcast.c
|
||||
3ddb79c4KZhNxUuYJ7lul8cc-wRkyg xen-2.4.16/net/devinit.c
|
||||
3ddb79c4NSDwiQ-AmrYdxcRAwLPzwQ xen-2.4.16/net/eth.c
|
||||
3ddb79c4KZhNxUuYJ7lul8cc-wRkyg xen-2.4.16/net/sch_generic.c
|
||||
3ddb79c4TZj1wXPKQt36O72SddtBNQ xen-2.4.16/net/skbuff.c
|
||||
3ddb79c4ARyIHqv3Y6YFckIUbyA8Tw xen-2.4.16/net/utils.c
|
||||
3ddb79c4x8dvwPtzclghWAKFWpEBFA xen-2.4.16/tools/Makefile
|
||||
3ddb79c4yGZ7_22QAFFwPzqP4NSHwA xen-2.4.16/tools/elf-reloc.c
|
||||
3ddb79bbYMXGmQTsr5BeGS_RuZ5f_w xenolinux-2.4.16-sparse/Makefile
|
||||
|
||||
+16
-11
@@ -54,29 +54,27 @@ net_vif_t *create_net_vif(int domain)
|
||||
net_shadow_ring_t *shadow_ring;
|
||||
struct task_struct *dom_task;
|
||||
|
||||
if ( !(dom_task = find_domain_by_id(domain)) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if ( !(dom_task = find_domain_by_id(domain)) )
|
||||
return NULL;
|
||||
|
||||
if ( (new_vif = kmem_cache_alloc(net_vif_cache, GFP_KERNEL)) == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
new_ring = dom_task->net_ring_base + dom_task->num_net_vifs;
|
||||
memset(new_ring, 0, sizeof(net_ring_t));
|
||||
|
||||
shadow_ring = kmalloc(sizeof(net_shadow_ring_t), GFP_KERNEL);
|
||||
if (shadow_ring == NULL) goto fail;
|
||||
if ( shadow_ring == NULL ) goto fail;
|
||||
|
||||
shadow_ring->rx_ring = kmalloc(RX_RING_SIZE
|
||||
* sizeof(rx_shadow_entry_t), GFP_KERNEL);
|
||||
if ( shadow_ring->rx_ring == NULL )
|
||||
shadow_ring->tx_ring = kmalloc(TX_RING_SIZE
|
||||
* sizeof(tx_shadow_entry_t), GFP_KERNEL);
|
||||
if ( (shadow_ring->rx_ring == NULL) || (shadow_ring->tx_ring == NULL) )
|
||||
goto fail;
|
||||
|
||||
shadow_ring->rx_prod = shadow_ring->rx_cons = shadow_ring->rx_idx = 0;
|
||||
shadow_ring->tx_cons = 0;
|
||||
shadow_ring->tx_prod = shadow_ring->tx_cons = shadow_ring->tx_idx = 0;
|
||||
|
||||
/* Fill in the new vif struct. */
|
||||
|
||||
@@ -98,7 +96,13 @@ net_vif_t *create_net_vif(int domain)
|
||||
return new_vif;
|
||||
|
||||
fail:
|
||||
printk("VIF allocation failed!\n");
|
||||
kmem_cache_free(net_vif_cache, new_vif);
|
||||
if ( shadow_ring != NULL )
|
||||
{
|
||||
if ( shadow_ring->rx_ring ) kfree(shadow_ring->rx_ring);
|
||||
if ( shadow_ring->tx_ring ) kfree(shadow_ring->tx_ring);
|
||||
kfree(shadow_ring);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -125,6 +129,7 @@ void destroy_net_vif(struct task_struct *p)
|
||||
sys_vif_list[p->net_vif_list[i]->id] = NULL; // system vif list not gc'ed
|
||||
write_unlock(&sys_vif_lock);
|
||||
|
||||
kfree(p->net_vif_list[i]->shadow_ring->tx_ring);
|
||||
kfree(p->net_vif_list[i]->shadow_ring->rx_ring);
|
||||
kfree(p->net_vif_list[i]->shadow_ring);
|
||||
kmem_cache_free(net_vif_cache, p->net_vif_list[i]);
|
||||
|
||||
@@ -423,8 +423,7 @@ void ether_setup(struct net_device *dev)
|
||||
dev->hard_header_len = ETH_HLEN;
|
||||
dev->mtu = 1500; /* eth_mtu */
|
||||
dev->addr_len = ETH_ALEN;
|
||||
dev->tx_queue_len = 100; /* Ethernet wants good queues */
|
||||
|
||||
|
||||
memset(dev->broadcast,0xFF, ETH_ALEN);
|
||||
|
||||
/* New-style flags. */
|
||||
@@ -449,7 +448,6 @@ void fddi_setup(struct net_device *dev)
|
||||
dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */
|
||||
dev->mtu = FDDI_K_SNAP_DLEN; /* Assume max payload of 802.2 SNAP frame */
|
||||
dev->addr_len = FDDI_K_ALEN;
|
||||
dev->tx_queue_len = 100; /* Long queues on FDDI */
|
||||
|
||||
memset(dev->broadcast, 0xFF, FDDI_K_ALEN);
|
||||
|
||||
@@ -482,9 +480,8 @@ void hippi_setup(struct net_device *dev)
|
||||
dev->hard_header_len = HIPPI_HLEN;
|
||||
dev->mtu = 65280;
|
||||
dev->addr_len = HIPPI_ALEN;
|
||||
dev->tx_queue_len = 25 /* 5 */;
|
||||
memset(dev->broadcast, 0xFF, HIPPI_ALEN);
|
||||
|
||||
memset(dev->broadcast, 0xFF, HIPPI_ALEN);
|
||||
|
||||
/*
|
||||
* HIPPI doesn't support broadcast+multicast and we only use
|
||||
@@ -523,7 +520,6 @@ void ltalk_setup(struct net_device *dev)
|
||||
dev->hard_header_len = LTALK_HLEN;
|
||||
dev->mtu = LTALK_MTU;
|
||||
dev->addr_len = LTALK_ALEN;
|
||||
dev->tx_queue_len = 10;
|
||||
|
||||
dev->broadcast[0] = 0xFF;
|
||||
|
||||
@@ -594,7 +590,6 @@ void tr_setup(struct net_device *dev)
|
||||
dev->hard_header_len = TR_HLEN;
|
||||
dev->mtu = 2000;
|
||||
dev->addr_len = TR_ALEN;
|
||||
dev->tx_queue_len = 100; /* Long queues on tr */
|
||||
|
||||
memset(dev->broadcast,0xFF, TR_ALEN);
|
||||
|
||||
@@ -671,7 +666,6 @@ void fc_setup(struct net_device *dev)
|
||||
dev->hard_header_len = FC_HLEN;
|
||||
dev->mtu = 2024;
|
||||
dev->addr_len = FC_ALEN;
|
||||
dev->tx_queue_len = 100; /* Long queues on fc */
|
||||
|
||||
memset(dev->broadcast,0xFF, FC_ALEN);
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#define TRY_SOFTIRQ
|
||||
#ifdef TRY_SOFTIRQ
|
||||
#define TRY_TASKLET
|
||||
#ifdef TRY_TASKLET
|
||||
/* XXX SMH: trying to use softirqs to trigger stuff done prev by threads */
|
||||
#include <xeno/interrupt.h> /* for softirq stuff */
|
||||
#include <xeno/interrupt.h> /* for tasklet/softirq stuff */
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
@@ -1408,8 +1408,9 @@ int aac_rx_init(struct aac_dev *dev, unsigned long devNumber);
|
||||
int aac_sa_init(struct aac_dev *dev, unsigned long devNumber);
|
||||
unsigned int aac_response_normal(struct aac_queue * q);
|
||||
unsigned int aac_command_normal(struct aac_queue * q);
|
||||
#ifdef TRY_SOFTIRQ
|
||||
int aac_command_thread(struct softirq_action *h);
|
||||
#ifdef TRY_TASKLET
|
||||
extern struct tasklet_struct aac_command_tasklet;
|
||||
int aac_command_thread(unsigned long data);
|
||||
#else
|
||||
int aac_command_thread(struct aac_dev * dev);
|
||||
#endif
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <xeno/pci.h>
|
||||
#include <xeno/spinlock.h>
|
||||
|
||||
#include <xeno/interrupt.h> // for softirq stuff
|
||||
#include <xeno/interrupt.h> /* tasklet stuff */
|
||||
|
||||
/* #include <xeno/slab.h> */
|
||||
/* #include <xeno/completion.h> */
|
||||
@@ -529,10 +529,15 @@ int fib_send(u16 command, struct fib * fibptr, unsigned long size, int priority
|
||||
#if 0
|
||||
down(&fibptr->event_wait);
|
||||
#endif
|
||||
#ifdef TRY_SOFTIRQ
|
||||
#ifdef TRY_TASKLET
|
||||
/*
|
||||
* XXX KAF: Well, this is pretty gross. We should probably
|
||||
* do_softirq() after scheduling the tasklet, as long as we
|
||||
* are _sure_ we hold no locks here...
|
||||
*/
|
||||
printk("about to softirq aac_command_thread...\n");
|
||||
while (!fibptr->done) {
|
||||
raise_softirq(SCSI_LOW_SOFTIRQ);
|
||||
tasklet_schedule(&aac_command_tasklet);
|
||||
mdelay(100);
|
||||
}
|
||||
printk("back from softirq cmd thread and fibptr->done!\n");
|
||||
@@ -837,13 +842,14 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
|
||||
* more FIBs.
|
||||
*/
|
||||
|
||||
#ifndef TRY_SOFTIRQ
|
||||
#ifndef TRY_TASKLET
|
||||
DECLARE_TASKLET_DISABLED(aac_command_tasklet, aac_command_thread, 0);
|
||||
int aac_command_thread(struct aac_dev * dev)
|
||||
{
|
||||
#else
|
||||
int aac_command_thread(struct softirq_action *h)
|
||||
int aac_command_thread(unsigned long data)
|
||||
{
|
||||
struct aac_dev *dev = (struct aac_dev *)h->data;
|
||||
struct aac_dev *dev = (struct aac_dev *)data;
|
||||
#endif
|
||||
struct hw_fib *fib, *newfib;
|
||||
struct fib fibptr; /* for error logging */
|
||||
|
||||
@@ -437,16 +437,16 @@ int aac_rx_init(struct aac_dev *dev, unsigned long num)
|
||||
|
||||
if (aac_init_adapter(dev) == NULL)
|
||||
return -1;
|
||||
#if 0
|
||||
#ifdef TRY_TASKLET
|
||||
aac_command_tasklet.data = (unsigned long)dev;
|
||||
tasklet_enable(&aac_command_tasklet);
|
||||
#else
|
||||
/*
|
||||
* Start any kernel threads needed
|
||||
*/
|
||||
dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread,
|
||||
dev, 0);
|
||||
#else
|
||||
/* XXX SMH: just put in a softirq handler instead... */
|
||||
open_softirq(SCSI_LOW_SOFTIRQ, aac_command_thread, dev);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Tell the adapter that all is configured, and it can start
|
||||
|
||||
@@ -135,12 +135,19 @@ struct vlan_skb_tx_cookie {
|
||||
u32 vlan_tag;
|
||||
};
|
||||
|
||||
#if 0
|
||||
#define VLAN_TX_COOKIE_MAGIC 0x564c414e /* "VLAN" in ascii. */
|
||||
#define VLAN_TX_SKB_CB(__skb) ((struct vlan_skb_tx_cookie *)&((__skb)->cb[0]))
|
||||
#define vlan_tx_tag_present(__skb) \
|
||||
(VLAN_TX_SKB_CB(__skb)->magic == VLAN_TX_COOKIE_MAGIC)
|
||||
#define vlan_tx_tag_get(__skb) (VLAN_TX_SKB_CB(__skb)->vlan_tag)
|
||||
#else /* XXX KAF: We don't support vlan tagging at the moment. */
|
||||
#define VLAN_TX_SKB_CB(__skb) NULL
|
||||
#define vlan_tx_tag_present(__skb) 0
|
||||
#define vlan_tx_tag_get(__skb) 0
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */
|
||||
static inline int __vlan_hwaccel_rx(struct sk_buff *skb,
|
||||
struct vlan_group *grp,
|
||||
@@ -203,6 +210,9 @@ static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb,
|
||||
{
|
||||
return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1);
|
||||
}
|
||||
#else
|
||||
#define vlan_hwaccel_rx(_skb, _grp, _tag) (netif_rx(_skb))
|
||||
#endif
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/* VLAN IOCTLs are found in sockios.h */
|
||||
|
||||
@@ -27,19 +27,8 @@ struct irqaction {
|
||||
enum {
|
||||
TIMER_BH = 0,
|
||||
TQUEUE_BH,
|
||||
DIGI_BH,
|
||||
SERIAL_BH,
|
||||
RISCOM8_BH,
|
||||
SPECIALIX_BH,
|
||||
AURORA_BH,
|
||||
ESP_BH,
|
||||
SCSI_BH,
|
||||
IMMEDIATE_BH,
|
||||
CYCLADES_BH,
|
||||
CM206_BH,
|
||||
JS_BH,
|
||||
MACSERIAL_BH,
|
||||
ISICOM_BH
|
||||
IMMEDIATE_BH
|
||||
};
|
||||
|
||||
#include <asm/hardirq.h>
|
||||
@@ -56,10 +45,7 @@ enum {
|
||||
enum
|
||||
{
|
||||
HI_SOFTIRQ=0,
|
||||
NET_TX_SOFTIRQ,
|
||||
NET_RX_SOFTIRQ,
|
||||
TASKLET_SOFTIRQ,
|
||||
SCSI_LOW_SOFTIRQ,
|
||||
TASKLET_SOFTIRQ
|
||||
};
|
||||
|
||||
/* softirq mask and active fields moved to irq_cpustat_t in
|
||||
|
||||
@@ -25,17 +25,18 @@
|
||||
#ifndef _LINUX_NETDEVICE_H
|
||||
#define _LINUX_NETDEVICE_H
|
||||
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/sched.h>
|
||||
#include <xeno/if.h>
|
||||
#include <xeno/if_ether.h>
|
||||
#include <xeno/if_packet.h>
|
||||
#include <xeno/sched.h>
|
||||
#include <xeno/interrupt.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/config.h>
|
||||
#include <xeno/config.h>
|
||||
|
||||
struct divert_blk;
|
||||
struct vlan_group;
|
||||
@@ -65,28 +66,6 @@ struct vlan_group;
|
||||
|
||||
#define MAX_ADDR_LEN 8 /* Largest hardware address length */
|
||||
|
||||
/*
|
||||
* Compute the worst case header length according to the protocols
|
||||
* used.
|
||||
*/
|
||||
|
||||
#if !defined(CONFIG_AX25) && !defined(CONFIG_AX25_MODULE) && !defined(CONFIG_TR)
|
||||
#define LL_MAX_HEADER 32
|
||||
#else
|
||||
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
|
||||
#define LL_MAX_HEADER 96
|
||||
#else
|
||||
#define LL_MAX_HEADER 48
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_NET_IPIP) && \
|
||||
!defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
|
||||
#define MAX_HEADER LL_MAX_HEADER
|
||||
#else
|
||||
#define MAX_HEADER (LL_MAX_HEADER + 48)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Network device statistics. Akin to the 2.0 ether stats but
|
||||
* with byte counters.
|
||||
@@ -141,8 +120,8 @@ enum {
|
||||
|
||||
extern const char *if_port_text[];
|
||||
|
||||
#include <linux/cache.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <xeno/cache.h>
|
||||
#include <xeno/skbuff.h>
|
||||
|
||||
struct neighbour;
|
||||
struct neigh_parms;
|
||||
@@ -311,18 +290,6 @@ struct net_device
|
||||
void *dn_ptr; /* DECnet specific data */
|
||||
void *ip6_ptr; /* IPv6 specific data */
|
||||
void *ec_ptr; /* Econet specific data */
|
||||
#if 0
|
||||
/* IAP: add fields but
|
||||
nothing else */
|
||||
struct list_head poll_list; /* Link to poll list */
|
||||
int quota;
|
||||
int weight;
|
||||
#endif
|
||||
struct Qdisc *qdisc;
|
||||
struct Qdisc *qdisc_sleeping;
|
||||
struct Qdisc *qdisc_list;
|
||||
struct Qdisc *qdisc_ingress;
|
||||
unsigned long tx_queue_len; /* Max frames per queue allowed */
|
||||
|
||||
/* hard_start_xmit synchronizer */
|
||||
spinlock_t xmit_lock;
|
||||
@@ -425,12 +392,10 @@ struct packet_type
|
||||
};
|
||||
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
//#include <linux/notifier.h>
|
||||
#include <xeno/interrupt.h>
|
||||
|
||||
extern struct net_device loopback_dev; /* The loopback */
|
||||
extern struct net_device *dev_base; /* All devices */
|
||||
extern rwlock_t dev_base_lock; /* Device list lock */
|
||||
extern struct net_device *dev_base; /* All devices */
|
||||
extern rwlock_t dev_base_lock; /* Device list lock */
|
||||
|
||||
extern int netdev_boot_setup_add(char *name, struct ifmap *map);
|
||||
extern int netdev_boot_setup_check(struct net_device *dev);
|
||||
@@ -447,8 +412,10 @@ extern int dev_close(struct net_device *dev);
|
||||
extern int dev_queue_xmit(struct sk_buff *skb);
|
||||
extern int register_netdevice(struct net_device *dev);
|
||||
extern int unregister_netdevice(struct net_device *dev);
|
||||
//extern int register_netdevice_notifier(struct notifier_block *nb);
|
||||
//extern int unregister_netdevice_notifier(struct notifier_block *nb);
|
||||
extern void dev_shutdown(struct net_device *dev);
|
||||
extern void dev_activate(struct net_device *dev);
|
||||
extern void dev_deactivate(struct net_device *dev);
|
||||
extern void dev_init_scheduler(struct net_device *dev);
|
||||
extern int dev_new_index(void);
|
||||
extern struct net_device *dev_get_by_index(int ifindex);
|
||||
extern struct net_device *__dev_get_by_index(int ifindex);
|
||||
@@ -461,17 +428,11 @@ static inline int unregister_gifconf(unsigned int family)
|
||||
return register_gifconf(family, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Incoming packets are placed on per-cpu queues so that
|
||||
* no locking is needed.
|
||||
*/
|
||||
extern struct tasklet_struct net_tx_tasklet;
|
||||
|
||||
|
||||
struct softnet_data
|
||||
{
|
||||
int throttle;
|
||||
int cng_level;
|
||||
int avg_blog;
|
||||
struct sk_buff_head input_pkt_queue;
|
||||
struct net_device *output_queue;
|
||||
struct sk_buff *completion_queue;
|
||||
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
|
||||
@@ -490,7 +451,7 @@ static inline void __netif_schedule(struct net_device *dev)
|
||||
local_irq_save(flags);
|
||||
dev->next_sched = softnet_data[cpu].output_queue;
|
||||
softnet_data[cpu].output_queue = dev;
|
||||
cpu_raise_softirq(cpu, NET_TX_SOFTIRQ);
|
||||
tasklet_schedule(&net_tx_tasklet);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
}
|
||||
@@ -533,13 +494,13 @@ static inline int netif_running(struct net_device *dev)
|
||||
static inline void dev_kfree_skb_irq(struct sk_buff *skb)
|
||||
{
|
||||
if (atomic_dec_and_test(&skb->users)) {
|
||||
int cpu =smp_processor_id();
|
||||
int cpu = smp_processor_id();
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
skb->next = softnet_data[cpu].completion_queue;
|
||||
softnet_data[cpu].completion_queue = skb;
|
||||
cpu_raise_softirq(cpu, NET_TX_SOFTIRQ);
|
||||
tasklet_schedule(&net_tx_tasklet);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
}
|
||||
@@ -577,11 +538,6 @@ static inline int netif_rx_ni(struct sk_buff *skb)
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void dev_init_buffers(struct net_device *dev)
|
||||
{
|
||||
/* WILL BE REMOVED IN 2.5.0 */
|
||||
}
|
||||
|
||||
extern int netdev_finish_unregister(struct net_device *dev);
|
||||
|
||||
static inline void dev_put(struct net_device *dev)
|
||||
|
||||
@@ -1,816 +0,0 @@
|
||||
#ifndef __NET_PKT_SCHED_H
|
||||
#define __NET_PKT_SCHED_H
|
||||
|
||||
#define PSCHED_GETTIMEOFDAY 1
|
||||
#define PSCHED_JIFFIES 2
|
||||
#define PSCHED_CPU 3
|
||||
|
||||
#define PSCHED_CLOCK_SOURCE PSCHED_JIFFIES
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
//#include <net/pkt_cls.h>
|
||||
|
||||
#ifdef CONFIG_X86_TSC
|
||||
#include <asm/msr.h>
|
||||
#endif
|
||||
|
||||
struct rtattr;
|
||||
struct Qdisc;
|
||||
|
||||
struct qdisc_walker
|
||||
{
|
||||
int stop;
|
||||
int skip;
|
||||
int count;
|
||||
int (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *);
|
||||
};
|
||||
|
||||
struct Qdisc_class_ops
|
||||
{
|
||||
/* Child qdisc manipulation */
|
||||
int (*graft)(struct Qdisc *, unsigned long cl, struct Qdisc *, struct Qdisc **);
|
||||
struct Qdisc * (*leaf)(struct Qdisc *, unsigned long cl);
|
||||
|
||||
/* Class manipulation routines */
|
||||
unsigned long (*get)(struct Qdisc *, u32 classid);
|
||||
void (*put)(struct Qdisc *, unsigned long);
|
||||
int (*change)(struct Qdisc *, u32, u32, struct rtattr **, unsigned long *);
|
||||
int (*delete)(struct Qdisc *, unsigned long);
|
||||
void (*walk)(struct Qdisc *, struct qdisc_walker * arg);
|
||||
|
||||
#if 0
|
||||
/* Filter manipulation */
|
||||
struct tcf_proto ** (*tcf_chain)(struct Qdisc *, unsigned long);
|
||||
unsigned long (*bind_tcf)(struct Qdisc *, unsigned long, u32 classid);
|
||||
void (*unbind_tcf)(struct Qdisc *, unsigned long);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Qdisc_ops
|
||||
{
|
||||
struct Qdisc_ops *next;
|
||||
struct Qdisc_class_ops *cl_ops;
|
||||
char id[IFNAMSIZ];
|
||||
int priv_size;
|
||||
|
||||
int (*enqueue)(struct sk_buff *, struct Qdisc *);
|
||||
struct sk_buff * (*dequeue)(struct Qdisc *);
|
||||
int (*requeue)(struct sk_buff *, struct Qdisc *);
|
||||
int (*drop)(struct Qdisc *);
|
||||
|
||||
int (*init)(struct Qdisc *, struct rtattr *arg);
|
||||
void (*reset)(struct Qdisc *);
|
||||
void (*destroy)(struct Qdisc *);
|
||||
int (*change)(struct Qdisc *, struct rtattr *arg);
|
||||
|
||||
int (*dump)(struct Qdisc *, struct sk_buff *);
|
||||
};
|
||||
|
||||
extern rwlock_t qdisc_tree_lock;
|
||||
|
||||
struct Qdisc
|
||||
{
|
||||
int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev);
|
||||
struct sk_buff * (*dequeue)(struct Qdisc *dev);
|
||||
unsigned flags;
|
||||
#define TCQ_F_BUILTIN 1
|
||||
#define TCQ_F_THROTTLED 2
|
||||
#define TCQ_F_INGRES 4
|
||||
struct Qdisc_ops *ops;
|
||||
struct Qdisc *next;
|
||||
u32 handle;
|
||||
atomic_t refcnt;
|
||||
struct sk_buff_head q;
|
||||
struct net_device *dev;
|
||||
|
||||
//struct tc_stats stats;
|
||||
int (*reshape_fail)(struct sk_buff *skb, struct Qdisc *q);
|
||||
|
||||
/* This field is deprecated, but it is still used by CBQ
|
||||
* and it will live until better solution will be invented.
|
||||
*/
|
||||
struct Qdisc *__parent;
|
||||
|
||||
char data[0];
|
||||
};
|
||||
|
||||
struct qdisc_rate_table
|
||||
{
|
||||
//struct tc_ratespec rate;
|
||||
u32 data[256];
|
||||
struct qdisc_rate_table *next;
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
static inline void sch_tree_lock(struct Qdisc *q)
|
||||
{
|
||||
write_lock(&qdisc_tree_lock);
|
||||
spin_lock_bh(&q->dev->queue_lock);
|
||||
}
|
||||
|
||||
static inline void sch_tree_unlock(struct Qdisc *q)
|
||||
{
|
||||
spin_unlock_bh(&q->dev->queue_lock);
|
||||
write_unlock(&qdisc_tree_lock);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline void tcf_tree_lock(struct tcf_proto *tp)
|
||||
{
|
||||
write_lock(&qdisc_tree_lock);
|
||||
spin_lock_bh(&tp->q->dev->queue_lock);
|
||||
}
|
||||
|
||||
static inline void tcf_tree_unlock(struct tcf_proto *tp)
|
||||
{
|
||||
spin_unlock_bh(&tp->q->dev->queue_lock);
|
||||
write_unlock(&qdisc_tree_lock);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
cls_set_class(struct tcf_proto *tp, unsigned long *clp, unsigned long cl)
|
||||
{
|
||||
unsigned long old_cl;
|
||||
|
||||
tcf_tree_lock(tp);
|
||||
old_cl = *clp;
|
||||
*clp = cl;
|
||||
tcf_tree_unlock(tp);
|
||||
return old_cl;
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
__cls_set_class(unsigned long *clp, unsigned long cl)
|
||||
{
|
||||
unsigned long old_cl;
|
||||
|
||||
old_cl = *clp;
|
||||
*clp = cl;
|
||||
return old_cl;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Timer resolution MUST BE < 10% of min_schedulable_packet_size/bandwidth
|
||||
|
||||
Normal IP packet size ~ 512byte, hence:
|
||||
|
||||
0.5Kbyte/1Mbyte/sec = 0.5msec, so that we need 50usec timer for
|
||||
10Mbit ethernet.
|
||||
|
||||
10msec resolution -> <50Kbit/sec.
|
||||
|
||||
The result: [34]86 is not good choice for QoS router :-(
|
||||
|
||||
The things are not so bad, because we may use artifical
|
||||
clock evaluated by integration of network data flow
|
||||
in the most critical places.
|
||||
|
||||
Note: we do not use fastgettimeofday.
|
||||
The reason is that, when it is not the same thing as
|
||||
gettimeofday, it returns invalid timestamp, which is
|
||||
not updated, when net_bh is active.
|
||||
|
||||
So, use PSCHED_CLOCK_SOURCE = PSCHED_CPU on alpha and pentiums
|
||||
with rtdsc. And PSCHED_JIFFIES on all other architectures, including [34]86
|
||||
and pentiums without rtdsc.
|
||||
You can use PSCHED_GETTIMEOFDAY on another architectures,
|
||||
which have fast and precise clock source, but it is too expensive.
|
||||
*/
|
||||
|
||||
/* General note about internal clock.
|
||||
|
||||
Any clock source returns time intervals, measured in units
|
||||
close to 1usec. With source PSCHED_GETTIMEOFDAY it is precisely
|
||||
microseconds, otherwise something close but different chosen to minimize
|
||||
arithmetic cost. Ratio usec/internal untis in form nominator/denominator
|
||||
may be read from /proc/net/psched.
|
||||
*/
|
||||
|
||||
|
||||
#if PSCHED_CLOCK_SOURCE == PSCHED_GETTIMEOFDAY
|
||||
|
||||
typedef struct timeval psched_time_t;
|
||||
typedef long psched_tdiff_t;
|
||||
|
||||
#define PSCHED_GET_TIME(stamp) do_gettimeofday(&(stamp))
|
||||
#define PSCHED_US2JIFFIE(usecs) (((usecs)+(1000000/HZ-1))/(1000000/HZ))
|
||||
|
||||
#define PSCHED_EXPORTLIST EXPORT_SYMBOL(psched_tod_diff);
|
||||
|
||||
#else /* PSCHED_CLOCK_SOURCE != PSCHED_GETTIMEOFDAY */
|
||||
|
||||
#define PSCHED_EXPORTLIST PSCHED_EXPORTLIST_1 PSCHED_EXPORTLIST_2
|
||||
|
||||
typedef u64 psched_time_t;
|
||||
typedef long psched_tdiff_t;
|
||||
|
||||
extern psched_time_t psched_time_base;
|
||||
|
||||
#if PSCHED_CLOCK_SOURCE == PSCHED_JIFFIES
|
||||
|
||||
#if HZ == 100
|
||||
#define PSCHED_JSCALE 13
|
||||
#elif HZ == 1024
|
||||
#define PSCHED_JSCALE 10
|
||||
#else
|
||||
#define PSCHED_JSCALE 0
|
||||
#endif
|
||||
|
||||
#define PSCHED_EXPORTLIST_2
|
||||
|
||||
#if ~0UL == 0xFFFFFFFF
|
||||
|
||||
#define PSCHED_WATCHER unsigned long
|
||||
|
||||
extern PSCHED_WATCHER psched_time_mark;
|
||||
|
||||
#define PSCHED_GET_TIME(stamp) ((stamp) = psched_time_base + (((unsigned long)(jiffies-psched_time_mark))<<PSCHED_JSCALE))
|
||||
|
||||
#define PSCHED_EXPORTLIST_1 EXPORT_SYMBOL(psched_time_base); \
|
||||
EXPORT_SYMBOL(psched_time_mark);
|
||||
|
||||
#else
|
||||
|
||||
#define PSCHED_GET_TIME(stamp) ((stamp) = (jiffies<<PSCHED_JSCALE))
|
||||
|
||||
#define PSCHED_EXPORTLIST_1
|
||||
|
||||
#endif
|
||||
|
||||
#define PSCHED_US2JIFFIE(delay) (((delay)+(1<<PSCHED_JSCALE)-1)>>PSCHED_JSCALE)
|
||||
|
||||
#elif PSCHED_CLOCK_SOURCE == PSCHED_CPU
|
||||
|
||||
extern psched_tdiff_t psched_clock_per_hz;
|
||||
extern int psched_clock_scale;
|
||||
|
||||
#define PSCHED_EXPORTLIST_2 EXPORT_SYMBOL(psched_clock_per_hz); \
|
||||
EXPORT_SYMBOL(psched_clock_scale);
|
||||
|
||||
#define PSCHED_US2JIFFIE(delay) (((delay)+psched_clock_per_hz-1)/psched_clock_per_hz)
|
||||
|
||||
#ifdef CONFIG_X86_TSC
|
||||
|
||||
#define PSCHED_GET_TIME(stamp) \
|
||||
({ u64 __cur; \
|
||||
rdtscll(__cur); \
|
||||
(stamp) = __cur>>psched_clock_scale; \
|
||||
})
|
||||
|
||||
#define PSCHED_EXPORTLIST_1
|
||||
|
||||
#elif defined (__alpha__)
|
||||
|
||||
#define PSCHED_WATCHER u32
|
||||
|
||||
extern PSCHED_WATCHER psched_time_mark;
|
||||
|
||||
#define PSCHED_GET_TIME(stamp) \
|
||||
({ u32 __res; \
|
||||
__asm__ __volatile__ ("rpcc %0" : "r="(__res)); \
|
||||
if (__res <= psched_time_mark) psched_time_base += 0x100000000UL; \
|
||||
psched_time_mark = __res; \
|
||||
(stamp) = (psched_time_base + __res)>>psched_clock_scale; \
|
||||
})
|
||||
|
||||
#define PSCHED_EXPORTLIST_1 EXPORT_SYMBOL(psched_time_base); \
|
||||
EXPORT_SYMBOL(psched_time_mark);
|
||||
|
||||
#else
|
||||
|
||||
#error PSCHED_CLOCK_SOURCE=PSCHED_CPU is not supported on this arch.
|
||||
|
||||
#endif /* ARCH */
|
||||
|
||||
#endif /* PSCHED_CLOCK_SOURCE == PSCHED_JIFFIES */
|
||||
|
||||
#endif /* PSCHED_CLOCK_SOURCE == PSCHED_GETTIMEOFDAY */
|
||||
|
||||
#if PSCHED_CLOCK_SOURCE == PSCHED_GETTIMEOFDAY
|
||||
#define PSCHED_TDIFF(tv1, tv2) \
|
||||
({ \
|
||||
int __delta_sec = (tv1).tv_sec - (tv2).tv_sec; \
|
||||
int __delta = (tv1).tv_usec - (tv2).tv_usec; \
|
||||
if (__delta_sec) { \
|
||||
switch (__delta_sec) { \
|
||||
default: \
|
||||
__delta = 0; \
|
||||
case 2: \
|
||||
__delta += 1000000; \
|
||||
case 1: \
|
||||
__delta += 1000000; \
|
||||
} \
|
||||
} \
|
||||
__delta; \
|
||||
})
|
||||
|
||||
extern int psched_tod_diff(int delta_sec, int bound);
|
||||
|
||||
#define PSCHED_TDIFF_SAFE(tv1, tv2, bound, guard) \
|
||||
({ \
|
||||
int __delta_sec = (tv1).tv_sec - (tv2).tv_sec; \
|
||||
int __delta = (tv1).tv_usec - (tv2).tv_usec; \
|
||||
switch (__delta_sec) { \
|
||||
default: \
|
||||
__delta = psched_tod_diff(__delta_sec, bound); guard; break; \
|
||||
case 2: \
|
||||
__delta += 1000000; \
|
||||
case 1: \
|
||||
__delta += 1000000; \
|
||||
case 0: ; \
|
||||
} \
|
||||
__delta; \
|
||||
})
|
||||
|
||||
#define PSCHED_TLESS(tv1, tv2) (((tv1).tv_usec < (tv2).tv_usec && \
|
||||
(tv1).tv_sec <= (tv2).tv_sec) || \
|
||||
(tv1).tv_sec < (tv2).tv_sec)
|
||||
|
||||
#define PSCHED_TADD2(tv, delta, tv_res) \
|
||||
({ \
|
||||
int __delta = (tv).tv_usec + (delta); \
|
||||
(tv_res).tv_sec = (tv).tv_sec; \
|
||||
if (__delta > 1000000) { (tv_res).tv_sec++; __delta -= 1000000; } \
|
||||
(tv_res).tv_usec = __delta; \
|
||||
})
|
||||
|
||||
#define PSCHED_TADD(tv, delta) \
|
||||
({ \
|
||||
(tv).tv_usec += (delta); \
|
||||
if ((tv).tv_usec > 1000000) { (tv).tv_sec++; \
|
||||
(tv).tv_usec -= 1000000; } \
|
||||
})
|
||||
|
||||
/* Set/check that time is in the "past perfect";
|
||||
it depends on concrete representation of system time
|
||||
*/
|
||||
|
||||
#define PSCHED_SET_PASTPERFECT(t) ((t).tv_sec = 0)
|
||||
#define PSCHED_IS_PASTPERFECT(t) ((t).tv_sec == 0)
|
||||
|
||||
#define PSCHED_AUDIT_TDIFF(t) ({ if ((t) > 2000000) (t) = 2000000; })
|
||||
|
||||
#else
|
||||
|
||||
#define PSCHED_TDIFF(tv1, tv2) (long)((tv1) - (tv2))
|
||||
#define PSCHED_TDIFF_SAFE(tv1, tv2, bound, guard) \
|
||||
({ \
|
||||
long __delta = (tv1) - (tv2); \
|
||||
if ( __delta > (bound)) { __delta = (bound); guard; } \
|
||||
__delta; \
|
||||
})
|
||||
|
||||
|
||||
#define PSCHED_TLESS(tv1, tv2) ((tv1) < (tv2))
|
||||
#define PSCHED_TADD2(tv, delta, tv_res) ((tv_res) = (tv) + (delta))
|
||||
#define PSCHED_TADD(tv, delta) ((tv) += (delta))
|
||||
#define PSCHED_SET_PASTPERFECT(t) ((t) = 0)
|
||||
#define PSCHED_IS_PASTPERFECT(t) ((t) == 0)
|
||||
#define PSCHED_AUDIT_TDIFF(t)
|
||||
|
||||
#endif
|
||||
|
||||
struct tcf_police
|
||||
{
|
||||
struct tcf_police *next;
|
||||
int refcnt;
|
||||
u32 index;
|
||||
|
||||
int action;
|
||||
int result;
|
||||
u32 ewma_rate;
|
||||
u32 burst;
|
||||
u32 mtu;
|
||||
|
||||
u32 toks;
|
||||
u32 ptoks;
|
||||
psched_time_t t_c;
|
||||
spinlock_t lock;
|
||||
struct qdisc_rate_table *R_tab;
|
||||
struct qdisc_rate_table *P_tab;
|
||||
|
||||
//struct tc_stats stats;
|
||||
};
|
||||
|
||||
//extern int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st);
|
||||
extern void tcf_police_destroy(struct tcf_police *p);
|
||||
extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est);
|
||||
extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p);
|
||||
extern int tcf_police(struct sk_buff *skb, struct tcf_police *p);
|
||||
|
||||
static inline void tcf_police_release(struct tcf_police *p)
|
||||
{
|
||||
if (p && --p->refcnt == 0)
|
||||
tcf_police_destroy(p);
|
||||
}
|
||||
|
||||
extern struct Qdisc noop_qdisc;
|
||||
extern struct Qdisc_ops noop_qdisc_ops;
|
||||
extern struct Qdisc_ops pfifo_qdisc_ops;
|
||||
extern struct Qdisc_ops bfifo_qdisc_ops;
|
||||
|
||||
int register_qdisc(struct Qdisc_ops *qops);
|
||||
int unregister_qdisc(struct Qdisc_ops *qops);
|
||||
struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle);
|
||||
struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle);
|
||||
void dev_init_scheduler(struct net_device *dev);
|
||||
void dev_shutdown(struct net_device *dev);
|
||||
void dev_activate(struct net_device *dev);
|
||||
void dev_deactivate(struct net_device *dev);
|
||||
void qdisc_reset(struct Qdisc *qdisc);
|
||||
void qdisc_destroy(struct Qdisc *qdisc);
|
||||
struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops);
|
||||
//int qdisc_new_estimator(struct tc_stats *stats, struct rtattr *opt);
|
||||
//void qdisc_kill_estimator(struct tc_stats *stats);
|
||||
//struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct rtattr *tab);
|
||||
void qdisc_put_rtab(struct qdisc_rate_table *tab);
|
||||
int teql_init(void);
|
||||
int tc_filter_init(void);
|
||||
int pktsched_init(void);
|
||||
|
||||
extern int qdisc_restart(struct net_device *dev);
|
||||
|
||||
static inline void qdisc_run(struct net_device *dev)
|
||||
{
|
||||
while (!netif_queue_stopped(dev) &&
|
||||
qdisc_restart(dev)<0)
|
||||
/* NOTHING */;
|
||||
}
|
||||
|
||||
/* Calculate maximal size of packet seen by hard_start_xmit
|
||||
routine of this device.
|
||||
*/
|
||||
static inline unsigned psched_mtu(struct net_device *dev)
|
||||
{
|
||||
unsigned mtu = dev->mtu;
|
||||
return dev->hard_header ? mtu + dev->hard_header_len : mtu;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* XXXXXXXXX Rest of this file is real linux/pkt_sched.h XXXXX
|
||||
*/
|
||||
|
||||
|
||||
/* Logical priority bands not depending on specific packet scheduler.
|
||||
Every scheduler will map them to real traffic classes, if it has
|
||||
no more precise mechanism to classify packets.
|
||||
|
||||
These numbers have no special meaning, though their coincidence
|
||||
with obsolete IPv6 values is not occasional :-). New IPv6 drafts
|
||||
preferred full anarchy inspired by diffserv group.
|
||||
|
||||
Note: TC_PRIO_BESTEFFORT does not mean that it is the most unhappy
|
||||
class, actually, as rule it will be handled with more care than
|
||||
filler or even bulk.
|
||||
*/
|
||||
|
||||
#define TC_PRIO_BESTEFFORT 0
|
||||
#define TC_PRIO_FILLER 1
|
||||
#define TC_PRIO_BULK 2
|
||||
#define TC_PRIO_INTERACTIVE_BULK 4
|
||||
#define TC_PRIO_INTERACTIVE 6
|
||||
#define TC_PRIO_CONTROL 7
|
||||
|
||||
#define TC_PRIO_MAX 15
|
||||
|
||||
/* Generic queue statistics, available for all the elements.
|
||||
Particular schedulers may have also their private records.
|
||||
*/
|
||||
|
||||
struct tc_stats
|
||||
{
|
||||
__u64 bytes; /* NUmber of enqueues bytes */
|
||||
__u32 packets; /* Number of enqueued packets */
|
||||
__u32 drops; /* Packets dropped because of lack of resources */
|
||||
__u32 overlimits; /* Number of throttle events when this
|
||||
* flow goes out of allocated bandwidth */
|
||||
__u32 bps; /* Current flow byte rate */
|
||||
__u32 pps; /* Current flow packet rate */
|
||||
__u32 qlen;
|
||||
__u32 backlog;
|
||||
#ifdef __KERNEL__
|
||||
spinlock_t *lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct tc_estimator
|
||||
{
|
||||
char interval;
|
||||
unsigned char ewma_log;
|
||||
};
|
||||
|
||||
/* "Handles"
|
||||
---------
|
||||
|
||||
All the traffic control objects have 32bit identifiers, or "handles".
|
||||
|
||||
They can be considered as opaque numbers from user API viewpoint,
|
||||
but actually they always consist of two fields: major and
|
||||
minor numbers, which are interpreted by kernel specially,
|
||||
that may be used by applications, though not recommended.
|
||||
|
||||
F.e. qdisc handles always have minor number equal to zero,
|
||||
classes (or flows) have major equal to parent qdisc major, and
|
||||
minor uniquely identifying class inside qdisc.
|
||||
|
||||
Macros to manipulate handles:
|
||||
*/
|
||||
|
||||
#define TC_H_MAJ_MASK (0xFFFF0000U)
|
||||
#define TC_H_MIN_MASK (0x0000FFFFU)
|
||||
#define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK)
|
||||
#define TC_H_MIN(h) ((h)&TC_H_MIN_MASK)
|
||||
#define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK))
|
||||
|
||||
#define TC_H_UNSPEC (0U)
|
||||
#define TC_H_ROOT (0xFFFFFFFFU)
|
||||
#define TC_H_INGRESS (0xFFFFFFF1U)
|
||||
|
||||
struct tc_ratespec
|
||||
{
|
||||
unsigned char cell_log;
|
||||
unsigned char __reserved;
|
||||
unsigned short feature;
|
||||
short addend;
|
||||
unsigned short mpu;
|
||||
__u32 rate;
|
||||
};
|
||||
|
||||
/* FIFO section */
|
||||
|
||||
struct tc_fifo_qopt
|
||||
{
|
||||
__u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */
|
||||
};
|
||||
|
||||
/* PRIO section */
|
||||
|
||||
#define TCQ_PRIO_BANDS 16
|
||||
|
||||
struct tc_prio_qopt
|
||||
{
|
||||
int bands; /* Number of bands */
|
||||
__u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
|
||||
};
|
||||
|
||||
/* CSZ section */
|
||||
|
||||
struct tc_csz_qopt
|
||||
{
|
||||
int flows; /* Maximal number of guaranteed flows */
|
||||
unsigned char R_log; /* Fixed point position for round number */
|
||||
unsigned char delta_log; /* Log of maximal managed time interval */
|
||||
__u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> CSZ band */
|
||||
};
|
||||
|
||||
struct tc_csz_copt
|
||||
{
|
||||
struct tc_ratespec slice;
|
||||
struct tc_ratespec rate;
|
||||
struct tc_ratespec peakrate;
|
||||
__u32 limit;
|
||||
__u32 buffer;
|
||||
__u32 mtu;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TCA_CSZ_UNSPEC,
|
||||
TCA_CSZ_PARMS,
|
||||
TCA_CSZ_RTAB,
|
||||
TCA_CSZ_PTAB,
|
||||
};
|
||||
|
||||
/* TBF section */
|
||||
|
||||
struct tc_tbf_qopt
|
||||
{
|
||||
struct tc_ratespec rate;
|
||||
struct tc_ratespec peakrate;
|
||||
__u32 limit;
|
||||
__u32 buffer;
|
||||
__u32 mtu;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TCA_TBF_UNSPEC,
|
||||
TCA_TBF_PARMS,
|
||||
TCA_TBF_RTAB,
|
||||
TCA_TBF_PTAB,
|
||||
};
|
||||
|
||||
|
||||
/* TEQL section */
|
||||
|
||||
/* TEQL does not require any parameters */
|
||||
|
||||
/* SFQ section */
|
||||
|
||||
struct tc_sfq_qopt
|
||||
{
|
||||
unsigned quantum; /* Bytes per round allocated to flow */
|
||||
int perturb_period; /* Period of hash perturbation */
|
||||
__u32 limit; /* Maximal packets in queue */
|
||||
unsigned divisor; /* Hash divisor */
|
||||
unsigned flows; /* Maximal number of flows */
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE: limit, divisor and flows are hardwired to code at the moment.
|
||||
*
|
||||
* limit=flows=128, divisor=1024;
|
||||
*
|
||||
* The only reason for this is efficiency, it is possible
|
||||
* to change these parameters in compile time.
|
||||
*/
|
||||
|
||||
/* RED section */
|
||||
|
||||
enum
|
||||
{
|
||||
TCA_RED_UNSPEC,
|
||||
TCA_RED_PARMS,
|
||||
TCA_RED_STAB,
|
||||
};
|
||||
|
||||
struct tc_red_qopt
|
||||
{
|
||||
__u32 limit; /* HARD maximal queue length (bytes) */
|
||||
__u32 qth_min; /* Min average length threshold (bytes) */
|
||||
__u32 qth_max; /* Max average length threshold (bytes) */
|
||||
unsigned char Wlog; /* log(W) */
|
||||
unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */
|
||||
unsigned char Scell_log; /* cell size for idle damping */
|
||||
unsigned char flags;
|
||||
#define TC_RED_ECN 1
|
||||
};
|
||||
|
||||
struct tc_red_xstats
|
||||
{
|
||||
__u32 early; /* Early drops */
|
||||
__u32 pdrop; /* Drops due to queue limits */
|
||||
__u32 other; /* Drops due to drop() calls */
|
||||
__u32 marked; /* Marked packets */
|
||||
};
|
||||
|
||||
/* GRED section */
|
||||
|
||||
#define MAX_DPs 16
|
||||
|
||||
enum
|
||||
{
|
||||
TCA_GRED_UNSPEC,
|
||||
TCA_GRED_PARMS,
|
||||
TCA_GRED_STAB,
|
||||
TCA_GRED_DPS,
|
||||
};
|
||||
|
||||
#define TCA_SET_OFF TCA_GRED_PARMS
|
||||
struct tc_gred_qopt
|
||||
{
|
||||
__u32 limit; /* HARD maximal queue length (bytes)
|
||||
*/
|
||||
__u32 qth_min; /* Min average length threshold (bytes)
|
||||
*/
|
||||
__u32 qth_max; /* Max average length threshold (bytes)
|
||||
*/
|
||||
__u32 DP; /* upto 2^32 DPs */
|
||||
__u32 backlog;
|
||||
__u32 qave;
|
||||
__u32 forced;
|
||||
__u32 early;
|
||||
__u32 other;
|
||||
__u32 pdrop;
|
||||
|
||||
unsigned char Wlog; /* log(W) */
|
||||
unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */
|
||||
unsigned char Scell_log; /* cell size for idle damping */
|
||||
__u8 prio; /* prio of this VQ */
|
||||
__u32 packets;
|
||||
__u32 bytesin;
|
||||
};
|
||||
/* gred setup */
|
||||
struct tc_gred_sopt
|
||||
{
|
||||
__u32 DPs;
|
||||
__u32 def_DP;
|
||||
__u8 grio;
|
||||
};
|
||||
|
||||
/* CBQ section */
|
||||
|
||||
#define TC_CBQ_MAXPRIO 8
|
||||
#define TC_CBQ_MAXLEVEL 8
|
||||
#define TC_CBQ_DEF_EWMA 5
|
||||
|
||||
struct tc_cbq_lssopt
|
||||
{
|
||||
unsigned char change;
|
||||
unsigned char flags;
|
||||
#define TCF_CBQ_LSS_BOUNDED 1
|
||||
#define TCF_CBQ_LSS_ISOLATED 2
|
||||
unsigned char ewma_log;
|
||||
unsigned char level;
|
||||
#define TCF_CBQ_LSS_FLAGS 1
|
||||
#define TCF_CBQ_LSS_EWMA 2
|
||||
#define TCF_CBQ_LSS_MAXIDLE 4
|
||||
#define TCF_CBQ_LSS_MINIDLE 8
|
||||
#define TCF_CBQ_LSS_OFFTIME 0x10
|
||||
#define TCF_CBQ_LSS_AVPKT 0x20
|
||||
__u32 maxidle;
|
||||
__u32 minidle;
|
||||
__u32 offtime;
|
||||
__u32 avpkt;
|
||||
};
|
||||
|
||||
struct tc_cbq_wrropt
|
||||
{
|
||||
unsigned char flags;
|
||||
unsigned char priority;
|
||||
unsigned char cpriority;
|
||||
unsigned char __reserved;
|
||||
__u32 allot;
|
||||
__u32 weight;
|
||||
};
|
||||
|
||||
struct tc_cbq_ovl
|
||||
{
|
||||
unsigned char strategy;
|
||||
#define TC_CBQ_OVL_CLASSIC 0
|
||||
#define TC_CBQ_OVL_DELAY 1
|
||||
#define TC_CBQ_OVL_LOWPRIO 2
|
||||
#define TC_CBQ_OVL_DROP 3
|
||||
#define TC_CBQ_OVL_RCLASSIC 4
|
||||
unsigned char priority2;
|
||||
__u32 penalty;
|
||||
};
|
||||
|
||||
struct tc_cbq_police
|
||||
{
|
||||
unsigned char police;
|
||||
unsigned char __res1;
|
||||
unsigned short __res2;
|
||||
};
|
||||
|
||||
struct tc_cbq_fopt
|
||||
{
|
||||
__u32 split;
|
||||
__u32 defmap;
|
||||
__u32 defchange;
|
||||
};
|
||||
|
||||
struct tc_cbq_xstats
|
||||
{
|
||||
__u32 borrows;
|
||||
__u32 overactions;
|
||||
__s32 avgidle;
|
||||
__s32 undertime;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TCA_CBQ_UNSPEC,
|
||||
TCA_CBQ_LSSOPT,
|
||||
TCA_CBQ_WRROPT,
|
||||
TCA_CBQ_FOPT,
|
||||
TCA_CBQ_OVL_STRATEGY,
|
||||
TCA_CBQ_RATE,
|
||||
TCA_CBQ_RTAB,
|
||||
TCA_CBQ_POLICE,
|
||||
};
|
||||
|
||||
#define TCA_CBQ_MAX TCA_CBQ_POLICE
|
||||
|
||||
/* dsmark section */
|
||||
|
||||
enum {
|
||||
TCA_DSMARK_UNSPEC,
|
||||
TCA_DSMARK_INDICES,
|
||||
TCA_DSMARK_DEFAULT_INDEX,
|
||||
TCA_DSMARK_SET_TC_INDEX,
|
||||
TCA_DSMARK_MASK,
|
||||
TCA_DSMARK_VALUE
|
||||
};
|
||||
|
||||
#define TCA_DSMARK_MAX TCA_DSMARK_VALUE
|
||||
|
||||
/* ATM section */
|
||||
|
||||
enum {
|
||||
TCA_ATM_UNSPEC,
|
||||
TCA_ATM_FD, /* file/socket descriptor */
|
||||
TCA_ATM_PTR, /* pointer to descriptor - later */
|
||||
TCA_ATM_HDR, /* LL header */
|
||||
TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */
|
||||
TCA_ATM_ADDR, /* PVC address (for output only) */
|
||||
TCA_ATM_STATE /* VC state (ATM_VS_*; for output only) */
|
||||
};
|
||||
|
||||
#define TCA_ATM_MAX TCA_ATM_STATE
|
||||
|
||||
#endif
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/lib.h>
|
||||
//#include <linux/kernel.h>
|
||||
//#include <linux/sched.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/cache.h>
|
||||
@@ -26,7 +24,6 @@
|
||||
#include <asm/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mm.h>
|
||||
//#include <linux/highmem.h>
|
||||
|
||||
// vif special values.
|
||||
#define VIF_PHYSICAL_INTERFACE -1
|
||||
@@ -144,8 +141,6 @@ struct sk_buff {
|
||||
struct sk_buff * prev; /* Previous buffer in list */
|
||||
|
||||
struct sk_buff_head * list; /* List we are on */
|
||||
struct sock *sk; /* Socket we are owned by */
|
||||
struct timeval stamp; /* Time we arrived */
|
||||
struct net_device *dev; /* Device we arrived on/are leaving by */
|
||||
|
||||
/* Transport layer header */
|
||||
@@ -177,66 +172,25 @@ struct sk_buff {
|
||||
unsigned char *raw;
|
||||
} mac;
|
||||
|
||||
// struct dst_entry *dst;
|
||||
|
||||
/*
|
||||
* This is the control buffer. It is free to use for every
|
||||
* layer. Please put your private variables there. If you
|
||||
* want to keep them across layers you have to do a skb_clone()
|
||||
* first. This is owned by whoever has the skb queued ATM.
|
||||
*/
|
||||
char cb[48];
|
||||
|
||||
unsigned int len; /* Length of actual data */
|
||||
unsigned int data_len;
|
||||
unsigned int csum; /* Checksum */
|
||||
unsigned char __unused, /* Dead field, may be reused */
|
||||
unsigned char skb_type,
|
||||
cloned, /* head may be cloned (check refcnt to be sure) */
|
||||
pkt_type, /* Packet class */
|
||||
ip_summed; /* Driver fed us an IP checksum */
|
||||
__u32 priority; /* Packet queueing priority */
|
||||
atomic_t users; /* User count - see datagram.c,tcp.c */
|
||||
unsigned short protocol; /* Packet protocol from driver. */
|
||||
unsigned short security; /* Security level of packet */
|
||||
unsigned int truesize; /* Buffer size */
|
||||
|
||||
unsigned char *head; /* Head of buffer */
|
||||
unsigned char *data; /* Data head pointer */
|
||||
unsigned char *tail; /* Tail pointer */
|
||||
unsigned char *end; /* End pointer */
|
||||
|
||||
void (*destructor)(struct sk_buff *); /* Destruct function */
|
||||
|
||||
unsigned int skb_type; /* SKB_NORMAL or SKB_ZERO_COPY */
|
||||
struct pfn_info *pf; /* record of physical pf address for freeing */
|
||||
int src_vif; /* vif we came from */
|
||||
int dst_vif; /* vif we are bound for */
|
||||
struct skb_shared_info shinfo; /* shared info is no longer shared in Xen. */
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_NETFILTER
|
||||
/* Can be used for communication between hooks. */
|
||||
unsigned long nfmark;
|
||||
/* Cache info */
|
||||
__u32 nfcache;
|
||||
/* Associated connection, if any */
|
||||
struct nf_ct_info *nfct;
|
||||
#ifdef CONFIG_NETFILTER_DEBUG
|
||||
unsigned int nf_debug;
|
||||
#endif
|
||||
#endif /*CONFIG_NETFILTER*/
|
||||
|
||||
#if defined(CONFIG_HIPPI)
|
||||
union{
|
||||
__u32 ifield;
|
||||
} private;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_SCHED
|
||||
__u32 tc_index; /* traffic control index */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define SK_WMEM_MAX 65535
|
||||
@@ -1000,7 +954,6 @@ static inline void skb_orphan(struct sk_buff *skb)
|
||||
if (skb->destructor)
|
||||
skb->destructor(skb);
|
||||
skb->destructor = NULL;
|
||||
skb->sk = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1130,10 +1083,8 @@ static inline void kunmap_skb_frag(void *vaddr)
|
||||
skb=skb->next)
|
||||
|
||||
|
||||
extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
|
||||
extern int skb_copy_datagram(const struct sk_buff *from, int offset, char *to,int size);
|
||||
extern int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int *csump);
|
||||
extern void skb_free_datagram(struct sock * sk, struct sk_buff *skb);
|
||||
|
||||
extern unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum);
|
||||
extern int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
|
||||
|
||||
@@ -69,9 +69,6 @@
|
||||
#define SIOCGIFBR 0x8940 /* Bridging support */
|
||||
#define SIOCSIFBR 0x8941 /* Set bridging options */
|
||||
|
||||
#define SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */
|
||||
#define SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */
|
||||
|
||||
#define SIOCGIFDIVERT 0x8944 /* Frame diversion support */
|
||||
#define SIOCSIFDIVERT 0x8945 /* Set frame diversion options */
|
||||
|
||||
|
||||
@@ -32,10 +32,17 @@ typedef struct rx_shadow_entry_st {
|
||||
unsigned long flush_count;
|
||||
} rx_shadow_entry_t;
|
||||
|
||||
typedef struct tx_shadow_entry_st {
|
||||
unsigned long addr;
|
||||
unsigned long size;
|
||||
int status;
|
||||
} tx_shadow_entry_t;
|
||||
|
||||
typedef struct net_shadow_ring_st {
|
||||
rx_shadow_entry_t *rx_ring;
|
||||
tx_shadow_entry_t *tx_ring;
|
||||
unsigned int rx_prod, rx_cons, rx_idx;
|
||||
unsigned int tx_cons; /* ahead of shared tx_cons */
|
||||
unsigned int tx_prod, tx_cons, tx_idx;
|
||||
} net_shadow_ring_t;
|
||||
|
||||
typedef struct net_vif_st {
|
||||
|
||||
+1093
-1177
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,114 @@
|
||||
/******************************************************************************
|
||||
* devinit.c
|
||||
*
|
||||
* This is the watchdog timer routines, ripped from sch_generic.c
|
||||
* Original copyright notice appears below.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
|
||||
* Jamal Hadi Salim, <hadi@nortelnetworks.com> 990601
|
||||
* - Ingress support
|
||||
*/
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/lib.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
static void dev_watchdog(unsigned long arg)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *)arg;
|
||||
|
||||
spin_lock(&dev->xmit_lock);
|
||||
if (netif_device_present(dev) &&
|
||||
netif_running(dev) &&
|
||||
netif_carrier_ok(dev)) {
|
||||
if (netif_queue_stopped(dev) &&
|
||||
(jiffies - dev->trans_start) > dev->watchdog_timeo) {
|
||||
printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name);
|
||||
dev->tx_timeout(dev);
|
||||
}
|
||||
if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
|
||||
dev_hold(dev);
|
||||
}
|
||||
spin_unlock(&dev->xmit_lock);
|
||||
|
||||
dev_put(dev);
|
||||
}
|
||||
|
||||
static void dev_watchdog_init(struct net_device *dev)
|
||||
{
|
||||
init_timer(&dev->watchdog_timer);
|
||||
dev->watchdog_timer.data = (unsigned long)dev;
|
||||
dev->watchdog_timer.function = dev_watchdog;
|
||||
}
|
||||
|
||||
void __netdev_watchdog_up(struct net_device *dev)
|
||||
{
|
||||
if (dev->tx_timeout) {
|
||||
if (dev->watchdog_timeo <= 0)
|
||||
dev->watchdog_timeo = 5*HZ;
|
||||
if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
|
||||
dev_hold(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void dev_watchdog_up(struct net_device *dev)
|
||||
{
|
||||
spin_lock_bh(&dev->xmit_lock);
|
||||
__netdev_watchdog_up(dev);
|
||||
spin_unlock_bh(&dev->xmit_lock);
|
||||
}
|
||||
|
||||
static void dev_watchdog_down(struct net_device *dev)
|
||||
{
|
||||
spin_lock_bh(&dev->xmit_lock);
|
||||
if (del_timer(&dev->watchdog_timer))
|
||||
__dev_put(dev);
|
||||
spin_unlock_bh(&dev->xmit_lock);
|
||||
}
|
||||
|
||||
void dev_activate(struct net_device *dev)
|
||||
{
|
||||
spin_lock_bh(&dev->queue_lock);
|
||||
dev->trans_start = jiffies;
|
||||
dev_watchdog_up(dev);
|
||||
spin_unlock_bh(&dev->queue_lock);
|
||||
}
|
||||
|
||||
void dev_deactivate(struct net_device *dev)
|
||||
{
|
||||
dev_watchdog_down(dev);
|
||||
|
||||
while (test_bit(__LINK_STATE_SCHED, &dev->state)) {
|
||||
current->policy |= SCHED_YIELD;
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
void dev_init_scheduler(struct net_device *dev)
|
||||
{
|
||||
dev_watchdog_init(dev);
|
||||
}
|
||||
|
||||
void dev_shutdown(struct net_device *dev)
|
||||
{
|
||||
}
|
||||
@@ -1,525 +0,0 @@
|
||||
/*
|
||||
* net/sched/sch_generic.c Generic packet scheduler routines.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
|
||||
* Jamal Hadi Salim, <hadi@nortelnetworks.com> 990601
|
||||
* - Ingress support
|
||||
*/
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/types.h>
|
||||
//#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/lib.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/sockios.h>
|
||||
//#include <linux/in.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
//#include <linux/rtnetlink.h>
|
||||
#include <linux/init.h>
|
||||
//#include <net/sock.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
|
||||
extern int net_ratelimit(void);
|
||||
#define BUG_TRAP ASSERT
|
||||
|
||||
/* Main transmission queue. */
|
||||
|
||||
/* Main qdisc structure lock.
|
||||
|
||||
However, modifications
|
||||
to data, participating in scheduling must be additionally
|
||||
protected with dev->queue_lock spinlock.
|
||||
|
||||
The idea is the following:
|
||||
- enqueue, dequeue are serialized via top level device
|
||||
spinlock dev->queue_lock.
|
||||
- tree walking is protected by read_lock(qdisc_tree_lock)
|
||||
and this lock is used only in process context.
|
||||
- updates to tree are made only under rtnl semaphore,
|
||||
hence this lock may be made without local bh disabling.
|
||||
|
||||
qdisc_tree_lock must be grabbed BEFORE dev->queue_lock!
|
||||
*/
|
||||
rwlock_t qdisc_tree_lock = RW_LOCK_UNLOCKED;
|
||||
|
||||
/*
|
||||
dev->queue_lock serializes queue accesses for this device
|
||||
AND dev->qdisc pointer itself.
|
||||
|
||||
dev->xmit_lock serializes accesses to device driver.
|
||||
|
||||
dev->queue_lock and dev->xmit_lock are mutually exclusive,
|
||||
if one is grabbed, another must be free.
|
||||
*/
|
||||
|
||||
|
||||
/* Kick device.
|
||||
Note, that this procedure can be called by a watchdog timer, so that
|
||||
we do not check dev->tbusy flag here.
|
||||
|
||||
Returns: 0 - queue is empty.
|
||||
>0 - queue is not empty, but throttled.
|
||||
<0 - queue is not empty. Device is throttled, if dev->tbusy != 0.
|
||||
|
||||
NOTE: Called under dev->queue_lock with locally disabled BH.
|
||||
*/
|
||||
|
||||
int qdisc_restart(struct net_device *dev)
|
||||
{
|
||||
struct Qdisc *q = dev->qdisc;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Dequeue packet */
|
||||
if ((skb = q->dequeue(q)) != NULL) {
|
||||
if (spin_trylock(&dev->xmit_lock)) {
|
||||
/* Remember that the driver is grabbed by us. */
|
||||
dev->xmit_lock_owner = smp_processor_id();
|
||||
|
||||
/* And release queue */
|
||||
spin_unlock(&dev->queue_lock);
|
||||
|
||||
if (!netif_queue_stopped(dev)) {
|
||||
#if 0
|
||||
if (netdev_nit)
|
||||
dev_queue_xmit_nit(skb, dev);
|
||||
#endif
|
||||
|
||||
if (dev->hard_start_xmit(skb, dev) == 0) {
|
||||
dev->xmit_lock_owner = -1;
|
||||
spin_unlock(&dev->xmit_lock);
|
||||
|
||||
spin_lock(&dev->queue_lock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the driver */
|
||||
dev->xmit_lock_owner = -1;
|
||||
spin_unlock(&dev->xmit_lock);
|
||||
spin_lock(&dev->queue_lock);
|
||||
q = dev->qdisc;
|
||||
} else {
|
||||
/* So, someone grabbed the driver. */
|
||||
|
||||
/* It may be transient configuration error,
|
||||
when hard_start_xmit() recurses. We detect
|
||||
it by checking xmit owner and drop the
|
||||
packet when deadloop is detected.
|
||||
*/
|
||||
if (dev->xmit_lock_owner == smp_processor_id()) {
|
||||
kfree_skb(skb);
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name);
|
||||
return -1;
|
||||
}
|
||||
netdev_rx_stat[smp_processor_id()].cpu_collision++;
|
||||
}
|
||||
|
||||
/* Device kicked us out :(
|
||||
This is possible in three cases:
|
||||
|
||||
0. driver is locked
|
||||
1. fastroute is enabled
|
||||
2. device cannot determine busy state
|
||||
before start of transmission (f.e. dialout)
|
||||
3. device is buggy (ppp)
|
||||
*/
|
||||
|
||||
q->ops->requeue(skb, q);
|
||||
netif_schedule(dev);
|
||||
return 1;
|
||||
}
|
||||
return q->q.qlen;
|
||||
}
|
||||
|
||||
static void dev_watchdog(unsigned long arg)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *)arg;
|
||||
|
||||
spin_lock(&dev->xmit_lock);
|
||||
if (dev->qdisc != &noop_qdisc) {
|
||||
if (netif_device_present(dev) &&
|
||||
netif_running(dev) &&
|
||||
netif_carrier_ok(dev)) {
|
||||
if (netif_queue_stopped(dev) &&
|
||||
(jiffies - dev->trans_start) > dev->watchdog_timeo) {
|
||||
printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name);
|
||||
dev->tx_timeout(dev);
|
||||
}
|
||||
if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
|
||||
dev_hold(dev);
|
||||
}
|
||||
}
|
||||
spin_unlock(&dev->xmit_lock);
|
||||
|
||||
dev_put(dev);
|
||||
}
|
||||
|
||||
static void dev_watchdog_init(struct net_device *dev)
|
||||
{
|
||||
init_timer(&dev->watchdog_timer);
|
||||
dev->watchdog_timer.data = (unsigned long)dev;
|
||||
dev->watchdog_timer.function = dev_watchdog;
|
||||
}
|
||||
|
||||
void __netdev_watchdog_up(struct net_device *dev)
|
||||
{
|
||||
if (dev->tx_timeout) {
|
||||
if (dev->watchdog_timeo <= 0)
|
||||
dev->watchdog_timeo = 5*HZ;
|
||||
if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
|
||||
dev_hold(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void dev_watchdog_up(struct net_device *dev)
|
||||
{
|
||||
spin_lock_bh(&dev->xmit_lock);
|
||||
__netdev_watchdog_up(dev);
|
||||
spin_unlock_bh(&dev->xmit_lock);
|
||||
}
|
||||
|
||||
static void dev_watchdog_down(struct net_device *dev)
|
||||
{
|
||||
spin_lock_bh(&dev->xmit_lock);
|
||||
if (del_timer(&dev->watchdog_timer))
|
||||
__dev_put(dev);
|
||||
spin_unlock_bh(&dev->xmit_lock);
|
||||
}
|
||||
|
||||
/* "NOOP" scheduler: the best scheduler, recommended for all interfaces
|
||||
under all circumstances. It is difficult to invent anything faster or
|
||||
cheaper.
|
||||
*/
|
||||
|
||||
static int
|
||||
noop_enqueue(struct sk_buff *skb, struct Qdisc * qdisc)
|
||||
{
|
||||
kfree_skb(skb);
|
||||
return NET_XMIT_CN;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
noop_dequeue(struct Qdisc * qdisc)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
noop_requeue(struct sk_buff *skb, struct Qdisc* qdisc)
|
||||
{
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s deferred output. It is buggy.\n", skb->dev->name);
|
||||
kfree_skb(skb);
|
||||
return NET_XMIT_CN;
|
||||
}
|
||||
|
||||
struct Qdisc_ops noop_qdisc_ops =
|
||||
{
|
||||
NULL,
|
||||
NULL,
|
||||
"noop",
|
||||
0,
|
||||
|
||||
noop_enqueue,
|
||||
noop_dequeue,
|
||||
noop_requeue,
|
||||
};
|
||||
|
||||
struct Qdisc noop_qdisc =
|
||||
{
|
||||
noop_enqueue,
|
||||
noop_dequeue,
|
||||
TCQ_F_BUILTIN,
|
||||
&noop_qdisc_ops,
|
||||
};
|
||||
|
||||
|
||||
struct Qdisc_ops noqueue_qdisc_ops =
|
||||
{
|
||||
NULL,
|
||||
NULL,
|
||||
"noqueue",
|
||||
0,
|
||||
|
||||
noop_enqueue,
|
||||
noop_dequeue,
|
||||
noop_requeue,
|
||||
|
||||
};
|
||||
|
||||
struct Qdisc noqueue_qdisc =
|
||||
{
|
||||
NULL,
|
||||
noop_dequeue,
|
||||
TCQ_F_BUILTIN,
|
||||
&noqueue_qdisc_ops,
|
||||
};
|
||||
|
||||
|
||||
static const u8 prio2band[TC_PRIO_MAX+1] =
|
||||
{ 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 };
|
||||
|
||||
/* 3-band FIFO queue: old style, but should be a bit faster than
|
||||
generic prio+fifo combination.
|
||||
*/
|
||||
|
||||
static int
|
||||
pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc)
|
||||
{
|
||||
struct sk_buff_head *list;
|
||||
|
||||
list = ((struct sk_buff_head*)qdisc->data) +
|
||||
prio2band[skb->priority&TC_PRIO_MAX];
|
||||
|
||||
if (list->qlen <= skb->dev->tx_queue_len) {
|
||||
__skb_queue_tail(list, skb);
|
||||
qdisc->q.qlen++;
|
||||
return 0;
|
||||
}
|
||||
//qdisc->stats.drops++;
|
||||
kfree_skb(skb);
|
||||
return NET_XMIT_DROP;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
pfifo_fast_dequeue(struct Qdisc* qdisc)
|
||||
{
|
||||
int prio;
|
||||
struct sk_buff_head *list = ((struct sk_buff_head*)qdisc->data);
|
||||
struct sk_buff *skb;
|
||||
|
||||
for (prio = 0; prio < 3; prio++, list++) {
|
||||
skb = __skb_dequeue(list);
|
||||
if (skb) {
|
||||
qdisc->q.qlen--;
|
||||
return skb;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
pfifo_fast_requeue(struct sk_buff *skb, struct Qdisc* qdisc)
|
||||
{
|
||||
struct sk_buff_head *list;
|
||||
|
||||
list = ((struct sk_buff_head*)qdisc->data) +
|
||||
prio2band[skb->priority&TC_PRIO_MAX];
|
||||
|
||||
__skb_queue_head(list, skb);
|
||||
qdisc->q.qlen++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pfifo_fast_reset(struct Qdisc* qdisc)
|
||||
{
|
||||
int prio;
|
||||
struct sk_buff_head *list = ((struct sk_buff_head*)qdisc->data);
|
||||
|
||||
for (prio=0; prio < 3; prio++)
|
||||
skb_queue_purge(list+prio);
|
||||
qdisc->q.qlen = 0;
|
||||
}
|
||||
|
||||
static int pfifo_fast_init(struct Qdisc *qdisc, struct rtattr *opt)
|
||||
{
|
||||
int i;
|
||||
struct sk_buff_head *list;
|
||||
|
||||
list = ((struct sk_buff_head*)qdisc->data);
|
||||
|
||||
for (i=0; i<3; i++)
|
||||
skb_queue_head_init(list+i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct Qdisc_ops pfifo_fast_ops =
|
||||
{
|
||||
NULL,
|
||||
NULL,
|
||||
"pfifo_fast",
|
||||
3 * sizeof(struct sk_buff_head),
|
||||
|
||||
pfifo_fast_enqueue,
|
||||
pfifo_fast_dequeue,
|
||||
pfifo_fast_requeue,
|
||||
NULL,
|
||||
|
||||
pfifo_fast_init,
|
||||
pfifo_fast_reset,
|
||||
};
|
||||
|
||||
struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops)
|
||||
{
|
||||
struct Qdisc *sch;
|
||||
int size = sizeof(*sch) + ops->priv_size;
|
||||
|
||||
sch = kmalloc(size, GFP_KERNEL);
|
||||
if (!sch)
|
||||
return NULL;
|
||||
memset(sch, 0, size);
|
||||
|
||||
skb_queue_head_init(&sch->q);
|
||||
sch->ops = ops;
|
||||
sch->enqueue = ops->enqueue;
|
||||
sch->dequeue = ops->dequeue;
|
||||
sch->dev = dev;
|
||||
//sch->stats.lock = &dev->queue_lock;
|
||||
atomic_set(&sch->refcnt, 1);
|
||||
if (!ops->init || ops->init(sch, NULL) == 0)
|
||||
return sch;
|
||||
|
||||
kfree(sch);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Under dev->queue_lock and BH! */
|
||||
|
||||
void qdisc_reset(struct Qdisc *qdisc)
|
||||
{
|
||||
struct Qdisc_ops *ops = qdisc->ops;
|
||||
|
||||
if (ops->reset)
|
||||
ops->reset(qdisc);
|
||||
}
|
||||
|
||||
/* Under dev->queue_lock and BH! */
|
||||
|
||||
void qdisc_destroy(struct Qdisc *qdisc)
|
||||
{
|
||||
struct Qdisc_ops *ops = qdisc->ops;
|
||||
struct net_device *dev;
|
||||
|
||||
if (!atomic_dec_and_test(&qdisc->refcnt))
|
||||
return;
|
||||
|
||||
dev = qdisc->dev;
|
||||
|
||||
#ifdef CONFIG_NET_SCHED
|
||||
if (dev) {
|
||||
struct Qdisc *q, **qp;
|
||||
for (qp = &qdisc->dev->qdisc_list; (q=*qp) != NULL; qp = &q->next) {
|
||||
if (q == qdisc) {
|
||||
*qp = q->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_NET_ESTIMATOR
|
||||
qdisc_kill_estimator(&qdisc->stats);
|
||||
#endif
|
||||
#endif
|
||||
if (ops->reset)
|
||||
ops->reset(qdisc);
|
||||
if (ops->destroy)
|
||||
ops->destroy(qdisc);
|
||||
if (!(qdisc->flags&TCQ_F_BUILTIN))
|
||||
kfree(qdisc);
|
||||
}
|
||||
|
||||
|
||||
void dev_activate(struct net_device *dev)
|
||||
{
|
||||
/* No queueing discipline is attached to device;
|
||||
create default one i.e. pfifo_fast for devices,
|
||||
which need queueing and noqueue_qdisc for
|
||||
virtual interfaces
|
||||
*/
|
||||
|
||||
if (dev->qdisc_sleeping == &noop_qdisc) {
|
||||
struct Qdisc *qdisc;
|
||||
if (dev->tx_queue_len) {
|
||||
qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops);
|
||||
if (qdisc == NULL) {
|
||||
printk(KERN_INFO "%s: activation failed\n", dev->name);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
qdisc = &noqueue_qdisc;
|
||||
}
|
||||
write_lock(&qdisc_tree_lock);
|
||||
dev->qdisc_sleeping = qdisc;
|
||||
write_unlock(&qdisc_tree_lock);
|
||||
}
|
||||
|
||||
spin_lock_bh(&dev->queue_lock);
|
||||
if ((dev->qdisc = dev->qdisc_sleeping) != &noqueue_qdisc) {
|
||||
dev->trans_start = jiffies;
|
||||
dev_watchdog_up(dev);
|
||||
}
|
||||
spin_unlock_bh(&dev->queue_lock);
|
||||
}
|
||||
|
||||
void dev_deactivate(struct net_device *dev)
|
||||
{
|
||||
struct Qdisc *qdisc;
|
||||
|
||||
spin_lock_bh(&dev->queue_lock);
|
||||
qdisc = dev->qdisc;
|
||||
dev->qdisc = &noop_qdisc;
|
||||
|
||||
qdisc_reset(qdisc);
|
||||
|
||||
spin_unlock_bh(&dev->queue_lock);
|
||||
|
||||
dev_watchdog_down(dev);
|
||||
|
||||
while (test_bit(__LINK_STATE_SCHED, &dev->state)) {
|
||||
current->policy |= SCHED_YIELD;
|
||||
schedule();
|
||||
}
|
||||
|
||||
spin_unlock_wait(&dev->xmit_lock);
|
||||
}
|
||||
|
||||
void dev_init_scheduler(struct net_device *dev)
|
||||
{
|
||||
write_lock(&qdisc_tree_lock);
|
||||
spin_lock_bh(&dev->queue_lock);
|
||||
dev->qdisc = &noop_qdisc;
|
||||
spin_unlock_bh(&dev->queue_lock);
|
||||
dev->qdisc_sleeping = &noop_qdisc;
|
||||
dev->qdisc_list = NULL;
|
||||
write_unlock(&qdisc_tree_lock);
|
||||
|
||||
dev_watchdog_init(dev);
|
||||
}
|
||||
|
||||
void dev_shutdown(struct net_device *dev)
|
||||
{
|
||||
struct Qdisc *qdisc;
|
||||
|
||||
write_lock(&qdisc_tree_lock);
|
||||
spin_lock_bh(&dev->queue_lock);
|
||||
qdisc = dev->qdisc_sleeping;
|
||||
dev->qdisc = &noop_qdisc;
|
||||
dev->qdisc_sleeping = &noop_qdisc;
|
||||
qdisc_destroy(qdisc);
|
||||
#if defined(CONFIG_NET_SCH_INGRESS) || defined(CONFIG_NET_SCH_INGRESS_MODULE)
|
||||
if ((qdisc = dev->qdisc_ingress) != NULL) {
|
||||
dev->qdisc_ingress = NULL;
|
||||
qdisc_destroy(qdisc);
|
||||
}
|
||||
#endif
|
||||
BUG_TRAP(dev->qdisc_list == NULL);
|
||||
BUG_TRAP(!timer_pending(&dev->watchdog_timer));
|
||||
dev->qdisc_list = NULL;
|
||||
spin_unlock_bh(&dev->queue_lock);
|
||||
write_unlock(&qdisc_tree_lock);
|
||||
}
|
||||
+3
-44
@@ -40,26 +40,14 @@
|
||||
#include <linux/lib.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
//#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
//#include <linux/in.h>
|
||||
//#include <linux/inet.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/netdevice.h>
|
||||
//#include <linux/string.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/cache.h>
|
||||
#include <linux/init.h>
|
||||
//#include <linux/highmem.h>
|
||||
|
||||
//#include <net/ip.h>
|
||||
//#include <net/protocol.h>
|
||||
//#include <net/dst.h>
|
||||
//#include <net/tcp.h>
|
||||
//#include <net/udp.h>
|
||||
//#include <net/sock.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
@@ -162,7 +150,7 @@ static inline u8 *alloc_skb_data_page(struct sk_buff *skb)
|
||||
|
||||
list_ptr = free_list.next;
|
||||
pf = list_entry(list_ptr, struct pfn_info, list);
|
||||
pf->flags = 0; // owned by dom0
|
||||
pf->flags = 0; /* owned by dom0 */
|
||||
list_del(&pf->list);
|
||||
free_pfns--;
|
||||
|
||||
@@ -218,14 +206,9 @@ struct sk_buff *alloc_zc_skb(unsigned int size,int gfp_mask)
|
||||
if (data == NULL)
|
||||
goto nodata;
|
||||
|
||||
// This is so that pci_map_single does the right thing in the driver.
|
||||
// If you want to ever use this pointer otherwise, you need to regenerate it
|
||||
// based on skb->pf.
|
||||
/* A FAKE virtual address, so that pci_map_xxx dor the right thing. */
|
||||
data = phys_to_virt((unsigned long)data);
|
||||
|
||||
/* XXX: does not include slab overhead */
|
||||
skb->truesize = size + sizeof(struct sk_buff);
|
||||
|
||||
/* Load the data pointers. */
|
||||
skb->head = data;
|
||||
skb->data = data;
|
||||
@@ -302,9 +285,6 @@ struct sk_buff *alloc_skb(unsigned int size,int gfp_mask)
|
||||
if (data == NULL)
|
||||
goto nodata;
|
||||
|
||||
/* XXX: does not include slab overhead */
|
||||
skb->truesize = size + sizeof(struct sk_buff);
|
||||
|
||||
/* Load the data pointers. */
|
||||
skb->head = data;
|
||||
skb->data = data;
|
||||
@@ -343,15 +323,9 @@ static inline void skb_headerinit(void *p, kmem_cache_t *cache,
|
||||
skb->next = NULL;
|
||||
skb->prev = NULL;
|
||||
skb->list = NULL;
|
||||
skb->sk = NULL;
|
||||
skb->stamp.tv_sec=0; /* No idea about time */
|
||||
skb->dev = NULL;
|
||||
// skb->dst = NULL;
|
||||
memset(skb->cb, 0, sizeof(skb->cb));
|
||||
skb->pkt_type = PACKET_HOST; /* Default type */
|
||||
skb->ip_summed = 0;
|
||||
skb->priority = 0;
|
||||
skb->security = 0; /* By default packets are insecure */
|
||||
skb->destructor = NULL;
|
||||
|
||||
#ifdef CONFIG_NETFILTER
|
||||
@@ -411,7 +385,7 @@ static void skb_release_data(struct sk_buff *skb)
|
||||
}
|
||||
else
|
||||
{
|
||||
BUG(); //skb_release_data called with unknown skb type!
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,7 +416,6 @@ void __kfree_skb(struct sk_buff *skb)
|
||||
BUG();
|
||||
}
|
||||
|
||||
// dst_release(skb->dst);
|
||||
if(skb->destructor) {
|
||||
if (in_irq()) {
|
||||
printk(KERN_WARNING "Warning: kfree_skb on hard IRQ %p\n",
|
||||
@@ -487,26 +460,18 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
|
||||
|
||||
n->next = n->prev = NULL;
|
||||
n->list = NULL;
|
||||
n->sk = NULL;
|
||||
C(stamp);
|
||||
C(dev);
|
||||
C(h);
|
||||
C(nh);
|
||||
C(mac);
|
||||
// C(dst);
|
||||
// dst_clone(n->dst);
|
||||
memcpy(n->cb, skb->cb, sizeof(skb->cb));
|
||||
C(len);
|
||||
C(data_len);
|
||||
C(csum);
|
||||
n->cloned = 1;
|
||||
C(pkt_type);
|
||||
C(ip_summed);
|
||||
C(priority);
|
||||
atomic_set(&n->users, 1);
|
||||
C(protocol);
|
||||
C(security);
|
||||
C(truesize);
|
||||
C(head);
|
||||
C(data);
|
||||
C(tail);
|
||||
@@ -543,20 +508,14 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
|
||||
unsigned long offset = new->data - old->data;
|
||||
|
||||
new->list=NULL;
|
||||
new->sk=NULL;
|
||||
new->dev=old->dev;
|
||||
new->priority=old->priority;
|
||||
new->protocol=old->protocol;
|
||||
// new->dst=dst_clone(old->dst);
|
||||
new->h.raw=old->h.raw+offset;
|
||||
new->nh.raw=old->nh.raw+offset;
|
||||
new->mac.raw=old->mac.raw+offset;
|
||||
memcpy(new->cb, old->cb, sizeof(old->cb));
|
||||
atomic_set(&new->users, 1);
|
||||
new->pkt_type=old->pkt_type;
|
||||
new->stamp=old->stamp;
|
||||
new->destructor = NULL;
|
||||
new->security=old->security;
|
||||
#ifdef CONFIG_NETFILTER
|
||||
new->nfmark=old->nfmark;
|
||||
new->nfcache=old->nfcache;
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Generic address resultion entity
|
||||
*
|
||||
* Authors:
|
||||
* net_random Alan Cox
|
||||
* net_ratelimit Andy Kleen
|
||||
*
|
||||
* Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/lib.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
#include <linux/types.h>
|
||||
//#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
//#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
static unsigned long net_rand_seed = 152L;
|
||||
|
||||
unsigned long net_random(void)
|
||||
{
|
||||
net_rand_seed=net_rand_seed*69069L+1;
|
||||
return net_rand_seed^jiffies;
|
||||
}
|
||||
|
||||
void net_srandom(unsigned long entropy)
|
||||
{
|
||||
net_rand_seed ^= entropy;
|
||||
net_random();
|
||||
}
|
||||
|
||||
int net_msg_cost = 5*HZ;
|
||||
int net_msg_burst = 10*5*HZ;
|
||||
|
||||
/*
|
||||
* This enforces a rate limit: not more than one kernel message
|
||||
* every 5secs to make a denial-of-service attack impossible.
|
||||
*
|
||||
* All warning printk()s should be guarded by this function.
|
||||
*/
|
||||
int net_ratelimit(void)
|
||||
{
|
||||
static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED;
|
||||
static unsigned long toks = 10*5*HZ;
|
||||
static unsigned long last_msg;
|
||||
static int missed;
|
||||
unsigned long flags;
|
||||
unsigned long now = jiffies;
|
||||
|
||||
spin_lock_irqsave(&ratelimit_lock, flags);
|
||||
toks += now - last_msg;
|
||||
last_msg = now;
|
||||
if (toks > net_msg_burst)
|
||||
toks = net_msg_burst;
|
||||
if (toks >= net_msg_cost) {
|
||||
int lost = missed;
|
||||
missed = 0;
|
||||
toks -= net_msg_cost;
|
||||
spin_unlock_irqrestore(&ratelimit_lock, flags);
|
||||
if (lost)
|
||||
printk(KERN_WARNING "NET: %d messages suppressed.\n", lost);
|
||||
return 1;
|
||||
}
|
||||
missed++;
|
||||
spin_unlock_irqrestore(&ratelimit_lock, flags);
|
||||
return 0;
|
||||
}
|
||||