内核中网卡的开启状态通过__LINK_STATE_START进行标识。网卡开启或关闭时,通过该标识会被置位。
内核专门提供了一个函数用于检测该标志位。函数定义如下:
static inline bool netif_running(const struct net_device *dev)
{
return test_bit(__LINK_STATE_START, &dev->state);
}
编写内核模块,通过开启和关闭网卡,观察该函数是否符合预期。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/net_namespace.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
struct net_device *eth;
static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev) {
kfree_skb(skb);
return 0;
}
int ndo_open(struct net_device *dev) {
printk(KERN_ALERT "open\n");
printk(KERN_ALERT "%d\n",netif_running(dev));
return 0;
}
int ndo_stop(struct net_device *dev) {
printk(KERN_ALERT "stop\n");
printk(KERN_ALERT "%d\n",netif_running(dev));
return 0;
}
static const struct net_device_ops vnetdev_ops = {
.ndo_start_xmit = virt_net_send_packet,
.ndo_open = ndo_open,
.ndo_stop = ndo_stop,
};
static void add_self_netdev(void) {
int result;
eth = alloc_etherdev(16);
if (!eth) {
printk(KERN_ALERT "eth failed\n");
}
eth->netdev_ops = &vnetdev_ops;
memcpy(eth->name,"eth%d",3);
eth->dev_addr = "abcedf";
eth->flags |= IFF_NOARP | IFF_UP | IFF_RUNNING;
eth->features |= NETIF_F_IP_CSUM;
result = register_netdev(eth);
if (result) {
printk(KERN_ALERT "eth register failed\n");
}
}
static int fishing_init(void) {
printk(KERN_ALERT "init\n");
add_self_netdev();
return 0;
}
static void fishing_exit(void) {
printk(KERN_ALERT "exit\n");
unregister_netdev(eth);
free_netdev(eth);
}
module_init(fishing_init);
module_exit(fishing_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("shakespeare");
Makefile文件:
obj-m += fishing.o
DIR_KERNEL=/lib/modules/$(shell uname -r)/build/
KDIR=/usr/src/linux-headers-$(shell uname -r)/
PWD=$(shell pwd)
all:
make M=$(PWD) -C $(KDIR) modules
clean:
rm *.o *.ko *.mod.c *.mod *.order *.symvers
编译,并加载到内核。
开启网卡或关闭网卡,然后打印内核日志:
打开网卡,netif_running函数返回状态1,关闭网卡则返回0。