本文探讨有线网络。
嵌入式网络硬件分为两部分:MAC 和 PHY,大家都是通过看数据手册来判断一款 SoC 是否支持网络,如果一款芯片数据手册说自己支持网络,一般都是说的这款 SoC 内置 MAC,MAC 类似 I2C 控制器、SPI 控制器一样的外设。但是光有 MAC 还不能直接驱动网络,还需要另外一个芯片:PHY,因此对于内置 MAC 的 SoC,其外部必须搭配一个 PHY 芯片。但是有些 SoC 内部没有 MAC,那也就没法搭配 PHY 芯片了,这些内部没有网络 MAC 的芯片如何上网呢?这里就要牵扯出常见的两个嵌入式网络硬件方案了。
1、SOC 内部没有网络 MAC 外设
2、SOC 内部集成网络 MAC 外设
一般情况下是 SOC 内部 MAC+外置 PHY 芯片这种方案。
Linux 内核网络驱动框架
Linux 内核使用 net_device 结构体表示一个具体的网络设备,net_device 是整个网络驱动的灵魂。网络驱动的核心就是初始化 net_device 结构体中的各个成员变量,然后将初始化完成以后的 net_device 注册到 Linux 内核中。
2005 struct net_device {
2006 char name[IFNAMSIZ];
2007 struct netdev_name_node *name_node;
2008 struct dev_ifalias __rcu *ifalias;
2009 /*
2010 * I/O specific fields
2011 * FIXME: Merge these and struct ifmap into one
2012 */
2013 unsigned long mem_end;
2014 unsigned long mem_start;
2015 unsigned long base_addr;
2016
2022
2023 unsigned long state;
2024
2025 struct list_head dev_list;
2026 struct list_head napi_list;
2027 struct list_head unreg_list;
2028 struct list_head close_list;
2029 struct list_head ptype_all;
2030 struct list_head ptype_specific;
2031
2032 struct {
2033 struct list_head upper;
2034 struct list_head lower;
2035 } adj_list;
2036
2037 /* Read-mostly cache-line for fast-path access */
2038 unsigned int flags;
2039 unsigned int priv_flags;
2040 const struct net_device_ops *netdev_ops;
2041 int ifindex;
2042 unsigned short gflags;
2043 unsigned short hard_header_len;
2044
2045 /* Note : dev->mtu is often read without holding a lock.
2046 * Writers usually hold RTNL.
2047 * It is recommended to use READ_ONCE() to annotate the reads,
2048 * and to use WRITE_ONCE() to annotate the writes.
2049 */
2050 unsigned int mtu;
2051 unsigned short needed_headroom;
2052 unsigned short needed_tailroom;
2053
2054 netdev_features_t features;
2055 netdev_features_t hw_features;
2056 netdev_features_t wanted_features;
2057 netdev_features_t vlan_features;
2058 netdev_features_t hw_enc_features;
2059 netdev_features_t mpls_features;
2060 netdev_features_t gso_partial_features;
2061
2062 unsigned int min_mtu;
2063 unsigned int max_mtu;
2064 unsigned short type;
2065 unsigned char min_header_len;
2066 unsigned char name_assign_type;
2067
2068 int group;
2069
2070 struct net_device_stats stats; /* not used by modern drivers */
2071
2072 atomic_long_t rx_dropped;
2073 atomic_long_t tx_dropped;
2074 atomic_long_t rx_nohandler;
2075
2076 /* Stats to monitor link on/off, flapping */
2077 atomic_t carrier_up_count;
2078 atomic_t carrier_down_count;
2079
2080 #ifdef CONFIG_WIRELESS_EXT
2081 const struct iw_handler_def *wireless_handlers;
2082 struct iw_public_data *wireless_data;
2083 #endif
2084 const struct ethtool_ops *ethtool_ops;
2085 #ifdef CONFIG_NET_L3_MASTER_DEV
2086 const struct l3mdev_ops *l3mdev_ops;
2087 #endif
2088 #if IS_ENABLED(CONFIG_IPV6)
2089 const struct ndisc_ops *ndisc_ops;
2090 #endif
2091
2092 #ifdef CONFIG_XFRM_OFFLOAD
2093 const struct xfrmdev_ops *xfrmdev_ops;
2094 #endif
2095
2096 #if IS_ENABLED(CONFIG_TLS_DEVICE)
2097 const struct tlsdev_ops *tlsdev_ops;
2098 #endif
2099
2100 const struct header_ops *header_ops;
2101
2102 unsigned char operstate;
2103 unsigned char link_mode;
2104
2105 unsigned char if_port;
2106 unsigned char dma;
2107
2108 /* Interface address info. */
2109 unsigned char perm_addr[MAX_ADDR_LEN];
2110 unsigned char addr_assign_type;
2111 unsigned char addr_len;
2112 unsigned char upper_level;
2113 unsigned char lower_level;
2114
2175 /* Interface address info used in eth_type_trans() */
2176 unsigned char *dev_addr;
2177
2178 struct netdev_rx_queue *_rx;
2179 unsigned int num_rx_queues;
2180 unsigned int real_num_rx_queues;
2181
2205 struct netdev_queue *_tx ____cacheline_aligned_in_smp;
2206 unsigned int num_tx_queues;
2207 unsigned int real_num_tx_queues;
2208 struct Qdisc __rcu *qdisc;
2209 unsigned int tx_queue_len;
2210 spinlock_t tx_global_lock;
2211
2287 /* for setting kernel sock attribute on TCP connection setup */
2288 #define GSO_MAX_SIZE 65536
2289 unsigned int gso_max_size;
2290 #define GSO_MAX_SEGS 65535
2291 u16 gso_max_segs;
2292
2293 #ifdef CONFIG_DCB
2294 const struct dcbnl_rtnl_ops *dcbnl_ops;
2295 #endif
2296 s16 num_tc;
2297 struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE];
2298 u8 prio_tc_map[TC_BITMASK + 1];
2299
2300 #if IS_ENABLED(CONFIG_FCOE)
2301 unsigned int fcoe_ddp_xid;
2302 #endif
2303 #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
2304 struct netprio_map __rcu *priomap;
2305 #endif
2306 struct phy_device *phydev;
2307 struct sfp_bus *sfp_bus;
2334 };
2335 #define to_net_dev(d) container_of(d, struct net_device, dev)
name 是网络设备的名字。mem_end 是共享内存结束地址。mem_start 是共享内存起始地址。base_addr 是网络设备 I/O 地址。irq 是网络设备的中断号。dev_list 是全局网络设备列表。napi_list 是 napi 网络设备的列表入口。unreg_list 是注销(unregister)的网络设备列表入口。close_list 是关闭的网络设备列表入口。netdev_ops 是网络设备的操作集函数,包含了一系列的网络设备操作回调函数,类似字符设备中的 file_operations。ethtool_ops 是网络管理工具相关函数集,用户空间网络管理工具会调用此结构体中的相关函数获取网卡状态或者配置网卡。header_ops 是头部的相关操作函数集,比如创建、解析、缓冲等。flags 是网络接口标志。if_port 指定接口的端口类型。dma 是网络设备所使用的 DMA 通道,不是所有的设备都会用到 DMA。mtu 是网络最大传输单元,为 1500。type 用于指定 ARP 模块的类型。perm_addr 是永久的硬件地址,如果某个网卡设备有永久的硬件地址,那么就会填充 perm_addr。addr_len 是硬件地址长度。dev_addr 也是硬件地址,是当前分配的 MAC 地址,可以通过软件修改。_rx 是接收队列。num_rx_queues 是接收队列数量,在调用 register_netdev 注册网络设备的时候会分配指定数量的接收队列。real_num_rx_queues 是当前活动的队列数量。_tx 是发送队列。num_tx_queues 是发送队列数量,通过 alloc_netdev_mq 函数分配指定数量的发送队列。real_num_tx_queues 是当前有效的发送队列数量。phydev 是对应的 PHY 设备。
申请 net_device:alloc_netdev
删除 net_device:free_netdev
注册 net_device:register_netdev
注销 net_device:unregister_netdev
net_device 有个非常重要的成员变量:netdev_ops,为 net_device_ops 结构体指针类型,这就是网络设备的操作集,net_device_ops 结构体里面都是一些以“ndo_”开头的函数,这些函数就需要网络驱动人员去实现,不需要全部都实现,根据实际驱动情况实现其中一小部分即可。
1395 struct net_device_ops {
1396 int (*ndo_init)(struct net_device *dev);
1397 void (*ndo_uninit)(struct net_device *dev);
1398 int (*ndo_open)(struct net_device *dev);
1399 int (*ndo_stop)(struct net_device *dev);
1400 netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb,
1401 struct net_device *dev);
1402 netdev_features_t (*ndo_features_check)(struct sk_buff *skb,
1403 struct net_device *dev,
1404 netdev_features_t features);
1405 u16 (*ndo_select_queue)(struct net_device *dev,
1406 struct sk_buff *skb,
1407 struct net_device *sb_dev);
1408 void (*ndo_change_rx_flags)(struct net_device *dev,
1409 int flags);
1410 void (*ndo_set_rx_mode)(struct net_device *dev);
1411 int (*ndo_set_mac_address)(struct net_device *dev,
1412 void *addr);
1413 int (*ndo_validate_addr)(struct net_device *dev);
1414 int (*ndo_do_ioctl)(struct net_device *dev,
1415 struct ifreq *ifr, int cmd);
1416 int (*ndo_eth_ioctl)(struct net_device *dev,
1417 struct ifreq *ifr, int cmd);
1418 int (*ndo_siocbond)(struct net_device *dev,
1419 struct ifreq *ifr, int cmd);
1420 int (*ndo_siocwandev)(struct net_device *dev,
1421 struct if_settings *ifs);
1422 int (*ndo_siocdevprivate)(struct net_device *dev,
1423 struct ifreq *ifr,
1424 void __user *data, int cmd);
1425 int (*ndo_set_config)(struct net_device *dev,
1426 struct ifmap *map);
1427 int (*ndo_change_mtu)(struct net_device *dev,
1428 int new_mtu);
1429 int (*ndo_neigh_setup)(struct net_device *dev,
1430 struct neigh_parms *);
1431 void (*ndo_tx_timeout) (struct net_device *dev,
1432 unsigned int txqueue);
1433
1446 #ifdef CONFIG_NET_POLL_CONTROLLER
1447 void (*ndo_poll_controller)(struct net_device *dev);
1448 int (*ndo_netpoll_setup)(struct net_device *dev,
1449 struct netpoll_info *info);
1450 void (*ndo_netpoll_cleanup)(struct net_device *dev);
1451 #endif
1521 int (*ndo_add_slave)(struct net_device *dev,
1522 struct net_device *slave_dev,
1523 struct netlink_ext_ack *extack);
1524 int (*ndo_del_slave)(struct net_device *dev,
1525 struct net_device *slave_dev);
1526 struct net_device* (*ndo_get_xmit_slave)(struct net_device *dev,
1527 struct sk_buff *skb,
1528 bool all_slaves);
1529 struct net_device* (*ndo_sk_get_lower_dev)(struct net_device *dev,
1530 struct sock *sk);
1531 netdev_features_t (*ndo_fix_features)(struct net_device *dev,
1532 netdev_features_t features);
1533 int (*ndo_set_features)(struct net_device *dev,
1534 netdev_features_t features);
1622 };
ndo_init 函数,当第一次注册网络设备的时候此函数会执行,设备可以在此函数中
做一些需要推后初始化的内容,不过一般驱动中不使用此函数,虚拟网络设备可能会使用。
ndo_uninit 函数,卸载网络设备的时候此函数会执行。
do_open 函数,打开网络设备的时候此函数会执行,网络驱动程序需要实现此函数,非常重要!
ndo_stop 函数,关闭网络设备的时候此函数会执行,网络驱动程序也需要实现此函数。
ndo_start_xmit 函数,当需要发送数据的时候此函数就会执行,此函数有一个参数
为 sk_buff 结构体指针,sk_buff 结构体在 Linux 的网络驱动中非常重要,sk_buff 保存了上层传递给网络驱动层的数据。也就是说,要发送出去的数据都存在了 sk_buff 中,关于 sk_buff 稍后会做详细的讲解。如果发送成功的话此函数返回 NETDEV_TX_OK,如果发送失败了就返回 NETDEV_TX_BUSY,如果发送失败了我们就需要停止队列。
do_select_queue 函数,当设备支持多传输队列的时候选择使用哪个队列。
ndo_set_rx_mode 函数,此函数用于改变地址过滤列表,根据 net_device 的 flags
成员变量来设置 SoC 的网络外设寄存器。比如 flags 可能为 IFF_PROMISC、IFF_ALLMULTI 或 IFF_MULTICAST,分别表示混杂模式、单播模式或多播模式。
ndo_set_mac_address 函数,此函数用于修改网卡的 MAC 地址,设置 net_device
的 dev_addr 成员变量,并且将 MAC 地址写入到网络外设的硬件寄存器中。
ndo_validate_addr 函数,验证 MAC 地址是否合法,也即是验证 net_device 的
dev_addr 中的 MAC 地址是否合法,直接调用 is_valid_ether_addr 函数。
ndo_do_ioctl 函数,用户程序调用 ioctl 的时候此函数就会执行,比如 PHY 芯片
相关的命令操作,一般会直接调用 phy_mii_ioctl 函数。
ndo_change_mtu 函数,更改 MTU 大小。
ndo_tx_timeout 函数,当发送超时的时候产生会执行,一般都是网络出问题了导
致发送超时。一般可能会重启 MAC 和 PHY,重新开始数据发送等。
ndo_poll_controller 函数,使用查询方式来处理网卡数据的收发。
ndo_set_features 函数,修改 net_device 的 features 属性,设置相应的硬件属性。