ovs对于vxlan的支持依赖datapath的类型,对于kernel space datapath来说,创建vxlan端口后,在将此端口添加到datapath时,会调用kernel自身提供的vxlan.ko模块创建出vxlan_sys_port来,ovs只需要将流表action指向vxlan_sys_port即可,vxlan报文的封装,封装后路由查找和邻居查找都由vxlan模块/kernel来实现;而对于userspace datapath来说,vxlan报文的封装,封装后路由查找和邻居查找都由ovs本身实现。

实验

下面分别实验两种datapath下的vxlan。
kernel space vxlan
拓扑图如下所示

image.png

对应的命令如下

//在vm1上操作,创建一个bridge,添加一个vxlan端口
ovs-vsctl add-br br0
ovs-vsctl add-port br0 vxlan1 -- set interface vxlan1 type=vxlan options:remote_ip=10.10.10.2 options:key=flow options:dst_port=8472
ifconfig br0 1.1.1.1/24
ifconfig ens8 10.10.10.1/24
//在vm2上操作
ovs-vsctl add-br br0
ovs-vsctl add-port br0 vxlan1 -- set interface vxlan1 type=vxlan options:remote_ip=10.10.10.1 options:key=flow options:dst_port=8472
ifconfig br0 1.1.1.2/24
ifconfig ens8 10.10.10.2/24

命令执行成功后,查看基本情况

//创建vlxna端口后会监听端口8472,用来接收vxlan报文
root@master:~# netstat -nap | grep 8472
udp        0      0 0.0.0.0:8472            0.0.0.0:*                           -
udp6       0      0 :::8472                 :::*                                -//查看vxlan端口驱动类型为vxlan
root@master:~# ethtool -i vxlan_sys_8472
driver: vxlan
version: 0.1
firmware-version:
expansion-rom-version:
bus-info:
supports-statistics: no
supports-test: no
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: no//查看ovs当前配置
root@master:~# ovs-vsctl show
1e633d2b-7a9e-44ba-9c16-89e12912c2d6Bridge "br0"Port "br0"Interface "br0"type: internalPort "vxlan1"Interface "vxlan1"type: vxlanoptions: {dst_port="8472", key=flow, remote_ip="10.10.10.2"}//查看datapath端口
root@master:~# ovs-appctl dpctl/show
system@ovs-system:lookups: hit:147 missed:23 lost:0flows: 4masks: hit:457 total:5 hit/pkt:2.69port 0: ovs-system (internal)port 1: br0 (internal)port 2: vxlan_sys_8472 (vxlan: packet_type=ptap)

在vm1上ping 1.1.1.2,可以ping通,查看流表及抓包情况

root@master:~# ping 1.1.1.2
PING 1.1.1.2 (1.1.1.2) 56(84) bytes of data.
64 bytes from 1.1.1.2: icmp_seq=1 ttl=64 time=4.58 ms
64 bytes from 1.1.1.2: icmp_seq=2 ttl=64 time=0.643 ms
^C
--- 1.1.1.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.643/2.610/4.578/1.967 ms//datapath流表信息,有4条流表,两条arp相关的,两条icmp相关的,从1口收到的报文转发给2口,从2口收到的报文转发给1口
root@master:~# ovs-appctl dpctl/dump-flows
recirc_id(0),tunnel(tun_id=0x0,src=10.10.10.2,dst=10.10.10.1,flags(-df-csum+key)),in_port(2),eth(src=d6:5a:9e:97:39:4f,dst=b6:7b:1a:1e:79:44),eth_type(0x0806), packets:1, bytes:42, used:8.528s, actions:1
recirc_id(0),in_port(1),eth(src=b6:7b:1a:1e:79:44,dst=d6:5a:9e:97:39:4f),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:13, bytes:1274, used:0.384s, actions:set(tunnel(tun_id=0x0,dst=10.10.10.2,ttl=64,tp_dst=8472,flags(df|key))),2
recirc_id(0),in_port(1),eth(src=b6:7b:1a:1e:79:44,dst=d6:5a:9e:97:39:4f),eth_type(0x0806), packets:0, bytes:0, used:never, actions:set(tunnel(tun_id=0x0,dst=10.10.10.2,ttl=64,tp_dst=8472,flags(df|key))),2
recirc_id(0),tunnel(tun_id=0x0,src=10.10.10.2,dst=10.10.10.1,flags(-df-csum+key)),in_port(2),eth(src=d6:5a:9e:97:39:4f,dst=b6:7b:1a:1e:79:44),eth_type(0x0800),ipv4(frag=no), packets:13, bytes:1274, used:0.384s, actions:1//在vxlan端口上抓包,此时只能抓到封装前的报文
root@master:~# tcpdump -vne -i vxlan_sys_8472
tcpdump: listening on vxlan_sys_8472, link-type EN10MB (Ethernet), capture size 262144 bytes
23:02:27.662008 0e:ed:bb:33:06:40 > 96:e5:e8:08:63:44, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 23800, offset 0, flags [DF], proto ICMP (1), length 84)1.1.1.2 > 1.1.1.1: ICMP echo request, id 9663, seq 89, length 64
23:02:27.662095 96:e5:e8:08:63:44 > 0e:ed:bb:33:06:40, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 64219, offset 0, flags [none], proto ICMP (1), length 84)1.1.1.1 > 1.1.1.2: ICMP echo reply, id 9663, seq 89, length 64//在最终出端口上抓包,可以抓到封装vxlan后的报文
root@master:~# tcpdump -vne -i ens8
tcpdump: listening on ens8, link-type EN10MB (Ethernet), capture size 262144 bytes
23:36:05.294029 52:54:00:9f:e8:0e > 52:54:00:9e:98:20, ethertype IPv4 (0x0800), length 148: (tos 0x0, ttl 64, id 36259, offset 0, flags [DF], proto UDP (17), length 134)10.10.10.2.49240 > 10.10.10.1.8472: OTV, flags [I] (0x08), overlay 0, instance 0
0e:ed:bb:33:06:40 > 96:e5:e8:08:63:44, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 11222, offset 0, flags [DF], proto ICMP (1), length 84)1.1.1.2 > 1.1.1.1: ICMP echo request, id 9663, seq 2061, length 64
23:36:05.294094 52:54:00:9e:98:20 > 52:54:00:9f:e8:0e, ethertype IPv4 (0x0800), length 148: (tos 0x0, ttl 64, id 55108, offset 0, flags [DF], proto UDP (17), length 134)10.10.10.1.51916 > 10.10.10.2.8472: OTV, flags [I] (0x08), overlay 0, instance 0
96:e5:e8:08:63:44 > 0e:ed:bb:33:06:40, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 57149, offset 0, flags [none], proto ICMP (1), length 84)1.1.1.1 > 1.1.1.2: ICMP echo reply, id 9663, seq 2061, length 64

ping流程如下

a. vm1上ping 1.1.1.2时,首先查找arp表,找不到后,会发送arp请求报文。arp请求报文从br0发出后,网桥br0收到,查找datapath流表,因为是首包肯定查不到,然后将收包上送用户态的slow-path处理。
b. 在slow-path查找openflow流表,action为 normal,需要查找fdb表。
root@master:~# ovs-ofctl dump-flows br0cookie=0x0, duration=62611.119s, table=0, n_packets=21004, n_bytes=1141452, priority=0 actions=NORMAL
因为目的mac为广播,所以需要广播到网桥br0上其他所有端口,目前只有端口vxlan_sys_8472。
c. 上一步查找流表结果是将报文从vxlan_sys_8472发出,因为vxlan_sys_8472为vxlan端口,所以会将vxlan相关配置一同下发到datapath流表
root@master:~# ovs-appctl dpctl/dump-flows
recirc_id(0),in_port(1),eth(src=b6:7b:1a:1e:79:44,dst=d6:5a:9e:97:39:4f),eth_type(0x0806), packets:0, bytes:0, used:never, actions:set(tunnel(tun_id=0x0,dst=10.10.10.2,ttl=64,tp_dst=8472,flags(df|key))),2
d. 除了下发流表到datapath外,还会将上送的首包下发到datapath,根据最新的流表执行。即将首包发给vxlan_sys_8472处理,同时携带vxlan相关配置(比如remote_ip,dst_port, tunnle id等信息)
e. 报文到达vxlan_sys_8472后根据vxlan配置,封装成vxlan报文,根据外层目的ip查找路由表可知,需要从ens8网卡发出
root@master:~# ip r
default via 192.168.122.1 dev ens3 proto static
1.1.1.0/24 dev br0 proto kernel scope link src 1.1.1.1
10.10.10.0/24 dev ens8 proto kernel scope link src 10.10.10.1
f. 封装后的vxlan报文经过底层网络转发到vm2,根据目的ip发现需要本机处理,经过协议栈处理后,相当于解封装vxlan报文,再根据目的端口号8472查找对应的socket可知,需要将udp的payload,即内层arp请求报文发给vm2上vxlan端口处理。
g. 因为vxlan端口在网桥上,也需要查找vm2上datapath流表,当然也会失败,将arp请求报文上送vm2上slow-path处理,广播报文发给网桥上其他端口,目前只有br0,最后将流表信息下发到datapath,并且将arp请求报文下发到datapath,最终发给端口br0。
h. 上一步在slow-path收到arp请求报文时,也会学到对端的mac,如下
root@node1:~# ovs-appctl fdb/show br0port  VLAN  MAC                Age1     0  b6:7b:1a:1e:79:44    1
LOCAL     0  d6:5a:9e:97:39:4f    1
vm2回复arp响应报文时,目的mac为单播地址。查找datapath流表失败,上送slow-path,查找openflow流表,查找fdb表成功找到出端口1。注意fdb表的出端口对应的是openflow端口,可通过ovs-ofctl show br0查看,不要和datapath端口号混淆了。
i. 将流表信息下发到datapath,并将报文发给vxlan端口,封装vxlan报文,查找路由表,发送出去。
j. vm1收到后,解封装vxlan报文,查找datapath流表失败,上送slow-path,查找fdb表成功找到出端口,同时学习到对端的mac。将流表下发到datapath,报文发给vm1上的br0。至此vm1学到了1.1.1.2的mac地址。
k. vm1上学到mac地址后发出ping报文,网桥br1收到ping包,查找datapath流表,因为是首包肯定查不到,上送用户态的slow-path处理,查找fdb表成功找到出端口,将流表下发到datapath,将报文发给vxlan端口,封装vxlan后发出。
l. 后续的流程都是类似的,不再赘述。后续的报文可以直接查找datapath流表进行转发即可。

userspace vxlan
拓扑图如下所示

image.png

注意:br1上通往外部的端口即可以是绑定到dpdk driver的(由pmd线程处理收发包),也可以是绑定到kernel driver的(由ovs的non-pmd线程(vswitchd主线程)处理它的收发包)。上图中的ens8端口是绑定在kernel driver的。

对应的命令如下

//以下命令在vm1上执行
ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev
ovs-vsctl add-port br0 vxlan1 -- set interface vxlan1 type=vxlan options:remote_ip=10.10.10.2 options:key=flow options:dst_port=8472
ifconfig br0 1.1.1.1/24ovs-vsctl add-br br1 -- set bridge br1 datapath_type=netdev
ovs-vsctl add-port br1 ens8
ip link set dev br1 up
ip addr add dev br1 10.10.10.1/24
ip link set dev ens8 up//以下命令在vm2上执行
ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev
ovs-vsctl add-port br0 vxlan1 -- set interface vxlan1 type=vxlan options:remote_ip=10.10.10.1 options:key=flow options:dst_port=8472
ifconfig br0 1.1.1.2/24ovs-vsctl add-br br1 -- set bridge br1 datapath_type=netdev
ovs-vsctl add-port br1 ens8
ip link set dev br1 up
ip addr add dev br1 10.10.10.2/24
ip link set dev ens8 up

查看下ovs配置,因为userspace vxlan,所以此时在vm上通过ifconfig是看不到类似vxlan_sys_8472的vxlan端口的。

root@master:~# ovs-vsctl show
163a03bf-8b1b-4043-8d37-8b2287bf94feBridge "br1"Port "br1"Interface "br1"type: internalPort "ens8"Interface "ens8"Bridge "br0"Port "vxlan1"Interface "vxlan1"type: vxlanoptions: {dst_port="8472", key=flow, remote_ip="10.10.10.2"}Port "br0"Interface "br0"type: internal//查看userspace datapath端口信息
root@master:~# ovs-appctl dpctl/show
netdev@ovs-netdev:lookups: hit:27 missed:26 lost:0flows: 1port 0: ovs-netdev (tap)port 1: br0 (tap)port 2: vxlan_sys_8472 (vxlan: packet_type=ptap)port 3: br1 (tap)port 4: ens8//查看路由信息,封装vxlan后,根据外层ip查找路由表,寻找出接口
root@master:~# ovs-appctl ovs/route/show
Route Table:
Cached: 1.1.1.1/32 dev br0 SRC 1.1.1.1
Cached: 10.10.10.1/32 dev br1 SRC 10.10.10.1
Cached: 127.0.0.1/32 dev lo SRC 127.0.0.1
Cached: 172.17.0.1/32 dev docker0 SRC 172.17.0.1
Cached: 192.168.122.20/32 dev ens3 SRC 192.168.122.20
Cached: ::1/128 dev lo SRC ::1
...
Cached: 1.1.1.0/24 dev br0 SRC 1.1.1.1
Cached: 10.10.10.0/24 dev br1 SRC 10.10.10.1
Cached: 192.168.122.0/24 dev ens3 SRC 192.168.122.20
Cached: 172.17.0.0/16 dev docker0 SRC 172.17.0.1
Cached: 127.0.0.0/8 dev lo SRC 127.0.0.1
Cached: 0.0.0.0/0 dev ens3 GW 192.168.122.1 SRC 192.168.122.20
Cached: fe80::/64 dev br1 SRC fe80::1031:66ff:fe3c:9547

在vm1上ping 1.1.1.2,可以ping通,查看流表及抓包情况

root@master:~# ping 1.1.1.2
PING 1.1.1.2 (1.1.1.2) 56(84) bytes of data.
64 bytes from 1.1.1.2: icmp_seq=1 ttl=64 time=1.85 ms
^C
--- 1.1.1.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.848/1.848/1.848/0.000 ms//datapath流表信息(先忽略arp流表),出方向流表只有一条,封装vxlan后,发给出端口即可,但是入方向需要两条,一条用于查找tunnel信息,解封装后将报文送到vxlan端口,第二条根据内层报文信息转到正确的端口
root@master:~# ovs-appctl dpctl/dump-flows
flow-dump from non-dpdk interfaces:
recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth(src=2e:ab:5f:92:6c:47,dst=12:31:66:3c:95:47),eth_type(0x0800),ipv4(dst=10.10.10.1,proto=17,frag=no),udp(dst=8472), packets:919, bytes:90148, used:0.409s, actions:tnl_pop(2)
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=6a:91:a4:4f:78:45,dst=b2:42:ef:84:79:4b),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:267, bytes:26166, used:0.410s, actions:clone(tnl_push(tnl_port(2),header(size=50,type=4,eth(dst=52:54:00:9f:e8:0e,src=12:31:66:3c:95:47,dl_type=0x0800),ipv4(src=10.10.10.1,dst=10.10.10.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=8472,csum=0x0),vxlan(flags=0x8000000,vni=0x0)),out_port(3)),4)
tunnel(tun_id=0x0,src=10.10.10.2,dst=10.10.10.1,flags(-df-csum+key)),recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth(src=b2:42:ef:84:79:4b,dst=6a:91:a4:4f:78:45),eth_type(0x0800),ipv4(dst=1.1.1.1,proto=1,frag=no), packets:100, bytes:9800, used:0.409s, actions:1//neigh信息
root@master:~# ovs-appctl tnl/neigh/show
IP                                            MAC                 Bridge
==========================================================================
1.1.1.1                                       6a:91:a4:4f:78:45   br0
1.1.1.2                                       b2:42:ef:84:79:4b   br0
10.10.10.1                                    12:31:66:3c:95:47   br1
10.10.10.2                                    52:54:00:9f:e8:0e   br1

ping流程如下(暂时忽略arp学习过程)

a. vm1上ping 1.1.1.2后,br0端口收到icmp报文,查找fast path失败,上送slow-path处理,广播到vxlan1端口。
b. 在vxlan1端口根据配置的remote_ip 10.10.10.2查找路由表,找到出接口br1和源ip。
Cached: 10.10.10.0/24 dev br1 SRC 10.10.10.1
再根据neigh表找到目的mac
10.10.10.2                                    52:54:00:9f:e8:0e   br1
c. 此时外层mac,ip和udp端口号都已知,根据这些信息构造外层报文信息。然后假装报文从br1收到,查找br1上的openflow流表,action为normal,需要查找fdb表,未知报文flood到br1上所有端口,当前只有ens8。所以最后的流表信息如下,会将此流表下发到datapath。
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=6a:91:a4:4f:78:45,dst=b2:42:ef:84:79:4b),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:267, bytes:26166, used:0.410s, actions:clone(tnl_push(tnl_port(2),header(size=50,type=4,eth(dst=52:54:00:9f:e8:0e,src=12:31:66:3c:95:47,dl_type=0x0800),ipv4(src=10.10.10.1,dst=10.10.10.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=8472,csum=0x0),vxlan(flags=0x8000000,vni=0x0)),out_port(3)),4)
d. 流表下发后,会将报文按照流表action封装成vxlan报文,从ens8发送出去。
e. vm2上的ens8收到vxlan报文后,查找fast path失败,上送slow-path,在函数terminate_native_tunnel中根据外层报文信息查找是否有匹配的tunnel,如果有将设置action为OVS_ACTION_ATTR_TUNNEL_POP,出端口为tunnel口。
f. 下发上面的流表到datapath,同时执行action处理报文。将外层封装去除,以出端口vxlan1为入端口,重新走slow-path,找到br0,将这次流表也下发到datapath。所以vxlan报文接收方向有两条流表。
g. 后续流程类型,不再赘述。

源码分析

创建vxlan端口流程

main -> bridge_run -> bridge_add_ports -> iface_create -> iface_create -> iface_do_create
在 iface_do_create函数中iface_set_netdev_config 将vxlan配置更新到 dev->tnl_cfgofproto_port_add port_add将vxlan端口添加到datapath中update_port ->ofport_install -> port_construct保存tunnel port到全局变量

在函数type_run中,将ofport->is_tunnel 转换到 xport->is_tunnel。后面流表转发只会用到xport相关。

发送vxlan报文流程
a. slow-path
slow-path处理流程,如果找到或者flood到vxlan端口后,调用compose_output_action__

upcall_cb -> process_upcall -> upcall_xlate -> xlate_actions -> do_xlate_actions -> xlate_output_action -> xlate_normal -> xlate_normal_flood -> output_normal -> compose_output_action -> compose_output_action__
static void
compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, const struct xlate_bond_recirc *xr, bool check_stp)if (xport->is_tunnel) {//userspace vxlan 这里主要设置is_native_tunnel为true,后面才会真正设置actionif (ovs_native_tunneling_is_on(ctx->xbridge->ofproto)) {xlate_report(ctx, OFT_DETAIL, "output to native tunnel");is_native_tunnel = true;} else {//kernelspace vxlan 这里主要添加两个action set和tunnelxlate_report(ctx, OFT_DETAIL, "output to kernel tunnel");commit_odp_tunnel_action(flow, &ctx->base_flow, ctx->odp_actions);nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SET);nl_msg_start_nested(a, OVS_KEY_ATTR_TUNNEL);}//userspace vxlan发送流程,调用build_tunnel_send根据remote_ip查找路由表,查找mac表,并且添加三个action:  //OVS_ACTION_ATTR_CLONE,OVS_ACTION_ATTR_TUNNEL_PUSH,OVS_ACTION_ATTR_OUTPUTif (is_native_tunnel) {/* Output to native tunnel port. */build_tunnel_send(ctx, xport, flow, odp_port);} else if (terminate_native_tunnel(ctx, ofp_port, flow, wc, &odp_tnl_port)) {//这个判断是接收到vxlan报文的处理//terminate_native_tunnel 根据外层flow查找tunnel信息,找到 odp 端口,即在datapath的端口号/* Intercept packet to be received on native tunnel port. */nl_msg_put_odp_port(ctx->odp_actions, OVS_ACTION_ATTR_TUNNEL_POP, odp_tnl_port);} else {//对于在kernelspace转发的vxlan来说,只需要把action的出端口设置为vxlan即可,不用ovs来封装vxlan报文nl_msg_put_odp_port(ctx->odp_actions, OVS_ACTION_ATTR_OUTPUT, out_port);}
}

对于userspace vxlan来说,主要下发三个action: OVS_ACTION_ATTR_CLONE,OVS_ACTION_ATTR_TUNNEL_PUSH,OVS_ACTION_ATTR_OUTPUT。其中OVS_ACTION_ATTR_TUNNEL_PUSH和OVS_ACTION_ATTR_OUTPUT嵌套在OVS_ACTION_ATTR_CLONE中。对应的流表如下

recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=6a:91:a4:4f:78:45,dst=b2:42:ef:84:79:4b),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:267, bytes:26166, used:0.410s, actions:clone(tnl_push(tnl_port(2),header(size=50,type=4,eth(dst=52:54:00:9f:e8:0e,src=12:31:66:3c:95:47,dl_type=0x0800),ipv4(src=10.10.10.1,dst=10.10.10.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=8472,csum=0x0),vxlan(flags=0x8000000,vni=0x0)),out_port(3)),4)actions:clone() 对应OVS_ACTION_ATTR_CLONE。
tnl_push()对应OVS_ACTION_ATTR_TUNNEL_PUSH。括号中的tnl_port(2)表示端口2是vxlan口,header()中的内容包含外层源目的mac,源目的ip和源目的端口号和vxlan头部的flag和vni,out_port(3)表示vxlan报文的出端口,但实际上报文不会直接从此端口发出,而是以它为入端口,再次走slow-path查找实际的出端口。
最后的数字4对应出端口OVS_ACTION_ATTR_OUTPUT。

对于kernel space vxlan来说,也会下发三个action: OVS_ACTION_ATTR_SET,OVS_KEY_ATTR_TUNNEL,OVS_ACTION_ATTR_OUTPUT。其中OVS_KEY_ATTR_TUNNEL嵌套在OVS_ACTION_ATTR_SET中。对应的流表如下

recirc_id(0),in_port(1),eth(src=96:e5:e8:08:63:44,dst=0e:ed:bb:33:06:40),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:400, bytes:39200, used:0.476s, actions:set(tunnel(tun_id=0x0,dst=10.10.10.2,ttl=64,tp_dst=8472,flags(df|key))),2actions:set() 对应OVS_ACTION_ATTR_SET。
tunnel()对应OVS_KEY_ATTR_TUNNEL。这个action主要保存封装vxlan需要的信息。
最后的数字2对应出端口 OVS_ACTION_ATTR_OUTPUT。这个action主要是将未封装的报文发送给vxlan口,由vxlan kernel模块来封装。需要注意的是必须安装actions的顺序执行,否则vxlan封装失败。因为首先通过OVS_KEY_ATTR_TUNNEL设置remote_ip等信息到skb的私有数据中,再执行OVS_ACTION_ATTR_OUTPUT时,从skb的私有数据中取出remote_ip等信息才能完成封装。

b. fast path
slow-path下发流表后,后续报文都可以在datapath找到流表直接转发。
对于userspace vxlan流程如下

dp_netdev_execute_actions -> odp_execute_actions -> odp_execute_clone执行clone action,这个函数里又依次执行tunnel push和output action OVS_ACTION_ATTR_TUNNEL_PUSH -> push_tnl_actionOVS_ACTION_ATTR_OUTPUT -> netdev_send

对于kernel space vxlan流程如下

ovs_vport_receive -> ovs_dp_process_packet -> ovs_execute_actionsOVS_ACTION_ATTR_SET -> ovs_skb_dst_set(skb, (struct dst_entry *)tun->tun_dst); 保存tunnel信息到skbOVS_ACTION_ATTR_OUTPUT -> vxlan_xmit 转发给vxlan模块处理

接收vxlan报文流程
slow-path接收vxlan报文流程和发送报文流程前面函数调用都相同,只不过在函数compose_output_action__中区分开来。

compose_output_action__//xport为出端口(flood到所有端口),一般不会是tunnel端口if (xport->is_tunnel) {}if (is_native_tunnel) {} else if (terminate_native_tunnel(ctx, ofp_port, flow, wc, &odp_tnl_port)) {//terminate_native_tunnel 根据外层flow查找tunnel信息,找到 odp 端口,即在datapath的端口号。添加出端口为 odp_tnl_port。/* Intercept packet to be received on native tunnel port. */nl_msg_put_odp_port(ctx->odp_actions, OVS_ACTION_ATTR_TUNNEL_POP, odp_tnl_port);} else {}

这一步会下发一条流表

recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth(src=2e:ab:5f:92:6c:47,dst=12:31:66:3c:95:47),eth_type(0x0800),ipv4(dst=10.10.10.1,proto=17,frag=no),udp(dst=8472), packets:919, bytes:90148, used:0.409s, actions:tnl_pop(2)

接着执行这条流表(以userspace vxlan为例)

dp_netdev_execute_actions -> odp_execute_actions -> dp_execute_cb -> OVS_ACTION_ATTR_TUNNEL_POP
struct dp_packet_batch *orig_packets_ = packets_;
odp_port_t portno = nl_attr_get_odp_port(a);
struct tx_port *p;p = pmd_tnl_port_cache_lookup(pmd, portno);
if (p) {//去掉外层头netdev_pop_header(p->port->netdev, packets_);struct dp_packet *packet;DP_PACKET_BATCH_FOR_EACH (packet, packets_) {//重新设置 in_port 为 portno,portno为vxlan端口号packet->md.in_port.odp_port = portno;}(*depth)++;//以vxlan端口为入端口,报文只有内层,重新走slow-path流程,添加第二条流表dp_netdev_recirculate(pmd, packets_);dp_netdev_input__(pmd, packets, true, 0);(*depth)--;
}

第二条流表如下

tunnel(tun_id=0x0,src=10.10.10.2,dst=10.10.10.1,flags(-df-csum+key)),recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth(src=b2:42:ef:84:79:4b,dst=6a:91:a4:4f:78:45),eth_type(0x0800),ipv4(dst=1.1.1.1,proto=1,frag=no), packets:100, bytes:9800, used:0.409s, actions:1

fast path就是按照datapath流表执行,不再赘述。

也可参考:openvswitch vxlan 源码分析 - 简书 (jianshu.com)

openvswitch vxlan 源码分析相关推荐

  1. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  2. SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...

  3. SpringBoot-web开发(二): 页面和图标定制(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) 目录 一.首页 1. 源码分析 2. 访问首页测试 二.动态页面 1. 动态资源目录t ...

  4. SpringBoot-web开发(一): 静态资源的导入(源码分析)

    目录 方式一:通过WebJars 1. 什么是webjars? 2. webjars的使用 3. webjars结构 4. 解析源码 5. 测试访问 方式二:放入静态资源目录 1. 源码分析 2. 测 ...

  5. Yolov3Yolov4网络结构与源码分析

    Yolov3&Yolov4网络结构与源码分析 从2018年Yolov3年提出的两年后,在原作者声名放弃更新Yolo算法后,俄罗斯的Alexey大神扛起了Yolov4的大旗. 文章目录 论文汇总 ...

  6. ViewGroup的Touch事件分发(源码分析)

    Android中Touch事件的分发又分为View和ViewGroup的事件分发,View的touch事件分发相对比较简单,可参考 View的Touch事件分发(一.初步了解) View的Touch事 ...

  7. View的Touch事件分发(二.源码分析)

    Android中Touch事件的分发又分为View和ViewGroup的事件分发,先来看简单的View的touch事件分发. 主要分析View的dispatchTouchEvent()方法和onTou ...

  8. MyBatis原理分析之四:一次SQL查询的源码分析

    上回我们讲到Mybatis加载相关的配置文件进行初始化,这回我们讲一下一次SQL查询怎么进行的. 准备工作 Mybatis完成一次SQL查询需要使用的代码如下: Java代码   String res ...

  9. [转]slf4j + log4j原理实现及源码分析

    slf4j + log4j原理实现及源码分析 转载于:https://www.cnblogs.com/jasonzeng888/p/6051080.html

  10. Spark源码分析之七:Task运行(一)

    在Task调度相关的两篇文章<Spark源码分析之五:Task调度(一)>与<Spark源码分析之六:Task调度(二)>中,我们大致了解了Task调度相关的主要逻辑,并且在T ...

最新文章

  1. Spring 面试问题
  2. “我为什么反对AI论文强制开源代码”
  3. 未排序数组中累加和为给定值的最长子数组系列问题
  4. linux如何根据端口看进程,linux 根据端口查看系统进程
  5. 忽然看懂了《大话西游》
  6. linux man命令_CentOS Linux中的man命令
  7. Pandas学习笔记1(序列部分)
  8. 日语学习-多邻国-关卡1-家居
  9. php功能代码下载,PHP实现下载功能的代码
  10. 整合重组叠加市场扩容 “广电云”发展将提速
  11. BIND9源码分析奠基
  12. IDL实现遥感影像融合(批量)TASK(三)
  13. 从 1.9 到 1.11,聊聊 PyFlink 的核心功能演进(附 Demo 代码)
  14. qtp java_QTP Java swing 一些控件的遍历
  15. java jre下载安装教程_java JRE下载、安装以及环境变量教程
  16. 游戏封包模拟器_问道模拟器人物移动封包分析教程
  17. java8中Lambda表达式写法详解
  18. MMA7455加速度传感器测量角度
  19. android frameworks下面config.xml属性
  20. UVA, 516 Prime Land

热门文章

  1. java ltp4j_ltp工具使用配置
  2. 【CSDN软件工程师能力认证学习精选】SQL语句查询
  3. dat图片 电脑端微信_写了一个电脑版微信的dat图片转换器
  4. Springboot 注解最全详解
  5. c语言将时速转换成配速,配速与时速换算(跑步配速和时速换算)
  6. 计算机上的del键功能是什么,计算机上的DEL是什么?
  7. 同一局域网下windows主机和wsl子系统相互网络服务访问
  8. 用户画像,原来是这么用的!看一个生活中的案例
  9. 正则正数,负数,整数,浮点数校验大全
  10. 开源项目—swift开发记事本APP