Add support for using kernel modules with docker for IT
[netvirt.git] / openstack / utils / netvirt-it-utils / src / main / java / org / opendaylight / netvirt / utils / netvirt / it / utils / PingableNeutronNetItUtil.java
1 /*
2  * Copyright (c) 2016 Red Hat, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netvirt.utils.netvirt.it.utils;
10
11 import org.junit.Assert;
12 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
13 import org.opendaylight.ovsdb.utils.ovsdb.it.utils.DockerOvs;
14 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
15 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
16
17 import java.io.IOException;
18
19 /**
20  * This class adds the ability to issue pings from one port to another to its base class, NeutronNetItUtil.
21  * Please see NetvirtIT#testNeutronNet for an example of how this class is used
22  * N.B. At this point this class only supports DockerOvs runs where the docker-compose file runs a single
23  * docker container with OVS. A little work will need to be invested to extend this functionality to support
24  * configuring "ping-ability" on multiple docker containers.
25  */
26 public class PingableNeutronNetItUtil extends NeutronNetItUtil {
27
28     private static final int DEFAULT_WAIT = 30 * 1000;
29     private DockerOvs dockerOvs;
30     private final Boolean isUserSpace;
31
32     public PingableNeutronNetItUtil(DockerOvs dockerOvs, SouthboundUtils southboundUtils, String tenantId,
33                                     Boolean isUserSpace) {
34         super(southboundUtils, tenantId);
35         this.dockerOvs = dockerOvs;
36         this.isUserSpace = isUserSpace;
37     }
38
39     public PingableNeutronNetItUtil(DockerOvs dockerOvs, SouthboundUtils southboundUtils, String tenantId,
40                                     String segId, String macPfx, String ipPfx, String cidr, Boolean isUserSpace) {
41         super(southboundUtils, tenantId, segId, macPfx, ipPfx, cidr);
42         this.dockerOvs = dockerOvs;
43         this.isUserSpace = isUserSpace;
44     }
45
46     /**
47      * Create a port on the network. The deviceOwner will be set to "compute:None".
48      * @param bridge bridge where the port will be created on OVS
49      * @param portName name for this port
50      * @param owner deviceOwner, e.g., "network:dhcp"
51      * @param secGroups Optional NeutronSecurityGroup objects see NeutronUtils.createNeutronSecurityGroup()
52      * @throws InterruptedException if we're interrupted while waiting for objects to be created
53      */
54     public void createPort(Node bridge, String portName, String owner, NeutronSecurityGroup... secGroups)
55             throws InterruptedException, IOException {
56         if (dockerOvs.usingExternalDocker()) {
57             super.createPort(bridge, portName, owner, secGroups);
58             return;
59         }
60
61         PortInfo portInfo = buildPortInfo(portName);
62
63         if (isUserSpace) {
64             dockerOvs.runInContainer(DEFAULT_WAIT, 0, "ip", "tuntap", "add", portInfo.name, "mode", "tap");
65             dockerOvs.runInContainer(DEFAULT_WAIT, 0, "ip", "link", "set", "dev",
66                     portInfo.name, "address", portInfo.mac);
67
68             doCreatePort(bridge, portInfo, owner, "tap", secGroups);
69         } else {
70             doCreatePort(bridge, portInfo, owner, "internal", secGroups);
71             dockerOvs.runInContainer(DEFAULT_WAIT, 0, "ip", "link", "set", "dev",
72                     portInfo.name, "address", portInfo.mac);
73         }
74     }
75
76     /**
77      * This method must be run on a port before calling ping() or pingIp()
78      * @param portName The name of the port used when it was created using createPort()
79      * @throws IOException if an IO error occurs with one of the spawned procs
80      * @throws InterruptedException because we sleep
81      */
82     public void preparePortForPing(String portName) throws IOException, InterruptedException {
83         if (dockerOvs.usingExternalDocker()) {
84             return;
85         }
86
87         String nsName = "ns-" + portName;
88
89         PortInfo portInfo = portInfoByName.get(portName);
90         Assert.assertNotNull(portInfo);
91         dockerOvs.runInContainer(DEFAULT_WAIT, 0, "ip", "netns", "add", nsName);
92         dockerOvs.runInContainer(DEFAULT_WAIT, 0, "ip", "link", "set", portName, "netns", nsName);
93         dockerOvs.runInContainer(DEFAULT_WAIT, 0, "ip", "netns", "exec", nsName, "ip", "addr",
94                 "add", "dev", portName, portInfo.ip + "/24");
95         dockerOvs.runInContainer(DEFAULT_WAIT, 0, "ip", "netns", "exec", nsName, "ip", "link",
96                 "set", "dev", "lo", "up");
97         dockerOvs.runInContainer(DEFAULT_WAIT, 0, "ip", "netns", "exec", nsName, "ip", "link",
98                 "set", "dev", portName, "up");
99         dockerOvs.runInContainer(DEFAULT_WAIT, 0, "ip", "netns", "exec", nsName, "ip", "route",
100                 "add", "default", "via", portInfo.ip);
101     }
102
103     /**
104      * Ping from one port to the other
105      * @param fromPort name of the port to ping from. This is the name you used for createPort.
106      * @param toPort name of the port to ping to. This is the name you used for createPort.
107      * @throws IOException if an IO error occurs with one of the spawned procs
108      * @throws InterruptedException because we sleep
109      */
110     public void ping(String fromPort, String toPort) throws IOException, InterruptedException {
111         if (dockerOvs.usingExternalDocker()) {
112             return;
113         }
114
115         PortInfo portInfo = portInfoByName.get(toPort);
116         Assert.assertNotNull(portInfo);
117         pingIp(fromPort, portInfo.ip);
118     }
119
120     /**
121      * Ping from one port to an IP address
122      * @param fromPort name of the port to ping from. This is the name you used for createPort.
123      * @param ip The IP address to ping
124      * @throws IOException if an IO error occurs with one of the spawned procs
125      * @throws InterruptedException because we sleep
126      */
127     public void pingIp(String fromPort, String ip) throws IOException, InterruptedException {
128         if (dockerOvs.usingExternalDocker()) {
129             return;
130         }
131
132         String fromNs = "ns-" + fromPort;
133         dockerOvs.runInContainer(0, DEFAULT_WAIT, 0, "ip", "netns", "exec", fromNs, "ping", "-c", "4", ip);
134     }
135 }