datapath: Add support for kernel 4.6
[cascardo/ovs.git] / tutorial / OVN-Tutorial.md
1 OVN Tutorial
2 ============
3
4 This tutorial is intended to give you a tour of the basic OVN features using
5 `ovs-sandbox` as a simulated test environment.  It’s assumed that you have an
6 understanding of OVS before going through this tutorial. Detail about OVN is
7 covered in [ovn-architecture(7)], but this tutorial lets you quickly see it in
8 action.
9
10 Getting Started
11 ---------------
12
13 For some general information about `ovs-sandbox`, see the “Getting Started”
14 section of [Tutorial.md].
15
16 `ovs-sandbox` does not include OVN support by default.  To enable OVN, you must
17 pass the `--ovn` flag.  For example, if running it straight from the ovs git
18 tree you would run:
19
20     $ make sandbox SANDBOXFLAGS=”--ovn”
21
22 Running the sandbox with OVN enabled does the following additional steps to the
23 environment:
24
25   1. Creates the `OVN_Northbound` and `OVN_Southbound` databases as described in
26      [ovn-nb(5)] and [ovn-sb(5)].
27
28   2. Creates the `hardware_vtep` database as described in [vtep(5)].
29
30   3. Runs the [ovn-northd(8)], [ovn-controller(8)], and [ovn-controller-vtep(8)]
31      daemons.
32
33   4. Makes OVN and VTEP utilities available for use in the environment,
34      including [vtep-ctl(8)], [ovn-nbctl(8)], and [ovn-sbctl(8)].
35
36 Note that each of these demos assumes you start with a fresh sandbox
37 environment. **Re-run `ovs-sandbox` before starting each section.**
38
39 Using GDB
40 ---------
41
42 GDB support is not required to go through the tutorial. See the “Using GDB”
43 section of [Tutorial.md] for more info. Additional flags exist for launching
44 the debugger for the OVN programs:
45
46   --gdb-ovn-northd
47   --gdb-ovn-controller
48   --gdb-ovn-controller-vtep
49
50
51 1) Simple two-port setup
52 ------------------------
53
54 This first environment is the simplest OVN example.  It demonstrates using OVN
55 with a single logical switch that has two logical ports, both residing on the
56 same hypervisor.
57
58 Start by running the setup script for this environment.
59
60 [View ovn/env1/setup.sh][env1setup].
61
62     $ ovn/env1/setup.sh
63
64 You can use the `ovn-nbctl` utility to see an overview of the logical topology.
65
66     $ ovn-nbctl show
67     switch 78687d53-e037-4555-bcd3-f4f8eaf3f2aa (sw0)
68         port sw0-port1
69             addresses: [“00:00:00:00:00:01”]
70         port sw0-port2
71             addresses: [“00:00:00:00:00:02”]
72
73 The `ovn-sbctl` utility can be used to see into the state stored in the
74 `OVN_Southbound` database.  The `show` command shows that there is a single
75 chassis with two logical ports bound to it.  In a more realistic
76 multi-hypervisor environment, this would list all hypervisors and where all
77 logical ports are located.
78
79     $ ovn-sbctl show
80     Chassis “56b18105-5706-46ef-80c4-ff20979ab068”
81         Encap geneve
82             ip: “127.0.0.1”
83         Port_Binding “sw0-port1”
84         Port_Binding “sw0-port2”
85
86 OVN creates logical flows to describe how the network should behave in logical
87 space.  Each chassis then creates OpenFlow flows based on those logical flows
88 that reflect its own local view of the network.  The `ovn-sbctl` command can
89 show the logical flows.
90
91     $ ovn-sbctl lflow-list
92     Datapath: 2503dd42-14b1-414a-abbf-33e554e09ddc  Pipeline: ingress
93       table=0 (ls_in_port_sec_l2  ), priority=100  , match=(eth.src[40]), action=(drop;)
94       table=0 (ls_in_port_sec_l2  ), priority=100  , match=(vlan.present), action=(drop;)
95       table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == “sw0-port1” && eth.src == {00:00:00:00:00:01}), action=(next;)
96       table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == “sw0-port2” && eth.src == {00:00:00:00:00:02}), action=(next;)
97       table=1 (ls_in_port_sec_ip  ), priority=0    , match=(1), action=(next;)
98       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == “sw0-port1” && eth.src == 00:00:00:00:00:01 && arp.sha == 00:00:00:00:00:01), action=(next;)
99       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == “sw0-port1” && eth.src == 00:00:00:00:00:01 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:01) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:01)))), action=(next;)
100       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == “sw0-port2” && eth.src == 00:00:00:00:00:02 && arp.sha == 00:00:00:00:00:02), action=(next;)
101       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == “sw0-port2” && eth.src == 00:00:00:00:00:02 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:02) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:02)))), action=(next;)
102       table=2 (ls_in_port_sec_nd  ), priority=80   , match=(inport == “sw0-port1” && (arp || nd)), action=(drop;)
103       table=2 (ls_in_port_sec_nd  ), priority=80   , match=(inport == “sw0-port2” && (arp || nd)), action=(drop;)
104       table=2 (ls_in_port_sec_nd  ), priority=0    , match=(1), action=(next;)
105       table=3 (ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
106       table=4 (ls_in_pre_lb       ), priority=0    , match=(1), action=(next;)
107       table=5 (ls_in_pre_stateful ), priority=100  , match=(reg0[0] == 1), action=(ct_next;)
108       table=5 (ls_in_pre_stateful ), priority=0    , match=(1), action=(next;)
109       table=6 (ls_in_acl          ), priority=0    , match=(1), action=(next;)
110       table=7 (ls_in_lb           ), priority=0    , match=(1), action=(next;)
111       table=8 (ls_in_stateful     ), priority=100  , match=(reg0[1] == 1), action=(ct_commit; next;)
112       table=8 (ls_in_stateful     ), priority=100  , match=(reg0[2] == 1), action=(ct_lb;)
113       table=8 (ls_in_stateful     ), priority=0    , match=(1), action=(next;)
114       table=9 (ls_in_arp_rsp      ), priority=0    , match=(1), action=(next;)
115       table=10(ls_in_l2_lkup      ), priority=100  , match=(eth.mcast), action=(outport = “_MC_flood”; output;)
116       table=10(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(outport = “sw0-port1”; output;)
117       table=10(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:02), action=(outport = “sw0-port2”; output;)
118     Datapath: 2503dd42-14b1-414a-abbf-33e554e09ddc  Pipeline: egress
119       table=0 (ls_out_pre_lb      ), priority=0    , match=(1), action=(next;)
120       table=1 (ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
121       table=2 (ls_out_pre_stateful), priority=100  , match=(reg0[0] == 1), action=(ct_next;)
122       table=2 (ls_out_pre_stateful), priority=0    , match=(1), action=(next;)
123       table=3 (ls_out_lb          ), priority=0    , match=(1), action=(next;)
124       table=4 (ls_out_acl         ), priority=0    , match=(1), action=(next;)
125       table=5 (ls_out_stateful    ), priority=100  , match=(reg0[1] == 1), action=(ct_commit; next;)
126       table=5 (ls_out_stateful    ), priority=100  , match=(reg0[2] == 1), action=(ct_lb;)
127       table=5 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
128       table=6 (ls_out_port_sec_ip ), priority=0    , match=(1), action=(next;)
129       table=7 (ls_out_port_sec_l2 ), priority=100  , match=(eth.mcast), action=(output;)
130       table=7 (ls_out_port_sec_l2 ), priority=50   , match=(outport == “sw0-port1” && eth.dst == {00:00:00:00:00:01}), action=(output;)
131       table=7 (ls_out_port_sec_l2 ), priority=50   , match=(outport == “sw0-port2” && eth.dst == {00:00:00:00:00:02}), action=(output;)
132
133 Now we can start taking a closer look at how `ovn-controller` has programmed the
134 local switch.  Before looking at the flows, we can use `ovs-ofctl` to verify the
135 OpenFlow port numbers for each of the logical ports on the switch.  The output
136 shows that `lport1`, which corresponds with our logical port `sw0-port1`, has an
137 OpenFlow port number of `1`.  Similarly, `lport2` has an OpenFlow port number of
138 `2`.
139
140     $ ovs-ofctl show br-int
141     OFPT_FEATURES_REPLY (xid=0x2): dpid:00003e1ba878364d
142     n_tables:254, n_buffers:256
143     capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
144     actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
145      1(lport1): addr:aa:55:aa:55:00:07
146          config:     PORT_DOWN
147          state:      LINK_DOWN
148          speed: 0 Mbps now, 0 Mbps max
149      2(lport2): addr:aa:55:aa:55:00:08
150          config:     PORT_DOWN
151          state:      LINK_DOWN
152          speed: 0 Mbps now, 0 Mbps max
153      LOCAL(br-int): addr:3e:1b:a8:78:36:4d
154          config:     PORT_DOWN
155          state:      LINK_DOWN
156          speed: 0 Mbps now, 0 Mbps max
157     OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
158
159 Finally, use `ovs-ofctl` to see the OpenFlow flows for `br-int`.  Note that some
160 fields have been omitted for brevity.
161
162     $ ovs-ofctl -O OpenFlow13 dump-flows br-int
163     OFPST_FLOW reply (OF1.3) (xid=0x2):
164      table=0, priority=100,in_port=1 actions=set_field:0x1->metadata,set_field:0x1->reg6,resubmit(,16)
165      table=0, priority=100,in_port=2 actions=set_field:0x1->metadata,set_field:0x2->reg6,resubmit(,16)
166      table=16, priority=100,metadata=0x1,vlan_tci=0x1000/0x1000 actions=drop
167      table=16, priority=100,metadata=0x1,dl_src=01:00:00:00:00:00/01:00:00:00:00:00 actions=drop
168      table=16, priority=50,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01 actions=resubmit(,17)
169      table=16, priority=50,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02 actions=resubmit(,17)
170      table=17, priority=0,metadata=0x1 actions=resubmit(,18)
171      table=18, priority=90,icmp6,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:00 actions=resubmit(,19)
172      table=18, priority=90,icmp6,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:02 actions=resubmit(,19)
173      table=18, priority=90,icmp6,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:00 actions=resubmit(,19)
174      table=18, priority=90,icmp6,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:01 actions=resubmit(,19)
175      table=18, priority=90,icmp6,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:01 actions=resubmit(,19)
176      table=18, priority=90,icmp6,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:00 actions=resubmit(,19)
177      table=18, priority=90,icmp6,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:00 actions=resubmit(,19)
178      table=18, priority=90,icmp6,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:02 actions=resubmit(,19)
179      table=18, priority=90,arp,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01,arp_sha=00:00:00:00:00:01 actions=resubmit(,19)
180      table=18, priority=90,arp,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02,arp_sha=00:00:00:00:00:02 actions=resubmit(,19)
181      table=18, priority=80,icmp6,reg6=0x2,metadata=0x1,icmp_type=136,icmp_code=0 actions=drop
182      table=18, priority=80,icmp6,reg6=0x1,metadata=0x1,icmp_type=136,icmp_code=0 actions=drop
183      table=18, priority=80,icmp6,reg6=0x1,metadata=0x1,icmp_type=135,icmp_code=0 actions=drop
184      table=18, priority=80,icmp6,reg6=0x2,metadata=0x1,icmp_type=135,icmp_code=0 actions=drop
185      table=18, priority=80,arp,reg6=0x2,metadata=0x1 actions=drop
186      table=18, priority=80,arp,reg6=0x1,metadata=0x1 actions=drop
187      table=18, priority=0,metadata=0x1 actions=resubmit(,19)
188      table=19, priority=0,metadata=0x1 actions=resubmit(,20)
189      table=20, priority=0,metadata=0x1 actions=resubmit(,21)
190      table=21, priority=0,metadata=0x1 actions=resubmit(,22)
191      table=22, priority=0,metadata=0x1 actions=resubmit(,23)
192      table=23, priority=0,metadata=0x1 actions=resubmit(,24)
193      table=24, priority=0,metadata=0x1 actions=resubmit(,25)
194      table=25, priority=0,metadata=0x1 actions=resubmit(,26)
195      table=26, priority=100,metadata=0x1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=set_field:0xffff->reg7,resubmit(,32)
196      table=26, priority=50,metadata=0x1,dl_dst=00:00:00:00:00:01 actions=set_field:0x1->reg7,resubmit(,32)
197      table=26, priority=50,metadata=0x1,dl_dst=00:00:00:00:00:02 actions=set_field:0x2->reg7,resubmit(,32)
198      table=32, priority=0 actions=resubmit(,33)
199      table=33, priority=100,reg7=0x1,metadata=0x1 actions=resubmit(,34)
200      table=33, priority=100,reg7=0xffff,metadata=0x1 actions=set_field:0x2->reg7,resubmit(,34),set_field:0x1->reg7,resubmit(,34),set_field:0xffff->reg7
201      table=33, priority=100,reg7=0x2,metadata=0x1 actions=resubmit(,34)
202      table=34, priority=100,reg6=0x1,reg7=0x1,metadata=0x1 actions=drop
203      table=34, priority=100,reg6=0x2,reg7=0x2,metadata=0x1 actions=drop
204      table=34, priority=0 actions=set_field:0->reg0,set_field:0->reg1,set_field:0->reg2,resubmit(,48)
205      table=48, priority=0,metadata=0x1 actions=resubmit(,49)
206      table=49, priority=0,metadata=0x1 actions=resubmit(,50)
207      table=50, priority=0,metadata=0x1 actions=resubmit(,51)
208      table=51, priority=0,metadata=0x1 actions=resubmit(,52)
209      table=52, priority=0,metadata=0x1 actions=resubmit(,53)
210      table=53, priority=0,metadata=0x1 actions=resubmit(,54)
211      table=54, priority=0,metadata=0x1 actions=resubmit(,55)
212      table=55, priority=100,metadata=0x1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,64)
213      table=55, priority=50,reg7=0x2,metadata=0x1,dl_dst=00:00:00:00:00:02 actions=resubmit(,64)
214      table=55, priority=50,reg7=0x1,metadata=0x1,dl_dst=00:00:00:00:00:01 actions=resubmit(,64)
215      table=64, priority=100,reg7=0x1,metadata=0x1 actions=output:1
216
217 The `ovs-appctl` command can be used to generate an OpenFlow trace of how a
218 packet would be processed in this configuration.  This first trace shows a
219 packet from `sw0-port1` to `sw0-port2`.  The packet arrives from port `1` and
220 should be output to port `2`.
221
222 [View ovn/env1/packet1.sh][env1packet1].
223
224     $ ovn/env1/packet1.sh
225
226 Trace a broadcast packet from `sw0-port1`.  The packet arrives from port `1` and
227 should be output to port `2`.
228
229 [View ovn/env1/packet2.sh][env1packet2].
230
231     $ ovn/env1/packet2.sh
232
233 You can extend this setup by adding additional ports.  For example, to add a
234 third port, run this command:
235
236 [View ovn/env1/add-third-port.sh][env1thirdport].
237
238     $ ovn/env1/add-third-port.sh
239
240 Now if you do another trace of a broadcast packet from `sw0-port1`, you will see
241 that it is output to both ports `2` and `3`.
242
243     $ ovn/env1/packet2.sh
244
245 The logical port may have an unknown set of Ethernet addresses.  When an OVN logical
246 switch processes a unicast Ethernet frame whose destination MAC address is not in any
247 logical port’s addresses column, it delivers it to the port (or ports) whose addresses
248 columns include unknown.
249
250 [View ovn/env1/add-unknown-ports.sh][env1unknownports].
251
252     $ ovn/env1/add-unknown-ports.sh
253
254 This trace shows a packet from `sw0-port1` to `sw0-port4`, `sw0-port5` whose addresses
255 columns include unknown.  You will see that it is output to both ports `4` and `5`.
256
257 [View ovn/env1/packet3.sh][env1packet3].
258
259     $ ovn/env1/packet3.sh
260
261 The logical port would restrict the host to sending packets from and receiving packets
262 to the ethernet addresses defined in the logical port’s port_security column.
263 In addition to the restrictions described for Ethernet addresses above, such an element
264 of port_security restricts the IPv4 or IPv6 addresses from which the host may send and
265 to which it may receive packets to the specified addresses.
266
267 [View ovn/env1/add-security-ip-ports.sh][env1securityport].
268
269     $ ovn/env1/add-security-ip-ports.sh
270
271 This trace shows a packet from `sw0-port6` to `sw0-port7`.
272
273 [View ovn/env1/packet4.sh][env1packet4].
274
275     $ ovn/env1/packet4.sh
276
277 2) 2 switches, 4 ports
278 ----------------------
279
280 This environment is an extension of the last example.  The previous example
281 showed two ports on a single logical switch.  In this environment we add a
282 second logical switch that also has two ports.  This lets you start to see how
283 `ovn-controller` creates flows for isolated networks to co-exist on the same
284 switch.
285
286 [View ovn/env2/setup.sh][env2setup].
287
288     $ ovn/env2/setup.sh
289
290 View the logical topology with `ovn-nbctl`.
291
292     $ ovn-nbctl show
293     switch e3190dc2-89d1-44ed-9308-e7077de782b3 (sw0)
294         port sw0-port1
295             addresses: 00:00:00:00:00:01
296         port sw0-port2
297             addresses: 00:00:00:00:00:02
298     switch c8ed4c5f-9733-43f6-93da-795b1aabacb1 (sw1)
299         port sw1-port1
300             addresses: 00:00:00:00:00:03
301         port sw1-port2
302             addresses: 00:00:00:00:00:04
303
304 Physically, all ports reside on the same chassis.
305
306     $ ovn-sbctl show
307     Chassis “56b18105-5706-46ef-80c4-ff20979ab068”
308         Encap geneve
309             ip: “127.0.0.1”
310         Port_Binding “sw1-port2”
311         Port_Binding “sw0-port2”
312         Port_Binding “sw0-port1”
313         Port_Binding “sw1-port1”
314
315 OVN creates separate logical flows for each logical switch.
316
317     $ ovn-sbctl lflow-list
318     Datapath: 7ee908c1-b0d3-4d03-acc9-42cd7ef7f27d  Pipeline: ingress
319       table=0 (ls_in_port_sec_l2  ), priority=100  , match=(eth.src[40]), action=(drop;)
320       table=0 (ls_in_port_sec_l2  ), priority=100  , match=(vlan.present), action=(drop;)
321       table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == "sw1-port1" && eth.src == {00:00:00:00:00:03}), action=(next;)
322       table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == "sw1-port2" && eth.src == {00:00:00:00:00:04}), action=(next;)
323       table=1 (ls_in_port_sec_ip  ), priority=0    , match=(1), action=(next;)
324       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw1-port1" && eth.src == 00:00:00:00:00:03 && arp.sha == 00:00:00:00:00:03), action=(next;)
325       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw1-port1" && eth.src == 00:00:00:00:00:03 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:03) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:03)))), action=(next;)
326       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw1-port2" && eth.src == 00:00:00:00:00:04 && arp.sha == 00:00:00:00:00:04), action=(next;)
327       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw1-port2" && eth.src == 00:00:00:00:00:04 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:04) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:04)))), action=(next;)
328       table=2 (ls_in_port_sec_nd  ), priority=80   , match=(inport == "sw1-port1" && (arp || nd)), action=(drop;)
329       table=2 (ls_in_port_sec_nd  ), priority=80   , match=(inport == "sw1-port2" && (arp || nd)), action=(drop;)
330       table=2 (ls_in_port_sec_nd  ), priority=0    , match=(1), action=(next;)
331       table=3 (ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
332       table=4 (ls_in_pre_lb       ), priority=0    , match=(1), action=(next;)
333       table=5 (ls_in_pre_stateful ), priority=100  , match=(reg0[0] == 1), action=(ct_next;)
334       table=5 (ls_in_pre_stateful ), priority=0    , match=(1), action=(next;)
335       table=6 (ls_in_acl          ), priority=0    , match=(1), action=(next;)
336       table=7 (ls_in_lb           ), priority=0    , match=(1), action=(next;)
337       table=8 (ls_in_stateful     ), priority=100  , match=(reg0[1] == 1), action=(ct_commit; next;)
338       table=8 (ls_in_stateful     ), priority=100  , match=(reg0[2] == 1), action=(ct_lb;)
339       table=8 (ls_in_stateful     ), priority=0    , match=(1), action=(next;)
340       table=9 (ls_in_arp_rsp      ), priority=0    , match=(1), action=(next;)
341       table=10(ls_in_l2_lkup      ), priority=100  , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
342       table=10(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:03), action=(outport = "sw1-port1"; output;)
343       table=10(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:04), action=(outport = "sw1-port2"; output;)
344     Datapath: 7ee908c1-b0d3-4d03-acc9-42cd7ef7f27d  Pipeline: egress
345       table=0 (ls_out_pre_lb      ), priority=0    , match=(1), action=(next;)
346       table=1 (ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
347       table=2 (ls_out_pre_stateful), priority=100  , match=(reg0[0] == 1), action=(ct_next;)
348       table=2 (ls_out_pre_stateful), priority=0    , match=(1), action=(next;)
349       table=3 (ls_out_lb          ), priority=0    , match=(1), action=(next;)
350       table=4 (ls_out_acl         ), priority=0    , match=(1), action=(next;)
351       table=5 (ls_out_stateful    ), priority=100  , match=(reg0[1] == 1), action=(ct_commit; next;)
352       table=5 (ls_out_stateful    ), priority=100  , match=(reg0[2] == 1), action=(ct_lb;)
353       table=5 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
354       table=6 (ls_out_port_sec_ip ), priority=0    , match=(1), action=(next;)
355       table=7 (ls_out_port_sec_l2 ), priority=100  , match=(eth.mcast), action=(output;)
356       table=7 (ls_out_port_sec_l2 ), priority=50   , match=(outport == "sw1-port1" && eth.dst == {00:00:00:00:00:03}), action=(output;)
357       table=7 (ls_out_port_sec_l2 ), priority=50   , match=(outport == "sw1-port2" && eth.dst == {00:00:00:00:00:04}), action=(output;)
358     Datapath: 9ea0c8f9-4f82-4be3-a6c7-6e6f9c2de583  Pipeline: ingress
359       table=0 (ls_in_port_sec_l2  ), priority=100  , match=(eth.src[40]), action=(drop;)
360       table=0 (ls_in_port_sec_l2  ), priority=100  , match=(vlan.present), action=(drop;)
361       table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == "sw0-port1" && eth.src == {00:00:00:00:00:01}), action=(next;)
362       table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == "sw0-port2" && eth.src == {00:00:00:00:00:02}), action=(next;)
363       table=1 (ls_in_port_sec_ip  ), priority=0    , match=(1), action=(next;)
364       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && arp.sha == 00:00:00:00:00:01), action=(next;)
365       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:01) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:01)))), action=(next;)
366       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw0-port2" && eth.src == 00:00:00:00:00:02 && arp.sha == 00:00:00:00:00:02), action=(next;)
367       table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw0-port2" && eth.src == 00:00:00:00:00:02 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:02) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:02)))), action=(next;)
368       table=2 (ls_in_port_sec_nd  ), priority=80   , match=(inport == "sw0-port1" && (arp || nd)), action=(drop;)
369       table=2 (ls_in_port_sec_nd  ), priority=80   , match=(inport == "sw0-port2" && (arp || nd)), action=(drop;)
370       table=2 (ls_in_port_sec_nd  ), priority=0    , match=(1), action=(next;)
371       table=3 (ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
372       table=4 (ls_in_pre_lb       ), priority=0    , match=(1), action=(next;)
373       table=5 (ls_in_pre_stateful ), priority=100  , match=(reg0[0] == 1), action=(ct_next;)
374       table=5 (ls_in_pre_stateful ), priority=0    , match=(1), action=(next;)
375       table=6 (ls_in_acl          ), priority=0    , match=(1), action=(next;)
376       table=7 (ls_in_lb           ), priority=0    , match=(1), action=(next;)
377       table=8 (ls_in_stateful     ), priority=100  , match=(reg0[1] == 1), action=(ct_commit; next;)
378       table=8 (ls_in_stateful     ), priority=100  , match=(reg0[2] == 1), action=(ct_lb;)
379       table=8 (ls_in_stateful     ), priority=0    , match=(1), action=(next;)
380       table=9 (ls_in_arp_rsp      ), priority=0    , match=(1), action=(next;)
381       table=10(ls_in_l2_lkup      ), priority=100  , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
382       table=10(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0-port1"; output;)
383       table=10(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0-port2"; output;)
384     Datapath: 9ea0c8f9-4f82-4be3-a6c7-6e6f9c2de583  Pipeline: egress
385       table=0 (ls_out_pre_lb      ), priority=0    , match=(1), action=(next;)
386       table=1 (ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
387       table=2 (ls_out_pre_stateful), priority=100  , match=(reg0[0] == 1), action=(ct_next;)
388       table=2 (ls_out_pre_stateful), priority=0    , match=(1), action=(next;)
389       table=3 (ls_out_lb          ), priority=0    , match=(1), action=(next;)
390       table=4 (ls_out_acl         ), priority=0    , match=(1), action=(next;)
391       table=5 (ls_out_stateful    ), priority=100  , match=(reg0[1] == 1), action=(ct_commit; next;)
392       table=5 (ls_out_stateful    ), priority=100  , match=(reg0[2] == 1), action=(ct_lb;)
393       table=5 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
394       table=6 (ls_out_port_sec_ip ), priority=0    , match=(1), action=(next;)
395       table=7 (ls_out_port_sec_l2 ), priority=100  , match=(eth.mcast), action=(output;)
396       table=7 (ls_out_port_sec_l2 ), priority=50   , match=(outport == "sw0-port1" && eth.dst == {00:00:00:00:00:01}), action=(output;)
397       table=7 (ls_out_port_sec_l2 ), priority=50   , match=(outport == "sw0-port2" && eth.dst == {00:00:00:00:00:02}), action=(output;)
398
399 In this setup, `sw0-port1` and `sw0-port2` can send packets to each other, but
400 not to either of the ports on `sw1`.  This first trace shows a packet from
401 `sw0-port1` to `sw0-port2`.  You should see th packet arrive on OpenFlow port
402 `1` and output to OpenFlow port `2`.
403
404 [View ovn/env2/packet1.sh][env2packet1].
405
406     $ ovn/env2/packet1.sh
407
408 This next example shows a packet from `sw0-port1` with a destination MAC address
409 of `00:00:00:00:00:03`, which is the MAC address for `sw1-port1`.  Since these
410 ports are not on the same logical switch, the packet should just be dropped.
411
412 [View ovn/env2/packet2.sh][env2packet2].
413
414     $ ovn/env2/packet2.sh
415
416 3) Two Hypervisors
417 ------------------
418
419 The first two examples started by showing OVN on a single hypervisor.  A more
420 realistic deployment of OVN would span multiple hypervisors.  This example
421 creates a single logical switch with 4 logical ports.  It then simulates having
422 two hypervisors with two of the logical ports bound to each hypervisor.
423
424 [View ovn/env3/setup.sh][env3setup].
425
426     $ ovn/env3/setup.sh
427
428 You can start by viewing the logical topology with `ovn-nbctl`.
429
430     $ ovn-nbctl show
431     switch b977dc03-79a5-41ba-9665-341a80e1abfd (sw0)
432         port sw0-port1
433             addresses: 00:00:00:00:00:01
434         port sw0-port2
435             addresses: 00:00:00:00:00:02
436         port sw0-port4
437             addresses: 00:00:00:00:00:04
438         port sw0-port3
439             addresses: 00:00:00:00:00:03
440
441 Using `ovn-sbctl` to view the state of the system, we can see that there are two
442 chassis: one local that we can interact with, and a fake remote chassis. Two
443 logical ports are bound to each.  Both chassis have an IP address of localhost,
444 but in a realistic deployment that would be the IP address used for tunnels to
445 that chassis.
446
447     $ ovn-sbctl show
448     Chassis “56b18105-5706-46ef-80c4-ff20979ab068”
449         Encap geneve
450             ip: “127.0.0.1”
451         Port_Binding “sw0-port2”
452         Port_Binding “sw0-port1”
453     Chassis fakechassis
454         Encap geneve
455             ip: “127.0.0.1”
456         Port_Binding “sw0-port4”
457         Port_Binding “sw0-port3”
458
459 Packets between `sw0-port1` and `sw0-port2` behave just like the previous
460 examples.  Packets to ports on a remote chassis are the interesting part of this
461 example.  You may have noticed before that OVN’s logical flows are broken up
462 into ingress and egress tables.  Given a packet from `sw0-port1` on the local
463 chassis to `sw0-port3` on the remote chassis, the ingress pipeline is executed
464 on the local switch.  OVN then determines that it must forward the packet over a
465 geneve tunnel.  When it arrives at the remote chassis, the egress pipeline will
466 be executed there.
467
468 This first packet trace shows the first part of this example.  It’s a packet
469 from `sw0-port1` to `sw0-port3` from the perspective of the local chassis.
470 `sw0-port1` is OpenFlow port `1`.  The tunnel to the fake remote chassis is
471 OpenFlow port `3`.  You should see the ingress pipeline being executed and then
472 the packet output to port `3`, the geneve tunnel.
473
474 [View ovn/env3/packet1.sh][env3packet1].
475
476     $ ovn/env3/packet1.sh
477
478 To simulate what would happen when that packet arrives at the remote chassis we
479 can flip this example around.  Consider a packet from `sw0-port3` to
480 `sw0-port1`.  This trace shows what would happen when that packet arrives at the
481 local chassis.  The packet arrives on OpenFlow port `3` (the tunnel).  You should
482 then see the egress pipeline get executed and the packet output to OpenFlow port
483 `1`.
484
485 [View ovn/env3/packet2.sh][env3packet2].
486
487     $ ovn/env3/packet2.sh
488
489 4) Locally attached networks
490 ----------------------------
491
492 While OVN is generally focused on the implementation of logical networks using
493 overlays, it’s also possible to use OVN as a control plane to manage logically
494 direct connectivity to networks that are locally accessible to each chassis.
495
496 This example includes two hypervisors.  Both hypervisors have two ports on them.
497 We want to use OVN to manage the connectivity of these ports to a network
498 attached to each hypervisor that we will call “physnet1”.
499
500 This scenario requires some additional configuration of `ovn-controller`.  We
501 must configure a mapping between `physnet1` and a local OVS bridge that provides
502 connectivity to that network.  We call these “bridge mappings”.  For our
503 example, the following script creates a bridge called `br-eth1` and then
504 configures `ovn-controller` with a bridge mapping from `physnet1` to `br-eth1`.
505
506 [View ovn/env4/setup1.sh][env4setup1].
507
508     $ ovn/env4/setup1.sh
509
510 At this point we should be able to see that `ovn-controller` has automatically
511 created patch ports between `br-int` and `br-eth1`.
512
513     $ ovs-vsctl show
514     aea39214-ebec-4210-aa34-1ae7d6921720
515         Bridge br-int
516             fail_mode: secure
517             Port “patch-br-int-to-br-eth1”
518                 Interface “patch-br-int-to-br-eth1”
519                     type: patch
520                     options: {peer=”patch-br-eth1-to-br-int”}
521             Port br-int
522                 Interface br-int
523                     type: internal
524         Bridge “br-eth1”
525             Port “br-eth1”
526                 Interface “br-eth1”
527                     type: internal
528             Port “patch-br-eth1-to-br-int”
529                 Interface “patch-br-eth1-to-br-int”
530                     type: patch
531                     options: {peer=”patch-br-int-to-br-eth1”}
532
533 Now we can move on to the next setup phase for this example.  We want to create
534 a fake second chassis and then create the topology that tells OVN we want both
535 ports on both hypervisors connected to `physnet1`.  The way this is modeled in
536 OVN is by creating a logical switch for each port.  The logical switch has the
537 regular VIF port and a `localnet` port.
538
539 [View ovn/env4/setup2.sh][env4setup2].
540
541     $ ovn/env4/setup2.sh
542
543 The logical topology from `ovn-nbctl` should look like this.
544
545     $ ovn-nbctl show
546         switch 5a652488-cfba-4f3e-929d-00010cdfde40 (provnet1-2)
547             port provnet1-2-physnet1
548                 addresses: unknown
549             port provnet1-2-port1
550                 addresses: 00:00:00:00:00:02
551         switch 5829b60a-eda8-4d78-94f6-7017ff9efcf0 (provnet1-4)
552             port provnet1-4-port1
553                 addresses: 00:00:00:00:00:04
554             port provnet1-4-physnet1
555                 addresses: unknown
556         switch 06cbbcb6-38e3-418d-a81e-634ec9b54ad6 (provnet1-1)
557             port provnet1-1-port1
558                 addresses: 00:00:00:00:00:01
559             port provnet1-1-physnet1
560                 addresses: unknown
561         switch 9cba3b3b-59ae-4175-95f5-b6f1cd9c2afb (provnet1-3)
562             port provnet1-3-physnet1
563                 addresses: unknown
564             port provnet1-3-port1
565                 addresses: 00:00:00:00:00:03
566
567 `port1` on each logical switch represents a regular logical port for a VIF on a
568 hypervisor.  `physnet1` on each logical switch is the special `localnet` port.
569 You can use `ovn-nbctl` to see that this port has a `type` and `options` set.
570
571     $ ovn-nbctl lsp-get-type provnet1-1-physnet1
572     localnet
573
574     $ ovn-nbctl lsp-get-options provnet1-1-physnet1
575     network_name=physnet1
576
577 The physical topology should reflect that there are two regular ports on each
578 chassis.
579
580     $ ovn-sbctl show
581     Chassis fakechassis
582         Encap geneve
583             ip: “127.0.0.1”
584         Port_Binding “provnet1-3-port1”
585         Port_Binding “provnet1-4-port1”
586     Chassis “56b18105-5706-46ef-80c4-ff20979ab068”
587         Encap geneve
588             ip: “127.0.0.1”
589         Port_Binding “provnet1-2-port1”
590         Port_Binding “provnet1-1-port1”
591
592 All four of our ports should be able to communicate with each other, but they do
593 so through `physnet1`.  A packet from any of these ports to any destination
594 should be output to the OpenFlow port number that corresponds to the patch port
595 to `br-eth1`.
596
597 This example assumes following OpenFlow port number mappings:
598
599 * 1 = patch port to `br-eth1`
600 * 2 = tunnel to the fake second chassis
601 * 3 = lport1, which is the logical port named `provnet1-1-port1`
602 * 4 = lport2, which is the logical port named `provnet1-2-port1`
603
604 We get those port numbers using `ovs-ofctl`:
605
606     $ ovs-ofctl show br-int
607     OFPT_FEATURES_REPLY (xid=0x2): dpid:0000765054700040
608     n_tables:254, n_buffers:256
609     capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
610     actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src
611     mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
612      1(patch-br-int-to): addr:de:29:14:95:8a:b8
613          config:     0
614          state:      0
615          speed: 0 Mbps now, 0 Mbps max
616      2(ovn-fakech-0): addr:aa:55:aa:55:00:08
617          config:     PORT_DOWN
618          state:      LINK_DOWN
619          speed: 0 Mbps now, 0 Mbps max
620      3(lport1): addr:aa:55:aa:55:00:09
621          config:     PORT_DOWN
622          state:      LINK_DOWN
623          speed: 0 Mbps now, 0 Mbps max
624      4(lport2): addr:aa:55:aa:55:00:0a
625          config:     PORT_DOWN
626          state:      LINK_DOWN
627          speed: 0 Mbps now, 0 Mbps max
628      LOCAL(br-int): addr:76:50:54:70:00:40
629          config:     PORT_DOWN
630          state:      LINK_DOWN
631          speed: 0 Mbps now, 0 Mbps max
632     OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
633
634 This first trace shows a packet from `provnet1-1-port1` with a destination MAC
635 address of `provnet1-2-port1`.  Despite both of these ports being on the same
636 local switch (`lport1` and `lport2`), we expect all packets to be sent out to
637 `br-eth1` (OpenFlow port 1).  We then expect the network to handle getting the
638 packet to its destination.  In practice, this will be optimized at `br-eth1` and
639 the packet won’t actually go out and back on the network.
640
641 [View ovn/env4/packet1.sh][env4packet1].
642
643     $ ovn/env4/packet1.sh
644
645 This next trace is a continuation of the previous one.  This shows the packet
646 coming back into `br-int` from `br-eth1`.  We now expect the packet to be output
647 to `provnet1-2-port1`, which is OpenFlow port 4.
648
649 [View ovn/env4/packet2.sh][env4packet2].
650
651     $ ovn/env4/packet2.sh
652
653 This next trace shows an example of a packet being sent to a destination on
654 another hypervisor.  The source is `provnet1-2-port1`, but the destination is
655 `provnet1-3-port1`, which is on the other fake chassis.  As usual, we expect the
656 output to be to OpenFlow port 1, the patch port to `br-et1`.
657
658 [View ovn/env4/packet3.sh][env4packet3].
659
660     $ ovn/env4/packet3.sh
661
662 This next test shows a broadcast packet.  The destination should still only be
663 OpenFlow port 1.
664
665 [View ovn/env4/packet4.sh][env4packet4]
666
667     $ ovn/env4/packet4.sh
668
669 Finally, this last trace shows what happens when a broadcast packet arrives
670 from the network.  In this case, it simulates a broadcast that originated from a
671 port on the remote fake chassis and arrived at the local chassis via `br-eth1`.
672 We should see it output to both local ports that are attached to this network
673 (OpenFlow ports 3 and 4).
674
675 [View ovn/env4/packet5.sh][env4packet5]
676
677     $ ovn/env4/packet5.sh
678
679 5) Locally attached networks with VLANs
680 ---------------------------------------
681
682 This example is an extension of the previous one.  We take the same setup and
683 add two more ports to each hypervisor.  Instead of having the new ports directly
684 connected to `physnet1` as before, we indicate that we want them on VLAN 101 of
685 `physnet1`.  This shows how `localnet` ports can be used to provide connectivity
686 to either a flat network or a VLAN on that network.
687
688 [View ovn/env5/setup.sh][env5setup]
689
690     $ ovn/env5/setup.sh
691
692 The logical topology shown by `ovn-nbctl` is similar to `env4`, except we now
693 have 8 regular VIF ports connected to `physnet1` instead of 4.  The additional 4
694 ports we have added are all on VLAN 101 of `physnet1`.  Note that the `localnet`
695 ports representing connectivity to VLAN 101 of `physnet1` have the `tag` field
696 set to `101`.
697
698     $ ovn-nbctl show
699         switch 12ea93d0-694b-48e9-adef-d0ddd3ec4ac9 (provnet1-7-101)
700             port provnet1-7-physnet1-101
701                 parent: , tag:101
702                 addresses: unknown
703             port provnet1-7-101-port1
704                 addresses: 00:00:00:00:00:07
705         switch c9a5ce3a-15ec-48ea-a898-416013463589 (provnet1-4)
706             port provnet1-4-port1
707                 addresses: 00:00:00:00:00:04
708             port provnet1-4-physnet1
709                 addresses: unknown
710         switch e07d4f7a-2085-4fbb-9937-d6192b79a397 (provnet1-1)
711             port provnet1-1-physnet1
712                 addresses: unknown
713             port provnet1-1-port1
714                 addresses: 00:00:00:00:00:01
715         switch 6c098474-0509-4219-bc9b-eb4e28dd1aeb (provnet1-2)
716             port provnet1-2-physnet1
717                 addresses: unknown
718             port provnet1-2-port1
719                 addresses: 00:00:00:00:00:02
720         switch 723c4684-5d58-4202-b8e3-4ba99ad5ed9e (provnet1-8-101)
721             port provnet1-8-101-port1
722                 addresses: 00:00:00:00:00:08
723             port provnet1-8-physnet1-101
724                 parent: , tag:101
725                 addresses: unknown
726         switch 8444e925-ceb2-4b02-ac20-eb2e4cfb954d (provnet1-6-101)
727             port provnet1-6-physnet1-101
728                 parent: , tag:101
729                 addresses: unknown
730             port provnet1-6-101-port1
731                 addresses: 00:00:00:00:00:06
732         switch e11e5605-7c46-4395-b28d-cff57451fc7e (provnet1-3)
733             port provnet1-3-port1
734                 addresses: 00:00:00:00:00:03
735             port provnet1-3-physnet1
736                 addresses: unknown
737         switch 0706b697-6c92-4d54-bc0a-db5bababb74a (provnet1-5-101)
738             port provnet1-5-101-port1
739                 addresses: 00:00:00:00:00:05
740             port provnet1-5-physnet1-101
741                 parent: , tag:101
742                 addresses: unknown
743
744 The physical topology shows that we have 4 regular VIF ports on each simulated
745 hypervisor.
746
747     $ ovn-sbctl show
748     Chassis “56b18105-5706-46ef-80c4-ff20979ab068”
749         Encap geneve
750             ip: “127.0.0.1”
751         Port_Binding “provnet1-6-101-port1”
752         Port_Binding “provnet1-1-port1”
753         Port_Binding “provnet1-2-port1”
754         Port_Binding “provnet1-5-101-port1”
755     Chassis fakechassis
756         Encap geneve
757             ip: “127.0.0.1”
758         Port_Binding “provnet1-4-port1”
759         Port_Binding “provnet1-3-port1”
760         Port_Binding “provnet1-8-101-port1”
761         Port_Binding “provnet1-7-101-port1”
762
763 All of the traces from the previous example, `env4`, should work in this
764 environment and provide the same result.  Now we can show what happens for the
765 ports connected to VLAN 101.  This first example shows a packet originating from
766 `provnet1-5-101-port1`, which is OpenFlow port 5.  We should see VLAN tag 101
767 pushed on the packet and then output to OpenFlow port 1, the patch port to
768 `br-eth1` (the bridge providing connectivity to `physnet1`).
769
770 [View ovn/env5/packet1.sh][env5packet1].
771
772     $ ovn/env5/packet1.sh
773
774 If we look at a broadcast packet arriving on VLAN 101 of `physnet1`, we should
775 see it output to OpenFlow ports 5 and 6 only.
776
777 [View ovn/env5/packet2.sh][env5packet2].
778
779     $ ovn/env5/packet2.sh
780
781
782 6) Stateful ACLs
783 ----------------
784
785 ACLs provide a way to do distributed packet filtering for OVN networks.  One
786 example use of ACLs is that OpenStack Neutron uses them to implement security
787 groups.  ACLs are implemented using conntrack integration with OVS.
788
789 Start with a simple logical switch with 2 logical ports.
790
791 [View ovn/env6/setup.sh][env6setup].
792
793     $ ovn/env6/setup.sh
794
795 A common use case would be the following policy applied for `sw0-port1`:
796
797 * Allow outbound IP traffic and associated return traffic.
798 * Allow incoming ICMP requests and associated return traffic.
799 * Allow incoming SSH connections and associated return traffic.
800 * Drop other incoming IP traffic.
801
802 The following script applies this policy to our environment.
803
804 [View ovn/env6/add-acls.sh][env6acls].
805
806     $ ovn/env6/add-acls.sh
807
808 We can view the configured ACLs on this network using the `ovn-nbctl` command.
809
810     $ ovn-nbctl acl-list sw0
811     from-lport  1002 (inport == “sw0-port1” && ip) allow-related
812       to-lport  1002 (outport == “sw0-port1” && ip && icmp) allow-related
813       to-lport  1002 (outport == “sw0-port1” && ip && tcp && tcp.dst == 22) allow-related
814       to-lport  1001 (outport == “sw0-port1” && ip) drop
815
816 Now that we have ACLs configured, there are new entries in the logical flow
817 table in the stages `switch_in_pre_acl`, switch_in_acl`, `switch_out_pre_acl`,
818 and `switch_out_acl`.
819
820     $ ovn-sbctl lflow-list
821
822 Let’s look more closely at `switch_out_pre_acl` and `switch_out_acl`.
823
824 In `switch_out_pre_acl`, we match IP traffic and put it through the connection
825 tracker.  This populates the connection state fields so that we can apply policy
826 as appropriate.
827
828     table=0(switch_out_pre_acl), priority=  100, match=(ip), action=(ct_next;)
829     table=1(switch_out_pre_acl), priority=    0, match=(1), action=(next;)
830
831 In `switch_out_acl`, we allow packets associated with existing connections.  We
832 drop packets that are deemed to be invalid (such as non-SYN TCP packet not
833 associated with an existing connection).
834
835     table=1(switch_out_acl), priority=65535, match=(!ct.est && ct.rel && !ct.new && !ct.inv), action=(next;)
836     table=1(switch_out_acl), priority=65535, match=(ct.est && !ct.rel && !ct.new && !ct.inv), action=(next;)
837     table=1(switch_out_acl), priority=65535, match=(ct.inv), action=(drop;)
838
839 For new connections, we apply our configured ACL policy to decide whether to
840 allow the connection or not.  In this case, we’ll allow ICMP or SSH.  Otherwise,
841 we’ll drop the packet.
842
843     table=1(switch_out_acl), priority= 2002, match=(ct.new && (outport == “sw0-port1” && ip && icmp)), action=(ct_commit; next;)
844     table=1(switch_out_acl), priority= 2002, match=(ct.new && (outport == “sw0-port1” && ip && tcp && tcp.dst == 22)), action=(ct_commit; next;)
845     table=1(switch_out_acl), priority= 2001, match=(outport == “sw0-port1” && ip), action=(drop;)
846
847 When using ACLs, the default policy is to allow and track IP connections.  Based
848 on our above policy, IP traffic directed at `sw0-port1` will never hit this flow
849 at priority 1.
850
851     table=1(switch_out_acl), priority=    1, match=(ip), action=(ct_commit; next;)
852     table=1(switch_out_acl), priority=    0, match=(1), action=(next;)
853
854 Note that conntrack integration is not yet supported in ovs-sandbox, so the
855 OpenFlow flows will not represent what you’d see in a real environment.  The
856 logical flows described above give a very good idea of what the flows look like,
857 though.
858
859 [This blog post][openstack-ovn-acl-blog] discusses OVN ACLs from an OpenStack
860 perspective and also provides an example of what the resulting OpenFlow flows
861 look like.
862
863 7) Container Ports
864 ------------------
865
866 OVN supports containers running directly on the hypervisors and running
867 containers inside VMs. This example shows how OVN supports network
868 virtualization to containers when run inside VMs. Details about how to use
869 docker containers in OVS can be found [here][openvswitch-docker].
870
871 To support container traffic created inside a VM and to distinguish network
872 traffic coming from different container vifs, for each container a logical
873 port needs to be created with parent name set to the VM's logical port and
874 the tag set to the vlan tag of the container vif.
875
876 Start with a simple logical switch with 3 logical ports.
877
878 [View ovn/env7/setup.sh][env7setup].
879
880     $ ovn/env7/setup.sh
881
882 Lets create a container vif attached to the logical port 'sw0-port1' and
883 another container vif attached to the logical port 'sw0-port2'.
884
885 [View ovn/env7/add-container-ports.sh][env7contports]
886
887     $ ovn/env7/add-container-ports.sh
888
889 Run the `ovn-nbctl` command to see the logical ports
890
891     $ovn-nbctl show
892
893
894 As you can see a logical port 'csw0-cport1' is created on a logical
895 switch 'csw0' whose parent is 'sw0-port1' and it has tag set to 42.
896 And a logical port 'csw0-cport2' is created on the logical switch 'csw0'
897 whose parent is 'sw0-port2' and it has tag set to 43.
898
899 Bridge 'br-vmport1' represents the ovs bridge running inside the VM
900 connected to the logical port 'sw0-port1'. In this tutorial the ovs port
901 to 'sw0-port1' is created as a patch port with its peer connected to the
902 ovs bridge 'br-vmport1'. An ovs port 'cport1' is added to 'br-vmport1'
903 which represents the container interface connected to the ovs bridge
904 and vlan tag set to 42. Similarly 'br-vmport2' represents the ovs bridge
905 for the logical port 'sw0-port2' and 'cport2' connected to 'br-vmport2'
906 with vlan tag set to 43.
907
908 This first trace shows a packet from 'csw0-port1' with a destination mac
909 address of 'csw0-port2'. You can see ovs bridge of the vm 'br-vmport1' tags
910 the traffic with vlan id 42 and the traffic reaches to the br-int because
911 of the patch port. As you can see below `ovn-controller` has added a flow
912 to strip the vlan tag and set the reg6 and metadata appropriately.
913
914     $ ovs-ofctl -O OpenFlow13 dump-flows br-int
915     OFPST_FLOW reply (OF1.3) (xid=0x2):
916     cookie=0x0, duration=2767.032s, table=0, n_packets=0, n_bytes=0, priority=150,in_port=3,dl_vlan=42 actions=pop_vlan,set_field:0x3->reg5,set_field:0x2->metadata,set_field:0x1->reg6,resubmit(,16)
917     cookie=0x0, duration=2767.002s, table=0, n_packets=0, n_bytes=0, priority=150,in_port=4,dl_vlan=43 actions=pop_vlan,set_field:0x4->reg5,set_field:0x2->metadata,set_field:0x2->reg6,resubmit(,16)
918     cookie=0x0, duration=2767.032s, table=0, n_packets=0, n_bytes=0, priority=100,in_port=3 actions=set_field:0x1->reg5,set_field:0x1->metadata,set_field:0x1->reg6,resubmit(,16)
919     cookie=0x0, duration=2767.001s, table=0, n_packets=0, n_bytes=0, priority=100,in_port=4 actions=set_field:0x2->reg5,set_field:0x1->metadata,set_field:0x2->reg6,resubmit(,16)
920
921 [View ovn/env7/packet1.sh][env7packet1].
922
923     $ ovn/env5/packet1.sh
924
925
926 The second trace shows a packet from 'csw0-port2' to 'csw0-port1'.
927
928 [View ovn/env7/packet2.sh][env7packet2].
929
930     $ ovn/env5/packet1.sh
931
932 You can extend this setup by adding additional container ports with two
933 hypervisors. Please see the tutorial 3 above.
934
935 [ovn-architecture(7)]:http://openvswitch.org/support/dist-docs/ovn-architecture.7.html
936 [Tutorial.md]:https://github.com/openvswitch/ovs/blob/master/tutorial/Tutorial.md
937 [ovn-nb(5)]:http://openvswitch.org/support/dist-docs/ovn-nb.5.html
938 [ovn-sb(5)]:http://openvswitch.org/support/dist-docs/ovn-sb.5.html
939 [vtep(5)]:http://openvswitch.org/support/dist-docs/vtep.5.html
940 [ovn-northd(8)]:http://openvswitch.org/support/dist-docs/ovn-northd.8.html
941 [ovn-controller(8)]:http://openvswitch.org/support/dist-docs/ovn-controller.8.html
942 [ovn-controller-vtep(8)]:http://openvswitch.org/support/dist-docs/ovn-controller-vtep.8.html
943 [vtep-ctl(8)]:http://openvswitch.org/support/dist-docs/vtep-ctl.8.html
944 [ovn-nbctl(8)]:http://openvswitch.org/support/dist-docs/ovn-nbctl.8.html
945 [ovn-sbctl(8)]:http://openvswitch.org/support/dist-docs/ovn-sbctl.8.html
946 [env1setup]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env1/setup.sh
947 [env1packet1]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env1/packet1.sh
948 [env1packet2]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env1/packet2.sh
949 [env1thirdport]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env1/add-third-port.sh
950 [env1unknownports]:https://github.com/nickcooper-zhangtonghao/ovs/blob/master/tutorial/ovn/env1/add-unknown-ports.sh
951 [env1securityport]:https://github.com/nickcooper-zhangtonghao/ovs/blob/master/tutorial/ovn/env1/add-security-ip-ports.sh
952 [env1packet3]:https://github.com/nickcooper-zhangtonghao/ovs/blob/master/tutorial/ovn/env1/packet3.sh
953 [env1packet4]:https://github.com/nickcooper-zhangtonghao/ovs/blob/master/tutorial/ovn/env1/packet4.sh
954 [env2setup]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env2/setup.sh
955 [env2packet1]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env2/packet1.sh
956 [env2packet2]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env2/packet2.sh
957 [env3setup]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env3/setup.sh
958 [env3packet1]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env3/packet1.sh
959 [env3packet2]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env3/packet2.sh
960 [env4setup1]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env4/setup1.sh
961 [env4setup2]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env4/setup2.sh
962 [env4packet1]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env4/packet1.sh
963 [env4packet2]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env4/packet2.sh
964 [env4packet3]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env4/packet3.sh
965 [env4packet4]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env4/packet4.sh
966 [env4packet5]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env4/packet5.sh
967 [env5setup]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env5/setup.sh
968 [env5packet1]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env5/packet1.sh
969 [env5packet2]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env5/packet2.sh
970 [env6setup]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env6/setup.sh
971 [env6acls]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env6/add-acls.sh
972 [env7setup]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env7/setup.sh
973 [env7contports]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env7/add-container-ports.sh
974 [env7packet1]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env7/packet1.sh
975 [env7packet2]:https://github.com/openvswitch/ovs/blob/master/tutorial/ovn/env7/packet2.sh
976 [openstack-ovn-acl-blog]:http://blog.russellbryant.net/2015/10/22/openstack-security-groups-using-ovn-acls/
977 [openvswitch-docker]:http://openvswitch.org/support/dist-docs/INSTALL.Docker.md.txt