SDN功能实现(二)--- 实现关键流去重

一:实现功能

(一)前提

1.无分组

2.首次实验:两条链路无时延迟;后面实验:考虑时延

3.使用UDP协议实现

(二)实验要求

1.只针对关键流进行,冗余链路传输,实现可靠传输

2.在目标主机的边缘交换机中实现去重功能

3.对非关键流,不进行冗余传输,正常单链路传输即可

4.根据源、目的IP,源、目的端口,还有上面的协议类型(UDP)进行区分是否为关键流

5.根据源、目的IP,源、目的端口,协议类型,以及id标识进行去冗余

6.重点--注意:我们对于关键流,第一个到达的直接发送给目标主机,将5中唯一标识(多个组合而成)记录,用于对后面到达的重复字段去冗余

(三)实验所需数据结构

1.队列进行去冗余,需要实现一个队列(这里使用数组即可,使用循环队列)----不太恰当

2.使用链表实现类似路由表功能(顺序查找)----恰当些

(四)所需实验

1.修改缓存队列大小,比如:4,8,16

2.修改两条链路时延,比如:下面链路时延是下面两倍

二:实验环境搭建

(一)网络拓扑实现

(二)OVS引擎实现

注意:这里的去重模块只是其中队列大小不同,是各自独立的实验

三:mininet拓扑、UDP通信实验开始

(一)实现UDP通信

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define MAX_LEN 1000

//#define SER_IP "10.0.0.1"
#define MAXSIZE 40

#define IPOPT_TAG 0x21        //IP选项标志字段
#define IPOPT_LEN 8            //IP选项长度字段

int str_to_number(const char* str);

int main(int argc, char** argv)
{
    int sk;
    char buf[MAX_LEN];
    struct sockaddr_in ser_addr;                                //是用于指定对方(目的主机)信息
    struct sockaddr_in loc_addr;                                //可以用来指定一些本地的信息,比如指定端口进行通信,而不是让系统随机分配
    int ser_addr_len,loc_addr_len;
    int ret,count;
    struct in_addr addr;
    unsigned int SeqID=0;
    unsigned char opt[MAXSIZE];             //ip option选项
    opt[0] = 0x21;    
    opt[1] = IPOPT_LEN;

    if (argc != 3)
    {
        printf("Error: the number of args must be 3\n");
        exit(0);
    }

    //配置服务器信息
    bzero(&ser_addr, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;                                //设置为IPV4通信
    //ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    ser_addr.sin_addr.s_addr = inet_addr(argv[1]);                //设置目的ip
    ser_addr.sin_port = htons(str_to_number(argv[2]));            //设置目的端口去链接服务器
    ser_addr_len = sizeof(ser_addr);

    //配置本地信息
    bzero(&loc_addr, sizeof(loc_addr));
    loc_addr.sin_family = AF_INET;                                //设置为IPV4通信
    //loc_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    loc_addr.sin_addr.s_addr = htonl(INADDR_ANY);                //设置目的ip
    loc_addr.sin_port = htons(8080);                            //设置本地端口去链接服务器
    loc_addr_len = sizeof(loc_addr);

    sk = socket(AF_INET, SOCK_DGRAM, 0);                        //设置UDP报文传输    0表示默认    SOCK_DGRAM 默认使用UDP
    //其中第三位 0 是调用方式标志位,设置socket通方式,比如非阻塞
    if(sk<0)
    {
        printf("socket create failure\n");
        return -1;
    }

    //将本地配置使用bind绑定
    ret = bind(sk,(struct sockaddr*)&loc_addr,loc_addr_len);
    if(ret < 0)
    {
        printf("socket bind failure\n");
        return -1;
    }

    for (;;)
    {
        printf("Input info:>>>");
        scanf("%s", buf);
        if (!strcmp(buf, "quit"))
            break;

        *(int *)(opt + 2) = htonl(++SeqID);  
        setsockopt(sk,IPPROTO_IP,IP_OPTIONS,(void *)opt,IPOPT_LEN);
        sendto(sk, buf, strlen(buf)+1, 0, (struct sockaddr*)&ser_addr, ser_addr_len);

    }

    printf("communicate end\n");
    close(sk);
    return 0;
}

int str_to_number(const char* str)
{
    int i,len, num = 0;
    len= strlen(str);

    for (i = 0; i < len;i++)
        num = num * 10 + str[i] - '0';

    return num;
}
UDP客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define MAX_LEN 1000

int str_to_number(const char* str);

int main(int argc, char** argv)
{
    char message[MAX_LEN];
    int sk;
    struct sockaddr_in src_addr;    //用于指定本地监听信息
    struct sockaddr_in cli_addr;    //獲取客戶端地址信息
    int src_addr_len,cli_addr_len;
    int count,ret;
    struct in_addr addr;

    if (argc != 2)    //获取监听端口
    {
        printf("Error: you must enter port to monite\n");
        exit(0);
    }

    bzero(&src_addr, sizeof(src_addr));
    src_addr.sin_family = AF_INET;
    src_addr.sin_port = htons(str_to_number(argv[1]));

    printf("port:%d\n",str_to_number(argv[1]));

    src_addr_len = sizeof(src_addr);
    cli_addr_len = sizeof(cli_addr);

    sk = socket(AF_INET, SOCK_DGRAM, 0);
    if(sk<0)
    {
        printf("socket create failure\n");
        return -1;
    }

    ret = bind(sk, (struct sockaddr*)&src_addr, src_addr_len);
    if(ret < 0)
    {
        printf("socket bind failure\n");
        return -1;
    }


    while (1)
    {
        printf("Waiting for data from sender \n");
        count = recvfrom(sk, message, MAX_LEN, 0, (struct sockaddr*)&cli_addr, &cli_addr_len);
        if(count==-1)
        {
            printf("receive data failure\n");
            return -1;
        }
        addr.s_addr = cli_addr.sin_addr.s_addr;

        printf("Receive info: %s from %s %d\n", message,inet_ntoa(addr),cli_addr.sin_port);
   }

    close(sk);

    return 0;
}

int str_to_number(const char* str)
{
    int i,len, num = 0;
    len= strlen(str);

    for (i = 0; i < len;i++)
        num = num * 10 + str[i] - '0';

    return num;
}
UDP服务端

(二)mininet创建拓扑

from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import RemoteController
from mininet.link import TCLink
from mininet.util import dumpNodeConnections

class MyTopo(Topo):
    def __init__(self):
        super(MyTopo,self).__init__()

        #add host
        Host1 = self.addHost('h1')
        Host2 = self.addHost('h2')

        switch1 = self.addSwitch('e1')
        switch2 = self.addSwitch('s1')
        switch3 = self.addSwitch('s2')
        switch4 = self.addSwitch('s3')
        switch5 = self.addSwitch('s4')
        switch6 = self.addSwitch('e2')

        self.addLink(Host1,switch1)
        self.addLink(switch1,switch2)
        self.addLink(switch1,switch4)
        self.addLink(switch2,switch3)
        self.addLink(switch4,switch5)
        self.addLink(switch3,switch6)
        self.addLink(switch5,switch6)
        self.addLink(switch6,Host2)

topos = {"mytopo":(lambda : MyTopo())}

注意:我们的通信网口从1开始,递增。在代码中我们对于同一个交换机按照代码顺序递增

例一:

        self.addLink(Host1,switch1)    对于交换机e1,网口1,对应主机1
        self.addLink(switch1,switch2)   对于交换机e1,网口2,对应s1 
        self.addLink(switch1,switch4)   对于交换机e1,网口3,对应s3

例二:

        self.addLink(switch3,switch6)    对于交换机e2,网口1,对应s2
        self.addLink(switch5,switch6)    对于交换机e2,网口2,对应s4
        self.addLink(switch6,Host2)     对于交换机e2,网口3,对应主机2

(三)mininet配置静态流表

1.删除原有流表

dpctl del-flows
dpctl dump-flows  查看为空

红色表示链路不通,绿色通路

2.添加全局流表(所有交换机都有---对应边缘e1 e2需要特殊处理)

dpctl add-flow in_port=1,actions=output:2 
dpctl add-flow in_port=2,actions=output:1 

3.修改E1流表

sh ovs-ofctl add-flow e1 in_port=1,actions=output:2,3  这里output:2是重复的额,可以要,可以不要,只写3,不影响
sh ovs-ofctl add-flow e1 in_port=3,actions=output:1   增加了从网口3进入,从网口1出去

4.修改E2交换机流表项解决网络风暴

sh ovs-ofctl del-flows e2                    删除原来的错误流表
sh ovs-ofctl add-flow e2 in_port=3,actions=output:1,2   添加流表,使得主机2发送数据可以从两条链路发送出去
sh ovs-ofctl add-flow e2 in_port=1,actions=output:3    添加流表,使得s2交换机传递过来的数据,发送给主机2
sh ovs-ofctl add-flow e2 in_port=2,actions=output:3    添加流表,使得s4交换机传递过来的数据,发送给主机2

dpctl del-flows
dpctl add-flow in_port=1,actions=output:2
dpctl add-flow in_port=2,actions=output:1
sh ovs-ofctl add-flow e1 in_port=1,actions=output:2,3
sh ovs-ofctl add-flow e1 in_port=3,actions=output:1
sh ovs-ofctl del-flows e2
sh ovs-ofctl add-flow e2 in_port=3,actions=output:1,2
sh ovs-ofctl add-flow e2 in_port=1,actions=output:3
sh ovs-ofctl add-flow e2 in_port=2,actions=output:3
全部流表

5.流表配置完毕,网络可以通信

可以看到,按我们预期所想,使得主机B接收了冗余数据

重点:流表覆盖问题******

第一种
sh ovs-ofctl add-flow e2 in_port=3,actions=output:1,2
不等于
第二种
sh ovs-ofctl add-flow e2 in_port=3,actions=output:1
sh ovs-ofctl add-flow e2 in_port=3,actions=output:2
第一种正确,第二种出现第二条流表覆盖第一条流表项的情况,导致出错

四:IP首部选项字段操作

五:实现队列、关键流数据结构

(一)队列实现

#ifndef __QUEUE_H__
#define __QUEUE_H__

#include <stdio.h>
#include <stdlib.h>

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);                    //获取队列大小

void 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);                        //显示队列数据

#endif
queue.h
#include "queue.h"

void InitQueue(Queue* q,int n)
{
    q->queue = (int *)malloc(sizeof(int)*n);
    memset(q->queue, 0, sizeof(int)*n);
    q->NUM = 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;
}

void PushQueue(Queue* q, int ele)
{
    if (RePushQueue(q, ele) == 1)
        return;

    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;
}

void ShowData(Queue q)
{
    int i;
    for (i = 0; i < QueueLength(q); i++)
        printf("%d ", q.queue[(i + q.TOP) % q.NUM]);    //打印数据,可能需要修改
    printf("\n");
}

int PopQueue(Queue* q)
{
    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(q); i++)
        if (q.queue[(i + q.TOP) % q.NUM] == ele)
        {
            *n = i + 1;                                                //返回队首到该元素,一共几个数据
            return (i + q.TOP + 1) % q.NUM;            //返回该元素位置的下一个位置,新的队首
        }
    return -1;        
}
queue.c
队列操作:对于第二次到达的数据,若是在队列中匹配到,则将该数据以及前面的数据全部出队

(二)关键流操作实现

#ifndef __KEY_FLOW_H__
#define __KEY_FLOW_H__

#include <string.h>
#include "queue.h"

#define IP_MAX_LEN 16
#define IP_GROUP_MAP 2

char FlowInfo[IP_GROUP_MAP][4][IP_MAX_LEN];

typedef struct
{
    char src_ip[IP_MAX_LEN];
    char dst_ip[IP_MAX_LEN];
    int src_port;
    int dst_port;
    Queue que;
}Flows;

typedef struct
{
    Flows flow[IP_GROUP_MAP];
}KeyFlows;

void InitKeyFlow(KeyFlows* kf, int n);        //初始化静态关键流
int Str2Num(char* str);                                //字符串转数字
unsigned int getIPNumber(char *s);            //IP字符串转数字

#endif // !__KEY_FLOW_H__
keyflows.h
#define _CRT_SECURE_NO_WARNINGS
#include "queue.h"
#include "keyflow.h"
#include <stdlib.h>
#include <string.h>

char FlowInfo[IP_GROUP_MAP][4][IP_MAX_LEN] = {
    { "10.0.0.1", "10.0.0.2", "8080", "9090" },
    { "10.0.0.1", "10.0.0.2", "7070", "8080" }
};

void InitKeyFlow(KeyFlows* kf, int n)
{
    int i;
    memset(kf, 0, sizeof(KeyFlows));
    for (i = 0; i < IP_GROUP_MAP;i++)
    {
        strcpy(kf->flow[i].src_ip, FlowInfo[i][0]);
        strcpy(kf->flow[i].dst_ip, FlowInfo[i][1]);
        kf->flow[i].src_port = Str2Num(FlowInfo[i][2]);
        kf->flow[i].dst_port = Str2Num(FlowInfo[i][3]);
        InitQueue(&kf->flow[i].que,n);
    }
}

int Str2Num(char* str)
{
    int i,num = 0;
    int len = strlen(str);
    for (i = 0; i <= len - 1; i++)
    {
        num = num * 10 + str[i]-'0';
    }
    return num;
}

unsigned int getIPNumber(char *s)
{
    char Ip_Part[4] = { 0 };
    unsigned int num=0,i=0,j=0,k=3,nums[4];
    while (s[i]!='\0'&&s[i]!=' ')
    {
        if (s[i] == '.'||s[i]=='\0')
        {
            nums[k--] = Str2Num(Ip_Part);
            memset(Ip_Part, 0, sizeof(Ip_Part));
            j = 0,i++;
        }
        else
        {
            Ip_Part[j++] = s[i++];
        }
    }
    nums[k--] = Str2Num(Ip_Part);
    
    for (i = 0; i < 4; i++)
        num = num * 256 + nums[i];
    return num;
}
keyflows.c

注意:其中内存分配上使用malloc在linux内核中需要使用kmalloc(物理上连续)或者vmalloc(逻辑上连续)替换

六:修改OVS源码实现队列去冗余

//-------------------queue  start---------------------
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);                        //ÏÔʾ¶ÓÁÐÊý¾Ý
//-----------------queue end----------------------------

//----------------keyflow  start------------------------

#define IP_MAX_LEN 16
#define IP_GROUP_MAP 2

typedef struct
{
    unsigned int src_ip;
    unsigned int dst_ip;
    int src_port;
    int dst_port;
    Queue que;
}Flows;

typedef struct
{
    Flows flow[IP_GROUP_MAP];
}KeyFlows;

void InitKeyFlow(KeyFlows* kf, int n);        //³õʼ»¯¾²Ì¬¹Ø¼üÁ÷
int Str2Num(char* str);                                //×Ö·û´®×ªÊý×Ö
unsigned int getIPNumber(char *s);            //IP×Ö·û´®×ªÊý×Ö
int getFlowSeq(KeyFlows kf,unsigned int sip,unsigned int dip,int sport,int dport);
//----------------keyflow  end------------------------

int Key_flows_pattarn(struct vport *, struct sk_buff *);
vport.h
//-------------------queue  start---------------------
void InitQueue(Queue* q,int n)
{
    q->queue = (int *)kmalloc(sizeof(int)*n,GFP_KERNEL);
    memset(q->queue, 0, sizeof(int)*n);
    q->NUM = 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 (RePushQueue(q, ele) == 1)
        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)
{
    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(q); i++)
        if (q.queue[(i + q.TOP) % q.NUM] == ele)
        {
            *n = i + 1;                                                //·µ»Ø¶ÓÊ×µ½¸ÃÔªËØ£¬Ò»¹²¼¸¸öÊý¾Ý
            return (i + q.TOP + 1) % q.NUM;            //·µ»Ø¸ÃÔªËØÎ»ÖõÄÏÂÒ»¸öλÖã¬ÐµĶÓÊ×
        }
    return -1;        
}
//-----------------queue end----------------------------

//----------------keyflow  start------------------------

char FlowInfo[IP_GROUP_MAP][4][IP_MAX_LEN] = {
    { "10.0.0.1", "10.0.0.2", "8080", "9090" },
    { "10.0.0.1", "10.0.0.2", "7070", "8080" }
};

void InitKeyFlow(KeyFlows* kf, int n)
{
    int i;
    memset(kf, 0, sizeof(KeyFlows));
    for (i = 0; i < IP_GROUP_MAP;i++)
    {
        kf->flow[i].src_ip = getIPNumber(FlowInfo[i][0]);
        kf->flow[i].dst_ip = getIPNumber(FlowInfo[i][1]);
        kf->flow[i].src_port = Str2Num(FlowInfo[i][2]);
        kf->flow[i].dst_port = Str2Num(FlowInfo[i][3]);
        InitQueue(&kf->flow[i].que,n);
    }
}

int Str2Num(char* str)
{
    int i,num = 0;
    int len = strlen(str);
    for (i = 0; i <= len - 1; i++)
    {
        num = num * 10 + str[i]-'0';
    }
    return num;
}

unsigned int getIPNumber(char *s)
{
    char Ip_Part[4] = { 0 };
    unsigned int num=0,i=0,j=0,k=3,nums[4];
    while (s[i]!='\0'&&s[i]!=' ')
    {
        if (s[i] == '.'||s[i]=='\0')
        {
            nums[k--] = Str2Num(Ip_Part);
            memset(Ip_Part, 0, sizeof(Ip_Part));
            j = 0,i++;
        }
        else
        {
            Ip_Part[j++] = s[i++];
        }
    }
    nums[k--] = Str2Num(Ip_Part);
    
    for (i = 0; i < 4; i++)
        num = num * 256 + nums[i];
    return num;
}

int getFlowSeq(KeyFlows kf,unsigned int sip,unsigned int dip,int sport,int dport)
{
    int i;
    for(i=0;i<IP_GROUP_MAP;i++)
    {
        if(kf.flow[i].src_ip==sip && kf.flow[i].dst_ip==dip && 
            kf.flow[i].src_port==sport && kf.flow[i].dst_port == dport)
            return i;
    }
    return -1;
}
//----------------keyflow  end------------------------


KeyFlows KF;
int Initflag=0;
vport.c前部分

vport.c后部分

int Key_flows_pattarn(struct vport *vport,struct sk_buff *skb)
{
        struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb);
        struct udphdr *udp_header;

        unsigned int i=0;

        unsigned int src_ip = (unsigned int)ip_header->saddr;
        unsigned int dest_ip = (unsigned int)ip_header->daddr;
        unsigned int src_port = 0;
        unsigned int dest_port = 0;
        unsigned int Seq_no=0;
        int flows_no=-1,reput_flag=0;

        char* IP_OptVal;
        const char *vp_name = ovs_vport_name(vport);
if (ip_header->protocol==17 && strstr(vp_name,"e2")!=NULL) {
            if(!Initflag){        //Init queue
                InitKeyFlow(&KF, 4);
                Initflag=1;
            }
            udp_header = (struct udphdr *)skb_transport_header(skb);
            src_port = (unsigned int)ntohs(udp_header->source);
            dest_port = (unsigned int)ntohs(udp_header->dest);
            IP_OptVal=(char*)((char*)ip_header+(ip_header->ihl*4-8));for(i=2;i<6;i++)
                   Seq_no = Seq_no*256+(unsigned int)IP_OptVal[i];//match key flows
            for(i=0;i<IP_GROUP_MAP;i++)
            {if(KF.flow[i].src_ip==src_ip && KF.flow[i].dst_ip==dest_ip && 
                    KF.flow[i].src_port==src_port && KF.flow[i].dst_port == dest_port)
                {
                    flows_no = i;
                    break;
                }
            }
            pr_info("flow_no:%d\n",flows_no);

            if(flows_no!=-1)    //key flows matched
            {
                reput_flag = PushQueue(&((KF.flow[flows_no]).que), Seq_no);return reput_flag;
            }
        }return reput_flag;
}


int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
              const struct ip_tunnel_info *tun_info)
{
    struct sw_flow_key key;
    int error=1;
    struct ovs_frag_data *data = this_cpu_ptr(&ovs_frag_data_storage);
    if (data->mac_proto == MAC_PROTO_ETHERNET) {
        pr_info("---- MAC_PROTO_ETHERNET -----\n");
    }

    error = Key_flows_pattarn(vport,skb);
    pr_info("ovs_vport_receive-----return :%d\n",error);

    if (error) {
        kfree_skb(skb);
        return -ENOMEM;
    }

    OVS_CB(skb)->input_vport = vport;

    OVS_CB(skb)->mru = 0;
    OVS_CB(skb)->cutlen = 0;
    if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) {
        u32 mark;

        mark = skb->mark;
        skb_scrub_packet(skb, true);
        skb->mark = mark;
        tun_info = NULL;
    }

    ovs_skb_init_inner_protocol(skb);
    skb_clear_ovs_gso_cb(skb);
    /* Extract flow from 'skb' into 'key'. */
    error = ovs_flow_key_extract(tun_info, skb, &key);
    if (unlikely(error)) {
        kfree_skb(skb);
        return error;
    }
    ovs_dp_process_packet(skb, &key);

    return 0;
}

对于关键流,实现去冗余,只收到一条数据。因为发送的是第二条数据,故选项字段数据为2.

 

对于非关键流,则不会去冗余,收到多条
posted @ 2020-01-07 20:41  山上有风景  阅读(296)  评论(0)    收藏  举报