Clean up VPN data on VPN delete.
[netvirt.git] / docs / openstack-guide / openstack-with-netvirt.rst
1 OpenStack with NetVirt
2 ======================
3 .. contents:: Table of Contents
4       :depth: 2
5
6 **Prerequisites**: OpenDaylight requires Java 1.8.0 and Open vSwitch >= 2.5.0
7
8 Installing OpenDaylight on an existing OpenStack
9 ------------------------------------------------
10 * On the control host, `Download the latest OpenDaylight release <https://www.opendaylight.org/software/downloads>`_
11 * Uncompress it as root, and start OpenDaylight (you can start OpenDaylight
12   by running karaf directly, but exiting from the shell will shut it down):
13
14   .. code-block:: bash
15
16       tar xvfz distribution-karaf-0.5.1-Boron-SR1.tar.gz
17       cd distribution-karaf-0.5.1-Boron-SR1
18       ./bin/start # Start OpenDaylight as a server process
19
20 * Connect to the Karaf shell, and install the odl-netvirt-openstack bundle,
21   dlux and their dependencies:
22
23   .. code-block:: bash
24
25       ./bin/client # Connect to OpenDaylight with the client
26       opendaylight-user@root> feature:install odl-netvirt-openstack odl-dlux-core odl-mdsal-apidocs
27
28 * If everything is installed correctly, you should now be able to log in to the dlux interface on
29   http://CONTROL_HOST:8181/index.html - the default username and password is "admin/admin" (see screenshot below)
30
31   .. figure:: dlux-login.png
32
33 Optional - Advanced OpenDaylight Installation - Configurations and Clustering
34 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35 * ACL Implementation - Security Groups - Stateful:
36
37   * Default implementation used is stateful, requiring OVS compiled with conntrack modules.
38   * This requires using a linux kernel that is >= 4.3
39   * To check if OVS is running with conntrack support:
40
41     .. code-block:: bash
42
43        root@devstack:~/# lsmod | grep conntrack | grep openvswitch
44          nf_conntrack          106496  9 xt_CT,openvswitch,nf_nat,nf_nat_ipv4,xt_conntrack,nf_conntrack_netlink,xt_connmark,nf_conntrack_ipv4,nf_conntrack_ipv6
45
46   * If the conntrack modules are not installed for OVS, either recompile/install an OVS version with conntrack support, or alternatively configure OpenDaylight to use a non-stateful implementation.
47   * OpenvSwitch 2.5 with conntrack support can be acquired from this repository for yum based linux distributions:
48
49     .. code-block:: bash
50
51        yum install -y http://rdoproject.org/repos/openstack-newton/rdo-release-newton.rpm
52        yum install -y --nogpgcheck openvswitch
53   * To spwan a VM with security groups disabled:
54
55     .. code-block:: bash
56
57        crudini --set /etc/neutron/plugins/dhcp_agent.ini ml2 extension_drivers port_security
58
59        openstack port create --network=net1 --disable-port-security port1
60        openstack server create --flavor m1.tiny --image cirros --port port1 vm1
61
62
63 * Running multiple OpenDaylight controllers in a cluster:
64
65   * For redundancy, it is possible to run OpenDaylight in a 3-node cluster.
66   * More info on Clustering available `here <http://docs.opendaylight.org/en/latest/getting-started-guide/common-features/clustering.html>`_.
67   * To configure OpenDaylight in clustered mode, run <ODL_FOLDER>/bin/configure_cluster.sh on each node prior to running OpenDaylight.
68     This script is used to configure cluster parameters on this controller. The user should restart controller to apply changes.
69
70     .. code-block:: bash
71
72        Usage: ./configure_cluster.sh <index> <seed_nodes_list>
73        - index: Integer within 1..N, where N is the number of seed nodes.
74        - seed_nodes_list: List of seed nodes, separated by comma or space.
75
76   * The address at the provided index should belong this controller.
77     When running this script on multiple seed nodes, keep the seed_node_list same,
78     and vary the index from 1 through N.
79
80   * Optionally, shards can be configured in a more granular way by modifying the file
81     "custom_shard_configs.txt" in the same folder as this tool.
82     Please see that file for more details.
83
84   .. note::
85      OpenDaylight should be restarted after applying any of the above changes via configuration files.
86
87 Ensuring OpenStack network state is clean
88 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
89 When using OpenDaylight as the Neutron back-end, OpenDaylight expects to be the only source of
90 truth for Neutron configurations. Because of this, it is necessary to remove existing OpenStack
91 configurations to give OpenDaylight a clean slate.
92
93 * Delete instances:
94
95   .. code-block:: bash
96
97       nova list
98       nova delete <instance names>
99
100 * Remove links from subnets to routers:
101
102   .. code-block:: bash
103
104       neutron subnet-list
105       neutron router-list
106       neutron router-port-list <router name>
107       neutron router-interface-delete <router name> <subnet ID or name>
108
109 * Delete subnets, networks, routers:
110
111   .. code-block:: bash
112
113       neutron subnet-delete <subnet name>
114       neutron net-list
115       neutron net-delete <net name>
116       neutron router-delete <router name>
117
118 * Check that all ports have been cleared - at this point, this should be an
119   empty list:
120
121   .. code-block:: bash
122
123       neutron port-list
124
125
126 Ensure Neutron is stopped
127 ^^^^^^^^^^^^^^^^^^^^^^^^^
128 While Neutron is managing the OVS instances on compute and control nodes,
129 OpenDaylight and Neutron can be in conflict. To prevent issues, we turn off
130 Neutron server on the network controller, and Neutron's Open vSwitch agents
131 on all hosts.
132
133 * Turn off neutron-server on control node:
134
135   .. code-block:: bash
136
137       systemctl stop neutron-server
138       systemctl stop neutron-l3-agent
139
140 * On each node in the cluster, shut down and disable Neutron's agent services to
141   ensure that they do not restart after a reboot:
142
143   .. code-block:: bash
144
145       systemctl stop neutron-openvswitch-agent
146       systemctl disable
147       neutron-openvswitch-agent
148       systemctl stop neutron-l3-agent
149       systemctl disable neutron-l3-agent
150
151
152 Configuring Open vSwitch to be managed by OpenDaylight
153 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
154 On each host (both compute and control nodes) we will clear the pre-existing
155 Open vSwitch config and set OpenDaylight to manage the switch:
156
157 * Stop the Open vSwitch service, and clear existing OVSDB (OpenDaylight expects to
158   manage vSwitches completely):
159
160   .. code-block:: bash
161
162       systemctl stop openvswitch
163       rm -rf /var/log/openvswitch/*
164       rm -rf /etc/openvswitch/conf.db
165       systemctl start openvswitch
166
167 * At this stage, your Open vSwitch configuration should be empty:
168
169   .. code-block:: bash
170
171       [root@odl-compute2 ~]# ovs-vsctl show
172       9f3b38cb-eefc-4bc7-828b-084b1f66fbfd
173           ovs_version: "2.5.1"
174
175 * Set OpenDaylight as the manager on all nodes:
176
177   .. code-block:: bash
178
179       ovs-vsctl set-manager tcp:{CONTROL_HOST}:6640
180
181 * Set the IP to be used for VXLAN connectivity on all nodes.
182   This IP must correspond to an actual linux interface on each machine.
183
184   .. code-block:: bash
185
186       sudo ovs-vsctl set Open_vSwitch . other_config:local_ip=<ip>
187
188 * You should now see a new section in your Open vSwitch configuration
189   showing that you are connected to the OpenDaylight server via OVSDB,
190   and OpenDaylight will automatically create a br-int bridge that is
191   connected via OpenFlow to the controller:
192
193   .. code-block:: bash
194      :emphasize-lines: 4,6-7
195
196      [root@odl-compute2 ~]# ovs-vsctl show
197      9f3b38cb-eefc-4bc7-828b-084b1f66fbfd
198           Manager "tcp:172.16.21.56:6640"
199               is_connected: true
200           Bridge br-int
201               Controller "tcp:172.16.21.56:6633"
202                   is_connected: true
203               fail_mode: secure
204               Port br-int
205                   Interface br-int
206           ovs_version: "2.5.1"
207
208       [root@odl-compute2 ~]# ovs-vsctl get Open_vSwitch . other_config
209       {local_ip="10.0.42.161"}
210
211 * If you do not see the result above (specifically, if you do not see "is_connected: true" in the Manager section or in the Controller section), you may not have a security policies in place to allow Open vSwitch remote administration.
212
213   .. note::
214      | There might be iptables restrictions - if so the relevant ports should be opened (6640, 6653).
215      | If SELinux is running on your linux, set to permissive mode on all nodes and ensure it stays that way after boot.
216
217      .. code-block:: bash
218
219         setenforce 0
220         sed -i -e 's/SELINUX=enforcing/SELINUX=permissive/g' /etc/selinux/config
221
222 * Make sure all nodes, including the control node, are connected to OpenDaylight.
223 * If you reload DLUX, you should now see that all of your Open vSwitch nodes are now connected to OpenDaylight.
224
225   .. figure:: dlux-with-switches.png
226
227 * If something has gone wrong, check ``data/log/karaf.log`` under
228   the OpenDaylight distribution directory. If you do not see any interesting
229   log entries, set logging for netvirt to TRACE level inside Karaf and try again:
230
231   .. code-block:: bash
232
233      log:set TRACE netvirt
234
235 Configuring Neutron to use OpenDaylight
236 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
237 Once you have configured the vSwitches to connect to OpenDaylight, you can
238 now ensure that OpenStack Neutron is using OpenDaylight.
239
240 This requires the neutron networking-odl module to be installed.
241 | ``pip install networking-odl``
242
243 First, ensure that port 8080 (which will be used by OpenDaylight to listen
244 for REST calls) is available. By default, swift-proxy-service listens on the
245 same port, and you may need to move it (to another port or another host), or
246 disable that service. It can be moved to a different port (e.g. 8081) by editing
247 ``/etc/swift/proxy-server.conf`` and ``/etc/cinder/cinder.conf``,
248 modifying iptables appropriately, and restarting swift-proxy-service.
249 Alternatively, OpenDaylight can be configured to listen on a different port,
250 by modifying the ``jetty.port`` property value in ``etc/jetty.conf``.
251
252 .. code-block:: bash
253
254    <Set name="port">
255        <Property name="jetty.port" default="8080" />
256    </Set>
257
258 * Configure Neutron to use OpenDaylight's ML2 driver:
259
260   .. code-block:: bash
261
262      crudini --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2 mechanism_drivers opendaylight
263      crudini --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2 tenant_network_types vxlan
264
265      cat <<EOT>> /etc/neutron/plugins/ml2/ml2_conf.ini
266      [ml2_odl]
267      url = http://{CONTROL_HOST}:8080/controller/nb/v2/neutron
268      password = admin
269      username = admin
270      EOT
271
272 * Configure Neutron to use OpenDaylight's odl-router service plugin for L3 connectivity:
273
274   .. code-block:: bash
275
276      crudini --set /etc/neutron/plugins/neutron.conf DEFAULT service_plugins odl-router
277
278 * Configure Neutron DHCP agent to provide metadata services:
279
280   .. code-block:: bash
281
282      crudini --set /etc/neutron/plugins/dhcp_agent.ini DEFAULT force_metadata True
283
284   .. note::
285      | If the OpenStack version being used is Newton, this workaround should be applied,
286      | configuring the Neutron DHCP agent to use vsctl as the OVSDB interface:
287
288      .. code-block:: bash
289
290         crudini --set /etc/neutron/plugins/dhcp_agent.ini OVS ovsdb_interface vsctl
291
292 * Reset Neutron's database
293
294   .. code-block:: bash
295
296      mysql -e "DROP DATABASE IF EXISTS neutron;"
297      mysql -e "CREATE DATABASE neutron CHARACTER SET utf8;"
298      /usr/local/bin/neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head
299
300 * Restart neutron-server:
301
302   .. code-block:: bash
303
304      systemctl start neutron-server
305
306 Verifying it works
307 ^^^^^^^^^^^^^^^^^^
308 * Verify that OpenDaylight's ML2 interface is working:
309
310   .. code-block:: bash
311
312      curl -u admin:admin http://{CONTROL_HOST}:8080/controller/nb/v2/neutron/networks
313
314      {
315         "networks" : [ ]
316      }
317
318   | If this does not work or gives an error, check Neutron's log file in ``/var/log/neutron/server.log``.
319   | Error messages here should give some clue as to what the problem is in the connection with OpenDaylight.
320
321 * Create a network, subnet, router, connect ports, and start an instance using the Neutron CLI:
322
323   .. code-block:: bash
324
325      neutron router-create router1
326      neutron net-create private
327      neutron subnet-create private --name=private_subnet 10.10.5.0/24
328      neutron router-interface-add router1 private_subnet
329      nova boot --flavor <flavor> --image <image id> --nic net-id=<network id> test1
330      nova boot --flavor <flavor> --image <image id> --nic net-id=<network id> test2
331
332 At this point, you have confirmed that OpenDaylight is creating network
333 end-points for instances on your network and managing traffic to them.
334
335 | VMs can be reached using Horizon console, or alternatively by issuing ``nova get-vnc-console <vm> novnc``
336 | Through the console, connectivity between VMs can be verified.
337
338 Adding an external network for floating IP connectivity
339 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
340 * In order to connect to the VM using a floating IP, we need to configure external network connectivity, by creating an external network and subnet. This external network must be linked to a physical port on the machine, which will provide connectivity to an external gateway.
341
342   .. code-block:: bash
343
344      sudo ovs-vsctl set Open_vSwitch . other_config:provider_mappings=physnet1:eth1
345      neutron net-create public-net -- --router:external --is-default --provider:network_type=flat --provider:physical_network=physnet1
346      neutron subnet-create --allocation-pool start=10.10.10.2,end=10.10.10.254 --gateway 10.10.10.1 --name public-subnet public-net 10.10.0.0/16 -- --enable_dhcp=False
347      neutron router-gateway-set router1 public-net
348
349      neutron floatingip-create public-net
350      nova floating-ip-associate test1 <floating_ip>
351
352 Installing OpenStack and OpenDaylight using DevStack
353 ----------------------------------------------------
354 The easiest way to load and OpenStack setup using OpenDaylight is by using devstack, which does all the steps mentioned in previous sections.
355 | ``git clone https://git.openstack.org/openstack-dev/devstack``
356
357 * The following lines need to be added to your local.conf:
358
359   .. code-block:: bash
360
361    enable_plugin networking-odl http://git.openstack.org/openstack/networking-odl <branch>
362    ODL_MODE=allinone
363    Q_ML2_PLUGIN_MECHANISM_DRIVERS=opendaylight,logger
364    ODL_GATE_SERVICE_PROVIDER=vpnservice
365    disable_service q-l3
366    ML2_L3_PLUGIN=odl-router
367    ODL_PROVIDER_MAPPINGS={PUBLIC_PHYSICAL_NETWORK}:<external linux interface>
368
369 * More details on using devstack can be found in the following links:
370
371   * `Devstack All-In-One Single Machine Tutorial <http://docs.openstack.org/developer/devstack/guides/single-machine.html>`_
372   * `Devstack networking-odl README <https://github.com/openstack/networking-odl/blob/master/devstack/README.rst>`_
373
374 Troubleshooting
375 ---------------
376 VM DHCP Issues
377 ^^^^^^^^^^^^^^
378 * Trigger DHCP requests - access VM console:
379
380   * View log: ``nova console-log <vm>``
381   * Access using VNC console: nova get-vnc-console <vm> novnc
382   * Trigger DHCP requests:
383     ``sudo ifdown eth0 ; sudo ifup eth0``
384
385     .. code-block:: bash
386
387        udhcpc (v1.20.1) started
388        Sending discover...
389        Sending select for 10.0.123.3...
390        Lease of 10.0.123.3 obtained, lease time 86400 # This only happens when DHCP is properly obtained.
391
392 * Check if the DHCP requests are reaching the qdhcp agent using the following commands on the OpenStack controller:
393
394   .. code-block:: bash
395
396      sudo ip netns
397      sudo ip netns exec qdhcp-xxxxx ifconfig # xxxx is the neutron network id
398      sudo ip netns exec qdhcp-xxxxx tcpdump -nei tapxxxxx # xxxxx is the neutron port id
399
400      # Valid request and response:
401      15:08:41.684932 fa:16:3e:02:14:bb > ff:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 329: 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from fa:16:3e:02:14:bb, length 287
402      15:08:41.685152 fa:16:3e:79:07:98 > fa:16:3e:02:14:bb, ethertype IPv4 (0x0800), length 354: 10.0.123.2.67 > 10.0.123.3.68: BOOTP/DHCP, Reply, length 312
403
404 * If the requests aren't reaching qdhcp:
405
406   * Verify VXLAN tunnels exist between compute and control nodes by using ``ovs-vsctl show``
407   * | Run the following commands to debug the OVS processing of the DHCP request packet:
408     | ``ovs-ofctl -OOpenFlow13 dump-ports-desc br-int`` # retrieve VMs ofport and MAC
409     | ``ovs-appctl ofproto/trace br-int in_port=<ofport>,dl_src=<mac>,dl_dst=ff:ff:ff:ff:ff:ff,udp,ip_src=0.0.0.0,ip_dst=255.255.255.255 | grep "Rule\|action"``
410
411     .. code-block:: bash
412
413        root@devstack:~# ovs-appctl ofproto/trace br-int in_port=1,dl_src=fe:16:3e:33:8b:d8,dl_dst=ff:ff:ff:ff:ff:ff,udp,ip_src=0.0.0.0,ip_dst=255.255.255.255 | grep "Rule\|action"
414            Rule: table=0 cookie=0x8000000 priority=1,in_port=1
415            OpenFlow actions=write_metadata:0x20000000001/0xffffff0000000001,goto_table:17
416                Rule: table=17 cookie=0x8000001 priority=5,metadata=0x20000000000/0xffffff0000000000
417                OpenFlow actions=write_metadata:0xc0000200000222e2/0xfffffffffffffffe,goto_table:19
418                    Rule: table=19 cookie=0x1080000 priority=0
419                    OpenFlow actions=resubmit(,17)
420                        Rule: table=17 cookie=0x8040000 priority=6,metadata=0xc000020000000000/0xffffff0000000000
421                        OpenFlow actions=write_metadata:0xe00002138a000000/0xfffffffffffffffe,goto_table:50
422                            Rule: table=50 cookie=0x8050000 priority=0
423                            OpenFlow actions=CONTROLLER:65535,goto_table:51
424                                Rule: table=51 cookie=0x8030000 priority=0
425                                OpenFlow actions=goto_table:52
426                                    Rule: table=52 cookie=0x870138a priority=5,metadata=0x138a000001/0xffff000001
427                                    OpenFlow actions=write_actions(group:210003)
428            Datapath actions: drop
429
430        root@devstack:~# ovs-ofctl -OOpenFlow13 dump-groups br-int | grep 'group_id=210003'
431            group_id=210003,type=all
432
433 * If the requests are reaching qdhcp, but the response isn't arriving to the VM:
434
435   * Locate the compute the VM is residing on (can use ``nova show <vm>``).
436
437     * | If the VM is on the same node as the qdhcp namespace, ``ofproto/trace`` can be used to track the packet:
438       | ``ovs-appctl ofproto/trace br-int in_port=<dhcp_ofport>,dl_src=<dhcp_port_mac>,dl_dst=<vm_port_mac>,udp,ip_src=<dhcp_port_ip>,ip_dst=<vm_port_ip> | grep "Rule\|action"``
439
440       .. code-block:: bash
441
442          root@devstack:~# ovs-appctl ofproto/trace br-int in_port=2,dl_src=fa:16:3e:79:07:98,dl_dst=fa:16:3e:02:14:bb,udp,ip_src=10.0.123.2,ip_dst=10.0.123.3 | grep "Rule\|action"
443              Rule: table=0 cookie=0x8000000 priority=4,in_port=2
444              OpenFlow actions=write_metadata:0x10000000000/0xffffff0000000001,goto_table:17
445                  Rule: table=17 cookie=0x8000001 priority=5,metadata=0x10000000000/0xffffff0000000000
446                  OpenFlow actions=write_metadata:0x60000100000222e0/0xfffffffffffffffe,goto_table:19
447                      Rule: table=19 cookie=0x1080000 priority=0
448                      OpenFlow actions=resubmit(,17)
449                          Rule: table=17 cookie=0x8040000 priority=6,metadata=0x6000010000000000/0xffffff0000000000
450                          OpenFlow actions=write_metadata:0x7000011389000000/0xfffffffffffffffe,goto_table:50
451                              Rule: table=50 cookie=0x8051389 priority=20,metadata=0x11389000000/0xfffffffff000000,dl_src=fa:16:3e:79:07:98
452                              OpenFlow actions=goto_table:51
453                                  Rule: table=51 cookie=0x8031389 priority=20,metadata=0x1389000000/0xffff000000,dl_dst=fa:16:3e:02:14:bb
454                                  OpenFlow actions=load:0x300->NXM_NX_REG6[],resubmit(,220)
455                                      Rule: table=220 cookie=0x8000007 priority=7,reg6=0x300
456                                      OpenFlow actions=output:3
457
458     * If the VM isn't on the same node as the qdhcp namepsace:
459
460       * Check if the packet is arriving via VXLAN by running ``tcpdump -nei <vxlan_port> port 4789``
461       * If it is arriving via VXLAN, the packet can be tracked on the compute node rules, using ``ofproto/trace``
462         in a similiar manner to the previous section. Note that packets arriving from a tunnels have a unique
463         tunnel_id (VNI) that should be used as well in the trace, due to the special processing of packets arriving
464         from a VXLAN tunnel.
465
466 Floating IP Issues
467 ^^^^^^^^^^^^^^^^^^
468 *  If you have assigned an external network and associated a floating IP to a VM but there is still no connectivity:
469
470    * Verify the external gateway IP is reachable through the provided provider network port.
471    * Verify OpenDaylight has successfully resolved the MAC address of the external gateway IP.
472      This can be verified by searching for the line "Installing ext-net group" in the karaf.log.
473    * Locate the compute the VM is residing on (can use ``nova show <vm>``).
474    * Run a ping to the VM floating IP.
475    * If the ping fails, execute a flow dump of br-int, and search for the flows that are relevant to the VM's floating IP address:
476      ``ovs-ofctl -OOpenFlow13 dump-flows br-int | grep "<floating_ip>"``
477
478      * | Are there packets on the incoming flow (matching dst_ip=<floating_ip>)?
479        | If not this probably means the provider network has not been set up properly, verify provider_mappings configuration and the configured external network physical_network value match. Also verify that the Flat/VLAN network configured is actually reachable via the configured port.
480      * | Are there packets on the outgoing flow (matching src_ip=<floating_ip>)?
481        | If not, this probably means that OpenDaylight is failing to resolve the MAC of the provided external gateway, required for forwarding packets to the external network.
482      * | Are there packets being sent on the external network port?
483        | This can be checked using ``tcpdump <port>`` or by viewing the appropriate OpenFlow rules. The mapping between the OpenFlow port number and the linux interface can be acquired using ``ovs-ofctl dump-ports-desc br-int``
484
485        .. code-block:: bash
486
487           ovs-ofctl -OOpenFlow13 dump-flows br-int | grep "<floating_ip>"
488           cookie=0x8000003, duration=436.710s, table=21, n_packets=190, n_bytes=22602, priority=42,ip,metadata=0x222e2/0xfffffffe,nw_dst=10.64.98.17 actions=goto_table:25
489           cookie=0x8000004, duration=436.739s, table=25, n_packets=190, n_bytes=22602, priority=10,ip,nw_dst=10.64.98.17 actions=set_field:10.0.123.3->ip_dst,write_metadata:0x222e0/0xfffffffe,goto_table:27
490           cookie=0x8000004, duration=436.730s, table=26, n_packets=120, n_bytes=15960, priority=10,ip,metadata=0x222e0/0xfffffffe,nw_src=10.0.123.3 actions=set_field:10.64.98.17->ip_src,write_metadata:0x222e2/0xfffffffe,goto_table:28
491           cookie=0x8000004, duration=436.728s, table=28, n_packets=120, n_bytes=15960, priority=10,ip,metadata=0x222e2/0xfffffffe,nw_src=10.64.98.17 actions=set_field:fa:16:3e:ec:a8:84->eth_src,group:200000
492
493 Useful Links
494 ------------
495 * `NetVirt Tables Pipeline <https://docs.google.com/presentation/d/15h4ZjPxblI5Pz9VWIYnzfyRcQrXYxA1uUoqJsgA53KM>`_
496 * `NetVirt Wiki Page <https://wiki.opendaylight.org/view/NetVirt>`_
497 * `NetVirt Basic Tutorial (OpenDaylight Summit 2016) <https://docs.google.com/presentation/d/1VLzRIOEptSOY1b0w4PezRIQ0gF5vx7GyLKECWXRV5mE>`_
498 * `NetVirt Advanced Tutorial (OpenDaylight Summit 2016) <https://docs.google.com/presentation/d/13K8Z1kl5XFZrWqBToMwFISSAPOKfzd3m9BtVcb-YAWs>`_
499 * `Other OpenDaylight Documentation <http://docs.opendaylight.org/>`_