• SDN功能实现(四)--- 实现自定义action(1)修改OVS源码<队列去重(内核态实现)>


     

    实现功能:设计一个新的action,实现在冗余链路中的数据包去重

    一:在内核级定义OVS  action

    (一)在datapath/linux/compat/include/linux/openvswitch.h中添加:

    enum ovs_action_attr {
        /* ... */
    
        /*
        * after #ifndef __KERNEL__ ... #endif.
        * the equals is thus ABSOLUTELY NECESSARY
        */
    
        OVS_ACTION_ATTR_RMDUPQUEUE = 23, /* struct ovs_action_rmdupqueue. */
    
        __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted
                                * from userspace. */
    
        /* ... */
    
    }

    (二)注意:指定显示值

    OVS_ACTION_ATTR_RMDUPQUEUE = 23 如果我们不为该枚举条目指定显式值,则内核和用户区部分 ovs-vswitchd将对新操作使用不同的代码(这里不加会出错)

    (三)定义内核级别的OVS  action的消息结构体

    /*
     * struct ovs_action_rmdupqueue - %OVS_ACTION_ATTR_RMDUPQUEUE action argument.
     * @queue_id: Algorithm used to choose queue number.
     * @max_len: basis used for setting queue[queue_id] size.
     */
    struct ovs_action_rmdupqueue{
        uint32_t queue_id;
        uint32_t max_len;
    };

    二:在内核模块中实现自定义action的实现函数,用于调用执行

    (一)队列业务实现,在datapath/flow_netlink.h中定义队列

    int nsh_hdr_from_nlattr(const struct nlattr *attr, struct nshhdr *nh,
                size_t size);
    
    //-------------------queue  start---------------------
    #define MAX_QUEUE_SIZE 1000                //最多可以为1000个流提供服务
    #define MAX_QUEUE_LEN 1000                           //----改进:动态自适应算法,自动选择队列大小   或者 滑动窗口协议PRP 
    typedef struct  
    {
        int *queue;                                //队列指针(动态分配队列空间)
        int NUM;                                   //队列大小
        int TOP, REAR;                             //队首队尾标识
        int EmpFlag;                               //队列判空标识
    }Queue;
    
    void InitQueue(Queue* q, int n);            //初始化队列
    int EmptyOrFullQueue(Queue q);            //队列判空以及判断满
    int QueueLength(Queue q);                    //获取队列大小
    
    int PushQueue(Queue* q,int ele);        //入队操作
    int PopQueue(Queue* q);                        //出队操作
    
    int RePushQueue(Queue* q, int ele);                                    //当一个数据第二次到达时对数据进行匹配出队操作
    int FindElePos(Queue q, int ele,int* n);                                        //查找元素位置
    
    void ShowData(Queue q);                        //显示队列数据
    
    extern Queue Que[];
    //-----------------queue end----------------------------
    #endif /* flow_netlink.h */

    (二)队列业务实现,在datapath/flow_netlink.c中实现队列

    //-------------------queue  start---------------------
    void InitQueue(Queue* q,int n)
    {
        q->NUM = n;
        //空间回收
        if (q->queue != NULL)
        {
            kfree(q->queue);      //改进:设置一个新的action(---del-flows指令,不是action) 实现队列的释放,清除上一个action
            q->queue = NULL;
        }
    
        if (q->NUM != 0)
        {
            q->queue = (int *)kmalloc(sizeof(int)*n,GFP_KERNEL);
            memset(q->queue, 0, sizeof(int)*n);
        }
        
        q->TOP = q->REAR = 0;
        q->EmpFlag = 1;                        //空队列
    }
    
    int EmptyOrFullQueue(Queue q)
    {
        return q.EmpFlag;
    }
    
    int QueueLength(Queue q)
    {
        if (EmptyOrFullQueue(q) == 1)
            return 0;
        if (EmptyOrFullQueue(q) == 2)
            return q.NUM;
        if (q.TOP > q.REAR)
            return q.REAR + q.NUM - q.TOP;
        else
            return q.REAR - q.TOP;
    }
    
    int PushQueue(Queue* q, int ele)
    {
        if (q->NUM <= 0)
            return 0;                    //队列空间已经释放        设置常量
    
        if (RePushQueue(q, ele) == 1)    //重复插入,冗余数据---重点    改进:定义网络新协议,替换ip标识
            return 1;
    
        if (q->EmpFlag == 2)                        //队列满的情况入队
            PopQueue(q);                                //先出队队首,再入队
    
        q->queue[q->REAR] = ele;
        q->REAR = (q->REAR + 1) % q->NUM;
        if (q->TOP == q->REAR)
            q->EmpFlag = 2;                            //为满队列
        else
            q->EmpFlag = 3;
    
        return 0;
    }
    
    
    int PopQueue(Queue* q)
    {
        if (q->NUM <= 0)
            return -2;                    //队列空间已经释放    改进:可以队列动态空间划分
    
        int temp = q->queue[q->TOP];
    
        if (q->EmpFlag == 1)    //队列为空时,不允许出队
            return -1;
    
        q->TOP++;
        if (q->TOP == q->NUM)
            q->TOP = 0;
        if (q->TOP == q->REAR)
            q->EmpFlag = 1;                            //为空队列
        else
            q->EmpFlag = 3;
        return temp;
    }
    
    int RePushQueue(Queue* q, int ele)
    {
        int n;                //用于记录元素个数
        int pos = FindElePos(*q, ele, &n);    
        if (pos == -1)
            return 0;        //可以直接插入
    
        q->TOP = pos;
        if (QueueLength(*q) == 0)
            q->EmpFlag = 1;
        else
            q->EmpFlag = 3;
    
        return 1;            //队列有重复
    }
    
    int FindElePos(Queue q, int ele,int* n)
    {
        int i;
        for (i = 0; i < QueueLength
  • 相关阅读:
    Push和Pull两种类型的消费者
    IDEA设置Maven 镜像
    ubuntu编译和链接特定版本的opencv和boost
    【JavaEE进阶系列 | 从小白到工程师】JavaEE中的迭代器,并发修改异常与增强for循环,一文上手使用
    JSX 中使用 js 表达式
    提振信心!1-7月新车智能化「持续增长」,同比增速超70%
    榜单首发——前装搭载率站上10%大关,数字钥匙方案供应商TOP10
    FPGA帧差算法实现图像识别跟踪,Verilog代码讲解全网最细,提供两套工程源码
    [附源码]java毕业设计医疗预约系统
    MySQL join和索引
  • 原文地址:https://blog.csdn.net/lingshengxiyou/article/details/127972444