网络设备驱动
一、网络驱动结构
应用 (socket)
↓
AF_INET / AF_PACKET
↓
TCP / UDP / IP / ...
↓
邻居子系统、L3 处理
↓
dev_queue_xmit(发送)
↓
NAPI / netif_rx(接收)
↓
驱动
↓
网卡硬件
二、关键数据结构
1. struct net_device
struct net_device {
char name[IFNAMSIZ]; // eth0, wlan0...
unsigned long state;
struct net_device_stats stats; // 统计
const struct net_device_ops *netdev_ops;
const struct ethtool_ops *ethtool_ops;
struct list_head dev_list;
// ...
};
2. struct sk_buff(socket buffer)
struct sk_buff {
struct net_device *dev;
__u16 protocol; // ETH_P_IP...
__be16 layer_4_proto; // TCP/UDP
unsigned int len;
unsigned int data_len;
__u8 *data; // 当前指针
__u8 *head;
__u8 *tail;
__u8 *end;
struct sk_buff *next;
// ...
};
3. struct net_device_ops
struct net_device_ops {
int (*ndo_open)(struct net_device *dev);
int (*ndo_stop)(struct net_device *dev);
netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, struct net_device *dev);
void (*ndo_set_rx_mode)(struct net_device *dev);
int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
// ...
};
4. ethtool_ops(可选)
struct ethtool_ops {
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
int (*set_settings)(struct net_device *, struct ethtool_cmd *);
void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
// ...
};
三、注册网络设备
static int my_init(void)
{
struct net_device *ndev = alloc_etherdev(sizeof(struct my_priv));
// alloc_etherdev = alloc_netdev(sizeof_priv, "eth%d", NET_NAME_UNKNOWN, ether_setup);
my_priv = netdev_priv(ndev);
ndev->netdev_ops = &my_netdev_ops;
ndev->ethtool_ops = &my_ethtool_ops;
ndev->flags |= IFF_NOARP; // 或不设
register_netdev(ndev);
return 0;
}
四、发送
static netdev_tx_t my_xmit(struct sk_buff *skb, struct net_device *dev)
{
// 1. 检查硬件队列
if (!netif_carrier_ok(dev) || !netif_running(dev)) {
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
if (netif_queue_stopped(dev)) {
return NETDEV_TX_BUSY;
}
// 2. 准备 DMA:把 skb 映射到 DMA 地址
dma_addr_t dma = dma_map_single(dev->dev.parent, skb->data, skb->len,
DMA_TO_DEVICE);
if (dma_mapping_error(dev->dev.parent, dma)) {
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
// 3. 写入 DMA 描述符 / 触发硬件
hw_send_packet(dma, skb->len);
// 4. 记账
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
return NETDEV_TX_OK;
}
五、接收(NAPI 模式)
// 中断中
static irqreturn_t my_irq(int irq, void *dev_id)
{
struct my_priv *priv = netdev_priv(dev);
if (likely(napi_schedule_prep(&priv->napi))) {
__napi_schedule(&priv->napi);
// 关中断
}
return IRQ_HANDLED;
}
// NAPI poll
static int my_poll(struct napi_struct *napi, int budget)
{
struct my_priv *priv = container_of(napi, struct my_priv, napi);
int work_done = 0;
while (work_done < budget) {
struct sk_buff *skb = rx_one_packet(priv);
if (!skb) break;
skb->protocol = eth_type_trans(skb, dev);
napi_gro_receive(napi, skb);
work_done++;
}
if (work_done < budget) {
napi_complete_done(napi, work_done);
// 开中断
}
return work_done;
}
// 初始化
netif_napi_add(dev, &priv->napi, my_poll, 64);
napi_enable(&priv->napi);
六、netif 操作
netif_start_queue(dev);
netif_stop_queue(dev);
netif_wake_queue(dev);
netif_carrier_on(dev);
netif_carrier_off(dev);
netif_queue_stopped(dev);
七、统计
dev->stats.rx_packets++;
dev->stats.tx_packets++;
dev->stats.rx_bytes++;
dev->stats.tx_bytes++;
dev->stats.rx_errors++;
dev->stats.tx_errors++;
dev->stats.collisions++;
dev->stats.rx_dropped++;
八、设备树
ethernet0: ethernet@40000000 {
compatible = "myvendor,myeth";
reg = <0x40000000 0x10000>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks 17>;
phy-mode = "rgmii";
pinctrl-0 = <&pinctrl_eth0>;
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@1 {
reg = <1>;
device_type = "ethernet-phy";
};
};
驱动中:
struct device_node *np = dev->of_node;
struct device_node *phy_np = of_parse_phandle(np, "phy-handle", 0);
priv->phy = of_phy_connect(ndev, phy_np, &my_adjust_link, 0, priv->phy_mode);
九、phylib 与 phylink
- phylib:管理 PHY(自动协商、link 状态)
- phylink:phylib 的下一代(5.x+)
struct phy_device *phy = phy_find_first(mii_bus);
phy_connect_direct(dev, phy, &adjust_link, PHY_INTERFACE_MODE_RGMII);
phy_start(phy);
十、Socket buffer 操作
// 分配
struct sk_buff *skb = dev_alloc_skb(len + NET_IP_ALIGN);
skb_reserve(skb, NET_IP_ALIGN); // 预留对齐空间
skb_put(skb, len); // 数据入尾
memcpy(skb->data, data, len); // 填充
// 释放
dev_kfree_skb(skb); // 发送失败
consume_skb(skb); // 发送成功
kfree_skb(skb); // 接收时申请后失败
// 推入头
skb_push(skb, hlen); // 给协议头留空间
// 拉出尾
skb_trim(skb, newlen);
十一、嵌入式网络要点
- 网络 MAC 驱动对实时性要求高
- NAPI + DMA 是主流
- 网卡控制器复杂,建议先研究 stmmac / sunxi-emac / fec 等开源驱动
- MAC + PHY 分工:MAC 处理协议栈,PHY 处理物理信号