Linux内核中以太网设备处理逻辑(1)-设备初始化

网友投稿 853 2022-10-12


Linux内核中以太网设备处理逻辑(1)-设备初始化

Linux内核中以太网设备处理逻辑

INET是Linux操作系统的TCP/IP协议套件的实现,INET使用BSD Socket接口作为与用户进程通信的手段。本文主要介绍以太网类型的设备处理过程,内核源码位于net/ethernet/eth.c文件中。

初始化以太网设备

// header_ops包含一系列函数指针,主要是对链路层协议头的操作,比如协议头的创建、解析、缓存等。 const struct header_ops eth_header_ops ____cacheline_aligned = { // 创建协议头函数 .create = eth_header, // 解析以太网源mac地址字段函数 .parse = eth_header_parse, // 根据arp查询的结果,构造hh_cache,供邻居子系统使用 .cache = eth_header_cache, // 更新hh_cache中的以太网头 .cache_update = eth_header_cache_update, // 解析以太网协议字段函数 .parse_protocol = eth_header_parse_protocol, }; // 初始化以太网设备,使用通用值填充以太网设备结构各字段 /** * ether_setup - setup Ethernet network device * @dev: network device * * Fill in the fields of the device structure with Ethernet-generic values. */ void ether_setup(struct net_device *dev) { // 链路层协议头操作函数 dev->header_ops = ð_header_ops; // 接口的硬件类型,这个type成员由ARP用来决定接口支持什么样的硬件地址,对以太网接口正确的值是ARPHRD_ETHER dev->type = ARPHRD_ETHER; // 链路层头部长度,14字节 dev->hard_header_len = ETH_HLEN; dev->min_header_len = ETH_HLEN; // MTU默认1500字节,最小68字节 dev->mtu = ETH_DATA_LEN; dev->min_mtu = ETH_MIN_MTU; dev->max_mtu = ETH_DATA_LEN; // 单个MAC地址长度 dev->addr_len = ETH_ALEN; // 设备发送队列中可以排队的最大帧数,默认1000 dev->tx_queue_len = DEFAULT_TX_QUEUE_LEN; // 使能广播地址和组播地址 dev->flags = IFF_BROADCAST|IFF_MULTICAST; // 私有flags,发送方向共享skb dev->priv_flags |= IFF_TX_SKB_SHARING; // 设置链路层广播地址:FF:FF:FF:FF:FF:FF eth_broadcast_addr(dev->broadcast); } EXPORT_SYMBOL(ether_setup);

协议头创建

/** * eth_header - create the Ethernet header * @skb: buffer to alter * @dev: source device * @type: Ethernet type field * @daddr: destination address (NULL leave destination address) * @saddr: source address (NULL use device source address) * @len: packet length (<= skb->len) * * * Set the protocol type. For a packet of type ETH_P_802_3/2 we put the length * in here instead. */ int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *daddr, const void *saddr, unsigned int len) { // 为以太网头准备空间,data指针指向以太网头部 struct ethhdr *eth = skb_push(skb, ETH_HLEN); // 通用Ethernet II型帧 if (type != ETH_P_802_3 && type != ETH_P_802_2) eth->h_proto = htons(type); else // IEEE 802.2或802.3型帧,协议字段为包长 eth->h_proto = htons(len); /* * Set the source hardware address. */ // 设置源mac地址,未指定则赋值为设备接口mac地址 if (!saddr) saddr = dev->dev_addr; memcpy(eth->h_source, saddr, ETH_ALEN); // 设置目的mac地址 if (daddr) { memcpy(eth->h_dest, daddr, ETH_ALEN); return ETH_HLEN; } /* * Anyway, the loopback-device should never use this function... */ // LOOPBACK接口或者未开启arp协议,则清空目的mac地址 if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { eth_zero_addr(eth->h_dest); return ETH_HLEN; } return -ETH_HLEN; } EXPORT_SYMBOL(eth_header);

解析以太网源mac地址

/** * eth_header_parse - extract hardware address from packet * @skb: packet to extract header from * @haddr: destination buffer */ int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) { // 获取以太网头 const struct ethhdr *eth = eth_hdr(skb); // 提取源mac地址 memcpy(haddr, eth->h_source, ETH_ALEN); return ETH_ALEN; } EXPORT_SYMBOL(eth_header_parse);

解析以太网协议字段

/** * eth_header_parse_protocol - extract protocol from L2 header * @skb: packet to extract protocol from */ __be16 eth_header_parse_protocol(const struct sk_buff *skb) { // 获取以太网头 const struct ethhdr *eth = eth_hdr(skb); // 提取以太网协议字段 return eth->h_proto; } EXPORT_SYMBOL(eth_header_parse_protocol);

缓存链路层信息

根据arp查询的结果,构造hh_cache,供邻居子系统使用。

/** * eth_header_cache - fill cache entry from neighbour * @neigh: source neighbour * @hh: destination cache entry * @type: Ethernet type field * * Create an Ethernet header template from the neighbour. */ int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh, __be16 type) { struct ethhdr *eth; const struct net_device *dev = neigh->dev; // 获取缓存中以太网头位置 eth = (struct ethhdr *) (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); if (type == htons(ETH_P_802_3)) return -1; // 设置缓存中以太网协议,源mac,目的mac eth->h_proto = type; // 源mac为设备接口mac地址 memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); // 目的mac为邻居子系统解析到的下一跳mac地址 memcpy(eth->h_dest, neigh->ha, ETH_ALEN); /* Pairs with READ_ONCE() in neigh_resolve_output(), * neigh_hh_output() and neigh_update_hhs(). */ smp_store_release(&hh->hh_len, ETH_HLEN); return 0; } EXPORT_SYMBOL(eth_header_cache);

更新链路层缓存信息

根据arp查询的结果,更新hh_cache,供邻居子系统使用。

/** * eth_header_cache_update - update cache entry * @hh: destination cache entry * @dev: network device * @haddr: new hardware address * * Called by Address Resolution module to notify changes in address. */ void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev, const unsigned char *haddr) { // 由ARP结果更新缓存中对应项的mac地址 memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), haddr, ETH_ALEN); } EXPORT_SYMBOL(eth_header_cache_update);


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:HTTP/HTTPS
下一篇:无线通信数据终端在飞机维修机库大门无线控制系统中的应用
相关文章

 发表评论

暂时没有评论,来抢沙发吧~