交换机协议栈FRR中使用

发布于:2025-09-13 ⋅ 阅读:(18) ⋅ 点赞:(0)

那么sdk的api接口如何在开源交换机协议栈FRR中使用,我的问题是FRR协议栈中开启或关闭端口这个简单的功能,如何去调用sdk,把整个流程讲清楚

好的,这是一个非常经典且实际的问题。将开源路由协议栈(如FRR)与厂商的SDK(如盛科)集成,是构建可商用的网络设备的核心工作。

下面我将详细拆解​​FRR中开启或关闭端口​​这个功能是如何一步步调用到底层SDK的完整流程。


​一、核心架构:分层与抽象​

整个系统是高度分层的,FRR运行在用户空间,它不直接接触硬件。调用流程遵循 ​​“FRR -> Linux内核 -> SDK驱动 -> 硬件”​​ 的路径。

其总体架构与数据流可以用下图清晰地展示:



flowchart TD A[FRR 用户空间进程] B[Linux 内核空间] subgraph B[Linux 内核空间] C[Netlink 监听器] D[内核网络协议栈] E[厂商SDK内核驱动<br>例如: ctc.ko] end F[硬件: 交换芯片] A -- "1. 通过Netlink协议<br>发送命令<br>(如设置端口状态)" --> C C -- "2. 内核收到指令<br>触发变更" --> D D -- "3. 调用驱动提供的<br>ioctl或私有接口" --> E E -- "4. 驱动执行寄存器<br>读写操作" --> F A -- "5. 通过Netlink<br>监听端口状态事件" --> C C -- "6. 内核感知到<br>链路状态变化" --> D D -- "7. 通过Netlink<br>通知用户空间" --> A

这个流程的核心在于 ​​“内核驱动”​​ ,它是承上启下的桥梁。接下来我们详细看驱动内部的实现。


​二、流程详细步骤​

我们以 ​FRR​ 使用 ​ip link set dev eth1 down​ 命令关闭端口为例,追踪整个调用链。

​第1步:FRR 发出指令​
  • FRR 通过其 ​zebra​ 组件来管理内核接口。

  • zebra不会直接调用 ioctl,而是通过更现代的方式:​​Netlink Socket​​。

  • FRR 构造一个 ​NETLINK_ROUTE​ 类型的 Netlink 消息,消息内容为 ​RTM_NEWLINK​ 命令,并设置 ​IFLA_OPERSTATE​ 为 DOWN

  • 这个消息通过 socket 发送到 Linux 内核。

​第2步:Linux 内核处理​
  • 内核的 Netlink 子系统接收到这个消息。

  • 内核网络栈根据消息找到对应的网络接口(如 eth1)。

  • 内核准备修改接口状态,并需要通知底层驱动。

​第3步:调用 SDK 驱动(最关键的一步)​
  • 内核通过​​驱动注册的​​ ​struct net_device_ops​ 结构体中的回调函数来与驱动交互。

  • 当需要改变接口状态时,内核会调用驱动中定义的 ​.ndo_stop​ 或 ​.ndo_open​ 函数。

    • ndo_stop​: 对应端口 DOWN

    • ndo_open​: 对应端口 UP

  • ​这个 ndo_stop函数,就是盛科SDK驱动的一部分!​

​第4步:SDK 驱动操作硬件​
  • 在盛科SDK驱动的 ​ndo_stop​ 函数中,会执行以下操作:

    1. ​准备配置参数​​: 确定要操作哪个端口(port_id),要做什么(DISABLE)。

    2. ​调用SDK API​​: 调用SDK提供的内部函数,如 ctc_port_set_property(...)

    3. ​映射为寄存器操作​​: SDK API 函数会将“关闭端口”这个命令,翻译成对交换芯片特定寄存器的​​写操作​​序列。例如:

      • 先查询当前状态。

      • 向​​端口控制寄存器​​的 ​​“使能”位​​ 写入 0

      • 等待操作完成。

    4. ​更新内核状态​​: 驱动通知内核端口状态已变更。

​第5步:硬件执行​
  • 交换芯片的CPU通过PCIe或内部总线接收到这个寄存器写入命令。

  • 芯片的硬件逻辑会执行命令,物理上​​关闭端口​​的收发器(停止发送光/电信号)。

​第6步:状态同步与反馈​
  • 端口关闭后,链路状态会变为 DOWN

  • 芯片驱动可能会通过​​中断​​或​​轮询​​方式检测到这个变化。

  • 驱动通过 ​​Netlink 接口​​向用户空间​​发送一个异步事件​​,通知 RTM_NEWLINK消息,告知 eth1的状态变为 DOWN

  • ​FRR 的 zebra进程一直在监听这个Netlink socket​​,它收到这个消息后,会更新其内部的接口状态数据库。


​三、代码层次示例(简化版)​



/* 1. 盛科SDK驱动代码 (内核模块, ctc_driver.c) */ // 内核要求的网络设备操作函数集 static const struct net_device_ops ctc_netdev_ops = { .ndo_open = ctc_ndo_open, .ndo_stop = ctc_ndo_stop, // <--- 这就是关闭端口的功能入口 .ndo_start_xmit = ctc_ndo_xmit, // ... 其他操作 }; // 具体的关闭端口函数 int ctc_ndo_stop(struct net_device *dev) { struct ctc_port *port = netdev_priv(dev); // 获取驱动私有数据 int ret = 0; // 调用SDK提供的API函数!这就是FRR最终调到的SDK接口。 ret = ctc_sdk_port_enable_set(port->port_id, CTC_PORT_DISABLE); if (ret) { printk(KERN_ERR "Failed to disable port %d\n", port->port_id); return ret; } // 其他清理工作... netif_stop_queue(dev); // 告诉内核停止向这个端口发送数据包 return 0; } /* 2. 盛科SDK内部实现 (sdk_port.c) */ int ctc_sdk_port_enable_set(int port_id, int enable) { // 1. 将端口ID映射到特定的硬件寄存器地址 uint32_t reg_addr = GET_PORT_CTRL_REG(port_id); // 2. 通过寄存器读写函数(最终是内存映射I/O)来操作硬件 uint32_t reg_val = ctc_reg_read(reg_addr); // 先读取当前值 // 3. 修改“使能”比特位 if (enable) { reg_val |= (1 << EN_BIT_OFFSET); } else { reg_val &= ~(1 << EN_BIT_OFFSET); } // 4. 将新值写回寄存器,硬件随即生效 ctc_reg_write(reg_addr, reg_val); return 0; }


​总结​

层级

组件

角色

​用户空间​

​FRR (zebra)​

生成配置命令,通过Netlink发给内核;监听内核事件。

​内核空间​

​Linux Kernel​

接收Netlink命令,调用驱动注册的回调函数。

​驱动层​

​SDK驱动 (ctc.ko)​

​承上启下的核心​​。提供.ndo_stop等函数,调用SDK API。

​硬件抽象层​

​SDK API​

将高级命令(禁用端口)翻译为底层寄存器读写序列。

​硬件层​

​交换芯片​

执行寄存器命令,物理上改变端口状态。

所以,FRR​​并不直接调用SDK​​。它是通过​​标准的Linux网络接口​​(Netlink)下发命令,由​​厂商提供的内核驱动​​来​​间接调用SDK​​的功能,最终操控硬件。

这种设计的优点是​​解耦​​:FRR无需关心底层是盛科、博通还是美满的芯片,它只和标准的Linux内核接口交互。芯片厂商则负责开发驱动,将标准调用“翻译”成自己芯片的专用操作。


网站公告

今日签到

点亮在社区的每一天
去签到