学无止境--linux 注册虚拟网卡将SDK(厂商)上送至CPU的报文注入协议栈
之类的驱动虽然SDK有将进入该部分的报文上送至CPU的API但是无法注入协议栈也就无法与CPU通信想要解决该问题要么就自己开发DSA驱动要么就需要注册一个虚拟网络设备无对应的物理网卡将报文注入协议栈并在协议栈发出应答报文时发送到SDK让SDK通过面板口发送出去。注才疏学浅能力有限如有描述不当敬请谅解欢迎各位大神指正。以下是流程以及代码需要确保有/dev/net/tun设备#include stdlib.h #include stdio.h #include string.h #include unistd.h #include fcntl.h #include sys/ioctl.h #include sys/socket.h #include linux/if.h #include linux/if_tun.h #include linux/if_packet.h #include pthread.h #include ifmHwCmd.h #include ifmIfApi.h #include vxw_hdrs.h int pkt_dbg 0; /*调试FLAG*/ int g_dst_port 0; /*记录源端口号*/ /************************* 配置参数 *************************/ #define TAP_DEV_NAME tap0 // 虚拟网卡名 #define TAP_IP_ADDR 192.168.11.231 // 协议栈IP #define TAP_MAC_ADDR 00:11:22:33:44:55 // 虚拟MAC #define TAP_NETMASK 255.255.255.0 #define MAX_PACKET_SIZE 1536 // 以太网最大帧 // ------------------- 全局变量 ------------------- int tap_fd -1; // TAP文件描述符 uint8_t tx_buf[MAX_PACKET_SIZE]; /************************* TAP网卡创建 *************************/ int tap_create(const char *dev) { struct ifreq ifr; int fd, err; printf(tap_create\r\n); // 打开TUN设备 if ((fd open(/dev/net/tun, O_RDWR)) 0) { printf(open /dev/net/tun failed\r\n); return -1; } memset(ifr, 0, sizeof(ifr)); ifr.ifr_flags IFF_TAP | IFF_NO_PI; // IFF_TAP二层以太网帧 IFF_NO_PI不带额外头部 strncpy(ifr.ifr_name, dev, IFNAMSIZ - 1); // 创建TAP网卡 if ((err ioctl(fd, TUNSETIFF, (void *)ifr)) 0) { printf(ioctl TUNSETIFF failed\r\n); close(fd); return -1; } tap_fd fd; printf(TAP网卡创建成功: %s\n, ifr.ifr_name); return fd; } /************************* TAP网卡配置IP/MAC *************************/ void tap_config(const char *dev, const char *ip, const char *mac, const char *netmask) { char cmd[256]; printf(tap_config\r\n); // 配置MAC地址 sprintf(cmd, ifconfig %s hw ether %s, dev, mac); system(cmd); // 配置IP和子网掩码 sprintf(cmd, ifconfig %s %s netmask %s up, dev, ip, netmask); system(cmd); printf(TAP网卡配置完成: IP%s MAC%s\n, ip, mac); } /************************* 【核心】平台SDK收包回调函数 *************************/ /*tPacket *pkt是平台中的数据结构包含了报文pkt-packet需要替换成自己的平台中的数据结构*/ /*该函数注册到了平台的收包流程*/ int gdi_packet_rx_recv(int unit, tPacket *pkt, void *cookie) { ssize_t wlen 0; int i 0; // 1. 合法性校验 if (!pkt || !pkt-packet || pkt-len 0 || pkt-len MAX_PACKET_SIZE) return ERROR; // 2. 将收到的完整二层报文 写入TAP → 注入Linux协议栈 wlen write(tap_fd, pkt-packet, pkt-len); if (wlen 0) { printf(write tap failed\r\n); return ERROR; } g_dst_port unit; /*调试信息打印注入协议栈的报文*/ if (pkt_dbg 0x02) { printf(【收包】从CPU口收到报文注入协议栈: 长度%d g_dst_port%d\r\n, pkt-len, g_dst_port); for (i 0; i pkt-len; i) { printf(%02x , pkt-packet[i]); if ((i 1) % 16 0) printf(\r\n); } printf(\r\n); } return OK; // 告诉SDK报文已处理 } /************************* 协议栈发包线程读TAP→SDK发送 *************************/ void *tx_thread(void *arg) { int len; int i 0; int chip_port 0; tPhyIfInfo phy_info; printf(协议栈回包线程运行中...\n); while (1) { // 从TAP读取协议栈发出的报文ARP应答/IP报文等 len read(tap_fd, tx_buf, MAX_PACKET_SIZE); if (len 0) continue; /*调试信息打印从协议栈发出的应答报文*/ if (pkt_dbg 0x01) { printf(\r\n← 协议栈应答报文发回交换芯片len%d\r\n, len); for (i 0; i len; i) { printf(%02x , tx_buf[i]); if ((i 1) % 16 0) printf(\r\n); } printf(\r\n); } /*这部分是平台的发包API需要根据自己的平台调整*/ /*平台的发包API内部调用了厂商的SDK发包流程*/ gdi_card_logic2phy_api((void *)g_dst_port, chip_port); gdi_pkt_local_send(0, chip_port, tx_buf, len); } return NULL; } /************************* 主函数 *************************/ int gdi_packet_net_create(void) { pthread_t tid; // 步骤1创建并配置TAP网卡 if (tap_create(TAP_DEV_NAME) 0) return -1; tap_config(TAP_DEV_NAME, TAP_IP_ADDR, TAP_MAC_ADDR, TAP_NETMASK); // 步骤2启动协议栈发包线程 pthread_create(tid, NULL, tx_thread, NULL); pthread_detach(tid); // 主线程保持运行 printf(交换芯片-协议栈 转发服务运行中...\n); return 0; }