UCloud的 SDN 网络是基于OVS做的。为了进行内网监控,需要 测试 用户的两台云主机通信是否正常。但是,作为服务方我们是无法登陆到用户的云主机的。因此,采用了向源端的OVS中注入一个ping包的方法测试网络是否正常。
基本原理
实验环境示意图:实现不登陆进SRC VM的前提下,发送Ping的请求包给DST VM,并捕获返回的应答包Ping Response。
染色:
用户有可能自己也会发送Ping包,为了区分用户的应答包和注入方式得到的应答包,需要对注入的Ping Request进行染色。首先看下ICMP包的格式,如下所示。
黄色标记起来的Identifier字段含义如下(RFC 792)
The identifier and sequence number may be used by the echo sender to aid in matching the replies with the echo requests
通过设置Identifier的值,可以区分不同的请求对应的应答包。
这里我们设置Identifier=111,捕获数据包时,需要指定ICMP包 icmp[4:2]=111,表明ICMP的第四、第五个字节的值等于111.
注入Ping Request包
需要使用ovs-ofctl packet-out进行注包 *** 作,命令格式如下:
ovs-ofctl packet-out switch in_port actions packet...
说明:
1、packet-out:连接到OVS,并且让OVS对Packet执行某个Action
Connects to switch and instructs it to execute the OpenFlow actions on each packet
2、switch:交换机的名字,比如实验环境中的br0
3、in_port:SRC VM连接到OVS的端口号,就是实验环境示意图中的In Port
4、packet:数据包,实验中就是染了色的Ping Request数据包。
5、Action:关键是Action的选择,我们采用的是resubmit,说明如下。resubmit会找到数据包对应的流表,然后更换掉in_port并执行流表中的Action。我们这里设置port=in_port。所以仅仅会执行流表中的Action。
resubmit([port],[table]):Re-searches this OpenFlow flow table with thein_portfield replaced byportand executes the actions found
捕获Ping的Response包
采用tcpdump进行捕获染了色的Ping数据包。命令如下
tcpdump -c 1 -iVIRTUAL_INTERFACEicmp and src hostSRC_IPand dst hostDST_IPand icmp[4:2]=111
1. VIRTUAL_INTERFACE: 云主机使用虚拟网卡的名字
2. SRC_IP:源云主机的IP地址
3. DST_IP:目的云主机的IP地址
4. 111:染色标记
golang实现的主逻辑
injectICMPCmd=util.GetInjectICMPPacket(srcIp,dstIp,srcMac,dstMac)//构造染了色的Ping Request包,以及注入命令tcpDumpCmd=util.TcpDumpICMPCommand(iface,srcIp,dstIp)//构造tcpdump的抓包命令tcpDumpResponse:=make(chanstring)srcHostIp:="XXX"//宿主机的IP地址gofunc(){command:=fmt.Sprintf("ssh %s@%s %s","root",srcHostIp,tcpDumpCmd)util.SshRunWithChannelResponse(command,tcpDumpResponse)}()// inject Packet into OVStime.Sleep(100*time.Millisecond)gofunc(){command:=fmt.Sprintf("ssh %s@%s %s","root",srcHostIp,injectICMPCmd)util.SshRun(command)}()success:=trueselect{casemsg:=<-tcpDumpResponse:ifstrings.Contains(msg,dstIp){fmt.Printf("Checking Success, Response: %s\n",msg)}else{success=falsefmt.Printf("Checking Fail, Response: %s\n",msg)}}returnsuccess
有如下三种方法可以删除openflow流表:
a. controller/ovs-ofctl主动发命令(OFPFC_DELETE or OFPFC_DELETE_STRICT)删除流表。OFPFC_DELETE_STRICT和OFPFC_DELETE 的区别是前者需要匹配所有的字段才能删除(包括优先级),并且一次只能删除一条流表,后者要求指定的字段必须是流表的一个子集(不能指定优先级),可以一次删除多个流表。
b. 流表的超时机制: 添加流表时如果指定idle_timeout或者hard_timeout参数,则流表超时后将被删除。如果不指定这俩参数,则默认不会被超时机制删除。hard_timeout指定的超时时间是从创建流表,或者修改流表开始计时,超时时间到后,不管此流表有没有被使用,都会被删除。idle_timeout指定流表空闲超时时间,从最近流表被使用开始计时,如果指定时间内此流表没有被使用,则被删除。
c. 强制回收机制: 添加流表时,如果当前流表个数大于等于最大流表个数,则判断是否可以强制回收之前添加的流表。可以通过Flow_Table里的overflow_policy参数指定当前流表个数大于等于最大流表个数时的行为,如果为refuse则拒绝添加新流表,如果为evict则强制删除即将超时的流表。强制回收只考虑指定了超时时间的流表。
添加流表时,如果指定了超时时间,并且流表指定的field包含group指定的field,则会将流表添加到一个分组中。具体为根据group指定的这些field计算hash值,再根据hash值到table->eviction_groups_by_id查找struct eviction_group。然后根据超时时间计算优先级,根据优先级将此流表插入struct eviction_group
针对强制删除流表,可以做如下实验
下面分析下这三种情况下的源码
controller/ovs-ofctl主动删除流表
将流表从分类器中删除
超时机制
添加流表时,如果指定了超时时间,则会将流表挂到链表ofproto->expirable上,在ovs-vswitchd的主循环中,会周期性的调用ofproto-dpif.c中的run函数,此函数会遍历链表ofproto->expirable判断流表是否超时,如果超时则将流表删除。
evict强制删除
添加流表时会将流表插入eviction_group中
当再次添加流表时,如果当前流表个数超过最大流表个数,则
因为科研需要做些小实验,涉及到交换机的网口数据的镜像转发。之前疫情在家使用一台本地虚拟机搭建OVS并作为KVM宿主机,OVS搭建网桥,OVS新建虚拟机并使用指定网桥。因为KVM中的虚拟机需要更改内核并重新编译,所以过程确实很繁琐。这次学校内的“私有云”搭建好了,所以准备用OVS+Linux Vxlan组网的形式把实验重新做一遍。我的实验需要将两台实验机和一台测试机,三个服务器进行组网。这里使用了三台2核4G的Centos 7.6的虚拟机
在前面查资料的时候发现,网上很多教程或者案例要不是两头都是Linux ip link来组网,要不就是两边都是OVS,使用OVS来组网。在我的场景里,两边都使用Linux ip link的话,不能很好地进行流量镜像转发,两头都是OVS的话虽然也可以,但是过于繁重了,所以我们的实验是一边是OVS,另一边是Linux ip link进行点对点的Vxlan组网。测试机作为虚拟交换设备承载OVS,两台实验机分别和测试机进行点对点的Vxlan组网。
Client1 :eth0 ip:10.122.0.22/16
Clinet2 :eth0 ip:10.122.3.152/16
Test(Server) :eth0 ip:10.122.1.103/16
Firewalld Status :Stop
三台机器的eth0网卡互通
管理 VXLAN 接口
Linux VXLAN 接口的基本管理如下:
创建点对点的 VXLAN 接口:
上面这条命令创建一个名字为 vxlan0,类型为 vxlan 的网络 interface,后面是 vxlan interface 需要的参数:
id 4100 :指定 VNI 的值,这个值可以在 1 到 2^24 之间,互联的两端的ID必须保持一致,相当于一根网线的两头
dstport :vtep 通信的端口,linux 默认使用 8472(为了保持兼容,默认值一直没有更改),而 IANA 分配的端口是 4789,且OVS默认的Vxlan通信端口也是4789,所以我们这里指定了它的值为4789
remote 10.122.1.103 :对方 vtep 的地址,类似于点对点协议
local 10.122.0.22 :当前节点 vtep 要使用的 IP 地址
dev eth0 :当节点用于 vtep 通信的网卡设备,用来读取 IP 地址。注意这个参数和 local 参数含义是相同的,在这里写出来是为了告诉大家有两个参数存在
创建多播模式的 VXLAN 接口:
多播组主要通过 ARP 泛洪来学习 MAC 地址,即在 Vxlan 子网内广播 ARP 请求,然后对应节点进行响应。group 指定多播组的地址。
查看 VXLAN 接口详细信息:
启动/关闭网卡
给指定网卡分配ip
Client1和Client2分别建立一个Vxlan0的网卡, remote address 为 Test 机器 eth0 网卡的地址 10.122.1.103 , local adress 为本地服务器的 eth0 网卡的地址。
这个时候使用 ip a 命令就可以看到两个新的 vxlan0 的网卡了。
给两个网卡配上IP并启动
到这一步相当于两根网线的一头插在了两台虚拟机上了,接下来就需要把这两个网线的另一头都插到交换机上就可以了。可以使用 ip r 命令看看,在新建网卡的时候,路由也自动加上了。
这个时候先给Test服务器上的vxlan0网卡配上IP并启动就可以了。
这个时候相当于把一根网线一头插在 Test 的网口上,另一头插在 Client1 的网卡上。看一看 Test 也自动生成了路由,可以进行 ping 命令检测点到点Vxlan是否建立成功。
这里大致思路就是在Test服务器上利用OVS搭建一个网桥,然后把两个vxlan网卡加到这个网桥就可以啦。
这里不要忘记手动更改路由,删除之前vxlan0和vxlan1的路由,把所有192.168.0.0/24的指向br0网桥就可以了。
到这里就可以进行ping测试了。后面的实验就是对网桥上port的 *** 作,就不多说了。
[参考] https://juejin.im/post/6844904126539628557
[参考] https://cizixs.com/2017/09/28/linux-vxlan/
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)