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


    一:拓扑搭建

    (一)代码实现

    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',ip='10.0.0.1')
            Host2 = self.addHost('h2',ip='10.0.0.2')
            Host3 = self.addHost('h3',ip='10.0.0.3')
            Host4 = self.addHost('h4',ip='10.0.0.4')
            Host5 = self.addHost('h5',ip='10.0.0.5')
            Host6 = self.addHost('h6',ip='10.0.0.11')
            Host7 = self.addHost('h7',ip='10.0.0.12')
            Host8 = self.addHost('h8',ip='10.0.0.13')
            Host9 = self.addHost('h9',ip='10.0.0.14')
            Host10 = self.addHost('h10',ip='10.0.0.15')
    
            switch1 = self.addSwitch('e1')
            switch2 = self.addSwitch('s1')
            switch3 = self.addSwitch('s2')
            switch4 = self.addSwitch('e2')
    
            self.addLink(Host1,switch1, bw=5, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(Host2,switch1, bw=5, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(Host3,switch1, bw=5, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(Host4,switch1, bw=5, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(Host5,switch1, bw=5, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(switch1,switch2, bw=5, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(switch2,switch4, bw=5, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(switch1,switch3, bw=5, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(switch3,switch4, bw=5, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(switch4,Host6, bw=50, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(switch4,Host7, bw=50, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(switch4,Host8, bw=50, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(switch4,Host9, bw=50, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
            self.addLink(switch4,Host10, bw=50, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)
    
    topos = {"mytopo":(lambda : MyTopo())}

    二:流表项实现

    dpctl del-flows
    sh ovs-ofctl add-flow s1 in_port=1,actions=output:2
    sh ovs-ofctl add-flow s1 in_port=2,actions=output:1
    sh ovs-ofctl add-flow s2 in_port=1,actions=output:2
    sh ovs-ofctl add-flow s2 in_port=2,actions=output:1
    sh ovs-ofctl add-flow e1 in_port=1,actions=output:6,7
    sh ovs-ofctl add-flow e1 in_port=2,actions=output:6,7
    sh ovs-ofctl add-flow e1 in_port=3,actions=output:6,7
    sh ovs-ofctl add-flow e1 in_port=4,actions=output:6,7
    sh ovs-ofctl add-flow e1 in_port=5,actions=output:6,7
    
    sh ovs-ofctl add-flow e2 in_port=3,actions=output:1,2
    sh ovs-ofctl add-flow e2 in_port=4,actions=output:1,2
    sh ovs-ofctl add-flow e2 in_port=5,actions=output:1,2
    sh ovs-ofctl add-flow e2 in_port=6,actions=output:1,2
    sh ovs-ofctl add-flow e2 in_port=7,actions=output:1,2
    
    
    sh ovs-ofctl add-flow e1 dl_type=0x0806,actions=output:1,2,3,4,5
    sh ovs-ofctl add-flow e2 dl_type=0x0806,actions=output:3,4,5,6,7
    
    sh ovs-ofctl add-flow e1 ip,nw_src=10.0.0.11,actions=output:1
    sh ovs-ofctl add-flow e1 ip,nw_src=10.0.0.12,actions=output:2
    sh ovs-ofctl add-flow e1 ip,nw_src=10.0.0.13,actions=output:3
    sh ovs-ofctl add-flow e1 ip,nw_src=10.0.0.14,actions=output:4
    sh ovs-ofctl add-flow e1 ip,nw_src=10.0.0.15,actions=output:5
    sh ovs-ofctl add-flow e2 "priority=100,dl_type=0x0800,nw_dst=10.0.0.11,actions=rmdupqueue(queue_id=50,max_len=100),3"        //去重复
    sh ovs-ofctl add-flow e2 "priority=100,dl_type=0x0806,nw_dst=10.0.0.11,actions=output:3"  //arp通过
    sh ovs-ofctl add-flow e2 ip,nw_src=10.0.0.2,actions=output:4
    sh ovs-ofctl add-flow e2 ip,nw_src=10.0.0.3,actions=output:5
    sh ovs-ofctl add-flow e2 ip,nw_src=10.0.0.4,actions=output:6
    sh ovs-ofctl add-flow e2 ip,nw_src=10.0.0.5,actions=output:7

    补充:上面0x0800针对ip报文,我们如果只考虑UDP,则使用如下:

    sh ovs-ofctl add-flow e2 "udp,nw_dst=10.0.0.11,actions=rmdupqueue(queue_id=50,max_len=100),3"        //去重复

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

    (二)客户端

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

    四:测试结果

    可以看到h1与h6使用队列,实现去重,h2与h7没有使用队列,收到重复数据。

  • 相关阅读:
    删除文件时,提示 "操作无法完成..." 怎么处理
    对象的理解
    TP5架构下链接SQL数据库的一种方法
    关于URL隐藏index.php方法
    非典型的千万用户后台之路
    就这样,再见2015
    理想的程序员
    4个小例子告诉你:如何成为一名数据极客
    馆中窥职:小公司没那么糟糕
    JAVA设计模式详解(六)----------状态模式
  • 原文地址:https://www.cnblogs.com/ssyfj/p/13622342.html
Copyright © 2020-2023  润新知