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没有使用队列,收到重复数据。

 

posted @ 2022-05-04 22:41  山上有风景  阅读(148)  评论(0编辑  收藏  举报