Add option to use netdev datapath_type
[netvirt.git] / openstack / net-virt-it / src / test / java / org / opendaylight / ovsdb / openstack / netvirt / it / NetvirtIT.java
1 /*
2  * Copyright (c) 2015 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 package org.opendaylight.ovsdb.openstack.netvirt.it;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15 import static org.ops4j.pax.exam.CoreOptions.composite;
16 import static org.ops4j.pax.exam.CoreOptions.maven;
17 import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
18 import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
19 import static org.ops4j.pax.exam.CoreOptions.vmOption;
20 import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
21 import static org.ops4j.pax.exam.MavenUtils.asInProject;
22 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
23 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
24 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
25
26 import com.google.common.collect.ImmutableBiMap;
27 import com.google.common.collect.Lists;
28
29 import java.net.InetAddress;
30 import java.net.NetworkInterface;
31 import java.net.UnknownHostException;
32 import java.util.ArrayList;
33 import java.util.Enumeration;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Properties;
37 import java.util.concurrent.atomic.AtomicBoolean;
38 import org.junit.Assert;
39 import org.junit.Before;
40 import org.junit.Ignore;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
44 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
45 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
46 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
47 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
48 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
49 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
50 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
51 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
52 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
53 import org.opendaylight.ovsdb.utils.config.ConfigProperties;
54 import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
55 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIds;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.InterfaceTypeEntryBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
72 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
74 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
75 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
76 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
77 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
78 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
79 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
80 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
81 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
82 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
83 import org.ops4j.pax.exam.Configuration;
84 import org.ops4j.pax.exam.Option;
85 import org.ops4j.pax.exam.junit.PaxExam;
86 import org.ops4j.pax.exam.karaf.options.LogLevelOption;
87 import org.ops4j.pax.exam.options.MavenUrlReference;
88 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
89 import org.ops4j.pax.exam.spi.reactors.PerClass;
90 import org.slf4j.Logger;
91 import org.slf4j.LoggerFactory;
92
93 /**
94  * Integration tests for netvirt
95  *
96  * @author Sam Hague (shague@redhat.com)
97  */
98 @RunWith(PaxExam.class)
99 @ExamReactorStrategy(PerClass.class)
100 public class NetvirtIT extends AbstractMdsalTestBase {
101     private static final Logger LOG = LoggerFactory.getLogger(NetvirtIT.class);
102     private static final int OVSDB_UPDATE_TIMEOUT = 1000;
103     private static DataBroker dataBroker = null;
104     private static String addressStr;
105     private static String portStr;
106     private static String connectionType;
107     private static String controllerStr;
108     private static AtomicBoolean setup = new AtomicBoolean(false);
109     private static MdsalUtils mdsalUtils = null;
110     private static Southbound southbound = null;
111     private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
112
113     @Override
114     public String getModuleName() {
115         return "netvirt-providers-impl";
116     }
117
118     @Override
119     public String getInstanceName() {
120         return "netvirt-providers-default";
121     }
122
123     @Override
124     public MavenUrlReference getFeatureRepo() {
125         return maven()
126                 .groupId("org.opendaylight.ovsdb")
127                 .artifactId("features-ovsdb")
128                 .classifier("features")
129                 .type("xml")
130                 .versionAsInProject();
131     }
132
133     @Override
134     public String getFeatureName() {
135         return "odl-ovsdb-openstack";
136     }
137
138     @Configuration
139     @Override
140     public Option[] config() {
141         Option[] parentOptions = super.config();
142         Option[] propertiesOptions = getPropertiesOptions();
143         Option[] otherOptions = getOtherOptions();
144         Option[] options = new Option[parentOptions.length + propertiesOptions.length + otherOptions.length];
145         System.arraycopy(parentOptions, 0, options, 0, parentOptions.length);
146         System.arraycopy(propertiesOptions, 0, options, parentOptions.length, propertiesOptions.length);
147         System.arraycopy(otherOptions, 0, options, parentOptions.length + propertiesOptions.length,
148                 otherOptions.length);
149         return options;
150     }
151
152     private Option[] getOtherOptions() {
153         return new Option[] {
154                 wrappedBundle(
155                         mavenBundle("org.opendaylight.ovsdb", "utils.mdsal-openflow")
156                                 .version(asInProject())
157                                 .type("jar")),
158                 wrappedBundle(
159                         mavenBundle("org.opendaylight.ovsdb", "utils.config")
160                                 .version(asInProject())
161                                 .type("jar")),
162                 configureConsole().startLocalConsole(),
163                 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
164                 keepRuntimeFolder()
165         };
166     }
167
168     public Option[] getPropertiesOptions() {
169         return new Option[] {
170                 propagateSystemProperties(NetvirtITConstants.SERVER_IPADDRESS,
171                         NetvirtITConstants.SERVER_PORT, NetvirtITConstants.CONNECTION_TYPE,
172                         NetvirtITConstants.CONTROLLER_IPADDRESS,
173                         NetvirtITConstants.USERSPACE_ENABLED)
174         };
175     }
176
177     @Override
178     public Option getLoggingOption() {
179         return composite(
180                 editConfigurationFilePut(NetvirtITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
181                         "log4j.logger.org.opendaylight.ovsdb",
182                         LogLevelOption.LogLevel.TRACE.name()),
183                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
184                         logConfiguration(NetvirtIT.class),
185                         LogLevelOption.LogLevel.INFO.name()),
186                 //editConfigurationFilePut(NetvirtITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
187                 //        "log4j.logger.org.opendaylight.ovsdb.lib",
188                 //        LogLevelOption.LogLevel.INFO.name()),
189                 super.getLoggingOption());
190     }
191
192     protected String usage() {
193         return "Integration Test needs a valid connection configuration as follows :\n"
194                 + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
195                 + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
196     }
197
198     private void getProperties() {
199         Properties props = System.getProperties();
200         addressStr = props.getProperty(NetvirtITConstants.SERVER_IPADDRESS);
201         portStr = props.getProperty(NetvirtITConstants.SERVER_PORT, NetvirtITConstants.DEFAULT_SERVER_PORT);
202         connectionType = props.getProperty(NetvirtITConstants.CONNECTION_TYPE, "active");
203         controllerStr = props.getProperty(NetvirtITConstants.CONTROLLER_IPADDRESS, "0.0.0.0");
204         String userSpaceEnabled = props.getProperty(NetvirtITConstants.USERSPACE_ENABLED, "no");
205         LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}, controller ip: {}, " +
206                 "userspace.enabled: {}",
207                 connectionType, addressStr, portStr, controllerStr, userSpaceEnabled);
208         if (connectionType.equalsIgnoreCase(NetvirtITConstants.CONNECTION_TYPE_ACTIVE)) {
209             if (addressStr == null) {
210                 fail(usage());
211             }
212         }
213     }
214
215     @Before
216     @Override
217     public void setup() throws InterruptedException {
218         if (setup.get()) {
219             LOG.info("Skipping setUp, already initialized");
220             return;
221         }
222
223         try {
224             super.setup();
225         } catch (Exception e) {
226             e.printStackTrace();
227         }
228
229         getProperties();
230
231         if (connectionType.equalsIgnoreCase(NetvirtITConstants.CONNECTION_TYPE_ACTIVE)) {
232             if (addressStr == null) {
233                 fail(usage());
234             }
235         }
236
237         dataBroker = getDatabroker(getProviderContext());
238         mdsalUtils = new MdsalUtils(dataBroker);
239         assertNotNull("mdsalUtils should not be null", mdsalUtils);
240         assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
241         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
242         assertNotNull("southbound should not be null", southbound);
243         setup.set(true);
244     }
245
246     private BindingAwareBroker.ProviderContext getProviderContext() {
247         BindingAwareBroker.ProviderContext providerContext = null;
248         for (int i=0; i < 60; i++) {
249             providerContext = getSession();
250             if (providerContext != null) {
251                 break;
252             } else {
253                 try {
254                     Thread.sleep(1000);
255                 } catch (InterruptedException e) {
256                     e.printStackTrace();
257                 }
258             }
259         }
260         assertNotNull("providercontext should not be null", providerContext);
261         /* One more second to let the provider finish initialization */
262         try {
263             Thread.sleep(1000);
264         } catch (InterruptedException e) {
265             e.printStackTrace();
266         }
267         return providerContext;
268     }
269
270     private DataBroker getDatabroker(BindingAwareBroker.ProviderContext providerContext) {
271         DataBroker dataBroker = providerContext.getSALService(DataBroker.class);
272         assertNotNull("dataBroker should not be null", dataBroker);
273         return dataBroker;
274     }
275
276     private Boolean getNetvirtTopology() {
277         LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
278         Boolean found = false;
279         final TopologyId topologyId = new TopologyId(new Uri(NETVIRT_TOPOLOGY_ID));
280         InstanceIdentifier<Topology> path =
281                 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
282         for (int i = 0; i < 60; i++) {
283             Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
284             if (topology != null) {
285                 LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
286                 found = true;
287                 break;
288             } else {
289                 LOG.info("getNetvirtTopology: still looking ({})...", i);
290                 try {
291                     Thread.sleep(1000);
292                 } catch (InterruptedException e) {
293                     e.printStackTrace();
294                 }
295             }
296         }
297         return found;
298     }
299
300     /**
301      * Test passive connection mode. The southbound starts in a listening mode waiting for connections on port
302      * 6640. This test will wait for incoming connections for {@link NetvirtITConstants.CONNECTION_INIT_TIMEOUT} ms.
303      *
304      * @throws InterruptedException
305      */
306     @Ignore
307     @Test
308     public void testPassiveNode() throws InterruptedException {
309         if (connectionType.equalsIgnoreCase(NetvirtITConstants.CONNECTION_TYPE_PASSIVE)) {
310             //Wait for CONNECTION_INIT_TIMEOUT for the Passive connection to be initiated by the ovsdb-server.
311             Thread.sleep(NetvirtITConstants.CONNECTION_INIT_TIMEOUT);
312         }
313     }
314
315     private ConnectionInfo getConnectionInfo(final String addressStr, final String portStr) {
316         InetAddress inetAddress = null;
317         try {
318             inetAddress = InetAddress.getByName(addressStr);
319         } catch (UnknownHostException e) {
320             fail("Could not allocate InetAddress: " + e);
321         }
322
323         IpAddress address = SouthboundMapper.createIpAddress(inetAddress);
324         PortNumber port = new PortNumber(Integer.parseInt(portStr));
325
326         LOG.info("connectionInfo: {}", new ConnectionInfoBuilder()
327                 .setRemoteIp(address)
328                 .setRemotePort(port)
329                 .build());
330         return new ConnectionInfoBuilder()
331                        .setRemoteIp(address)
332                        .setRemotePort(port)
333                        .build();
334     }
335
336     private String connectionInfoToString(final ConnectionInfo connectionInfo) {
337         return new String(connectionInfo.getRemoteIp().getValue()) + ":" + connectionInfo.getRemotePort().getValue();
338     }
339
340     private boolean addOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
341         boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION,
342                 SouthboundMapper.createInstanceIdentifier(connectionInfo),
343                 SouthboundMapper.createNode(connectionInfo));
344         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
345         return result;
346     }
347
348     private Node getOvsdbNode(final ConnectionInfo connectionInfo) {
349         return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
350                 SouthboundMapper.createInstanceIdentifier(connectionInfo));
351     }
352
353     private boolean deleteOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
354         boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
355                 SouthboundMapper.createInstanceIdentifier(connectionInfo));
356         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
357         return result;
358     }
359
360     private Node connectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
361         Assert.assertTrue(addOvsdbNode(connectionInfo));
362         Node node = getOvsdbNode(connectionInfo);
363         Assert.assertNotNull("Should find OVSDB node after connect", node);
364         LOG.info("Connected to {}", connectionInfoToString(connectionInfo));
365         return node;
366     }
367
368     private boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
369         Assert.assertTrue(deleteOvsdbNode(connectionInfo));
370         Node node = getOvsdbNode(connectionInfo);
371         Assert.assertNull("Should not find OVSDB node after disconnect", node);
372         //Assume.assumeNotNull(node); // Using assumeNotNull because there is no assumeNull
373         LOG.info("Disconnected from {}", connectionInfoToString(connectionInfo));
374         return true;
375     }
376
377     private String getControllerIPAddress() {
378         String addressString = ConfigProperties.getProperty(this.getClass(), "ovsdb.controller.address");
379         if (addressString != null) {
380             try {
381                 if (InetAddress.getByName(addressString) != null) {
382                     return addressString;
383                 }
384             } catch (UnknownHostException e) {
385                 LOG.error("Host {} is invalid", addressString);
386             }
387         }
388
389         addressString = ConfigProperties.getProperty(this.getClass(), "of.address");
390         if (addressString != null) {
391             try {
392                 if (InetAddress.getByName(addressString) != null) {
393                     return addressString;
394                 }
395             } catch (UnknownHostException e) {
396                 LOG.error("Host {} is invalid", addressString);
397             }
398         }
399
400         return null;
401     }
402
403     private short getControllerOFPort() {
404         short openFlowPort = Constants.OPENFLOW_PORT;
405         String portString = ConfigProperties.getProperty(this.getClass(), "of.listenPort");
406         if (portString != null) {
407             try {
408                 openFlowPort = Short.parseShort(portString);
409             } catch (NumberFormatException e) {
410                 LOG.warn("Invalid port:{}, use default({})", portString,
411                         openFlowPort);
412             }
413         }
414         return openFlowPort;
415     }
416
417     private List<String> getControllersFromOvsdbNode(Node node) {
418         List<String> controllersStr = new ArrayList<>();
419
420         String controllerIpStr = getControllerIPAddress();
421         if (controllerIpStr != null) {
422             // If codepath makes it here, the ip address to be used was explicitly provided.
423             // Being so, also fetch openflowPort provided via ConfigProperties.
424             controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
425                     + ":" + controllerIpStr + ":" + getControllerOFPort());
426         } else {
427             // Check if ovsdb node has manager entries
428             OvsdbNodeAugmentation ovsdbNodeAugmentation = southbound.extractOvsdbNode(node);
429             if (ovsdbNodeAugmentation != null) {
430                 List<ManagerEntry> managerEntries = ovsdbNodeAugmentation.getManagerEntry();
431                 if (managerEntries != null && !managerEntries.isEmpty()) {
432                     for (ManagerEntry managerEntry : managerEntries) {
433                         if (managerEntry == null || managerEntry.getTarget() == null) {
434                             continue;
435                         }
436                         String[] tokens = managerEntry.getTarget().getValue().split(":");
437                         if (tokens.length == 3 && tokens[0].equalsIgnoreCase("tcp")) {
438                             controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
439                                     + ":" + tokens[1] + ":" + getControllerOFPort());
440                         } else if (tokens[0].equalsIgnoreCase("ptcp")) {
441                             ConnectionInfo connectionInfo = ovsdbNodeAugmentation.getConnectionInfo();
442                             if (connectionInfo != null && connectionInfo.getLocalIp() != null) {
443                                 controllerIpStr = new String(connectionInfo.getLocalIp().getValue());
444                                 controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
445                                         + ":" + controllerIpStr + ":" + Constants.OPENFLOW_PORT);
446                             } else {
447                                 LOG.warn("Ovsdb Node does not contain connection info: {}", node);
448                             }
449                         } else {
450                             LOG.trace("Skipping manager entry {} for node {}",
451                                     managerEntry.getTarget(), node.getNodeId().getValue());
452                         }
453                     }
454                 } else {
455                     LOG.warn("Ovsdb Node does not contain manager entries : {}", node);
456                 }
457             }
458         }
459
460         if (controllersStr.isEmpty()) {
461             // Neither user provided ip nor ovsdb node has manager entries. Lets use local machine ip address.
462             LOG.debug("Use local machine ip address as a OpenFlow Controller ip address");
463             controllerIpStr = getLocalControllerHostIpAddress();
464             if (controllerIpStr != null) {
465                 controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
466                         + ":" + controllerIpStr + ":" + Constants.OPENFLOW_PORT);
467             }
468         }
469
470         if (controllersStr.isEmpty()) {
471             LOG.warn("Failed to determine OpenFlow controller ip address");
472         } else if (LOG.isDebugEnabled()) {
473             controllerIpStr = "";
474             for (String currControllerIpStr : controllersStr) {
475                 controllerIpStr += " " + currControllerIpStr;
476             }
477             LOG.debug("Found {} OpenFlow Controller(s) :{}", controllersStr.size(), controllerIpStr);
478         }
479
480         return controllersStr;
481     }
482
483     private String getLocalControllerHostIpAddress() {
484         String ipaddress = null;
485         try{
486             for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();ifaces.hasMoreElements();){
487                 NetworkInterface iface = ifaces.nextElement();
488
489                 for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
490                     InetAddress inetAddr = inetAddrs.nextElement();
491                     if (!inetAddr.isLoopbackAddress() && inetAddr.isSiteLocalAddress()) {
492                         ipaddress = inetAddr.getHostAddress();
493                         break;
494                     }
495                 }
496             }
497         }catch (Exception e){
498             LOG.warn("Exception while fetching local host ip address ", e);
499         }
500         return ipaddress;
501     }
502
503     private String getControllerTarget(Node ovsdbNode) {
504         return getControllersFromOvsdbNode(ovsdbNode).get(0);
505     }
506
507     @Test
508     public void testAddDeleteOvsdbNode() throws InterruptedException {
509         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
510         connectOvsdbNode(connectionInfo);
511         ControllerEntry controllerEntry;
512         for (int i = 0; i < 10; i++) {
513             Node ovsdbNode = getOvsdbNode(connectionInfo);
514             Assert.assertNotNull("ovsdb node not found", ovsdbNode);
515             String controllerTarget = getControllerTarget(ovsdbNode);
516             Assert.assertNotNull("Failed to get controller target", controllerTarget);
517             OvsdbBridgeAugmentation bridge = getBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
518             Assert.assertNotNull(bridge);
519             Assert.assertNotNull(bridge.getControllerEntry());
520             controllerEntry = bridge.getControllerEntry().iterator().next();
521             Assert.assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
522             if (controllerEntry.isIsConnected()) {
523                 Assert.assertTrue(controllerEntry.isIsConnected());
524                 break;
525             }
526             Thread.sleep(1000);
527         }
528
529         Assert.assertTrue(deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
530         Thread.sleep(1000);
531         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
532     }
533
534     @Ignore
535     @Test
536     public void testOpenVSwitchOtherConfig() throws InterruptedException {
537         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
538         Node ovsdbNode = connectOvsdbNode(connectionInfo);
539         OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
540         Assert.assertNotNull(ovsdbNodeAugmentation);
541         List<OpenvswitchOtherConfigs> otherConfigsList = ovsdbNodeAugmentation.getOpenvswitchOtherConfigs();
542         if (otherConfigsList != null) {
543             for (OpenvswitchOtherConfigs otherConfig : otherConfigsList) {
544                 if (otherConfig.getOtherConfigKey().equals("local_ip")) {
545                     LOG.info("local_ip: {}", otherConfig.getOtherConfigValue());
546                     break;
547                 } else {
548                     LOG.info("other_config {}:{}", otherConfig.getOtherConfigKey(), otherConfig.getOtherConfigValue());
549                 }
550             }
551         } else {
552             LOG.info("other_config is not present");
553         }
554         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
555         //Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
556     }
557
558     private void setManagedBy(final OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
559                               final ConnectionInfo connectionInfo) {
560         InstanceIdentifier<Node> connectionNodePath = SouthboundMapper.createInstanceIdentifier(connectionInfo);
561         ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
562     }
563
564     private List<ProtocolEntry> createMdsalProtocols() {
565         List<ProtocolEntry> protocolList = new ArrayList<>();
566         ImmutableBiMap<String, Class<? extends OvsdbBridgeProtocolBase>> mapper =
567                 SouthboundConstants.OVSDB_PROTOCOL_MAP.inverse();
568         protocolList.add(new ProtocolEntryBuilder().
569                 setProtocol(mapper.get("OpenFlow13")).build());
570         return protocolList;
571     }
572
573     private OvsdbTerminationPointAugmentationBuilder createGenericOvsdbTerminationPointAugmentationBuilder() {
574         OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointAugmentationBuilder =
575                 new OvsdbTerminationPointAugmentationBuilder();
576         ovsdbTerminationPointAugmentationBuilder.setInterfaceType(
577                 new InterfaceTypeEntryBuilder()
578                         .setInterfaceType(
579                                 SouthboundMapper.createInterfaceType("internal"))
580                         .build().getInterfaceType());
581         return ovsdbTerminationPointAugmentationBuilder;
582     }
583
584     private boolean addTerminationPoint(final NodeId bridgeNodeId, final String portName,
585             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointAugmentationBuilder)
586         throws InterruptedException {
587
588         InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(bridgeNodeId);
589         NodeBuilder portNodeBuilder = new NodeBuilder();
590         NodeId portNodeId = SouthboundMapper.createManagedNodeId(portIid);
591         portNodeBuilder.setNodeId(portNodeId);
592         TerminationPointBuilder entry = new TerminationPointBuilder();
593         entry.setKey(new TerminationPointKey(new TpId(portName)));
594         entry.addAugmentation(
595                 OvsdbTerminationPointAugmentation.class,
596                 ovsdbTerminationPointAugmentationBuilder.build());
597         portNodeBuilder.setTerminationPoint(Lists.newArrayList(entry.build()));
598         boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
599                 portIid, portNodeBuilder.build());
600         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
601         return result;
602     }
603
604     /*
605      * base method for adding test bridges.  Other helper methods used to create bridges should utilize this method.
606      *
607      * @param connectionInfo
608      * @param bridgeIid if passed null, one is created
609      * @param bridgeName cannot be null
610      * @param bridgeNodeId if passed null, one is created based on <code>bridgeIid</code>
611      * @param setProtocolEntries toggles whether default protocol entries are set for the bridge
612      * @param failMode toggles whether default fail mode is set for the bridge
613      * @param setManagedBy toggles whether to setManagedBy for the bridge
614      * @param dpType if passed null, this parameter is ignored
615      * @param externalIds if passed null, this parameter is ignored
616      * @param otherConfig if passed null, this parameter is ignored
617      * @return success of bridge addition
618      * @throws InterruptedException
619      */
620     private boolean addBridge(final ConnectionInfo connectionInfo, InstanceIdentifier<Node> bridgeIid,
621             final String bridgeName, NodeId bridgeNodeId, final boolean setProtocolEntries,
622             final Class<? extends OvsdbFailModeBase> failMode, final boolean setManagedBy,
623             final Class<? extends DatapathTypeBase> dpType,
624             final List<BridgeExternalIds> externalIds,
625             final List<BridgeOtherConfigs> otherConfigs) throws InterruptedException {
626
627         NodeBuilder bridgeNodeBuilder = new NodeBuilder();
628         if (bridgeIid == null) {
629             bridgeIid = SouthboundMapper.createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName));
630         }
631         if (bridgeNodeId == null) {
632             bridgeNodeId = SouthboundMapper.createManagedNodeId(bridgeIid);
633         }
634         bridgeNodeBuilder.setNodeId(bridgeNodeId);
635         OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
636         ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(bridgeName));
637         if (setProtocolEntries) {
638             ovsdbBridgeAugmentationBuilder.setProtocolEntry(createMdsalProtocols());
639         }
640         if (failMode != null) {
641             ovsdbBridgeAugmentationBuilder.setFailMode(failMode);
642         }
643         if (setManagedBy) {
644             setManagedBy(ovsdbBridgeAugmentationBuilder, connectionInfo);
645         }
646         if (dpType != null) {
647             ovsdbBridgeAugmentationBuilder.setDatapathType(dpType);
648         }
649         if (externalIds != null) {
650             ovsdbBridgeAugmentationBuilder.setBridgeExternalIds(externalIds);
651         }
652         if (otherConfigs != null) {
653             ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(otherConfigs);
654         }
655         bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
656         LOG.debug("Built with the intent to store bridge data {}",
657                 ovsdbBridgeAugmentationBuilder.toString());
658         boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
659                 bridgeIid, bridgeNodeBuilder.build());
660         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
661         return result;
662     }
663
664     private boolean addBridge(final ConnectionInfo connectionInfo, final String bridgeName)
665         throws InterruptedException {
666
667         return addBridge(connectionInfo, null, bridgeName, null, true,
668                 SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null, null);
669     }
670
671     private OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo) {
672         return getBridge(connectionInfo, NetvirtITConstants.BRIDGE_NAME);
673     }
674
675     /**
676      * Extract the <code>store</code> type data store contents for the particular bridge identified by
677      * <code>bridgeName</code>.
678      *
679      * @param connectionInfo
680      * @param bridgeName
681      * @param store defined by the <code>LogicalDatastoreType</code> enumeration
682      * @return <code>store</code> type data store contents
683      */
684     private OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo, String bridgeName,
685             LogicalDatastoreType store) {
686         Node bridgeNode = getBridgeNode(connectionInfo, bridgeName, store);
687         Assert.assertNotNull(bridgeNode);
688         OvsdbBridgeAugmentation ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
689         Assert.assertNotNull(ovsdbBridgeAugmentation);
690         return ovsdbBridgeAugmentation;
691     }
692
693     /**
694      * extract the <code>LogicalDataStoreType.OPERATIONAL</code> type data store contents for the particular bridge
695      * identified by <code>bridgeName</code>
696      *
697      * @param connectionInfo
698      * @param bridgeName
699      * @see <code>NetvirtIT.getBridge(ConnectionInfo, String, LogicalDatastoreType)</code>
700      * @return <code>LogicalDatastoreType.OPERATIONAL</code> type data store contents
701      */
702     private OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo, String bridgeName) {
703         return getBridge(connectionInfo, bridgeName, LogicalDatastoreType.OPERATIONAL);
704     }
705
706     /**
707      * Extract the node contents from <code>store</code> type data store for the
708      * bridge identified by <code>bridgeName</code>
709      *
710      * @param connectionInfo
711      * @param bridgeName
712      * @param store defined by the <code>LogicalDatastoreType</code> enumeration
713      * @return <code>store</code> type data store contents
714      */
715     private Node getBridgeNode(ConnectionInfo connectionInfo, String bridgeName, LogicalDatastoreType store) {
716         InstanceIdentifier<Node> bridgeIid =
717                 SouthboundMapper.createInstanceIdentifier(connectionInfo,
718                     new OvsdbBridgeName(bridgeName));
719         return mdsalUtils.read(store, bridgeIid);
720     }
721
722     /**
723      * Extract the node contents from <code>LogicalDataStoreType.OPERATIONAL</code> data store for the
724      * bridge identified by <code>bridgeName</code>
725      *
726      * @param connectionInfo
727      * @param bridgeName
728      * @return <code>LogicalDatastoreType.OPERATIONAL</code> type data store contents
729      */
730     private Node getBridgeNode(ConnectionInfo connectionInfo, String bridgeName) {
731         return getBridgeNode(connectionInfo, bridgeName, LogicalDatastoreType.OPERATIONAL);
732     }
733
734     private boolean deleteBridge(ConnectionInfo connectionInfo) throws InterruptedException {
735         return deleteBridge(connectionInfo, NetvirtITConstants.BRIDGE_NAME);
736     }
737
738     private boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName)
739         throws InterruptedException {
740
741         boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
742                 SouthboundMapper.createInstanceIdentifier(connectionInfo,
743                         new OvsdbBridgeName(bridgeName)));
744         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
745         return result;
746     }
747
748     private InstanceIdentifier<Node> getTpIid(ConnectionInfo connectionInfo, OvsdbBridgeAugmentation bridge) {
749         return SouthboundMapper.createInstanceIdentifier(connectionInfo,
750             bridge.getBridgeName());
751     }
752
753     private void netVirtAddPort(ConnectionInfo connectionInfo) throws InterruptedException {
754         OvsdbBridgeAugmentation bridge = getBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
755         Assert.assertNotNull(bridge);
756         NodeId nodeId = SouthboundMapper.createManagedNodeId(SouthboundMapper.createInstanceIdentifier(
757                 connectionInfo, bridge.getBridgeName()));
758         OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
759                 createGenericOvsdbTerminationPointAugmentationBuilder();
760         String portName = NetvirtITConstants.PORT_NAME;
761         ovsdbTerminationBuilder.setName(portName);
762         Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
763         InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
764         Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
765         Assert.assertNotNull(terminationPointNode);
766     }
767
768     /**
769      * Test for basic southbound events to netvirt.
770      * <pre>The test will:
771      * - connect to an OVSDB node and verify it is added to operational
772      * - then verify that br-int was created on the node and stored in operational
773      * - a port is then added to the bridge to verify that it is ignored by netvirt
774      * - remove the bridge
775      * - remove the node and verify it is not in operational
776      * </pre>
777      * @throws InterruptedException
778      */
779     @Test
780     public void testNetVirt() throws InterruptedException {
781         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
782         Node ovsdbNode = connectOvsdbNode(connectionInfo);
783
784         Thread.sleep(15000);
785         // Verify the pipeline flows were installed
786         PipelineOrchestrator pipelineOrchestrator =
787                 (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
788         assertNotNull("Could not find PipelineOrchestrator Service", pipelineOrchestrator);
789         Node bridgeNode = southbound.getBridgeNode(ovsdbNode, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
790         assertNotNull("bridge " + NetvirtITConstants.INTEGRATION_BRIDGE_NAME + " was not found", bridgeNode);
791         LOG.info("testNetVirt: bridgeNode: {}", bridgeNode);
792         long datapathId = southbound.getDataPathId(bridgeNode);
793         assertNotEquals("datapathId was not found", datapathId, 0);
794         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
795                 FlowUtils.createNodeBuilder(datapathId);
796
797         List<Service> staticPipeline = pipelineOrchestrator.getStaticPipeline();
798         List<Service> staticPipelineFound = Lists.newArrayList();
799         for (Service service : pipelineOrchestrator.getServiceRegistry().keySet()) {
800             if (staticPipeline.contains(service)) {
801                 staticPipelineFound.add(service);
802             }
803             FlowBuilder flowBuilder = FlowUtils.getPipelineFlow(service.getTable(), (short)0);
804             Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
805             assertNotNull("Could not find flow in config", flow);
806             flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
807             assertNotNull("Could not find flow in operational", flow);
808         }
809         assertEquals("did not find all expected flows in static pipeline",
810                 staticPipeline.size(), staticPipelineFound.size());
811
812         netVirtAddPort(connectionInfo);
813         Thread.sleep(10000);
814         Assert.assertTrue(deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
815         Thread.sleep(10000);
816         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
817     }
818
819     @Ignore
820     @Test
821     public void testNetVirt2() throws InterruptedException {
822         Thread.sleep(60000);
823     }
824
825     @Ignore
826     @Test
827     public void testReadOvsdbTopologyNodes() throws InterruptedException {
828         Thread.sleep(10000);
829         List<Node> ovsdbNodes = southbound.readOvsdbTopologyNodes();
830         for (Node node : ovsdbNodes) {
831             LOG.info(">>>>> node: {}", node);
832         }
833     }
834
835     private Flow getFlow (
836             FlowBuilder flowBuilder,
837             org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder,
838             LogicalDatastoreType store)
839             throws InterruptedException {
840
841         Flow flow = null;
842         for (int i = 0; i < 10; i++) {
843             flow = FlowUtils.getFlow(flowBuilder, nodeBuilder, dataBroker.newReadOnlyTransaction(), store);
844             if (flow != null) {
845                 LOG.info("getFlow: flow({}): {}", store, flow);
846                 break;
847             }
848             Thread.sleep(1000);
849         }
850         return flow;
851     }
852 }