2 * Copyright © 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
9 package org.opendaylight.ovsdb.openstack.netvirt.sfc;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.ops4j.pax.exam.CoreOptions.composite;
17 import static org.ops4j.pax.exam.CoreOptions.maven;
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.karaf.options.KarafDistributionOption.editConfigurationFilePut;
21 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
23 import java.util.List;
24 import java.util.Properties;
25 import java.util.concurrent.atomic.AtomicBoolean;
26 import org.junit.Assert;
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
33 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
34 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.AclUtils;
35 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ClassifierUtils;
36 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcUtils;
37 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
38 import org.opendaylight.ovsdb.southbound.SouthboundUtil;
39 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
40 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.ClassifiersBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.ClassifierBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.SffsBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.SffBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.Sfc;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.SfcBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
64 import org.opendaylight.yangtools.concepts.Builder;
65 import org.opendaylight.yangtools.yang.binding.DataObject;
66 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 import org.ops4j.pax.exam.Configuration;
69 import org.ops4j.pax.exam.Option;
70 import org.ops4j.pax.exam.junit.PaxExam;
71 import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
72 import org.ops4j.pax.exam.options.MavenUrlReference;
73 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
74 import org.ops4j.pax.exam.spi.reactors.PerClass;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
78 @RunWith(PaxExam.class)
79 @ExamReactorStrategy(PerClass.class)
80 public class NetvirtSfcIT extends AbstractMdsalTestBase {
81 private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcIT.class);
82 private static AclUtils aclUtils = new AclUtils();
83 private static ClassifierUtils classifierUtils = new ClassifierUtils();
84 private static SfcUtils sfcUtils = new SfcUtils();
85 private static MdsalUtils mdsalUtils;
86 private static AtomicBoolean setup = new AtomicBoolean(false);
87 private static SouthboundUtils southboundUtils;
88 private static String addressStr;
89 private static String portStr;
90 private static String connectionType;
91 public static final String SERVER_IPADDRESS = "ovsdbserver.ipaddress";
92 public static final String SERVER_PORT = "ovsdbserver.port";
93 public static final String CONNECTION_TYPE = "ovsdbserver.connection";
94 public static final String CONNECTION_TYPE_ACTIVE = "active";
95 public static final String CONNECTION_TYPE_PASSIVE = "passive";
96 public static final String DEFAULT_SERVER_PORT = "6640";
97 public static final String INTEGRATION_BRIDGE_NAME = "br-int";
98 private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
101 public String getModuleName() {
102 return "netvirt-sfc";
106 public String getInstanceName() {
107 return "netvirt-sfc-default";
111 public MavenUrlReference getFeatureRepo() {
113 .groupId("org.opendaylight.ovsdb")
114 .artifactId("openstack.net-virt-sfc-features-test")
115 .classifier("features")
117 .versionAsInProject();
121 public String getFeatureName() {
122 return "odl-ovsdb-sfc-test";
127 public Option[] config() {
128 Option[] parentOptions = super.config();
129 Option[] propertiesOptions = getPropertiesOptions();
130 Option[] otherOptions = getOtherOptions();
131 Option[] options = new Option[parentOptions.length + propertiesOptions.length + otherOptions.length];
132 System.arraycopy(parentOptions, 0, options, 0, parentOptions.length);
133 System.arraycopy(propertiesOptions, 0, options, parentOptions.length, propertiesOptions.length);
134 System.arraycopy(otherOptions, 0, options, parentOptions.length + propertiesOptions.length,
135 otherOptions.length);
139 private Option[] getOtherOptions() {
140 return new Option[] {
141 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
146 public Option[] getPropertiesOptions() {
147 return new Option[] {
148 propagateSystemProperties(SERVER_IPADDRESS, SERVER_PORT, CONNECTION_TYPE),
153 public Option getLoggingOption() {
155 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
156 logConfiguration(NetvirtSfcIT.class),
157 LogLevel.INFO.name()),
158 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
159 "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc",
160 LogLevel.TRACE.name()),
161 /*editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
162 "log4j.logger.org.opendaylight.ovsdb",
163 LogLevelOption.LogLevel.TRACE.name()),*/
164 super.getLoggingOption());
167 protected String usage() {
168 return "Integration Test needs a valid connection configuration as follows :\n"
169 + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
170 + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
173 private void getProperties() {
174 Properties props = System.getProperties();
175 addressStr = props.getProperty(SERVER_IPADDRESS);
176 portStr = props.getProperty(SERVER_PORT, DEFAULT_SERVER_PORT);
177 connectionType = props.getProperty(CONNECTION_TYPE, "active");
178 LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}",
179 connectionType, addressStr, portStr);
180 if (connectionType.equalsIgnoreCase(CONNECTION_TYPE_ACTIVE)) {
181 if (addressStr == null) {
189 public void setup() {
191 LOG.info("Skipping setUp, already initialized");
198 } catch (Exception e) {
204 DataBroker dataBroker = getDatabroker(getProviderContext());
205 mdsalUtils = new MdsalUtils(dataBroker);
206 assertNotNull("mdsalUtils should not be null", mdsalUtils);
207 southboundUtils = new SouthboundUtils(mdsalUtils);
208 assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
212 private ProviderContext getProviderContext() {
213 ProviderContext providerContext = null;
214 for (int i=0; i < 60; i++) {
215 providerContext = getSession();
216 if (providerContext != null) {
221 } catch (InterruptedException e) {
226 assertNotNull("providercontext should not be null", providerContext);
227 /* One more second to let the provider finish initialization */
230 } catch (InterruptedException e) {
233 return providerContext;
236 private DataBroker getDatabroker(ProviderContext providerContext) {
237 DataBroker dataBroker = providerContext.getSALService(DataBroker.class);
238 assertNotNull("dataBroker should not be null", dataBroker);
242 private Boolean getNetvirtTopology() {
243 LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
244 Boolean found = false;
245 final TopologyId topologyId = new TopologyId(new Uri(NETVIRT_TOPOLOGY_ID));
246 InstanceIdentifier<Topology> path =
247 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
248 for (int i = 0; i < 60; i++) {
249 Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
250 if (topology != null) {
251 LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
255 LOG.info("getNetvirtTopology: still looking ({})...", i);
258 } catch (InterruptedException e) {
267 public void testNetvirtSfcFeatureLoad() {
271 private AccessListsBuilder setAccessLists () {
272 MatchesBuilder matchesBuilder = aclUtils.createMatches(new MatchesBuilder(), 80);
273 ActionsBuilder actionsBuilder = aclUtils.createActions(new ActionsBuilder(), Boolean.TRUE);
274 AceBuilder accessListEntryBuilder = aclUtils.createAccessListEntryBuilder(
275 new AceBuilder(), "http", matchesBuilder, actionsBuilder);
276 AccessListEntriesBuilder accessListEntriesBuilder = aclUtils.createAccessListEntries(
277 new AccessListEntriesBuilder(), accessListEntryBuilder);
278 AclBuilder accessListBuilder = aclUtils.createAccessList(new AclBuilder(),
279 "http", accessListEntriesBuilder);
280 AccessListsBuilder accessListsBuilder = aclUtils.createAccessLists(new AccessListsBuilder(),
282 LOG.info("AccessLists: {}", accessListsBuilder.build());
283 return accessListsBuilder;
287 public void testAccessLists() {
288 testModel(setAccessLists(), AccessLists.class);
291 private ClassifiersBuilder setClassifiers() {
292 SffBuilder sffBuilder = classifierUtils.createSff(new SffBuilder(), "sffname");
293 SffsBuilder sffsBuilder = classifierUtils.createSffs(new SffsBuilder(), sffBuilder);
294 ClassifierBuilder classifierBuilder = classifierUtils.createClassifier(new ClassifierBuilder(),
295 "classifierName", "aclName", sffsBuilder);
296 ClassifiersBuilder classifiersBuilder = classifierUtils.createClassifiers(new ClassifiersBuilder(),
298 LOG.info("Classifiers: {}", classifiersBuilder.build());
299 return classifiersBuilder;
303 public void testClassifiers() {
304 testModel(setClassifiers(), Classifiers.class);
307 private SfcBuilder setSfc() {
308 return sfcUtils.createSfc(new SfcBuilder(), "sfc");
312 public void testSfc() {
313 testModel(setSfc(), Sfc.class);
316 private <T extends DataObject> void testModel(Builder<T> builder, Class<T> clazz) {
317 InstanceIdentifier<T> path = InstanceIdentifier.create(clazz);
318 assertTrue(mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, path, builder.build()));
319 T result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
320 assertNotNull(clazz.getSimpleName() + " should not be null", result);
321 assertTrue("Failed to remove " + clazz.getSimpleName(),
322 mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, path));
323 result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
324 assertNull(clazz.getSimpleName() + " should be null", result);
328 * Connect to an ovsdb node. Netvirt should add br-int, add the controller address
329 * and program the pipeline flows.
332 public void testDoIt() throws InterruptedException {
333 ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(addressStr, portStr);
334 assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
335 assertNotNull("node is not connected", southboundUtils.getOvsdbNode(connectionInfo));
336 ControllerEntry controllerEntry;
337 // Loop 10s checking if the controller was added
338 for (int i = 0; i < 10; i++) {
339 Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
340 assertNotNull("ovsdb node not found", ovsdbNode);
341 String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
342 assertNotNull("Failed to get controller target", controllerTarget);
343 OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, INTEGRATION_BRIDGE_NAME);
344 assertNotNull(bridge);
345 assertNotNull(bridge.getControllerEntry());
346 controllerEntry = bridge.getControllerEntry().iterator().next();
347 assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
348 if (controllerEntry.isIsConnected()) {
349 Assert.assertTrue(controllerEntry.isIsConnected());
355 /* TODO: add code to write to mdsal to exercise the sfc dataChangeListener */
356 /* allow some time to let the impl code do it's work to push flows */
357 /* or just comment out below lines and just manually verify on the bridges and reset them */
358 //Thread.sleep(10000);
360 assertTrue(southboundUtils.deleteBridge(connectionInfo, INTEGRATION_BRIDGE_NAME));
362 assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
366 public void testDemo() throws InterruptedException {
367 for (DemoVm vm : demoVms){
368 ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(vm.ipAddr, vm.ipPort);
369 assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
370 Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
371 assertNotNull("node is not connected", ovsdbNode);
372 String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
373 assertNotNull("Failed to get controller target", controllerTarget);
374 List<ControllerEntry> setControllerEntry = southboundUtils.createControllerEntry(controllerTarget);
375 Uri setUri = new Uri(controllerTarget);
376 assertTrue(southboundUtils.addBridge(connectionInfo, null, vm.name, null, true,
377 SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
378 setControllerEntry, null));
380 for (int i = 0; i < 10; i++) {
381 OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, vm.name);
382 assertNotNull("bridge was not found: " + vm.name, bridge);
383 assertNotNull("ControllerEntry was not found: "
384 + southboundUtils.createControllerEntry(controllerTarget),
385 bridge.getControllerEntry());
386 List<ControllerEntry> getControllerEntries = bridge.getControllerEntry();
387 for (ControllerEntry entry : getControllerEntries) {
388 if (entry.isIsConnected()) {
389 assertTrue(entry.isIsConnected());
396 assertTrue(southboundUtils.deleteBridge(connectionInfo, vm.name));
398 assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
402 private class DemoVm {
407 DemoVm(String name, String ipAddr, String ipPort) {
409 this.ipAddr = ipAddr;
410 this.ipPort = ipPort;
414 private DemoVm[] demoVms = {
415 new DemoVm("sw1", "192.168.50.70", "6640"),
416 //new DemoVm("sw2", "192.168.50.71", "6640"),