使用slab memory 、hlist table、setup_timer、SPINLOCK筆記:
typedef struct _traffic_entry
{
struct hlist_node hlist;
unsigned char dev[DEV_NAME_LEN];
unsigned int ipaddr;
unsigned char macaddr[ETH_ALEN];
unsigned long TX_pkts;
unsigned long RX_pkts;
unsigned long TX_bytes;
unsigned long RX_bytes;
unsigned long init_time;
unsigned long timestamp;
struct rcu_head rcu;
} traffic_entry;
static traffic_entry *tm_entry; /*用於指向暫存entry的指標*/
static struct kmem_cache *tf_db_cache __read_mostly; /*宣告使用slab memory*/
static DEFINE_SPINLOCK(hlist_lock); /*宣告用來做SPINLOCK的flag*/
static struct timer_list tfm_timer; /*宣告用來做Timer*/
#define TF_TIMEOUT 300000 //ms (5 minutes)
#define EXE_INTERVAL 60000 //ms (30 seconds)
static void tdb_rcu_free(struct rcu_head *head)
{
struct _traffic_entry *ent= container_of(head, struct _traffic_entry, rcu);
kmem_cache_free(tf_db_cache, ent);
}
/*用來釋放不需使用的slab memory*/
static inline void tdb_delete(struct _traffic_entry *f)
{
hlist_del_rcu(&f->hlist);
call_rcu(&f->rcu, tdb_rcu_free);
}
/*刪除逾期的資料,由setup_timer所trigger*/
static inline void tfm_entry_cleanup(void)
{
int i = 0,hash_cnt = 0;
struct hlist_node *node = NULL;
traffic_entry *entry = NULL;
/*為了避免共同存取eth_hash這個hash table的structure,因此在存取eth_hash時,會先將之lock住*/
spin_lock_bh(&hlist_lock);
for(i = 0; i < TRAFFIC_HEAD_SIZE; i++)
{
for(hash_cnt = 0; hash_cnt < TRAFFIC_HASH_SIZE; hash_cnt++)
{
hlist_for_each_entry_rcu(entry,node,ð_hash[hash_cnt],hlist)
{
this_timer = entry->timestamp + TF_TIMEOUT;
if (time_before_eq(this_timer, jiffies))
{
tdb_delete(entry);
}
}
}
}
/*待eth_hash table 存取完之後,會將之unlock*/
spin_unlock_bh(&hlist_lock);
/*由mod_timer去修改下一次要被trigger的時間,EXE_INTERVAL為時間間隔*/
mod_timer(&tfm_timer, jiffies + msecs_to_jiffies(EXE_INTERVAL));
return;
}
int traffic_monitor(struct sk_buff *mskb)
{
spin_lock_bh(&hlist_lock);
add_dentry = find_macaddr_entry(ethh->h_dest, mskb->dev->name);
if (add_dentry==NULL)
{
tm_entry = kmem_cache_alloc(tf_db_cache, GFP_ATOMIC);
if (tm_entry)
{
if (add_dentry == NULL)
{
hash_addr = mac_hash(ethh->h_dest);
memset(tm_entry->dev,0x0,DEV_NAME_LEN);
memcpy(tm_entry->dev,mskb->dev->name,DEV_NAME_LEN );
memset(tm_entry->macaddr,0x0,ETH_ALEN );
memcpy(tm_entry->macaddr,ethh->h_dest,ETH_ALEN );
tm_entry->ipaddr = iph->daddr;
tm_entry->TX_pkts = 0;
tm_entry->TX_bytes = 0;
tm_entry->RX_pkts = 1;
tm_entry->RX_bytes = mskb->len;
tm_entry->init_time = jiffies;
tm_entry->timestamp = jiffies;
}
hlist_add_head_rcu(&tm_entry->hlist,ð_hash[hash_addr]);
}
}
spin_unlock_bh(&hlist_lock);
return 0;
}
/*用來trigger 檢查是否有entry已逾時,可以將之刪除*/
int initial_timer()
{
int ret = 0;
printk("Initial timer \n");
setup_timer(&tfm_timer, tfm_entry_cleanup, 0);
/*2秒後trigger一次tfm_entry_cleanup*/
ret = mod_timer(&tfm_timer, jiffies + msecs_to_jiffies(2000));
if(ret) printk("can't trigger tfm_timer\n");
return 0;
}
int clear_timer()
{
int ret = 0;
printk("Delete Timer\n");
ret = del_timer(&tfm_timer);
if (ret)
{
printk("can't delete tfm_timer, try again after 5 ms!");
mdelay(5);
ret = del_timer(&tfm_timer);
if (ret) printk("still can't delete timer!");
}
return 0;
}
static int tfm_func(struct sk_buff *skb)
{
if(!skb || !skb->data) return 0;
traffic_monitor(skb);
return 0;
}
static int __init init(void)
{
tf_db_cache= kmem_cache_create("traffic_db_cache", sizeof(struct _traffic_entry),0,SLAB_HWCACHE_ALIGN, NULL);
if (!tf_db_cache)
return -ENOMEM;
return 0;
}
static void __exit fini(void)
{
kmem_cache_destroy(tf_db_cache);
}
參考網址1: http://bbs.chinaunix.net/thread-2093822-1-1.html (投石问路:kmem_cache_alloc函数使用问题)
參考網址2: http://blog.csdn.net/z1179675084/article/details/8741971 (z1179675084的專欄 linux內核定時器)
參考網址3:http://nano-chicken.blogspot.tw/search?q=timer (Nano 雞排 Linux Kernel (7.1)-timer)
參考網址4: http://www.ibm.com/developerworks/cn/linux/l-timers-list/ (內核API, 第3部份: 2.6內核中的計時器和列表)
文章標籤
全站熱搜