NetDev

NetDev组件

Net 组件的主要内容有 4 个方面,分别是 sal ,AT,lwip 与 netdev。

使用 RT-Thread上网的联网设备,品类繁多,方式各异,但其实追踪到依赖的基础 net 能力其实也没有多复杂。实际上大部分的功能依赖的基础能力,只有两组而已,即 AT ,Lwip;而到用户,大部分就只用到 Sal 这一个概念。

请添加图片描述


netdev介绍

netdev(network interface device),即网络接口设备,又称网卡。每一个用于网络连接的设备都可以注册成网卡,为了适配更多的种类的网卡,避免系统中对单一网卡的依赖,RT-Thread 系统提供了 netdev 组件用于网卡管理和控制。

功能
  1. 抽象网卡概念,每个网络连接设备可注册唯一网卡;
  2. 提供多种网络连接信息查询,方便用户实时获取当前网卡网络状态;
  3. 建立网卡列表和默认网卡,可用于网络连接的切换;
  4. 提供多种网卡操作接口(设置 IP、DNS 服务器地址,设置网卡状态等);
  5. 统一管理网卡调试命令(ping、ifconfig、netstat、dns 等命令);
结构体
struct netdev
{
    rt_slist_t list;

    char name[RT_NAME_MAX];                            /* network interface device name */
    ip_addr_t ip_addr;                                 /* IP address */
    ip_addr_t netmask;                                 /* subnet mask */
    ip_addr_t gw;                                      /* gateway */
#if NETDEV_IPV6
    ip_addr_t ip6_addr[NETDEV_IPV6_NUM_ADDRESSES];     /* array of IPv6 addresses */
#endif /* NETDEV_IPV6 */
    ip_addr_t dns_servers[NETDEV_DNS_SERVERS_NUM];     /* DNS server */
    uint8_t hwaddr_len;                                /* hardware address length */
    uint8_t hwaddr[NETDEV_HWADDR_MAX_LEN];             /* hardware address */

    uint16_t flags;                                    /* network interface device status flag */
    uint16_t mtu;                                      /* maximum transfer unit (in bytes) */
    const struct netdev_ops *ops;                      /* network interface device operations */

    netdev_callback_fn status_callback;                /* network interface device flags change callback */
    netdev_callback_fn addr_callback;                  /* network interface device address information change callback */

#ifdef RT_USING_SAL
    void *sal_user_data;                               /* user-specific data for SAL */ // to sal pfs and ops
#endif /* RT_USING_SAL */
    void *user_data;                                   /* user-specific data */         // to netif(在netdev_register(...)当中赋值的)
};

网卡OPS

struct netdev_ops
{
    /* set network interface device hardware status operations */
    int (*set_up)(struct netdev *netdev);
    int (*set_down)(struct netdev *netdev);

    /* set network interface device address information operations */
    int (*set_addr_info)(struct netdev *netdev, ip_addr_t *ip_addr, ip_addr_t *netmask, ip_addr_t *gw);
    int (*set_dns_server)(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server);
    int (*set_dhcp)(struct netdev *netdev, rt_bool_t is_enabled);

#ifdef RT_USING_FINSH
    /* set network interface device common network interface device operations */
    int (*ping)(struct netdev *netdev, const char *host, size_t data_len, uint32_t timeout, struct netdev_ping_resp *ping_resp);
    void (*netstat)(struct netdev *netdev);
#endif

    /* set default network interface device in current network stack*/
    int (*set_default)(struct netdev *netdev);
};

/* sal network database name resolving */
struct sal_netdb_ops
{
    struct hostent* (*gethostbyname)  (const char *name);
    int             (*gethostbyname_r)(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop);
    int             (*getaddrinfo)    (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
    void            (*freeaddrinfo)   (struct addrinfo *ai);
};

netdev状态


/* whether the network interface device is 'up' (set by the network interface driver or application) */
#define NETDEV_FLAG_UP                 0x01U      //--------->up/down
/* if set, the network interface device has broadcast capability, only supported in the 'lwIP' stack */
#define NETDEV_FLAG_BROADCAST          0x02U
/* if set, the network interface device has an active link (set by the network interface driver) */
#define NETDEV_FLAG_LINK_UP            0x04U      //--------->link_up/link_down
/* if set, the network interface device is an ethernet device using ARP, only supported in the 'lwIP' stack */
#define NETDEV_FLAG_ETHARP             0x08U
/* if set, the network interface device is an ethernet device, only supported in the 'lwIP' stack */
#define NETDEV_FLAG_ETHERNET           0x10U
/* if set, the network interface device has IGMP capability, only supported in the 'lwIP' stack */
#define NETDEV_FLAG_IGMP               0x20U
/* if set, the network interface device has MLD6 capability, only supported in the 'lwIP' stack */
#define NETDEV_FLAG_MLD6               0x40U
/* if set, the network interface device connected to internet successfully (set by the network interface driver) */
#define NETDEV_FLAG_INTERNET_UP        0x80U      //--------->internet_up/internet_down
/* if set, the network interface device has DHCP capability (set by the network interface device driver or application) */
#define NETDEV_FLAG_DHCP               0x100U
API
#include <arpa/inet.h>         /* 包含 ip_addr_t 等地址相关的头文件 */
#include <netdev.h>            /* 包含全部的 netdev 相关操作接口函数 */
int netdev_register(struct netdev *netdev, const char *name, void *user_data);
int netdev_unregister(struct netdev *netdev);
struct netdev *netdev_get_first_by_flags(uint16_t flags);
struct netdev *netdev_get_by_family(int family);
struct netdev *netdev_get_by_ipaddr(ip_addr_t *ip_addr);
struct netdev *netdev_get_by_name(const char *name);    // 网卡名称唯一
void netdev_set_default(struct netdev *netdev);
int netdev_set_up(struct netdev *netdev);
int netdev_set_down(struct netdev *netdev);
int netdev_dhcp_enabled(struct netdev *netdev, rt_bool_t is_enabled);
/* 设置网卡 IP 地址 */
int netdev_set_ipaddr(struct netdev *netdev, const ip_addr_t *ipaddr);      // dhcp关闭状态下使用
/* 设置网卡网关地址 */
int netdev_set_gw(struct netdev *netdev, const ip_addr_t *gw);              // dhcp关闭状态下使用
/* 设置网卡子网掩码地址 */
int netdev_set_netmask(struct netdev *netdev, const ip_addr_t *netmask);    // dhcp关闭状态下使用
int netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, const ip_addr_t *dns_server); // dhcp关闭状态下使用
typedef void (*netdev_callback_fn )(struct netdev *netdev, enum netdev_cb_type type);
void netdev_set_status_callback(struct netdev *netdev, netdev_callback_fn status_callback); // 网卡可以设置回调用函数,状态改变时调用 TODO
void netdev_set_addr_callback(struct netdev *netdev, netdev_callback_fn addr_callback)      // 地址改变时调用
#define netdev_is_up(netdev)
#define netdev_is_link_up(netdev)
#define netdev_is_internet_up(netdev)
#define netdev_is_dhcp_enable(netdev)
状态设置调用路径

up/down 状态以及 dhcp_enable/dhcp_disable 状态可以通过 netdev 组件提供的接口设置,可以在应用层控制。其他状态是由网卡底层驱动或者 netdev 组件根据当前网卡网络连接情况自动设置

状态含义设置
up网卡开启底层: eth_device_init(…)/lwip_netdev_set_up(struct netdev *netif) ->
netif_set_up(struct netif *netif)->
netdev_low_level_set_status(struct netdev *netdev, rt_bool_t is_up);
上层:netdev->ops->set_up( );
down网卡禁用eth_device_deinit(…)/lwip_netdev_set_down(struct netdev *netif)->
netif_set_down(struct netif *netif)->
netdev_low_level_set_status(struct netdev *netdev, rt_bool_t is_up)
link_up链路有效eth_device_linkchange(struct eth_device* dev, rt_bool_t up)->
netif_set_link_up(struct netif *netif)->
netdev_low_level_set_link_status(struct netdev *netdev, rt_bool_t is_up)
link_down链路无效eth_device_linkchange(struct eth_device* dev, rt_bool_t up)->
netif_set_link_down(struct netif *netif )->
netdev_low_level_set_link_status(struct netdev *netdev, rt_bool_t is_up)
internet_up连接到因特网check_netdev_internet_up_work(struct rt_work *work, void *work_data)->
netdev_low_level_set_internet_status(struct netdev *netdev, rt_bool_t is_up);
internet_down未连接到因特网netdev_low_level_set_…(…)->
sal_check_netdev_internet_up(…)->
check_netdev_internet_up_work(struct rt_work *work, void *work_data)->
netdev_low_level_set_internet_status(struct netdev *netdev, rt_bool_t is_up);
dhcp_enable开启 DHCP
dhcp_disable关闭 DHCP

Lwip 设备eth_device及网卡netif 和rt-thread网卡netdev的状态同步,通过上面的函数间的调用关系,如果使用lwip的网卡来是适配我们的协议栈,底层调用关系已经设置好了。

文件结构
├─ netdev                 // netdev 组件
│  ├─ include
│  │  ├─ arpa             // 引用了netdev_ipaddr.h
│  │  │  └─ inet.h
│  │  ├─ netdev.h         // netdev 结构体定义及相关操作声明,netdev状态定义
│  │  └─ netdev_ipaddr.h  // 一些IP 地址相关的操作
│  ├─ Kconfig
│  ├─ SConscript
│  └─ src
│     ├─ netdev.c
│     └─ netdev_ipaddr.c

Lwip 介绍


Lwip网卡注册调用关系
xxx_hw_init();--->
  rt_err_t eth_device_init(struct eth_device * dev, const char *name); --->
    rt_err_t eth_device_init_with_flag(struct eth_device *dev, const char *name, rt_uint16_t flags);--->
      netifapi_netif_add(...);--->
        tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call);--->     // TODO:why call this func?? 猜测是为了线程安全。
          static err_t eth_netif_device_init(struct netif *netif); --->
            static int netdev_add(struct netif *lwip_netif); --->
              int netdev_register(struct netdev *netdev, const char *name, void *user_data); --->   // struct netif 作为user data在netdev中进行链接


网卡设备继承关系

RT-Thread 的设备模型是建立在内核对象模型基础之上的,设备被认为是一类对象,被纳入对象管理器的范畴。每个设备对象都是由基对象派生而来,每个具体设备都可以继承其父类对象的属性,并派生出其私有属性,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VfzGzvi8-1667636788512)(25a40859735f5684b1fe6a76ebc98593.png)]

struct rt_object --->
  struct rt_device --->
    struct eth_device --->
      struct eth_device_xxx    // device type: RT_Device_Class_NetIf

Lwip 函数调用流程图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8MRfYM3s-1667636788513)(8e47ad50f996d7368e2788de6d98d5ef.png)]

网络接口层:
lwip 的ETH 层可以单独分两个线程进行数据的发送和接收,连线程和tcpip线程间通过邮箱通信。是否开这两个线程和邮箱通过 LWIP_NO_TX_THREAD/LWIP_NO_RX_THREAD 宏进行控制(开线程和不开的区别在哪?)。

收发线程和邮箱的初始化放在lwip初始化的时候, lwip_system_init()时完成。

rx:硬件收到数据后,产生一个对应的中断,调用eth_device_ready(...)通过邮箱通知eth_rx_thread去读取数据并处理存放进 struct pbuf 中,再调用网卡netif入口函数ethernet_input(...)进行处理。

tx:发送线程,从邮箱中接收到数据后,调用底层提供的接口,把数据写到FIFO中,等待发送完成的反馈。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LuAujJV9-1667636788513)(255d43f7d1e8d0470c90cc427f53f3c2.png)]

网卡信息的配置

目前认为有两种方式获取Ip地址,一种是DHCP分配,一种是调用netdev提供的接口手动设置。

DHCP 动态分配

根据rt-thread的代码,当设置了DHCP自动分配IP地址的时候,无法手动设置IP地址;但是DHCP申请到了IP地址是如何给netdev的呢?

DHCP打开的时候,手动进行IP地址的设置会失败。

dhcp_bind(struct netif *netif)->
  netif_set_addr(...)->

DHCP可以在程序运行中打开/关闭,列一下有哪些时候会进行DHCP的打来关闭

dhcp_start(struct netif *netif);      // DHCP 开  初始化时:eth_netif_device_init(struct netif *netif) ->dhcp_start();
                                                  程序运行中:通过netdev提供的接口lwip_netdev_set_dhcp(...)
                                                            
dhcp_stop(struct netif *netif);       // DHCP 关  删除eth_device时:eth_device_deinit(struct eth_device *dev)
                                                  程序运行时同dhcp_start(...)

dhcp 静态分配

当在配置文件中关闭通过DHCP分配IP地址后,rt_thread会给网卡分配一个静态IP地址,换个说法就是,当打开dhcp 时,rt_thread会把网卡的初始地址设成0,否则初始地址为一个局部IP地址。

手动设置

eth_device&netdev&netif

eth_device 网络接口设备

struct eth_device
{
    /* inherit from rt_device */
    struct rt_device parent;

    /* network interface for lwip */
    struct netif *netif;                // to netif

    rt_uint16_t flags;
    rt_uint8_t  link_changed;
    rt_uint8_t  link_status;
    rt_uint8_t  rx_notice;

    /* eth device interface */
    struct pbuf* (*eth_rx)(rt_device_t dev);                  // send data
    rt_err_t (*eth_tx)(rt_device_t dev, struct pbuf* p);      // recv data
};

netdev 是对 lwip 中 netif 的继承。因为 netdev 从 netif 中取出了一些字节用于关键信息的填充。

请添加图片描述

需求

需要在rt_thread和DR之间搭一个数据传输通道,那么需要在rt_thread中注册一个网卡;----需要写一个虚拟网卡驱动;

需要给rt_thread暴露一个ip地址;—有两种实现方式,一种是通过DHCP和DR的dhcp_service获取一个地址,这种方式需要我们先把想要分配的地址写到DR的dhcp_service中;另外一种方式是,关闭dhcp功能的情况下,通过调用netdev提供的接口把IP地址等设置好。(不使用dhcp似乎是更好的选择)

<think>好的,用户现在想了解U-Boot中网络设备(netdev)的配置和使用方法。我需要先回忆一下U-Boot的基本结构和网络配置相关的部分。首先,U-Boot通常通过环境变量来配置网络参数,比如ip地址、服务器地址、子网掩码等。用户可能需要知道如何设置这些变量,以及如何测试网络连接。 接下来,我需要检查用户提供的引用内容,看看是否有相关信息。引用[2]提到设置bootargs参数与内核一致,特别是mtdblock的分区,但这里主要涉及文件系统启动,可能和网络配置关系不大。引用[3]提到了YAFFS2文件系统和NAND相关配置,可能也不直接相关。但用户的问题是关于netdev的,所以可能需要专注于U-Boot自身的网络配置部分,而不是内核或文件系统。 用户可能需要知道具体的环境变量设置,比如ipaddr、serverip、netmask、gatewayip等,以及如何用ping命令测试网络。另外,U-Boot中的网络设备驱动可能涉及不同的硬件,比如以太网控制器,可能需要设置ethaddr这个MAC地址。还可能涉及到TFTP下载,这在引用[2]中提到过bootargs的设置,但需要确认U-Boot中如何配置TFTP服务器地址和使用tftp命令。 需要注意的是,不同硬件平台的U-Boot可能有不同的配置方式,比如使用phy地址或驱动名称。例如,有些板子可能需要设置ethact变量来选择活动的网络接口。此外,用户可能遇到网络无法连接的情况,这时候需要检查环境变量是否正确,物理连接是否正常,或者驱动是否支持。 另外,用户可能想了解如何通过U-Boot进行网络启动,比如使用DHCP自动获取IP,或者使用NFS挂载根文件系统,但这些可能属于更高级的配置。不过根据用户的问题,重点应在netdev的配置和使用,所以保持回答集中在基础配置和常用命令上比较合适。 最后,确保回答结构清晰,分步骤说明配置方法,并提供示例命令,这样用户能更容易理解和操作。同时,生成的相关问题需要围绕可能的后续疑问,比如环境变量保存、TFTP使用、多网卡处理等,帮助用户深入探索。</think>### U-Boot网络设备配置与使用详解 在嵌入式系统开发中,U-Boot的网络配置是实现TFTP下载、NFS挂载等高级功能的基础。以下是网络设备的配置要素与操作步骤: #### 一、核心环境变量配置 1. **IP地址配置** ```bash setenv ipaddr 192.168.1.100 # 开发板IP地址 setenv serverip 192.168.1.10 # TFTP服务器IP setenv netmask 255.255.255.0 # 子网掩码 setenv gatewayip 192.168.1.1 # 网关地址 ``` 所有网络相关操作必须保证开发板与主机处于同一网段[^2] 2. **物理层参数** ```bash setenv ethaddr 00:0a:35:02:1c:33 # 设置MAC地址(需唯一) setenv ethprime eth0 # 指定主网卡(多网卡场景) ``` #### 二、网络设备驱动配置 在`include/configs/<board>.h`硬件配置文件中需定义: ```c #define CONFIG_CMD_NET #define CONFIG_NET_MULTI #define CONFIG_ETHADDR 00:0a:35:02:1c:33 #define CONFIG_IPADDR 192.168.1.100 #define CONFIG_SERVERIP 192.168.1.10 ``` 不同硬件平台可能需指定PHY地址: ```c #define CONFIG_PHY_ADDR 0x1f # 针对特定PHY芯片的设置 ``` #### 三、网络功能验证 1. **连接性测试** ```bash ping ${serverip} # 测试与服务器的连通性 ``` 出现`host 192.168.1.10 is alive`表示链路正常 2. **TFTP传输示例** ```bash tftp 0x82000000 uImage # 将内核镜像加载到内存 ``` 传输速度典型值为10-12MB/s(百兆网络环境) #### 四、高级配置场景 1. **多网卡选择** ```bash setenv ethact eth1 # 切换活动网卡 usb start # 启用USB网络适配器 ``` 2. **DHCP自动获取** ```bash setenv autoload no dhcp # 自动获取IP地址 ``` 3. **NFS挂载配置** ```bash setenv nfsroot /opt/rootfs nfs ${loadaddr} ${serverip}:${nfsroot} ``` #### 五、故障排查要点 1. 出现`*** ERROR: `ethaddr` not set`时,需检查MAC地址是否重复 2. `PHY found at 0xXX`提示表示驱动识别到物理层芯片 3. 传输中断时检查MTU设置: ```bash setenv tftpblocksize 1468 # 适配特定网络环境 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值