OpenvSwitch 2.5 代码分析与编译安装

首先,写这篇博客主要是记录一下博主在前前后后两三个月的时间里,编译安装OVS所采过的坑。水平有限,牛人勿喷。

###OpenvSwitch代码分析:

首先看一下OVS在一个SDN网络中的位置和与各部分组件的关系图:
这里写图片描述
上图绿框部分是博主想自己写的模块,也是想改动的地方。

继续看一张OVS自身的架构图:

这里写图片描述
每个模块都有不同的功能,主要就是 内核模块 + ovs-vswitchd + ovsdb-server

ovs-vswitchd 为主要模块,实现交换机的守护进程daemon
openvswitch.ko为Linux内核模块,支持数据流在内核的交换
ovsdb-server为轻量级数据库服务器,保存配置信息,ovs-vswitchd通过这个数据库获取配置信息

博主就是在安装内核模块的时候踩过了一些坑,一会再说。= =!

再看一下openvswitch的代码结构:

openvswitch2.5代码结构图
在如上的代码结构中,vswitchd中就是ovs-vswitchd的入口代码,ovsdb就是ovsdb-server的代码,ofproto即上述的中间抽象层,lib下面有netdev,dpif的实现,datapath里面就是内核模块openvswitch.ko的代码。
在OVS中有很多复杂而精妙的数据结构和程序构架,博主也是看了很多大牛的分析分享在这推荐几个博客:

庾志辉OVS 专栏
http://blog.csdn.net/column/details/openvswitch.html
datapath 模块分析
http://vinllen.com/ovs-datapathbi-ji/
NightCat的分析整理
http://www.jianshu.com/p/bf112793d658

###OpenvSwitch安装

安装Open vSwitch,主要是两大块:内核层的openvswitch-datapath模块和用户层的openvswitch-common模块和openvswitch-switch模块。

因为博主的特殊需求,所以要对openvswitch的代码进行自己编译安装。所以如果只是想安装openvswitch的话,大可不必自己编译安装,直接用apt-get或者yum等包管理工具直接自动化安装即可。

因为博主主要是想实现对OpenFlow消息的加密和认证,所以修改openvswitch 2.5 源代码的 ovs/ofproto/ofproto.c 中的handle_flow_mod函数。该函数用来处理FLOW_MOD消息,方便后续的验证和调试。

博主在这想让OVS接收到FLOW_MOD消息后在桌面上创建一个文件并连接本机的一个socket端口发送一个消息。改动如下:

static enum ofperr
handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofproto_flow_mod ofm;
    uint64_t ofpacts_stub[1024 / 8];
    struct ofpbuf ofpacts;
    enum ofperr error;

    FILE *FSpointer;
    #define MYPORT  11777
    #define BUFFER_SIZE 1024

    error = reject_slave_controller(ofconn);
    if (error) {
        goto exit;
    }

    ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
    error = ofputil_decode_flow_mod(&ofm.fm, oh, ofconn_get_protocol(ofconn),
                                    &ofpacts,
                                    u16_to_ofp(ofproto->max_ports),
                                    ofproto->n_tables);
    /*
    @PeterWang 2017-06-24
    @Create a flie to FS&Connect to socket 
    */
    //*******************************************************************************//
    FSpointer = fopen("/home/peter/Desktop/test.txt","a");
    fprintf(FSpointer, "%s\n","received a FLOW_MOD Info:");
    fprintf(FSpointer, "%x / %x :%d\n\n",ofm.fm.cookie,ofm.fm.cookie_mask,ofm.fm.command);

    int sock_cli = socket(AF_INET,SOCK_STREAM, 0);
    ///定义sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(MYPORT);  ///服务器端口
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  ///服务器ip

    ///连接服务器,成功返回0,错误返回-1
    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("connect error!");
        fprintf(FSpointer, "%s\n","connect error!");
    }
    char sendbuf[BUFFER_SIZE]="received a FLOW_MOD Info.";
    ///发送
    if(send(sock_cli, sendbuf, strlen(sendbuf),0)<0){
        perror("send error!");
        fprintf(FSpointer, "%s\n","send error!");
    }
    memset(sendbuf, 0, sizeof(sendbuf));
    //关闭文件和连接
    close(sock_cli);   
    fclose(FSpointer);
    //*******************************************************************************//
    if (!error) {
        error = ofproto_check_ofpacts(ofproto, ofm.fm.ofpacts,
                                      ofm.fm.ofpacts_len);
    }
    if (!error) {
        struct flow_mod_requester req;

        req.ofconn = ofconn;
        req.request = oh;
        error = handle_flow_mod__(ofproto, &ofm, &req);
    }
    if (error) {
        goto exit_free_ofpacts;
    }

    ofconn_report_flow_mod(ofconn, ofm.fm.command);

exit_free_ofpacts:
    ofpbuf_uninit(&ofpacts);
exit:
    return error;
}

接下来就是编译安装了,关于编译安装,博主使用两种方法,一种是直接make编译安装,另一种是打包成各个独立的deb安装包。这其中因为OVS的内核模块与Linux内核有的版本不兼容所以OVS官方给出了以下的版本对应关系:

Open vSwitchLinux kernel
1.4.x2.6.18 to 3.2
1.5.x2.6.18 to 3.2
1.6.x2.6.18 to 3.2
1.7.x2.6.18 to 3.3
1.8.x2.6.18 to 3.4
1.9.x2.6.18 to 3.8
1.10.x2.6.18 to 3.8
1.11.x2.6.18 to 3.8
2.0.x2.6.32 to 3.10
2.1.x2.6.32 to 3.11
2.3.x2.6.32 to 3.14
2.4.x2.6.32 to 4.0
2.5.x2.6.32 to 4.3
2.6.x3.10 to 4.7
2.7.x3.10 to 4.9
博主修改的是2.5.2版本的OVS源码,所以按上述表格来看linux内核应该是2.6.32到4.3是都可以兼容的。所以博主在https://www.kernel.org 下载并安装了3.16.44的内核并安装了,但是在后续的OVS安装过程中却并没有那么顺利。主要遇到问题是安装内核模块的时候总是报依赖错误,但是所报的依赖关系博主都一一用modprobe载入到内核了 = =!
后来换到了3.4.113的内核版本才正常安装,关于在3.16.44的内核报错,在后来看的一些博文中有的牛人曾提到,需要提前将内核中bridge模块卸载掉用openvswitch来替换。但是博主也试验过就算是卸载了bridge模块openvswitch模块还是报依赖错误。

(关于安装内核的时候遇到的问题请见博主的另一篇博客)

####直接make编译安装
下载源码:

wget https://github.com/openvswitch/ovs/archive/branch-2.5.zip

解压:

unzip branch-2.5.zip 
cd ovs-branch-2.5/

配置编译环境(root用户):

./configure --with-linux=/lib/modules/`uname -r`/build 2>/dev/null
./boot.sh

需要的编译的工具(root用户):

apt-get update
apt-get install  graphviz autoconf automake automake1.10 dh-autoreconf libssl-dev libtool python-all python-twisted-conch

关于解决其他依赖关系:
用 dpkg-checkbuilddeps 可以查看一下当前主机还有什么依赖关系没有安装,用apt-get或yum等包管理工具安装上即可

编译安装(root用户):

./boot.sh
make -j4  #这里-j后边的数字代表用多线程来进行编译,可以按自己机器配置选择
make install 
modprobe gre
insmod datapath/linux/openvswitch.ko
make modules_install
modprobe openvswitch

####打包成deb安装
博主第一次就是通过这种办法安装成功的,这也是OVS2.5官方给出的安装方法:
下载源码:

wget https://github.com/openvswitch/ovs/archive/branch-2.5.zip

解压:

unzip branch-2.5.zip 
cd ovs-branch-2.5/

首先,先安装两个工具:

apt-get install build-essential fakeroot

用 dpkg-checkbuilddeps 命令来检查依赖关系有没有安装好,将其提示的依赖关系用apt-get或yum包管理工具安装好。
安装好依赖关系后,执行以下命令来进行打包:

fakeroot debian/rules binary

编译打包过程有10分钟左右,时间因为机器配置可能有所差异。产生的 .deb安装包会在源码目录的上一级文件目录中看到,如下图:
打包完成生成的安装包文件

打包完了,下面就开始安装了。首先安装内核模块,博主在此费了不少时间,因为之前没有用过module-assistant安装过内核模块所以走了很多弯路。在上述的图片中可以看到跟内核有关的.deb文件(跟datapath有关的)有两个:

openvswitch-datapath-source_2.5.3-1_all.deb
openvswitch-datapath-dkms_2.5.3-1_all.deb

再次博主一直以为 -dkms是所谓的内核模块,安装好以后也加载不上 = =
其实,正确的安装方法如下:
首先安装openvswitch-datapath-source:

dpkg -i openvswitch-datapath-source_2.5.3-1_all.deb
module-assistant build openvswitch-datapath
module-assistant install openvswitch-datapath

现在lsmod就可以看到当前跟openvswitch相关的内核模块:

加载了的内核

继续安装其他组件:

dpkg -i openvswitch-common_2.5.3-1_amd64.deb

dpkg -i openvswitch-switch_2.5.3-1_amd64.deb

安装上这两个模块,OVS的大部分功能已经可以用了,其他几个模块组件用的很少。

到此安装就结束了,为了验证一下自己的改动是否被执行,所以将ovs创建一个br0 并将其连接到内网的一个ODL控制器,配置如下:
网桥配置情况
然后我准备用postman向ODL发送下发流表请求:
这里写图片描述
其中请求连接为:

http://192.168.1.177:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:59781766371651/flow-node-inventory:table/0

发送内容为(json格式):

{
    "table": [
        {
            "id": "0",
            "flow": [
                {
                    "id": "0",
                    "match": {
                        "in-port": "1",
                        "vlan-match": {
                            "vlan-id": {
                                "vlan-id-present": "true",
                                "vlan-id": "20"
                            }
                        }
                    },
                    "instructions": {
                        "instruction": [
                            {
                                "apply-actions": {
                                    "action": [
                                        {
                                            "output-action": {
                                                "output-node-connector": "3",
                                                "max-length": "65535"
                                            },
                                            "order": "1"
                                        },
                                        {
                                            "pop-vlan-action": {},
                                            "order": "0"
                                        }
                                    ]
                                },
                                "order": "0"
                            }
                        ]
                    },
                    "buffer_id": "65535",
                    "installHw": "true",
                    "barrier": "true",
                    "strict": "true",
                    "priority": "162",
                    "idle-timeout": "0",
                    "hard-timeout": "0",
                    "table_id": "0"
                }
            ]
        }
    ]
}

然后在OVS的主机上运行一个python脚本来监听,代码如下:

#!/usr/bin/python
#coding=utf-8
import socket  
import commands  
import threading
from time import ctime
import time
import fcntl
import struct

global host_IP,port
host_IP = "127.0.0.1"
port = 11111

def serverCallMulti(host_ip = "127.0.0.1",port = 11777):
    count = 0
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 定义socket类型,网络通信,TCP
    s.bind((host_ip, port))  # 套接字绑定的IP与端口
    s.listen(1)  # 开始TCP监听
    print "开始监听..."

    while True :
        conn, addr = s.accept()  # 接受TCP连接,并返回新的套接字与IP地址
        print'Connected by', addr ,". Create a new thread :(",count,")" # 输出客户端的IP地址
        t = threading.Thread(target=oneThread, args=(addr,count,conn,),name=addr[0]+'|'+str(count))
        t.start()
        count+=1
def oneThread(addr,count,conn):
    print ctime(),'开启新线程', threading.current_thread().getName()
    date = conn.recv(1024)  # 把接收的数据实例化 !!考虑存在阻塞
    print threading.current_thread().getName(),'send: ',date
    print "校验数据库流表信息..."
    time.sleep(0.2)
    print"ok.."
       
if __name__ =='__main__':
    host_ip = socket.gethostname()
    # serverCallMulti(host_ip=host)
    # host_ip = get_ip_address('eth0')
    print '监听IP :',host_ip
    serverCallMulti()

下面是执行情况:
效果展示

可以看到,OVS接收到FLOW_MOD消息时就会执行博主所加的代码,向python脚本发送一句“received a FLOW_MOD Info.”
至此,博主喜极而泣啊…

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值