2 * Copyright (c) 2015 Red Hat, Inc. and others. All rights reserved.
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
8 package org.opendaylight.ovsdb.openstack.netvirt.it;
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;
26 import com.google.common.collect.Lists;
27 import com.google.common.collect.Maps;
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;
36 import java.util.Properties;
37 import java.util.concurrent.atomic.AtomicBoolean;
39 import org.junit.Assert;
40 import org.junit.Before;
41 import org.junit.Ignore;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
45 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
46 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
47 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
48 import org.opendaylight.neutron.spi.INeutronPortCRUD;
49 import org.opendaylight.neutron.spi.INeutronSecurityGroupCRUD;
50 import org.opendaylight.neutron.spi.INeutronSecurityRuleCRUD;
51 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
52 import org.opendaylight.neutron.spi.NeutronPort;
53 import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
54 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
55 import org.opendaylight.neutron.spi.NeutronSecurityRule;
56 import org.opendaylight.neutron.spi.NeutronNetwork;
57 import org.opendaylight.neutron.spi.NeutronSubnet;
58 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
59 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
60 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
61 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
62 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
63 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
64 import org.opendaylight.ovsdb.utils.config.ConfigProperties;
65 import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
66 import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
67 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
68 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
69 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
71 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.InterfaceTypeEntryBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
85 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
86 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
87 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
88 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
89 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
90 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
91 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
92 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
93 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
94 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
95 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
96 import org.ops4j.pax.exam.Configuration;
97 import org.ops4j.pax.exam.Option;
98 import org.ops4j.pax.exam.junit.PaxExam;
99 import org.ops4j.pax.exam.karaf.options.LogLevelOption;
100 import org.ops4j.pax.exam.options.MavenUrlReference;
101 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
102 import org.ops4j.pax.exam.spi.reactors.PerClass;
103 import org.slf4j.Logger;
104 import org.slf4j.LoggerFactory;
107 * Integration tests for netvirt
109 * @author Sam Hague (shague@redhat.com)
111 @RunWith(PaxExam.class)
112 @ExamReactorStrategy(PerClass.class)
113 public class NetvirtIT extends AbstractMdsalTestBase {
114 private static final Logger LOG = LoggerFactory.getLogger(NetvirtIT.class);
115 private static final int OVSDB_UPDATE_TIMEOUT = 1000;
116 private static DataBroker dataBroker = null;
117 private static String addressStr;
118 private static String portStr;
119 private static String connectionType;
120 private static String controllerStr;
121 private static AtomicBoolean setup = new AtomicBoolean(false);
122 private static MdsalUtils mdsalUtils = null;
123 private static Southbound southbound = null;
124 private static SouthboundUtils southboundUtils;
125 private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
126 private static final String SDPLNAME = "sg1";
127 private static final String NETWORK_ID = "521e29d6-67b8-4b3c-8633-027d21195111";
128 private static final String TENANT_ID = "521e29d6-67b8-4b3c-8633-027d21195100";
129 private static final String SUBNET_ID = "521e29d6-67b8-4b3c-8633-027d21195112";
130 private static final String PORT1_ID = "521e29d6-67b8-4b3c-8633-027d21195113";
131 private static final String DHCPPORT_ID ="521e29d6-67b8-4b3c-8633-027d21195115";
134 public String getModuleName() {
135 return "netvirt-providers-impl";
139 public String getInstanceName() {
140 return "netvirt-providers-default";
144 public MavenUrlReference getFeatureRepo() {
146 .groupId("org.opendaylight.ovsdb")
147 .artifactId("features-ovsdb")
148 .classifier("features")
150 .versionAsInProject();
154 public String getFeatureName() {
155 return "odl-ovsdb-openstack";
160 public Option[] config() {
161 Option[] parentOptions = super.config();
162 Option[] propertiesOptions = getPropertiesOptions();
163 Option[] otherOptions = getOtherOptions();
164 Option[] options = new Option[parentOptions.length + propertiesOptions.length + otherOptions.length];
165 System.arraycopy(parentOptions, 0, options, 0, parentOptions.length);
166 System.arraycopy(propertiesOptions, 0, options, parentOptions.length, propertiesOptions.length);
167 System.arraycopy(otherOptions, 0, options, parentOptions.length + propertiesOptions.length,
168 otherOptions.length);
172 private Option[] getOtherOptions() {
173 return new Option[] {
175 mavenBundle("org.opendaylight.ovsdb", "utils.mdsal-openflow")
176 .version(asInProject())
179 mavenBundle("org.opendaylight.ovsdb", "utils.config")
180 .version(asInProject())
182 configureConsole().startLocalConsole(),
183 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
188 public Option[] getPropertiesOptions() {
189 return new Option[] {
190 propagateSystemProperties(NetvirtITConstants.SERVER_IPADDRESS,
191 NetvirtITConstants.SERVER_PORT, NetvirtITConstants.CONNECTION_TYPE,
192 NetvirtITConstants.CONTROLLER_IPADDRESS,
193 NetvirtITConstants.USERSPACE_ENABLED)
198 public Option getLoggingOption() {
200 //editConfigurationFilePut(NetvirtITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
201 // "log4j.logger.org.opendaylight.controller",
202 // LogLevelOption.LogLevel.TRACE.name()),
203 editConfigurationFilePut(NetvirtITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
204 "log4j.logger.org.opendaylight.ovsdb",
205 LogLevelOption.LogLevel.TRACE.name()),
206 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
207 logConfiguration(NetvirtIT.class),
208 LogLevelOption.LogLevel.INFO.name()),
209 editConfigurationFilePut(NetvirtITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
210 "log4j.logger.org.opendaylight.ovsdb.lib",
211 LogLevelOption.LogLevel.INFO.name()),
212 super.getLoggingOption());
215 protected String usage() {
216 return "Integration Test needs a valid connection configuration as follows :\n"
217 + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
218 + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
221 private void getProperties() {
222 Properties props = System.getProperties();
223 addressStr = props.getProperty(NetvirtITConstants.SERVER_IPADDRESS);
224 portStr = props.getProperty(NetvirtITConstants.SERVER_PORT, NetvirtITConstants.DEFAULT_SERVER_PORT);
225 connectionType = props.getProperty(NetvirtITConstants.CONNECTION_TYPE, "active");
226 controllerStr = props.getProperty(NetvirtITConstants.CONTROLLER_IPADDRESS, "0.0.0.0");
227 String userSpaceEnabled = props.getProperty(NetvirtITConstants.USERSPACE_ENABLED, "no");
228 LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}, controller ip: {}, " +
229 "userspace.enabled: {}",
230 connectionType, addressStr, portStr, controllerStr, userSpaceEnabled);
231 if (connectionType.equalsIgnoreCase(NetvirtITConstants.CONNECTION_TYPE_ACTIVE)) {
232 if (addressStr == null) {
240 public void setup() throws InterruptedException {
242 LOG.info("Skipping setUp, already initialized");
248 } catch (Exception e) {
254 if (connectionType.equalsIgnoreCase(NetvirtITConstants.CONNECTION_TYPE_ACTIVE)) {
255 if (addressStr == null) {
260 dataBroker = getDatabroker(getProviderContext());
261 mdsalUtils = new MdsalUtils(dataBroker);
262 assertNotNull("mdsalUtils should not be null", mdsalUtils);
263 assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
264 southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
265 assertNotNull("southbound should not be null", southbound);
266 southboundUtils = new SouthboundUtils(mdsalUtils);
270 private BindingAwareBroker.ProviderContext getProviderContext() {
271 BindingAwareBroker.ProviderContext providerContext = null;
272 for (int i=0; i < 60; i++) {
273 providerContext = getSession();
274 if (providerContext != null) {
279 } catch (InterruptedException e) {
284 assertNotNull("providercontext should not be null", providerContext);
285 /* One more second to let the provider finish initialization */
288 } catch (InterruptedException e) {
291 return providerContext;
294 private DataBroker getDatabroker(BindingAwareBroker.ProviderContext providerContext) {
295 DataBroker dataBroker = providerContext.getSALService(DataBroker.class);
296 assertNotNull("dataBroker should not be null", dataBroker);
300 private Boolean getNetvirtTopology() {
301 LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
302 Boolean found = false;
303 final TopologyId topologyId = new TopologyId(new Uri(NETVIRT_TOPOLOGY_ID));
304 InstanceIdentifier<Topology> path =
305 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
306 for (int i = 0; i < 60; i++) {
307 Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
308 if (topology != null) {
309 LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
313 LOG.info("getNetvirtTopology: still looking ({})...", i);
316 } catch (InterruptedException e) {
325 * Test passive connection mode. The southbound starts in a listening mode waiting for connections on port
326 * 6640. This test will wait for incoming connections for {@link NetvirtITConstants#CONNECTION_INIT_TIMEOUT} ms.
328 * @throws InterruptedException
332 public void testPassiveNode() throws InterruptedException {
333 if (connectionType.equalsIgnoreCase(NetvirtITConstants.CONNECTION_TYPE_PASSIVE)) {
334 //Wait for CONNECTION_INIT_TIMEOUT for the Passive connection to be initiated by the ovsdb-server.
335 Thread.sleep(NetvirtITConstants.CONNECTION_INIT_TIMEOUT);
339 private ConnectionInfo getConnectionInfo(final String addressStr, final String portStr) {
340 InetAddress inetAddress = null;
342 inetAddress = InetAddress.getByName(addressStr);
343 } catch (UnknownHostException e) {
344 fail("Could not allocate InetAddress: " + e);
347 IpAddress address = SouthboundMapper.createIpAddress(inetAddress);
348 PortNumber port = new PortNumber(Integer.parseInt(portStr));
350 LOG.info("connectionInfo: {}", new ConnectionInfoBuilder()
351 .setRemoteIp(address)
354 return new ConnectionInfoBuilder()
355 .setRemoteIp(address)
360 private String connectionInfoToString(final ConnectionInfo connectionInfo) {
361 return String.valueOf(connectionInfo.getRemoteIp().getValue()) + ":" + connectionInfo.getRemotePort().getValue();
364 private boolean addOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
365 boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION,
366 SouthboundUtils.createInstanceIdentifier(connectionInfo),
367 SouthboundUtils.createNode(connectionInfo));
368 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
372 private Node getOvsdbNode(final ConnectionInfo connectionInfo) {
373 return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
374 SouthboundUtils.createInstanceIdentifier(connectionInfo));
377 private boolean deleteOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
378 boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
379 SouthboundUtils.createInstanceIdentifier(connectionInfo));
380 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
384 private Node connectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
385 Assert.assertTrue(addOvsdbNode(connectionInfo));
386 Node node = getOvsdbNode(connectionInfo);
387 Assert.assertNotNull("Should find OVSDB node after connect", node);
388 LOG.info("Connected to {}", connectionInfoToString(connectionInfo));
392 private boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
393 Assert.assertTrue(deleteOvsdbNode(connectionInfo));
394 Node node = getOvsdbNode(connectionInfo);
395 Assert.assertNull("Should not find OVSDB node after disconnect", node);
396 //Assume.assumeNotNull(node); // Using assumeNotNull because there is no assumeNull
397 LOG.info("Disconnected from {}", connectionInfoToString(connectionInfo));
401 private String getControllerIPAddress() {
402 String addressString = ConfigProperties.getProperty(this.getClass(), "ovsdb.controller.address");
403 if (addressString != null) {
405 if (InetAddress.getByName(addressString) != null) {
406 return addressString;
408 } catch (UnknownHostException e) {
409 LOG.error("Host {} is invalid", addressString);
413 addressString = ConfigProperties.getProperty(this.getClass(), "of.address");
414 if (addressString != null) {
416 if (InetAddress.getByName(addressString) != null) {
417 return addressString;
419 } catch (UnknownHostException e) {
420 LOG.error("Host {} is invalid", addressString);
427 private short getControllerOFPort() {
428 short openFlowPort = Constants.OPENFLOW_PORT;
429 String portString = ConfigProperties.getProperty(this.getClass(), "of.listenPort");
430 if (portString != null) {
432 openFlowPort = Short.parseShort(portString);
433 } catch (NumberFormatException e) {
434 LOG.warn("Invalid port:{}, use default({})", portString,
441 private List<String> getControllersFromOvsdbNode(Node node) {
442 List<String> controllersStr = new ArrayList<>();
444 String controllerIpStr = getControllerIPAddress();
445 if (controllerIpStr != null) {
446 // If codepath makes it here, the ip address to be used was explicitly provided.
447 // Being so, also fetch openflowPort provided via ConfigProperties.
448 controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
449 + ":" + controllerIpStr + ":" + getControllerOFPort());
451 // Check if ovsdb node has manager entries
452 OvsdbNodeAugmentation ovsdbNodeAugmentation = southbound.extractOvsdbNode(node);
453 if (ovsdbNodeAugmentation != null) {
454 List<ManagerEntry> managerEntries = ovsdbNodeAugmentation.getManagerEntry();
455 if (managerEntries != null && !managerEntries.isEmpty()) {
456 for (ManagerEntry managerEntry : managerEntries) {
457 if (managerEntry == null || managerEntry.getTarget() == null) {
460 String[] tokens = managerEntry.getTarget().getValue().split(":");
461 if (tokens.length == 3 && tokens[0].equalsIgnoreCase("tcp")) {
462 controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
463 + ":" + tokens[1] + ":" + getControllerOFPort());
464 } else if (tokens[0].equalsIgnoreCase("ptcp")) {
465 ConnectionInfo connectionInfo = ovsdbNodeAugmentation.getConnectionInfo();
466 if (connectionInfo != null && connectionInfo.getLocalIp() != null) {
467 controllerIpStr = String.valueOf(connectionInfo.getLocalIp().getValue());
468 controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
469 + ":" + controllerIpStr + ":" + Constants.OPENFLOW_PORT);
471 LOG.warn("Ovsdb Node does not contain connection info: {}", node);
474 LOG.trace("Skipping manager entry {} for node {}",
475 managerEntry.getTarget(), node.getNodeId().getValue());
479 LOG.warn("Ovsdb Node does not contain manager entries : {}", node);
484 if (controllersStr.isEmpty()) {
485 // Neither user provided ip nor ovsdb node has manager entries. Lets use local machine ip address.
486 LOG.debug("Use local machine ip address as a OpenFlow Controller ip address");
487 controllerIpStr = getLocalControllerHostIpAddress();
488 if (controllerIpStr != null) {
489 controllersStr.add(Constants.OPENFLOW_CONNECTION_PROTOCOL
490 + ":" + controllerIpStr + ":" + Constants.OPENFLOW_PORT);
494 if (controllersStr.isEmpty()) {
495 LOG.warn("Failed to determine OpenFlow controller ip address");
496 } else if (LOG.isDebugEnabled()) {
497 controllerIpStr = "";
498 for (String currControllerIpStr : controllersStr) {
499 controllerIpStr += " " + currControllerIpStr;
501 LOG.debug("Found {} OpenFlow Controller(s) :{}", controllersStr.size(), controllerIpStr);
504 return controllersStr;
507 private String getLocalControllerHostIpAddress() {
508 String ipaddress = null;
510 for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();ifaces.hasMoreElements();){
511 NetworkInterface iface = ifaces.nextElement();
513 for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
514 InetAddress inetAddr = inetAddrs.nextElement();
515 if (!inetAddr.isLoopbackAddress() && inetAddr.isSiteLocalAddress()) {
516 ipaddress = inetAddr.getHostAddress();
521 }catch (Exception e){
522 LOG.warn("Exception while fetching local host ip address ", e);
527 private String getControllerTarget(Node ovsdbNode) {
528 return getControllersFromOvsdbNode(ovsdbNode).get(0);
532 public void testAddDeleteOvsdbNode() throws InterruptedException {
533 LOG.info("testAddDeleteOvsdbNode enter 3");
534 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
535 connectOvsdbNode(connectionInfo);
536 ControllerEntry controllerEntry;
537 for (int i = 0; i < 10; i++) {
538 LOG.info("testAddDeleteOvsdbNode ({}): looking for controller", i);
539 Node ovsdbNode = getOvsdbNode(connectionInfo);
540 Assert.assertNotNull("ovsdb node not found", ovsdbNode);
541 String controllerTarget = getControllerTarget(ovsdbNode);
542 Assert.assertNotNull("Failed to get controller target", controllerTarget);
543 OvsdbBridgeAugmentation bridge = getBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
544 Assert.assertNotNull(bridge);
545 Assert.assertNotNull(bridge.getControllerEntry());
546 controllerEntry = bridge.getControllerEntry().iterator().next();
547 Assert.assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
548 if (controllerEntry.isIsConnected()) {
549 Assert.assertTrue(controllerEntry.isIsConnected());
555 Assert.assertTrue(deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
557 Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
562 public void testOpenVSwitchOtherConfig() throws InterruptedException {
563 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
564 Node ovsdbNode = connectOvsdbNode(connectionInfo);
565 OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
566 Assert.assertNotNull(ovsdbNodeAugmentation);
567 List<OpenvswitchOtherConfigs> otherConfigsList = ovsdbNodeAugmentation.getOpenvswitchOtherConfigs();
568 if (otherConfigsList != null) {
569 for (OpenvswitchOtherConfigs otherConfig : otherConfigsList) {
570 if (otherConfig.getOtherConfigKey().equals("local_ip")) {
571 LOG.info("local_ip: {}", otherConfig.getOtherConfigValue());
574 LOG.info("other_config {}:{}", otherConfig.getOtherConfigKey(), otherConfig.getOtherConfigValue());
578 LOG.info("other_config is not present");
580 Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
581 //Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
584 private OvsdbTerminationPointAugmentationBuilder createGenericOvsdbTerminationPointAugmentationBuilder() {
585 OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointAugmentationBuilder =
586 new OvsdbTerminationPointAugmentationBuilder();
587 ovsdbTerminationPointAugmentationBuilder.setInterfaceType(
588 new InterfaceTypeEntryBuilder()
590 SouthboundMapper.createInterfaceType("internal"))
591 .build().getInterfaceType());
592 return ovsdbTerminationPointAugmentationBuilder;
595 private boolean addTerminationPoint(final NodeId bridgeNodeId, final String portName,
596 final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointAugmentationBuilder)
597 throws InterruptedException {
599 InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(bridgeNodeId);
600 NodeBuilder portNodeBuilder = new NodeBuilder();
601 NodeId portNodeId = SouthboundMapper.createManagedNodeId(portIid);
602 portNodeBuilder.setNodeId(portNodeId);
603 TerminationPointBuilder entry = new TerminationPointBuilder();
604 entry.setKey(new TerminationPointKey(new TpId(portName)));
605 entry.addAugmentation(
606 OvsdbTerminationPointAugmentation.class,
607 ovsdbTerminationPointAugmentationBuilder.build());
608 portNodeBuilder.setTerminationPoint(Lists.newArrayList(entry.build()));
609 boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
610 portIid, portNodeBuilder.build());
611 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
616 * Extract the <code>store</code> type data store contents for the particular bridge identified by
617 * <code>bridgeName</code>.
619 * @param connectionInfo The connection information.
620 * @param bridgeName The bridge name.
621 * @param store defined by the <code>LogicalDatastoreType</code> enumeration
622 * @return <code>store</code> type data store contents
624 private OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo, String bridgeName,
625 LogicalDatastoreType store) {
626 Node bridgeNode = getBridgeNode(connectionInfo, bridgeName, store);
627 Assert.assertNotNull(bridgeNode);
628 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
629 Assert.assertNotNull(ovsdbBridgeAugmentation);
630 return ovsdbBridgeAugmentation;
634 * extract the <code>LogicalDataStoreType.OPERATIONAL</code> type data store contents for the particular bridge
635 * identified by <code>bridgeName</code>
637 * @param connectionInfo The connection information.
638 * @param bridgeName The bridge name.
639 * @see <code>NetvirtIT.getBridge(ConnectionInfo, String, LogicalDatastoreType)</code>
640 * @return <code>LogicalDatastoreType.OPERATIONAL</code> type data store contents
642 private OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo, String bridgeName) {
643 return getBridge(connectionInfo, bridgeName, LogicalDatastoreType.OPERATIONAL);
647 * Extract the node contents from <code>store</code> type data store for the
648 * bridge identified by <code>bridgeName</code>
650 * @param connectionInfo The connection information.
651 * @param bridgeName The bridge name.
652 * @param store defined by the <code>LogicalDatastoreType</code> enumeration
653 * @return <code>store</code> type data store contents
655 private Node getBridgeNode(ConnectionInfo connectionInfo, String bridgeName, LogicalDatastoreType store) {
656 InstanceIdentifier<Node> bridgeIid =
657 SouthboundUtils.createInstanceIdentifier(connectionInfo,
658 new OvsdbBridgeName(bridgeName));
659 return mdsalUtils.read(store, bridgeIid);
662 private boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName)
663 throws InterruptedException {
665 boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
666 SouthboundUtils.createInstanceIdentifier(connectionInfo,
667 new OvsdbBridgeName(bridgeName)));
668 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
672 private InstanceIdentifier<Node> getTpIid(ConnectionInfo connectionInfo, OvsdbBridgeAugmentation bridge) {
673 return SouthboundUtils.createInstanceIdentifier(connectionInfo,
674 bridge.getBridgeName());
677 private void netVirtAddPort(ConnectionInfo connectionInfo) throws InterruptedException {
678 OvsdbBridgeAugmentation bridge = getBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
679 Assert.assertNotNull(bridge);
680 NodeId nodeId = SouthboundMapper.createManagedNodeId(SouthboundUtils.createInstanceIdentifier(
681 connectionInfo, bridge.getBridgeName()));
682 OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
683 createGenericOvsdbTerminationPointAugmentationBuilder();
684 String portName = NetvirtITConstants.PORT_NAME;
685 ovsdbTerminationBuilder.setName(portName);
686 Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
687 InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
688 Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
689 Assert.assertNotNull(terminationPointNode);
693 * Test for basic southbound events to netvirt.
694 * <pre>The test will:
695 * - connect to an OVSDB node and verify it is added to operational
696 * - then verify that br-int was created on the node and stored in operational
697 * - a port is then added to the bridge to verify that it is ignored by netvirt
698 * - remove the bridge
699 * - remove the node and verify it is not in operational
701 * @throws InterruptedException
704 public void testNetVirt() throws InterruptedException {
705 LOG.info("testNetVirt: starting test 2");
706 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
707 Node ovsdbNode = connectOvsdbNode(connectionInfo);
708 LOG.info("testNetVirt: should be connected");
711 LOG.info("testNetVirt: should really be connected after sleep");
712 // Verify the pipeline flows were installed
713 PipelineOrchestrator pipelineOrchestrator =
714 (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
715 assertNotNull("Could not find PipelineOrchestrator Service", pipelineOrchestrator);
716 Node bridgeNode = southbound.getBridgeNode(ovsdbNode, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
717 assertNotNull("bridge " + NetvirtITConstants.INTEGRATION_BRIDGE_NAME + " was not found", bridgeNode);
718 LOG.info("testNetVirt: bridgeNode: {}", bridgeNode);
719 long datapathId = southbound.getDataPathId(bridgeNode);
720 assertNotEquals("datapathId was not found", datapathId, 0);
722 //TODO add check for controller connection
723 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
724 FlowUtils.createNodeBuilder(datapathId);
726 List<Service> staticPipeline = pipelineOrchestrator.getStaticPipeline();
727 List<Service> staticPipelineFound = Lists.newArrayList();
728 for (Service service : pipelineOrchestrator.getServiceRegistry().keySet()) {
729 if (staticPipeline.contains(service)) {
730 staticPipelineFound.add(service);
732 FlowBuilder flowBuilder = FlowUtils.getPipelineFlow(service.getTable(), (short)0);
733 Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
734 assertNotNull("Could not find flow in config", flow);
736 flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
737 assertNotNull("Could not find flow in operational", flow);
739 assertEquals("did not find all expected flows in static pipeline",
740 staticPipeline.size(), staticPipelineFound.size());
742 netVirtAddPort(connectionInfo);
744 Assert.assertTrue(deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
746 Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
751 public void testNetVirt2() throws InterruptedException {
757 public void testReadOvsdbTopologyNodes() throws InterruptedException {
759 List<Node> ovsdbNodes = southbound.readOvsdbTopologyNodes();
760 for (Node node : ovsdbNodes) {
761 LOG.info(">>>>> node: {}", node);
766 public void testNetVirtFixedSG() throws InterruptedException {
767 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
768 assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
769 Node ovsdbNode = connectOvsdbNode(connectionInfo);
770 assertNotNull("node is not connected", ovsdbNode);
773 Node bridgeNode = southbound.getBridgeNode(ovsdbNode, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
774 assertNotNull("bridge " + NetvirtITConstants.INTEGRATION_BRIDGE_NAME + " was not found", bridgeNode);
775 long datapathId = southbound.getDataPathId(bridgeNode);
776 assertNotEquals("datapathId was not found", datapathId, 0);
778 NeutronNetwork nn = createNeutronNetwork(NETWORK_ID, TENANT_ID,NetworkHandler.NETWORK_TYPE_VXLAN, "100");
779 NeutronSubnet ns = createNeutronSubnet(SUBNET_ID, TENANT_ID, NETWORK_ID, "10.0.0.0/24");
780 NeutronPort nport = createNeutronPort(NETWORK_ID, SUBNET_ID, PORT1_ID, "compute", "10.0.0.10", "f6:00:00:0f:00:01");
781 NeutronPort dhcp = createNeutronPort(NETWORK_ID, SUBNET_ID, DHCPPORT_ID, "dhcp", "10.0.0.1", "f6:00:00:0f:00:02");
784 Map<String, String> externalIds = Maps.newHashMap();
785 externalIds.put("attached-mac", "f6:00:00:0f:00:01");
786 externalIds.put("iface-id", PORT1_ID);
787 southboundUtils.addTerminationPoint(bridgeNode, SDPLNAME, "internal", null, externalIds, 3L);
788 southboundUtils.addTerminationPoint(bridgeNode, "vm1", "internal", null, null, 0L);
789 southboundUtils.addTerminationPoint(bridgeNode, "vm2", "internal", null, null, 0L);
790 Map<String, String> options = Maps.newHashMap();
791 options.put("key", "flow");
792 options.put("remote_ip", "192.168.120.32");
793 southboundUtils.addTerminationPoint(bridgeNode, "vx", "vxlan", options, null, 4L);
796 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
797 FlowUtils.createNodeBuilder(datapathId);
798 MatchBuilder matchBuilder1 = new MatchBuilder();
799 matchBuilder1 = MatchUtils.createDhcpMatch(matchBuilder1, 68, 67);
800 String flowId1 = "Egress_DHCP_Client" + "_Permit_";
801 FlowBuilder flowBuilder1 = initFlowBuilder(matchBuilder1, flowId1, (short)40);
802 Flow flow1 = getFlow(flowBuilder1, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
803 assertNotNull("EgressSG : Could not find flow in configuration ", flow1);
804 flow1 = getFlow(flowBuilder1, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
805 assertNotNull("EgressSG Operational : Could not find flow in config", flow1);
807 testDefaultsSG(nport, datapathId, nn);
809 Assert.assertTrue(deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
811 Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
814 private void testDefaultsSG(NeutronPort nport, long datapathId, NeutronNetwork nn)
815 throws InterruptedException {
816 INeutronSecurityGroupCRUD ineutronSecurityGroupCRUD =
817 (INeutronSecurityGroupCRUD) ServiceHelper.getGlobalInstance(INeutronSecurityGroupCRUD.class, this);
818 assertNotNull("Could not find ineutronSecurityGroupCRUD Service", ineutronSecurityGroupCRUD);
819 INeutronSecurityRuleCRUD ineutronSecurityRuleCRUD =
820 (INeutronSecurityRuleCRUD) ServiceHelper.getGlobalInstance(INeutronSecurityRuleCRUD.class, this);
821 assertNotNull("Could not find ineutronSecurityRuleCRUD Service", ineutronSecurityRuleCRUD);
823 NeutronSecurityGroup neutronSG = new NeutronSecurityGroup();
824 neutronSG.setSecurityGroupDescription("testig defaultSG-IT");
825 neutronSG.setSecurityGroupName("DefaultSG");
826 neutronSG.setSecurityGroupUUID("d3329053-bae5-4bf4-a2d1-7330f11ba5db");
827 neutronSG.setTenantID(TENANT_ID);
829 List<NeutronSecurityRule> nsrs = new ArrayList<>();
830 NeutronSecurityRule nsrIN = new NeutronSecurityRule();
831 nsrIN.setSecurityRemoteGroupID(null);
832 nsrIN.setSecurityRuleDirection("ingress");
833 nsrIN.setSecurityRuleEthertype("IPv4");
834 nsrIN.setSecurityRuleGroupID("d3329053-bae5-4bf4-a2d1-7330f11ba5db");
835 nsrIN.setSecurityRuleProtocol("TCP");
836 nsrIN.setSecurityRuleRemoteIpPrefix("10.0.0.0/24");
837 nsrIN.setSecurityRuleUUID("823faaf7-175d-4f01-a271-0bf56fb1e7e6");
838 nsrIN.setTenantID(TENANT_ID);
840 NeutronSecurityRule nsrEG = new NeutronSecurityRule();
841 nsrEG.setSecurityRemoteGroupID(null);
842 nsrEG.setSecurityRuleDirection("egress");
843 nsrEG.setSecurityRuleEthertype("IPv4");
844 nsrEG.setSecurityRuleGroupID("d3329053-bae5-4bf4-a2d1-7330f11ba5db");
845 nsrEG.setSecurityRuleProtocol("TCP");
846 nsrEG.setSecurityRuleRemoteIpPrefix("10.0.0.0/24");
847 nsrEG.setSecurityRuleUUID("823faaf7-175d-4f01-a271-0bf56fb1e7e1");
848 nsrEG.setTenantID(TENANT_ID);
853 neutronSG.setSecurityRules(nsrs);
854 ineutronSecurityRuleCRUD.addNeutronSecurityRule(nsrIN);
855 ineutronSecurityRuleCRUD.addNeutronSecurityRule(nsrEG);
856 ineutronSecurityGroupCRUD.add(neutronSG);
858 List<NeutronSecurityGroup> sgs = new ArrayList<>();
860 nport.setSecurityGroups(sgs);
862 INeutronPortCRUD iNeutronPortCRUD =
863 (INeutronPortCRUD) ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
864 iNeutronPortCRUD.update(PORT1_ID, nport);
867 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilderEg =
868 FlowUtils.createNodeBuilder(datapathId);
869 MatchBuilder matchBuilderEg = new MatchBuilder();
870 matchBuilderEg = MatchUtils.createEtherMatchWithType(matchBuilderEg, null, nport.getMacAddress());
871 String flowIdEg = "Egress_IP" + nn.getProviderSegmentationID() + "_" + nport.getMacAddress() + "_Permit_";
872 FlowBuilder flowBuilderEg = initFlowBuilder(matchBuilderEg, flowIdEg, (short)40);
873 Flow flowEg = getFlow(flowBuilderEg, nodeBuilderEg, LogicalDatastoreType.CONFIGURATION);
874 assertNotNull("EgressSG : Could not find flow in configuration ", flowEg);
875 flowEg = getFlow(flowBuilderEg, nodeBuilderEg, LogicalDatastoreType.OPERATIONAL);
876 assertNotNull("EgressSG Operational : Could not find flow in config", flowEg);
878 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilderIng =
879 FlowUtils.createNodeBuilder(datapathId);
880 MatchBuilder matchBuilderIng = new MatchBuilder();
881 matchBuilderIng = MatchUtils.createEtherMatchWithType(matchBuilderIng,null, nport.getMacAddress());
882 String flowIdIng = "Ingress_IP" + nn.getProviderSegmentationID() + "_" + nport.getMacAddress() + "_Permit_";
883 FlowBuilder flowBuilderIng = initFlowBuilder(matchBuilderIng, flowIdIng, (short)90);
884 Flow flowIng = getFlow(flowBuilderIng, nodeBuilderIng, LogicalDatastoreType.CONFIGURATION);
885 assertNotNull("IngressSG : Could not find flow in configuration ", flowIng);
886 flowIng = getFlow(flowBuilderIng, nodeBuilderIng, LogicalDatastoreType.OPERATIONAL);
887 assertNotNull("IngressSG Operational : Could not find flow in config", flowIng);
891 private NeutronPort createNeutronPort(String networkId, String subnetId,
892 String id, String owner, String ipaddr, String mac) {
893 INeutronPortCRUD iNeutronPortCRUD =
894 (INeutronPortCRUD) ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
895 NeutronPort np = new NeutronPort();
898 np.setDeviceOwner(owner);
899 np.setMacAddress(mac);
900 np.setNetworkUUID(networkId);
901 List<org.opendaylight.neutron.spi.Neutron_IPs> srcAddressList =
903 org.opendaylight.neutron.spi.Neutron_IPs nip = new org.opendaylight.neutron.spi.Neutron_IPs();
904 nip.setIpAddress(ipaddr);
905 nip.setSubnetUUID(subnetId);
906 srcAddressList.add(nip);
907 np.setFixedIPs(srcAddressList);
908 List<NeutronSecurityGroup> nsgs = new ArrayList<>();
909 np.setSecurityGroups(nsgs);
910 iNeutronPortCRUD.add(np);
914 private NeutronSubnet createNeutronSubnet(String subnetId, String tenantId,
915 String networkId, String cidr) {
916 INeutronSubnetCRUD iNeutronSubnetCRUD =
917 (INeutronSubnetCRUD) ServiceHelper.getGlobalInstance(INeutronSubnetCRUD.class, this);
918 NeutronSubnet ns = new NeutronSubnet();
922 ns.setNetworkUUID(networkId);
923 ns.setTenantID(tenantId);
924 iNeutronSubnetCRUD.add(ns);
928 private NeutronNetwork createNeutronNetwork(String uuid, String tenantID, String networkTypeVxlan, String segId) {
929 INeutronNetworkCRUD iNeutronNetworkCRUD =
930 (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
931 NeutronNetwork nn = new NeutronNetwork();
934 nn.setTenantID(tenantID);
935 nn.setProviderNetworkType(networkTypeVxlan);
936 nn.setProviderSegmentationID(segId);
937 iNeutronNetworkCRUD.addNetwork(nn);
941 private FlowBuilder initFlowBuilder(MatchBuilder matchBuilder, String flowId, short tableId) {
942 FlowBuilder flowBuilder = new FlowBuilder();
943 flowBuilder.setMatch(matchBuilder.build());
944 flowBuilder.setId(new FlowId(flowId));
945 flowBuilder.setFlowName(flowId);
946 FlowKey key = new FlowKey(new FlowId(flowId));
947 flowBuilder.setStrict(true);
948 flowBuilder.setTableId(tableId);
949 flowBuilder.setKey(key);
953 private Flow getFlow (
954 FlowBuilder flowBuilder,
955 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder,
956 LogicalDatastoreType store)
957 throws InterruptedException {
960 for (int i = 0; i < 10; i++) {
961 LOG.info("getFlow {}-{}: looking for flowBuilder: {}, nodeBuilder: {}",
962 i, store, flowBuilder.build(), nodeBuilder.build());
963 flow = FlowUtils.getFlow(flowBuilder, nodeBuilder, dataBroker.newReadOnlyTransaction(), store);
965 LOG.info("getFlow: found flow({}): {}", store, flow);