ovs snat

环境背景

Untitled Diagram

脚本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ip netns add ns1
ip netns add ns2
ovs-vsctl add-br br0
ovs-vsctl add-br br-sw
ovs-vsctl add-port br0 tap1 -- set Interface tap1 type=internal
ip link set tap1 netns ns1
ip netns exec ns1 ip link set dev tap1 up
ovs-vsctl add-port br0 tap2 -- set Interface tap2 type=internal
ip link set tap2 netns ns2
ip netns exec ns2 ip link set dev tap2 up
ip netns exec ns1 ip addr add 192.168.1.102/24 dev tap1
ip netns exec ns2 ip addr add 192.168.1.1/24 dev tap2
ip netns exec ns1 ip link set lo up
ip netns exec ns2 ip link set lo up
ip netns exec ns1 ping -c 4 192.168.1.102
ip netns exec ns1 ping -c 4 192.168.1.1


ovs-vsctl add-port br0 patch-ovs-0 -- set Interface patch-ovs-0 type=patch options:peer=patch-sw-1
ovs-vsctl add-port br-sw patch-sw-1 -- set Interface patch-sw-1 type=patch options:peer=patch-ovs-0

把外网接口加入到br-sw

1
2
3
4
5
6
7
ip addr flush dev enp0s3

ovs-vsctl add-port br-sw enp0s3

ifconfig br-sw 10.30.10.141/24 up

route add default gw 10.30.10.1

配置访问同网段流表10.30.10.175

1
2
3
4
5
6
7
8
9
#如果进入trk可以直接查找连接,如果没有执行相应action
ovs-ofctl add-flow br0 'table=0,priority=10,ip,ct_state=-trk,action=ct(nat,table=1)'

#新建连接,执行ct commit;创建链接,执行nat规则
ovs-ofctl add-flow br0 'table=1,in_port=1,ip,ct_state=+trk+new,action=ct(nat(src=10.30.10.141-10.30.10.141:5000-50000),commit),mod_dl_src:08:00:27:99:81:b7,mod_dl_dst:00:0e:c6:cf:da:c7,3'
#到外网流量,已经建立号连接,直接发给3口
ovs-ofctl add-flow br0 'table=1,in_port=1,ip,ct_state=+trk+est,action=mod_dl_src:08:00:27:99:81:b7,mod_dl_dst:00:0e:c6:cf:da:c7,3'
#回来流量,已经建立连接,直接发给1口
ovs-ofctl add-flow br0 'table=1,in_port=3,ip,ct_state=+trk+est,action=mod_dl_src:1e:33:f9:73:48:d0,mod_dl_dst:92:25:03:9d:0f:34,1'

配置访问外网114.114.114.114

1
2
3
4
5
6
7
8
9
10
#如果进入trk可以直接查找连接,如果没有执行相应action
ovs-ofctl add-flow br0 'table=0,priority=10,ip,ct_state=-trk,action=ct(nat,table=1)'

#新建连接,执行ct commit;创建链接,执行nat规则
ovs-ofctl add-flow br0 'table=1,in_port=1,ip,ct_state=+trk+new,action=ct(nat(src=10.30.10.141-10.30.10.141:5000-50000),commit),mod_dl_src:08:00:27:99:81:b7,mod_dl_dst:d4:ee:7:50:78:c2,3'

#到外网流量,已经建立号连接,直接发给3口
ovs-ofctl add-flow br0 'table=1,in_port=1,ip,ct_state=+trk+est,action=mod_dl_src:08:00:27:99:81:b7,mod_dl_dst:d4:ee:7:50:78:c2,3'
#回来流量,已经建立连接,直接发给1口
ovs-ofctl add-flow br0 'table=1,in_port=3,ip,ct_state=+trk+est,action=mod_dl_src:1e:33:f9:73:48:d0,mod_dl_dst:92:25:03:9d:0f:34,1'

流表删除

1
2
3
4
5
6
7
ovs-ofctl del-flows br0 'table=0,ip,ct_state=-trk'

ovs-ofctl del-flows br0 'table=1,in_port=1,ip,ct_state=+trk+new'

ovs-ofctl del-flows br0 'table=1,in_port=1,ip,ct_state=+trk+est'

ovs-ofctl del-flows br0 'table=1,in_port=3,ip,ct_state=+trk+est'

按照dragonflow社区想法实现snat

snat社区实现流量原理

流量从br0流出后,修改源mac为已设定 80:88:88:88:88:99,目的mac修改为出口网桥的mac 08:00:27:99:81:b7

流量从br0流到br-sw后,br-sw收到上述流量后,查看目的mac为桥的mac,属于三层转发流量,br-sw将上述流量源mac变为br-sw mac ,目的mac变为具体地址活着网关的mac。

snat社区实现要点

通过将snat发出流量直接发给出口网桥,通过网桥三层转发给具体的目的地址,这样实现从br0中流表不用关心snat访问的具体目标mac地址(访问的具体目标br-sw会主动学习具体mac地址),只需要关注外网网桥的mac即可。

SNAT 的ARP被动回复流表

1
2
3
4
5
ovs-ofctl add-flow br0 "priority=100 arp arp_op=1 arp_tpa=10.30.10.111 action=move:OXM_OF_ARP_TPA[]->NXM_NX_REG2[],resubmit(,8),goto_table:10"

ovs-ofctl add-flow br0 "table=8,reg2=0x0a1e0a6f/0xffffffff,action=load:0x808888888888->OXM_OF_PKT_REG0[]"

ovs-ofctl add-flow br0 "table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[],move:OXM_OF_ARP_SHA[]->OXM_OF_ARP_THA[],move:OXM_OF_PKT_REG0[0..47]->OXM_OF_ARP_SHA[],move:OXM_OF_ARP_SPA[]->OXM_OF_ARP_TPA[],move:NXM_NX_REG2[]->OXM_OF_ARP_SPA[],move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],move:OXM_OF_PKT_REG0[0..47]->NXM_OF_ETH_SRC[],move:NXM_OF_IN_PORT[]->NXM_NX_REG3[0..15],load:0->NXM_OF_IN_PORT[],output:NXM_NX_REG3[0..15]"

SNAT流表

1
2
3
4
ovs-ofctl add-flow br0 "in_port=1,ip,action=ct(commit,zone=1,nat(src=10.30.10.111-10.30.10.111)),mod_dl_src:80:88:88:88:88:99,mod_dl_dst:08:00:27:99:81:b7,3"
ovs-ofctl add-flow br0 "in_port=3,ct_state=-trk,ip,action=ct(table=0,zone=1,nat)"

ovs-ofctl add-flow br0 "in_port=3,ct_state=+trk,ct_zone=1,ip,action=mod_dl_src:80:88:88:88:88:99,mod_dl_dst:92:25:03:9d:0f:34,1"

生成流表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cookie=0x0, duration=881.078s, table=0, n_packets=850, n_bytes=83300, idle_age=0, ip,in_port=1 actions=ct(commit,zone=1,nat(src=10.30.
10.111)),mod_dl_src:80:88:88:88:88:99,mod_dl_dst:08:00:27:99:81:b7,output:3
cookie=0x0, duration=732.960s, table=0, n_packets=1621, n_bytes=421788, idle_age=0, ct_state=-trk,ip,in_port=3 actions=ct(table=0,zone
=1,nat)
cookie=0x0, duration=710.396s, table=0, n_packets=1584, n_bytes=408966, idle_age=0, ct_state=+trk,ct_zone=1,ip,in_port=3 actions=mod_d
l_src:80:88:88:88:88:99,mod_dl_dst:92:25:03:9d:0f:34,output:1
cookie=0x0, duration=2336.028s, table=0, n_packets=18, n_bytes=1026, idle_age=4, priority=100,arp,arp_tpa=10.30.10.111,arp_op=1 action
s=move:NXM_OF_ARP_TPA[]->NXM_NX_REG2[],resubmit(,8),resubmit(,10)
cookie=0x0, duration=38932.939s, table=0, n_packets=17775, n_bytes=5974547, idle_age=332, priority=0 actions=NORMAL
cookie=0x0, duration=2171.189s, table=8, n_packets=18, n_bytes=1026, idle_age=4, reg2=0xa1e0a6f actions=load:0x808888888899->OXM_OF_PK
T_REG0[]
cookie=0x0, duration=2110.202s, table=10, n_packets=18, n_bytes=1026, idle_age=4, priority=10,arp,arp_op=1 actions=load:0x2->NXM_OF_AR
P_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],move:OXM_OF_PKT_REG0[0..47]->NXM_NX_ARP_SHA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],mo
ve:NXM_NX_REG2[]->NXM_OF_ARP_SPA[],move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],move:OXM_OF_PKT_REG0[0..47]->NXM_OF_ETH_SRC[],move:NXM_OF_IN
_PORT[]->NXM_NX_REG3[0..15],load:0->NXM_OF_IN_PORT[],output:NXM_NX_REG3[0..15]