学无止境--linux 注册虚拟网卡将SDK(厂商)上送至CPU的报文注入协议栈

备注:学习记录所用,若有高手不吝赐教,万分感谢!

一、问题描述:

image

如图中所示,是楠菲微的SF9056架构,厂商将图中1的两个RGMII注册成了管理/调试网口,使能相关选项就能看到有eth0和eth1两个网络设备,但是厂商的SDK只将图中2的部分进行了数据转发功能,该部分没有开发诸如DSA之类的驱动,虽然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;
}
posted @ 2026-04-29 17:57  xMofang  阅读(5)  评论(0)    收藏  举报