20150419 IMX257虚拟网卡vnet驱动程序
2015-04-19 Lover雪儿
一、一个简单的虚拟网卡驱动
1 static struct net_device *vnet_dev; //定义一个网络设备结构体
2
3
4 static const struct net_device_ops virt_netdev_ops = {
5 .ndo_start_xmit = NULL,
6 };
7
8
9 static int virt_net_init(void){
10
11 /* 1.分配一个net_device结构体 */
12 vnet_dev = alloc_netdev(0,"vnet%d",ether_setup); //私有数据为0,
13 /* 2.设置 */
14 vnet_dev->netdev_ops = &virt_netdev_ops;
15 /* 3.注册 */
16 //register_netdevice(vnet_dev); //会报锁的错误
17 register_netdev(vnet_dev); //rtnl_lock();
18 return 0;
19 }
20
21 static void virt_net_exit(void){
22 if(vnet_dev){
23 unregister_netdev(vnet_dev);
24 free_netdev(vnet_dev);
25 }
26 }
27
28 module_init(virt_net_init);
29 module_exit(virt_net_exit);
30 MODULE_AUTHOR("Lover雪儿");
31 MODULE_LICENSE("GPL");
如上面程序所示,定义分配一个net_device结构体,注册结构体,这样就实现了一个简单的虚拟网卡驱动。
实现效果:
如图所示,在/sys/class/net/目录下多生成了一个vnet0的文件夹
附驱动程序virt_net1.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17
18 #include
19 #include
20 #include
21
22 static struct net_device *vnet_dev; //定义一个网络设备结构体
23
24
25 static const struct net_device_ops virt_netdev_ops = {
26 .ndo_start_xmit = NULL,
27 };
28
29
30 static int virt_net_init(void){
31
32 /* 1.分配一个net_device结构体 */
33 vnet_dev = alloc_netdev(0,"vnet%d",ether_setup); //私有数据为0,
34 /* 2.设置 */
35 vnet_dev->netdev_ops = &virt_netdev_ops;
36 /* 3.注册 */
37 //register_netdevice(vnet_dev); //会报锁的错误
38 register_netdev(vnet_dev); //rtnl_lock();
39 return 0;
40 }
41
42 static void virt_net_exit(void){
43 if(vnet_dev){
44 unregister_netdev(vnet_dev);
45 free_netdev(vnet_dev);
46 }
47 }
48
49 module_init(virt_net_init);
50 module_exit(virt_net_exit);
51 MODULE_AUTHOR("Lover雪儿");
52 MODULE_LICENSE("GPL");
53
54
55 /*
56
57 /////////////////////////////////////////////////////////////////////
58 网卡驱动程序框架:
59 app: socket
60 --------------------------------------------------------------------
61 -----------------
62 ----------------- 若干层网络协议--纯软件
63 -----------------
64 hard_start_xmit() 用于发送数据包 ↑↑↑
65 ↓↓↓ sk_buff netif_rx()用于上报数据包
66 调用硬件相关的驱动程序(要提供har_start_xmit,有数据时用netif_rx上报)
67 --------------------------------------------------------------------
68 硬件
69 //////////////////////////////////////////////////////////////////////
70
71 网卡驱动编写:
72 1.分配一个net_device结构体
73 2.设置
74 2.1 发包函数:hard_start_xmit
75 2.2 收到到数据时,(在中断处理函数中)用netif_rx上报数据
76 2.3 其他设置
77 3.注册 register_netdevice
78
79
80 一、测试1th
81 insmod virt_net.ko
82 ifconfig vnet0 3.3.3.3
83 ping 3.3.3.3
84 ping 3.3.3.4 看效果
85
86
87 */
virt_net1.c
二、增加ping功能
下面是我画的一个网卡驱动程序框架。
所以此处我们增加一个发送数据包的函数 hard_start_xmit用于转发数据包。
1.在net_device结构体下定义hard_start_xmit。
vnet_dev->hard_start_xmit = vir_net_send_packet;
2.实现vir_net_send_packet函数
此处我们的代码只是增加一些打印语句,以便确定当我们ping的时候,是否会调用该函数。
1 //转发发送数据包
2 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev){
3 static int cnt = 0;
4 printk("vir_net_send_packet cnt = %d\n",++cnt);
5 return 0;
6 }
7
8 static const struct net_device_ops virt_netdev_ops = {
9 .ndo_start_xmit = virt_net_send_packet,
10 };
11 //接着在入口函数中增加net_device_ops
12
13 vnet_dev->netdev_ops = &virt_netdev_ops;
实现效果:
ping 测试:
附驱动程序virt_net2.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17
18 #include
19 #include
20 #include
21
22 static struct net_device *vnet_dev; //定义一个网络设备结构体
23
24 //转发发送数据包
25 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev){
26 static int cnt = 0;
27 printk("vir_net_send_packet cnt = %d\n",++cnt);
28 return 0;
29 }
30
31 static const struct net_device_ops virt_netdev_ops = {
32 .ndo_start_xmit = virt_net_send_packet,
33 };
34
35
36 static int virt_net_init(void){
37
38 /* 1.分配一个net_device结构体 */
39 vnet_dev = alloc_netdev(0,"vnet%d",ether_setup); //私有数据为0,
40 /* 2.设置 */
41 vnet_dev->netdev_ops = &virt_netdev_ops;
42 /* 3.注册 */
43 //register_netdevice(vnet_dev); //会报锁的错误
44 register_netdev(vnet_dev); //rtnl_lock();
45 return 0;
46 }
47
48 static void virt_net_exit(void){
49 if(vnet_dev){
50 unregister_netdev(vnet_dev);
51 free_netdev(vnet_dev);
52 }
53 }
54
55 module_init(virt_net_init);
56 module_exit(virt_net_exit);
57 MODULE_AUTHOR("Lover雪儿");
58 MODULE_LICENSE("GPL");
59
60
61 /*
62
63 /////////////////////////////////////////////////////////////////////
64 网卡驱动程序框架:
65 app: socket
66 --------------------------------------------------------------------
67 -----------------
68 ----------------- 若干层网络协议--纯软件
69 -----------------
70 hard_start_xmit() 用于发送数据包 ↑↑↑
71 ↓↓↓ sk_buff netif_rx()用于上报数据包
72 调用硬件相关的驱动程序(要提供har_start_xmit,有数据时用netif_rx上报)
73 --------------------------------------------------------------------
74 硬件
75 //////////////////////////////////////////////////////////////////////
76
77 网卡驱动编写:
78 1.分配一个net_device结构体
79 2.设置
80 2.1 发包函数:hard_start_xmit
81 2.2 收到到数据时,(在中断处理函数中)用netif_rx上报数据
82 2.3 其他设置
83 3.注册 register_netdevice
84
85
86 一、测试1th
87 insmod virt_net.ko
88 ifconfig vnet0 3.3.3.3
89 ping 3.3.3.3
90 ping 3.3.3.4 看效果
91
92 */
virt_net2.c
三、增加数据包的统计,设置MAC地址
有关于数据包的统计信息定义在net_device结构体的stats结构体下,主要是定义了收发数据包的个数,字节数,时间等。此处,我们就增加一个统计发送数据包的个数,以及字节数。
stats结构体如下:
发送数据包的统计
struct net_device_stats
{
unsigned long rx_packets; / * total packets received * /
unsigned long tx_packets; / * total packets transmitted * /
unsigned long rx_bytes; / * total bytes received * /
unsigned long tx_bytes; / * total bytes transmitted * /
unsigned long rx_errors; / * bad packets received * /
unsigned long tx_errors; / * packet transmit probls * /
unsigned long rx_dropped; / * no space in linux buffers * /
unsigned long tx_dropped; / * no space available in linux * /
unsigned long multicast; / * multicast packets received * /
unsigned long collisions;
/ * detailed rx_errors: * /
unsigned long rx_length_errors;
unsigned long rx_over_errors; / * receiver ring buff overflow * /
unsigned long rx_crc_errors; / * recved pkt with crc error * /
unsigned long rx_frame_errors; / * recv'd frame alignment error * /
unsigned long rx_fifo_errors; / * recv'r fifo overrun * /
unsigned long rx_missed_errors; / * receiver missed packet * /
/ * detailed tx_errors * /
unsigned long tx_aborted_errors;
unsigned long tx_carrier_errors;
unsigned long tx_fifo_errors;
unsigned long tx_heartbeat_errors;
unsigned long tx_window_errors;
/ * for cslip etc * /
unsigned long rx_compressed;
unsigned long tx_compressed;
};
接下来就是在virt_net_send_packet实现数据包的自加。
1 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)
2 {
3 static int cnt = 0;
4 printk("virt_net_send_packet cnt = %d\n", ++cnt);
5
6 /* 更新统计信息 */
7 dev->stats.tx_packets++;
8 dev->stats.tx_bytes += skb->len;
9
10 return 0;
11 }
设置mac地址
1 static int virt_net_init(void)
2 {
3 /* 1. 分配一个net_device结构体 */
4 vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);; /* alloc_etherdev */
5
6 /* 2. 设置 */
7 vnet_dev->netdev_ops = &virt_netdev_ops;
8
9 /* 设置MAC地址 */
10 vnet_dev->dev_addr[0] = 0x08;
11 vnet_dev->dev_addr[1] = 0x89;
12 vnet_dev->dev_addr[2] = 0x89;
13 vnet_dev->dev_addr[3] = 0x89;
14 vnet_dev->dev_addr[4] = 0x89;
15 vnet_dev->dev_addr[5] = 0x11;
16
17 /* 设置下面两项才能ping通 */
18 //vnet_dev->flags |= IFF_NOARP;
19 //vnet_dev->features |= NETIF_F_NO_CSUM;
20
21 /* 3. 注册 */
22 //register_netdevice(vnet_dev);
23 register_netdev(vnet_dev);
24
25 return 0;
26 }
实现效果:
附驱动程序virt_net3.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #include
18 #include
19
20 #include
21 #include
22 #include
23
24 static struct net_device *vnet_dev;
25
26
27 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)
28 {
29 static int cnt = 0;
30 printk("virt_net_send_packet cnt = %d\n", ++cnt);
31
32 /* 更新统计信息 */
33 dev->stats.tx_packets++;
34 dev->stats.tx_bytes += skb->len;
35
36 return 0;
37 }
38
39 static const struct net_device_ops virt_netdev_ops = {
40 .ndo_start_xmit = virt_net_send_packet,
41 };
42
43 static int virt_net_init(void)
44 {
45 /* 1. 分配一个net_device结构体 */
46 vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);; /* alloc_etherdev */
47
48 /* 2. 设置 */
49 vnet_dev->netdev_ops = &virt_netdev_ops;
50
51 /* 设置MAC地址 */
52 vnet_dev->dev_addr[0] = 0x08;
53 vnet_dev->dev_addr[1] = 0x89;
54 vnet_dev->dev_addr[2] = 0x89;
55 vnet_dev->dev_addr[3] = 0x89;
56 vnet_dev->dev_addr[4] = 0x89;
57 vnet_dev->dev_addr[5] = 0x11;
58
59 /* 设置下面两项才能ping通 */
60 //vnet_dev->flags |= IFF_NOARP;
61 //vnet_dev->features |= NETIF_F_NO_CSUM;
62
63 /* 3. 注册 */
64 //register_netdevice(vnet_dev);
65 register_netdev(vnet_dev);
66
67 return 0;
68 }
69
70 static void virt_net_exit(void)
71 {
72 unregister_netdev(vnet_dev);
73 free_netdev(vnet_dev);
74 }
75
76 module_init(virt_net_init);
77 module_exit(virt_net_exit);
78 MODULE_AUTHOR("Lover雪儿");
79 MODULE_LICENSE("GPL");
80
81
82 /*
83
84 /////////////////////////////////////////////////////////////////////
85 网卡驱动程序框架:
86 app: socket
87 --------------------------------------------------------------------
88 -----------------
89 ----------------- 若干层网络协议--纯软件
90 -----------------
91 hard_start_xmit() 用于发送数据包 ↑↑↑
92 ↓↓↓ sk_buff netif_rx()用于上报数据包
93 调用硬件相关的驱动程序(要提供har_start_xmit,有数据时用netif_rx上报)
94 --------------------------------------------------------------------
95 硬件
96 //////////////////////////////////////////////////////////////////////
97
98 网卡驱动编写:
99 1.分配一个net_device结构体
100 2.设置
101 2.1 发包函数:hard_start_xmit
102 2.2 收到到数据时,(在中断处理函数中)用netif_rx上报数据
103 2.3 其他设置
104 3.注册 register_netdevice
105
106
107 一、测试1th
108 insmod virt_net.ko
109 ifconfig vnet0 3.3.3.3
110 ping 3.3.3.3
111 ping 3.3.3.4 看效果
112
113 */
virt_net3.c
四、模拟回环网卡程序,实现数据包的收发过程
前面我们已经实现了转发数据包的功能,此处我们增加一个接受数据包的功能。
如程序中所示,主要就是交换数据包中的源目的MAC头信息,源目的IP信息等功能。
1 static void emulator_rx_packet(struct sk_buff *skb, struct net_device *dev)
2 {
3 /* 参考LDD3 */
4 unsigned char *type;
5 struct iphdr *ih;
6 __be32 *saddr, *daddr, tmp;
7 unsigned char tmp_dev_addr[ETH_ALEN];
8 struct ethhdr *ethhdr;
9
10 struct sk_buff *rx_skb;
11
12 // 从硬件读出/保存数据
13 /* 对调"源/目的"的mac地址 */
14 ethhdr = (struct ethhdr *)skb->data;
15 memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);
16 memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);
17 memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);
18
19 /* 对调"源/目的"的ip地址 */
20 ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
21 saddr = &ih->saddr;
22 daddr = &ih->daddr;
23
24 tmp = *saddr;
25 *saddr = *daddr;
26 *daddr = tmp;
27
28 //((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */
29 //((u8 *)daddr)[2] ^= 1;
30 type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);
31 //printk("tx package type = %02x\n", *type);
32 // 修改类型, 原来0x8表示ping
33 *type = 0; /* 0表示reply */
34
35 ih->check = 0; /* and rebuild the checksum (ip needs it) */
36 ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
37
38 // 构造一个sk_buff
39 rx_skb = dev_alloc_skb(skb->len + 2);
40 skb_reserve(rx_skb, 2); /* align IP on 16B boundary */
41 memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);
42
43 /* Write metadata, and then pass to the receive level */
44 rx_skb->dev = dev;
45 rx_skb->protocol = eth_type_trans(rx_skb, dev);
46 rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
47 dev->stats.rx_packets++;
48 dev->stats.rx_bytes += skb->len;
49
50 // 提交sk_buff
51 netif_rx(rx_skb);
52 }
接着在发送数据包函数中:
1 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)
2 {
3 static int cnt = 0;
4 //printk("virt_net_send_packet cnt = %d\n", ++cnt);
5
6 /* 对于真实的网卡, 把skb里的数据通过网卡发送出去 */
7 netif_stop_queue(dev); /* 停止该网卡的队列 */
8 /* ...... */ /* 把skb的数据写入网卡 */
9
10 /* 构造一个假的sk_buff,上报 */
11 emulator_rx_packet(skb, dev);
12
13 dev_kfree_skb (skb); /* 释放skb */
14 netif_wake_queue(dev); /* 数据全部发送出去后,唤醒网卡的队列 */
15
16 /* 更新统计信息 */
17 dev->stats.tx_packets++;
18 dev->stats.tx_bytes += skb->len;
19
20 return 0;
21 }
实现效果:
附驱动程序virt_net4.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #include
18 #include
19
20 #include
21 #include
22 #include
23
24 static struct net_device *vnet_dev;
25
26 static void emulator_rx_packet(struct sk_buff *skb, struct net_device *dev)
27 {
28 /* 参考LDD3 */
29 unsigned char *type;
30 struct iphdr *ih;
31 __be32 *saddr, *daddr, tmp;
32 unsigned char tmp_dev_addr[ETH_ALEN];
33 struct ethhdr *ethhdr;
34
35 struct sk_buff *rx_skb;
36
37 // 从硬件读出/保存数据
38 /* 对调"源/目的"的mac地址 */
39 ethhdr = (struct ethhdr *)skb->data;
40 memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);
41 memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);
42 memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);
43
44 /* 对调"源/目的"的ip地址 */
45 ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
46 saddr = &ih->saddr;
47 daddr = &ih->daddr;
48
49 tmp = *saddr;
50 *saddr = *daddr;
51 *daddr = tmp;
52
53 //((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */
54 //((u8 *)daddr)[2] ^= 1;
55 type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);
56 //printk("tx package type = %02x\n", *type);
57 // 修改类型, 原来0x8表示ping
58 *type = 0; /* 0表示reply */
59
60 ih->check = 0; /* and rebuild the checksum (ip needs it) */
61 ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
62
63 // 构造一个sk_buff
64 rx_skb = dev_alloc_skb(skb->len + 2);
65 skb_reserve(rx_skb, 2); /* align IP on 16B boundary */
66 memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);
67
68 /* Write metadata, and then pass to the receive level */
69 rx_skb->dev = dev;
70 rx_skb->protocol = eth_type_trans(rx_skb, dev);
71 rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
72 dev->stats.rx_packets++;
73 dev->stats.rx_bytes += skb->len;
74
75 // 提交sk_buff
76 netif_rx(rx_skb);
77 }
78
79 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)
80 {
81 static int cnt = 0;
82 //printk("virt_net_send_packet cnt = %d\n", ++cnt);
83
84 /* 对于真实的网卡, 把skb里的数据通过网卡发送出去 */
85 netif_stop_queue(dev); /* 停止该网卡的队列 */
86 /* ...... */ /* 把skb的数据写入网卡 */
87
88 /* 构造一个假的sk_buff,上报 */
89 emulator_rx_packet(skb, dev);
90
91 dev_kfree_skb (skb); /* 释放skb */
92 netif_wake_queue(dev); /* 数据全部发送出去后,唤醒网卡的队列 */
93
94 /* 更新统计信息 */
95 dev->stats.tx_packets++;
96 dev->stats.tx_bytes += skb->len;
97
98 return 0;
99 }
100
101 static const struct net_device_ops virt_netdev_ops = {
102 .ndo_start_xmit = virt_net_send_packet,
103 };
104
105 static int virt_net_init(void)
106 {
107 /* 1. 分配一个net_device结构体 */
108 vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);; /* alloc_etherdev */
109
110 /* 2. 设置 */
111 vnet_dev->netdev_ops = &virt_netdev_ops;
112
113 /* 设置MAC地址 */
114 vnet_dev->dev_addr[0] = 0x08;
115 vnet_dev->dev_addr[1] = 0x89;
116 vnet_dev->dev_addr[2] = 0x89;
117 vnet_dev->dev_addr[3] = 0x89;
118 vnet_dev->dev_addr[4] = 0x89;
119 vnet_dev->dev_addr[5] = 0x11;
120
121 /* 设置下面两项才能ping通 */
122 vnet_dev->flags |= IFF_NOARP;
123 vnet_dev->features |= NETIF_F_NO_CSUM;
124
125 /* 3. 注册 */
126 //register_netdevice(vnet_dev);
127 register_netdev(vnet_dev);
128
129 return 0;
130 }
131
132 static void virt_net_exit(void)
133 {
134 unregister_netdev(vnet_dev);
135 free_netdev(vnet_dev);
136 }
137
138 module_init(virt_net_init);
139 module_exit(virt_net_exit);
140 MODULE_AUTHOR("Lover雪儿");
141 MODULE_LICENSE("GPL");
142
143
144 /*
145
146 /////////////////////////////////////////////////////////////////////
147 网卡驱动程序框架:
148 app: socket
149 --------------------------------------------------------------------
150 -----------------
151 ----------------- 若干层网络协议--纯软件
152 -----------------
153 hard_start_xmit() 用于发送数据包 ↑↑↑
154 ↓↓↓ sk_buff netif_rx()用于上报数据包
155 调用硬件相关的驱动程序(要提供har_start_xmit,有数据时用netif_rx上报)
156 --------------------------------------------------------------------
157 硬件
158 //////////////////////////////////////////////////////////////////////
159
160 网卡驱动编写:
161 1.分配一个net_device结构体
162 2.设置
163 2.1 发包函数:hard_start_xmit
164 2.2 收到到数据时,(在中断处理函数中)用netif_rx上报数据
165 2.3 其他设置
166 3.注册 register_netdevice
167
168
169 一、测试1th
170 insmod virt_net.ko
171 ifconfig vnet0 3.3.3.3
172 ping 3.3.3.3
173 ping 3.3.3.4 看效果
174
175
176 */
virt_net4.c