目录
本专栏文章将有70篇左右,欢迎+关注,查看后续文章。
12.7 网络设备层
12.7.1 网络设备的表示
struct net_device:表示一个网络设备。
按命名空间管理。
net_device 初始化步骤:
1. 分配并初始化net_device。
2. 调用 register_netdev 注册 net_device。
将创建 /sys/class/net/。
1. 数据结构
内核如何管理网络设备?
1. 所有net_device 都在单链表 dev_base 中。
2. 按设备名为hash索引的数组。
struct net_device *dev_get_by_name(struct net *net, const char *name);
3. 按 interface index为 hash索引的数组。
struct net_device *dev_get_by_index(struct net *net, int ifindex);
struct net_device {
char name[IFNAMSIZ]; // 设备名。
struct hlist_node name_hlist; // 连接到设备名的hash表。
//设备IO
unsigned long mem_end;
unsigned long mem_start;
unsigned long base_addr;
unsigned int irq; // 设备中断号。
unsigned long state; // 如:STAR,PRESENT,NOCARRIER。
int (*init)(struct net_device *dev);
int ifindex; // 被dev_get_by_index 函数使用。
struct net_device_stats * (*get_stats)(struct net_device *dev);
// 网卡驱动自定义实现,获取网卡统计信息。
struct header_ops *header_ops;
// 包含协议头创建、解析、重建函数指针。
// 包含create,parse,rebuild等函数。
unsigned short flags;
unsigned mtu;
unsigned short type;
// 如:ARPHRD_ETHER,ARPHRD_LOOPBACK
unsigned short hard_header_len;
unsigned char addr_len; // MAC地址长度。
unsigned long last_rx // 接收时间 jiffies。
unsigned long trans_start // 发送时间。
unsigned char dev_addr[MAX_ADDR_LEN]; // 硬件地址,如MAC地址。
unsigned char broadcast[MAX_ADDR_LEN]; // 多播地址。
int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);
// 驱动各自实现,发送报文,完成后从队列中删除。
int (*open)(struct net_device *dev);
// 初始化硬件。包括注册irq,DMA,IO端口等资源。
int (*stop)(struct net_device *dev);
int (*set_mac_address)(struct net_device *dev);
int (*do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
// 如SIOCGIFHWADDR:设置网卡硬件地址。
int (*change_mtu)(struct net_device *dev, int new_mtu);
int (*tx_timeout)(struct net_device *dev);
struct net *nd_net; // 所在命名空间。
struct device dev; // /sys/class/net/name项。
}
上述函数指针由不同网卡驱动自定义。
struct header_ops eth_header_ops = {
.create = eth_header, // 创建以太网头。
.parse = eth_header_parse, // 获取报文源MAC。
.rebuild = eth_rebuild_header,
// dev_queue_xmit 发包时,调用该函数完成以太网头封装(涉及ARP表查找)
};
2. 注册网络设备
注册流程:
1. 分配 net_device,并初始化。
以太网设备为例:
netdev = alloc_netdev( sizeof(Tipster), "eth%d", ether_setup);
初始化 net_device 通用成员,然后调用 ether_setup 继续初始化。
2. 注册net_device
register_netdev 或 register_netdevice
两者区别:
register_netdev 可以指定 eth%d
register_netdevice流程: