Cleanup exception logging
[ovsdb.git] / openstack / net-virt-sfc / it / src / test / java / org / opendaylight / ovsdb / openstack / netvirt / sfc / it / NetvirtSfcIT.java
1 /*
2  * Copyright © 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
9 package org.opendaylight.ovsdb.openstack.netvirt.sfc.it;
10
11 import static org.junit.Assert.assertNotEquals;
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.mavenBundle;
19 import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
20 import static org.ops4j.pax.exam.CoreOptions.vmOption;
21 import static org.ops4j.pax.exam.CoreOptions.when;
22 import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
23 import static org.ops4j.pax.exam.MavenUtils.asInProject;
24 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
25 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
26 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
27
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.HashSet;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Properties;
35 import java.util.Set;
36 import java.util.concurrent.atomic.AtomicBoolean;
37
38 import org.junit.After;
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.binding.api.DataChangeListener;
46 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
47 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
48 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
49 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
50 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
51 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
52 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
53 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
54 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
55 import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
56 import org.opendaylight.ovsdb.openstack.netvirt.sfc.SfcUtils;
57 import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.RenderedServicePathUtils;
58 import org.opendaylight.ovsdb.openstack.netvirt.sfc.standalone.openflow13.SfcClassifier;
59 import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.AclUtils;
60 import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.ClassifierUtils;
61 import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.NetvirtConfigUtils;
62 import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.ServiceFunctionChainUtils;
63 import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.ServiceFunctionForwarderUtils;
64 import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.ServiceFunctionPathUtils;
65 import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.ServiceFunctionUtils;
66 import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.SfcConfigUtils;
67 import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.NetvirtSfcUtils;
68 import org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services.FlowNames;
69 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
70 import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
71 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
72 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
73 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
74 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
75 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
76 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SftType;
77 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
78 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePaths;
79 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
80 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathKey;
81 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
82 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctions;
83 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctionsBuilder;
84 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
85 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionBuilder;
86 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.ServiceFunctionChains;
87 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.ServiceFunctionChainsBuilder;
88 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain;
89 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChainBuilder;
90 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunction;
91 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunctionBuilder;
92 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwarders;
93 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwardersBuilder;
94 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
95 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderBuilder;
96 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
97 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPathsBuilder;
98 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
99 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathBuilder;
100 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.of.renderer.rev151123.SfcOfRendererConfig;
101 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.of.renderer.rev151123.SfcOfRendererConfigBuilder;
102 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
103 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
104 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
105 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
106 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
107 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;
108 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;
109 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
110 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
111 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.config.rev160109.NetvirtProvidersConfig;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.config.rev160109.NetvirtProvidersConfigBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.ClassifiersBuilder;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.ClassifierBuilder;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.SffsBuilder;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.SffBuilder;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.Sfc;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.SfcBuilder;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
126 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
127 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
128 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
129 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
130 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
131 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
132 import org.opendaylight.yangtools.concepts.Builder;
133 import org.opendaylight.yangtools.concepts.ListenerRegistration;
134 import org.opendaylight.yangtools.yang.binding.DataObject;
135 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
136 import org.ops4j.pax.exam.Configuration;
137 import org.ops4j.pax.exam.Option;
138 import org.ops4j.pax.exam.junit.PaxExam;
139 import org.ops4j.pax.exam.karaf.options.LogLevelOption;
140 import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
141 import org.ops4j.pax.exam.options.MavenUrlReference;
142 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
143 import org.ops4j.pax.exam.spi.reactors.PerClass;
144 import org.slf4j.Logger;
145 import org.slf4j.LoggerFactory;
146
147 import com.google.common.collect.Maps;
148
149 @RunWith(PaxExam.class)
150 @ExamReactorStrategy(PerClass.class)
151 public class NetvirtSfcIT extends AbstractMdsalTestBase {
152     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcIT.class);
153     private static final int MDSAL_TIMEOUT = 10000;
154     private static final int NO_MDSAL_TIMEOUT = 0;
155     private static AclUtils aclUtils = new AclUtils();
156     private static ClassifierUtils classifierUtils = new ClassifierUtils();
157     private static NetvirtSfcUtils netvirtSfcUtils = new NetvirtSfcUtils();
158     private static ServiceFunctionUtils serviceFunctionUtils = new ServiceFunctionUtils();
159     private static ServiceFunctionForwarderUtils serviceFunctionForwarderUtils = new ServiceFunctionForwarderUtils();
160     private static ServiceFunctionChainUtils serviceFunctionChainUtils = new ServiceFunctionChainUtils();
161     private static ServiceFunctionPathUtils serviceFunctionPathUtils = new ServiceFunctionPathUtils();
162     private static RenderedServicePathUtils renderedServicePathUtils = new RenderedServicePathUtils();
163     private static SfcConfigUtils sfcConfigUtils = new SfcConfigUtils();
164     private static NetvirtConfigUtils netvirtConfigUtils = new NetvirtConfigUtils();
165     private static MdsalUtils mdsalUtils;
166     private static AtomicBoolean setup = new AtomicBoolean(false);
167     private static SouthboundUtils southboundUtils;
168     private static SfcUtils sfcUtils;
169     private static String addressStr;
170     private static String portStr;
171     private static String connectionType;
172     private static String controllerStr;
173     private static boolean ovsdb_wait = false;
174     private static String userSpaceEnabled = "no";
175     private static PipelineOrchestrator pipelineOrchestrator;
176     private static Southbound southbound;
177     private static DataBroker dataBroker;
178     public static final String CONTROLLER_IPADDRESS = "ovsdb.controller.address";
179     public static final String SERVER_IPADDRESS = "ovsdbserver.ipaddress";
180     public static final String SERVER_PORT = "ovsdbserver.port";
181     public static final String CONNECTION_TYPE = "ovsdbserver.connection";
182     public static final String CONNECTION_TYPE_ACTIVE = "active";
183     public static final String CONNECTION_TYPE_PASSIVE = "passive";
184     public static final String DEFAULT_SERVER_PORT = "6640";
185     public static final String USERSPACE_ENABLED = "ovsdb.userspace.enabled";
186     public static final String INTEGRATION_BRIDGE_NAME = "br-int";
187     private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
188     private static final String OVSDB_TRACE = "ovsdb.trace";
189     private static final String OVSDB_WAIT = "ovsdb.wait";
190     private static final String SF1NAME = "firewall-72";
191     private static final String SF2NAME = "dpi-72";
192     private static final String SF1IP = "10.2.1.1";//"192.168.50.70";//"192.168.120.31";
193     private static final String SF2IP = "10.2.1.2";
194     private static final String SF1DPLNAME = "sf1";
195     private static final String SF2DPLNAME = "sf2";
196     // Use 192.168.50.70 when running against vagrant vm for workaround testing, eg. netvirtsfc-env
197     // Use 192.168.1.129 (or whatever address is dhcp'ed) for tacker-vm
198     // "192.168.50.70"; "127.0.0.1"; "192.168.1.129";
199     private static final String SFF1IP = "192.168.50.70";
200     private static final String SFF2IP = "127.0.0.1";
201     private static final String SFF1NAME = "sff1";
202     private static final String SFF2NAME = "sff2";
203     private static final String SFFDPL1NAME = "vxgpe";
204     private static final String SFFDPL2NAME = "vxgpe";
205     private static final String SN1NAME = "ovsdb1";
206     private static final String SN2NAME = "ovsdb2";
207     private static final String BRIDGE1NAME= "br-int";
208     private static final String BRIDGE2NAME= "br-int";
209     private static final String ACLNAME= "httpAcl";
210     private static final String RULENAME= "httpRule";
211     private static final String SFCNAME = "SFC";
212     private static final String SFCPATH = "SFC-Path";
213     private static final String RSPNAME = SFCPATH + "_rsp";
214     private static final String SFCSF1NAME = "firewall-abstract";
215     private static final SftType SFCSF1TYPE = new SftType("firewall");
216     private static final int GPEUDPPORT = 6633;
217
218     @Override
219     public String getModuleName() {
220         return "netvirt-sfc";
221     }
222
223     @Override
224     public String getInstanceName() {
225         return "netvirt-sfc-default";
226     }
227
228     @Override
229     public MavenUrlReference getFeatureRepo() {
230         return maven()
231                 .groupId("org.opendaylight.ovsdb")
232                 .artifactId("openstack.net-virt-sfc-features-test")
233                 .classifier("features")
234                 .type("xml")
235                 .versionAsInProject();
236     }
237
238     @Override
239     public String getFeatureName() {
240         return "odl-ovsdb-sfc-test";
241     }
242
243     @Configuration
244     @Override
245     public Option[] config() {
246         Option[] parentOptions = super.config();
247         Option[] propertiesOptions = getPropertiesOptions();
248         Option[] otherOptions = getOtherOptions();
249         Option[] options = new Option[parentOptions.length + propertiesOptions.length + otherOptions.length];
250         System.arraycopy(parentOptions, 0, options, 0, parentOptions.length);
251         System.arraycopy(propertiesOptions, 0, options, parentOptions.length, propertiesOptions.length);
252         System.arraycopy(otherOptions, 0, options, parentOptions.length + propertiesOptions.length,
253                 otherOptions.length);
254         return options;
255     }
256
257     private Option[] getOtherOptions() {
258         return new Option[] {
259                 wrappedBundle(
260                         mavenBundle("org.opendaylight.ovsdb", "utils.mdsal-openflow")
261                                 .version(asInProject())
262                                 .type("jar")),
263                 configureConsole().startLocalConsole(),
264                 //vmOption("-verbose:class"),
265                 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
266                 keepRuntimeFolder()
267         };
268     }
269
270     public Option[] getPropertiesOptions() {
271         return new Option[] {
272                 propagateSystemProperties(SERVER_IPADDRESS, SERVER_PORT, CONNECTION_TYPE,
273                         CONTROLLER_IPADDRESS, OVSDB_TRACE, OVSDB_WAIT, USERSPACE_ENABLED),
274         };
275     }
276
277     @Override
278     public Option getLoggingOption() {
279         return composite(
280                 when(Boolean.getBoolean(OVSDB_TRACE)).useOptions(
281                         editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
282                                 "log4j.logger.org.opendaylight.ovsdb",
283                                 LogLevelOption.LogLevel.TRACE.name())),
284                 //editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
285                 //        "log4j.logger.org.opendaylight.ovsdb",
286                 //        LogLevelOption.LogLevel.TRACE.name()),
287                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
288                         "log4j.logger.org.opendaylight.ovsdb.library",
289                         LogLevel.INFO.name()),
290                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
291                         logConfiguration(NetvirtSfcIT.class),
292                         LogLevel.INFO.name()),
293                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
294                         "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc",
295                         LogLevel.TRACE.name()),
296                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
297                         "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13",
298                         LogLevel.TRACE.name()),
299                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
300                         "log4j.logger.org.opendaylight.sfc",
301                         LogLevel.TRACE.name()),
302                 super.getLoggingOption());
303     }
304
305     protected String usage() {
306         return "Integration Test needs a valid connection configuration as follows :\n"
307                 + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
308                 + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
309     }
310
311     private void getProperties() {
312         Properties props = System.getProperties();
313         addressStr = props.getProperty(SERVER_IPADDRESS);
314         portStr = props.getProperty(SERVER_PORT, DEFAULT_SERVER_PORT);
315         connectionType = props.getProperty(CONNECTION_TYPE, "active");
316         controllerStr = props.getProperty(CONTROLLER_IPADDRESS, "0.0.0.0");
317         userSpaceEnabled = props.getProperty(USERSPACE_ENABLED, "no");
318         LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}, controller ip: {}, " +
319                         "userspace.enabled: {}",
320                 connectionType, addressStr, portStr, controllerStr, userSpaceEnabled);
321         if (connectionType.equalsIgnoreCase(CONNECTION_TYPE_ACTIVE)) {
322             if (addressStr == null) {
323                 fail(usage());
324             }
325         }
326         LOG.info("getProperties {}: {}", OVSDB_TRACE, props.getProperty(OVSDB_TRACE));
327         LOG.info("getProperties {}: {}", OVSDB_WAIT, props.getProperty(OVSDB_WAIT));
328         if (props.getProperty(OVSDB_WAIT) != null && props.getProperty(OVSDB_WAIT).equals("true")) {
329             ovsdb_wait = true;
330         }
331     }
332
333     @Before
334     @Override
335     public void setup() {
336         if (setup.get()) {
337             LOG.info("Skipping setUp, already initialized");
338             return;
339         }
340
341         try {
342             Thread.sleep(1000);
343             super.setup();
344         } catch (Exception e) {
345             LOG.warn("Failed to setup test", e);
346             fail("Failed to setup test: " + e);
347         }
348
349         getProperties();
350
351         dataBroker = getDatabroker(getProviderContext());
352         mdsalUtils = new MdsalUtils(dataBroker);
353         assertNotNull("mdsalUtils should not be null", mdsalUtils);
354         southboundUtils = new SouthboundUtils(mdsalUtils);
355         sfcUtils = new SfcUtils(mdsalUtils);
356         assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
357         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
358         assertNotNull("southbound should not be null", southbound);
359         pipelineOrchestrator =
360                 (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
361         assertNotNull("pipelineOrchestrator should not be null", pipelineOrchestrator);
362
363         setup.set(true);
364     }
365
366     @After
367     public void teardown() {
368         closeWaitFors();
369     }
370
371     private ProviderContext getProviderContext() {
372         ProviderContext providerContext = null;
373         for (int i=0; i < 60; i++) {
374             providerContext = getSession();
375             if (providerContext != null) {
376                 break;
377             } else {
378                 try {
379                     Thread.sleep(1000);
380                 } catch (InterruptedException e) {
381                     LOG.warn("Interrupted while waiting for provider context", e);
382                 }
383             }
384         }
385         assertNotNull("providercontext should not be null", providerContext);
386         /* One more second to let the provider finish initialization */
387         try {
388             Thread.sleep(1000);
389         } catch (InterruptedException e) {
390             LOG.warn("Interrupted while waiting for other provider", e);
391         }
392         return providerContext;
393     }
394
395     private DataBroker getDatabroker(ProviderContext providerContext) {
396         DataBroker dataBroker = providerContext.getSALService(DataBroker.class);
397         assertNotNull("dataBroker should not be null", dataBroker);
398         return dataBroker;
399     }
400
401     private Boolean getNetvirtTopology() {
402         LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
403         Boolean found = false;
404         final TopologyId topologyId = new TopologyId(new Uri(NETVIRT_TOPOLOGY_ID));
405         InstanceIdentifier<Topology> path =
406                 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
407         for (int i = 0; i < 60; i++) {
408             Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
409             if (topology != null) {
410                 LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
411                 found = true;
412                 break;
413             } else {
414                 LOG.info("getNetvirtTopology: still looking ({})...", i);
415                 try {
416                     Thread.sleep(1000);
417                 } catch (InterruptedException e) {
418                     LOG.warn("Interrupted while waiting for {}", NETVIRT_TOPOLOGY_ID, e);
419                 }
420             }
421         }
422         return found;
423     }
424
425     private AccessListsBuilder accessListsBuilder() {
426         return accessListsBuilder(false);
427     }
428
429     private AccessListsBuilder accessListsBuilder(boolean renderRsp) {
430         String ruleName = RULENAME;
431         String sfcName = SFCNAME;
432         MatchesBuilder matchesBuilder = aclUtils.matchesBuilder(new MatchesBuilder(), 80);
433         LOG.info("Matches: {}", matchesBuilder.build());
434         ActionsBuilder actionsBuilder = aclUtils.actionsBuilder(new ActionsBuilder(), sfcName, renderRsp);
435         AceBuilder accessListEntryBuilder =
436                 aclUtils.aceBuilder(new AceBuilder(), ruleName, matchesBuilder, actionsBuilder);
437         AccessListEntriesBuilder accessListEntriesBuilder =
438                 aclUtils.accessListEntriesBuidler(new AccessListEntriesBuilder(), accessListEntryBuilder);
439         AclBuilder accessListBuilder =
440                 aclUtils.aclBuilder(new AclBuilder(), ACLNAME, accessListEntriesBuilder);
441         AccessListsBuilder accessListsBuilder =
442                 aclUtils.accesslistsbuilder(new AccessListsBuilder(), accessListBuilder);
443         LOG.info("AccessLists: {}", accessListsBuilder.build());
444         return accessListsBuilder;
445     }
446
447     @Test
448     public void testAccessLists() throws InterruptedException {
449         testModel(accessListsBuilder(), AccessLists.class, 0);
450     }
451
452     private ClassifiersBuilder classifiersBuilder() {
453         SffBuilder sffBuilder = classifierUtils.sffBuilder(new SffBuilder(), SFF1NAME);
454         SffsBuilder sffsBuilder = classifierUtils.sffsBuilder(new SffsBuilder(), sffBuilder);
455         ClassifierBuilder classifierBuilder = classifierUtils.classifierBuilder(new ClassifierBuilder(),
456                 "classifierName", ACLNAME, sffsBuilder);
457         ClassifiersBuilder classifiersBuilder = classifierUtils.classifiersBuilder(new ClassifiersBuilder(),
458                 classifierBuilder);
459         LOG.info("Classifiers: {}", classifiersBuilder.build());
460         return classifiersBuilder;
461     }
462
463     @Test
464     public void testClassifiers() throws InterruptedException {
465         testModel(classifiersBuilder(), Classifiers.class, 0);
466     }
467
468     private SfcBuilder netvirtSfcBuilder() {
469         return netvirtSfcUtils.sfcBuilder(new SfcBuilder(), "sfc");
470     }
471
472     @Test
473     public void testNetvirtSfcModel() throws InterruptedException {
474         testModel(netvirtSfcBuilder(), Sfc.class, 0);
475     }
476
477     private <T extends DataObject> void testModelPut(Builder<T> builder, Class<T> clazz) {
478         InstanceIdentifier<T> path = InstanceIdentifier.create(clazz);
479         assertTrue(mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, path, builder.build()));
480         T result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
481         assertNotNull(clazz.getSimpleName() + " should not be null", result);
482     }
483
484     private <T extends DataObject> void testModelDelete(Builder<T> builder, Class<T> clazz)
485             throws InterruptedException {
486         InstanceIdentifier<T> path = InstanceIdentifier.create(clazz);
487         assertTrue("Failed to remove " + clazz.getSimpleName(),
488                 mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, path));
489         T result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
490         assertNull(clazz.getSimpleName() + " should be null", result);
491     }
492
493     private <T extends DataObject> void testModel(Builder<T> builder, Class<T> clazz, long wait)
494             throws InterruptedException {
495         testModelPut(builder, clazz);
496         Thread.sleep(wait);
497         testModelDelete(builder, clazz);
498     }
499
500     private <T extends DataObject> void testModel(Builder<T> builder, Class<T> clazz)
501             throws InterruptedException {
502         testModelPut(builder, clazz);
503         Thread.sleep(1000);
504         testModelDelete(builder, clazz);
505     }
506
507     private ServiceFunctionsBuilder serviceFunctionsBuilder() {
508         String sf1Name = SF1NAME;
509         String sf1Ip = SF1IP;
510         String sff1Name = SFF1NAME;
511         String sf1DplName = SF1DPLNAME;
512         int port = GPEUDPPORT;
513
514         ServiceFunctionBuilder serviceFunctionBuilder =
515                 serviceFunctionUtils.serviceFunctionBuilder(sf1Ip, port, sf1DplName, sff1Name, sf1Name);
516         List<ServiceFunction> serviceFunctionList = serviceFunctionUtils.list(
517                 new ArrayList<ServiceFunction>(), serviceFunctionBuilder);
518
519         ServiceFunctionsBuilder serviceFunctionsBuilder =
520                 serviceFunctionUtils.serviceFunctionsBuilder(new ServiceFunctionsBuilder(),
521                         serviceFunctionList);
522         LOG.info("ServiceFunctions: {}", serviceFunctionsBuilder.build());
523         return serviceFunctionsBuilder;
524     }
525
526     private ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder() {
527         String sf1Name = SF1NAME;
528         String sf1Ip = SF1IP;
529         String sf1DplName = SF1DPLNAME;
530         String sff1Ip = SFF1IP;
531         String sff1Name = SFF1NAME;
532         String sffDpl1Name = SFFDPL1NAME;
533         String sn1Name = SN1NAME;
534         String bridge1Name= BRIDGE1NAME;
535         int port = GPEUDPPORT;
536
537         ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder =
538                 serviceFunctionForwarderUtils.serviceFunctionForwarderBuilder(
539                         sff1Name, sff1Ip, port, sffDpl1Name, sf1Ip, sn1Name, bridge1Name, sf1Name, sf1DplName);
540         List<ServiceFunctionForwarder>  serviceFunctionForwarderList = serviceFunctionForwarderUtils.list(
541                 new ArrayList<ServiceFunctionForwarder>(), serviceFunctionForwarderBuilder);
542
543         ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder =
544                 serviceFunctionForwarderUtils.serviceFunctionForwardersBuilder(
545                         new ServiceFunctionForwardersBuilder(), serviceFunctionForwarderList);
546         LOG.info("ServiceFunctionForwarders: {}", serviceFunctionForwardersBuilder.build());
547         return serviceFunctionForwardersBuilder;
548     }
549
550     private ServiceFunctionChainsBuilder serviceFunctionChainsBuilder() {
551         String sf1Name = SFCSF1NAME;
552         SftType sfType = SFCSF1TYPE;
553         String sfcName = SFCNAME;
554
555         SfcServiceFunctionBuilder sfcServiceFunctionBuilder = serviceFunctionChainUtils.sfcServiceFunctionBuilder(
556                 new SfcServiceFunctionBuilder(), sf1Name, sfType);
557         List<SfcServiceFunction> sfcServiceFunctionList =
558                 serviceFunctionChainUtils.list(new ArrayList<SfcServiceFunction>(), sfcServiceFunctionBuilder);
559
560         ServiceFunctionChainBuilder serviceFunctionChainBuilder =
561                 serviceFunctionChainUtils.serviceFunctionChainBuilder(
562                         new ServiceFunctionChainBuilder(), sfcName, false, sfcServiceFunctionList);
563         ServiceFunctionChainsBuilder serviceFunctionChainsBuilder =
564                 serviceFunctionChainUtils.serviceFunctionChainsBuilder(
565                         new ServiceFunctionChainsBuilder(),
566                         serviceFunctionChainUtils.list(new ArrayList<ServiceFunctionChain>(),
567                                 serviceFunctionChainBuilder));
568         LOG.info("ServiceFunctionChains: {}", serviceFunctionChainBuilder.build());
569         return serviceFunctionChainsBuilder;
570     }
571
572     private ServiceFunctionPathsBuilder serviceFunctionPathsBuilder() {
573         String sfpName = SFCPATH;
574         String sfcName = SFCNAME;
575         short startingIndex = 255;
576
577         ServiceFunctionPathBuilder serviceFunctionPathBuilder =
578                 serviceFunctionPathUtils.serviceFunctionPathBuilder(
579                         new ServiceFunctionPathBuilder(), sfpName, sfcName, startingIndex, false);
580         ServiceFunctionPathsBuilder serviceFunctionPathsBuilder =
581                 serviceFunctionPathUtils.serviceFunctionPathsBuilder(
582                         serviceFunctionPathUtils.list(new ArrayList<ServiceFunctionPath>(),
583                                 serviceFunctionPathBuilder));
584         LOG.info("ServiceFunctionPaths: {}", serviceFunctionPathsBuilder.build());
585         return serviceFunctionPathsBuilder;
586     }
587
588     private SfcOfRendererConfigBuilder sfcOfRendererConfigBuilder(short tableOffset, short egressTable) {
589         SfcOfRendererConfigBuilder sfcOfRendererConfigBuilder =
590                 sfcConfigUtils.sfcOfRendererConfigBuilder(new SfcOfRendererConfigBuilder(), tableOffset, egressTable);
591         LOG.info("SfcOfRendererConfig: {}", sfcOfRendererConfigBuilder.build());
592         return sfcOfRendererConfigBuilder;
593     }
594
595     private NetvirtProvidersConfigBuilder netvirtProvidersConfigBuilder(short tableOffset) {
596         NetvirtProvidersConfigBuilder netvirtProvidersConfigBuilder =
597                 netvirtConfigUtils.netvirtProvidersConfigBuilder(new NetvirtProvidersConfigBuilder(), tableOffset);
598         LOG.info("NetvirtProvidersConfig: {}", netvirtProvidersConfigBuilder.build());
599         return netvirtProvidersConfigBuilder;
600     }
601
602     @Test
603     public void testSfcModel() throws InterruptedException {
604         int timeout = 1000;
605         testModel(serviceFunctionsBuilder(), ServiceFunctions.class, timeout);
606         testModel(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class, timeout);
607         testModel(serviceFunctionChainsBuilder(), ServiceFunctionChains.class, timeout);
608         testModel(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class, timeout);
609     }
610
611     @Test
612     public void testSfcModels() throws InterruptedException {
613         testModel(serviceFunctionsBuilder(), ServiceFunctions.class);
614         testModel(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class);
615         testModel(serviceFunctionChainsBuilder(), ServiceFunctionChains.class);
616         testModel(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class);
617
618         testModel(accessListsBuilder(), AccessLists.class);
619         testModel(classifiersBuilder(), Classifiers.class);
620     }
621
622     private class NodeInfo {
623         private ConnectionInfo connectionInfo;
624         private InstanceIdentifier<Node> ovsdbIid;
625         private String bridgeName = INTEGRATION_BRIDGE_NAME;
626         InstanceIdentifier<Node> bridgeIid;
627         NotifyingDataChangeListener ovsdbOperationalListener;
628         NotifyingDataChangeListener bridgeOperationalListener;
629         long datapathId;
630         Node ovsdbNode;
631         Node bridgeNode;
632
633         NodeInfo(ConnectionInfo connectionInfo) {
634             this.connectionInfo = connectionInfo;
635             ovsdbIid = SouthboundUtils.createInstanceIdentifier(connectionInfo);
636             bridgeIid = SouthboundUtils.createInstanceIdentifier(connectionInfo, bridgeName);
637         }
638
639         private void connect() throws InterruptedException {
640             ovsdbOperationalListener = new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
641             ovsdbOperationalListener.registerDataChangeListener();
642             bridgeOperationalListener = new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, bridgeIid);
643             bridgeOperationalListener.registerDataChangeListener();
644             assertNotNull("connection failed", southboundUtils.addOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
645
646             ovsdbOperationalListener.waitForCreation();
647             ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
648             assertNotNull("node is not connected", ovsdbNode);
649
650             bridgeOperationalListener.waitForCreation();
651             assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
652                     + " is not connected", isControllerConnected(connectionInfo));
653
654             bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
655             assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
656             datapathId = southbound.getDataPathId(bridgeNode);
657             String datapathIdString = southbound.getDatapathId(bridgeNode);
658             LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
659             assertNotEquals("datapathId was not found", datapathId, 0);
660         }
661
662         void disconnect() throws InterruptedException {
663             assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName, NO_MDSAL_TIMEOUT));
664             bridgeOperationalListener.waitForDeletion();
665             Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
666             assertNull("Bridge should not be found", bridgeNode);
667             assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
668             ovsdbOperationalListener.waitForDeletion();
669             Node ovsdbNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
670             assertNull("Ovsdb node should not be found", ovsdbNode);
671         }
672     }
673
674     /**
675      * Test that the NetvirtSfc SfcClassifierService is added to the Netvirt pipeline. The test
676      * sets the table offset and verifies the correct flow is programmed with the offset.
677      */
678     @Test
679     public void testNetvirtSfcPipeline() throws InterruptedException {
680         short netvirtTableOffset = 1;
681         testModelPut(netvirtProvidersConfigBuilder(netvirtTableOffset), NetvirtProvidersConfig.class);
682
683         NodeInfo nodeInfo = new NodeInfo(SouthboundUtils.getConnectionInfo(addressStr, portStr));
684         nodeInfo.connect();
685
686         String flowId = "DEFAULT_PIPELINE_FLOW_" + pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER);
687         verifyFlow(nodeInfo.datapathId, flowId, Service.SFC_CLASSIFIER);
688
689         nodeInfo.disconnect();
690     }
691
692     /**
693      * Test the full NetvirtSfc functionality by creating everything needed to realize a chain and
694      * then verify all flows have been created.
695      * NOTE: This test requires an OVS with the NSH v8 patch, otherwise it will fail miserably.
696      * @throws InterruptedException
697      */
698     @Test
699     public void testNetvirtSfcAll() throws Exception {
700         if (userSpaceEnabled.equals("yes")) {
701             LOG.info("testNetvirtSfcAll: skipping test because userSpaceEnabled {}", userSpaceEnabled);
702             return;
703         }
704
705         String sfpName = SFCPATH;
706         String sfcName = SFCNAME;
707         short startingIndex = 255;
708
709         short netvirtTableOffset = 1;
710         testModelPut(netvirtProvidersConfigBuilder(netvirtTableOffset), NetvirtProvidersConfig.class);
711         short sfcTableoffset = 150;
712         short egressTable = pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER);
713         testModelPut(sfcOfRendererConfigBuilder(sfcTableoffset, egressTable), SfcOfRendererConfig.class);
714
715         NodeInfo nodeInfo = new NodeInfo(SouthboundUtils.getConnectionInfo(addressStr, portStr));
716         nodeInfo.connect();
717
718         String flowId = "DEFAULT_PIPELINE_FLOW_" + pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER);
719         verifyFlow(nodeInfo.datapathId, flowId, Service.SFC_CLASSIFIER);
720
721         Map<String, String> externalIds = Maps.newHashMap();
722         externalIds.put("attached-mac", "f6:00:00:0f:00:01");
723         southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, SF1DPLNAME, "internal", null, externalIds);
724         externalIds.clear();
725         externalIds.put("attached-mac", "f6:00:00:0c:00:01");
726         southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, "vm1", "internal");
727         externalIds.clear();
728         externalIds.put("attached-mac", "f6:00:00:0c:00:02");
729         southboundUtils.addTerminationPoint(nodeInfo.bridgeNode, "vm2", "internal");
730
731         InstanceIdentifier<TerminationPoint> tpIid =
732                 southboundUtils.createTerminationPointInstanceIdentifier(nodeInfo.bridgeNode, SFFDPL1NAME);
733         final NotifyingDataChangeListener portOperationalListener =
734                 new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, tpIid);
735         portOperationalListener.registerDataChangeListener();
736
737         InstanceIdentifier<RenderedServicePath> rspIid = sfcUtils.getRspId(RSPNAME);
738         final NotifyingDataChangeListener rspOperationalListener =
739                 new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, rspIid);
740         rspOperationalListener.registerDataChangeListener();
741
742         testModelPut(serviceFunctionsBuilder(), ServiceFunctions.class);
743         testModelPut(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class);
744         testModelPut(serviceFunctionChainsBuilder(), ServiceFunctionChains.class);
745         testModelPut(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class);
746
747         testModelPut(accessListsBuilder(false), AccessLists.class);
748         testModelPut(classifiersBuilder(), Classifiers.class);
749         ServiceFunctionPathBuilder serviceFunctionPathBuilder =
750                 serviceFunctionPathUtils.serviceFunctionPathBuilder(
751                         new ServiceFunctionPathBuilder(), sfpName, sfcName, startingIndex, false);
752         SfcProviderRenderedPathAPI.createRenderedServicePathAndState(serviceFunctionPathBuilder.build(),
753                 renderedServicePathUtils.createRenderedPathInputBuilder(new CreateRenderedPathInputBuilder(),
754                         SFCPATH, RSPNAME).build());
755
756         portOperationalListener.waitForCreation();
757         long vxGpeOfPort = southbound.getOFPort(nodeInfo.bridgeNode, SFFDPL1NAME);
758         assertNotEquals("vxGpePort was not found", 0, vxGpeOfPort);
759
760         rspOperationalListener.waitForCreation();
761         RenderedServicePath rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, rspIid);
762         assertNotNull("RSP was not found", rsp);
763
764         flowId = FlowNames.getSfcIngressClass(RULENAME, rsp.getPathId(), rsp.getStartingIndex());
765         verifyFlow(nodeInfo.datapathId, flowId, Service.SFC_CLASSIFIER);
766         RenderedServicePathHop lastHop = sfcUtils.getLastHop(rsp);
767         short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
768         flowId = FlowNames.getSfcEgressClass(vxGpeOfPort, rsp.getPathId(), lastServiceindex);
769         verifyFlow(nodeInfo.datapathId, flowId, Service.SFC_CLASSIFIER);
770         flowId = FlowNames.getSfcEgressClassBypass(rsp.getPathId(), lastServiceindex, 1);
771         verifyFlow(nodeInfo.datapathId, flowId, Service.CLASSIFIER);
772         flowId = FlowNames.getArpResponder(SF1IP);
773         verifyFlow(nodeInfo.datapathId, flowId, Service.ARP_RESPONDER);
774
775         InstanceIdentifier<Flow> flowIid = createFlowIid(nodeInfo.datapathId, flowId,
776                 pipelineOrchestrator.getTable(Service.CLASSIFIER));
777
778         final NotifyingDataChangeListener flowConfigurationListener =
779                 new NotifyingDataChangeListener(LogicalDatastoreType.CONFIGURATION, flowIid);
780         flowConfigurationListener.registerDataChangeListener();
781         final NotifyingDataChangeListener flowOperationalListener =
782                 new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, flowIid);
783         flowOperationalListener.registerDataChangeListener();
784
785         deleteRsp(RSPNAME);
786         rspOperationalListener.waitForDeletion();
787         rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, rspIid);
788         assertNull("RSP should not be found", rsp);
789
790         flowConfigurationListener.waitForDeletion();
791         Flow flow = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, flowIid);
792         assertNull("Flow should not be found in CONFIGURATION " + flowIid, flow);
793
794         flowOperationalListener.waitForDeletion();
795         flow = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, flowIid);
796         assertNull("Flow should not be found in OPERATIONAL " + flowIid, flow);
797
798         nodeInfo.disconnect();
799     }
800
801     private void deleteRsp(String rspName) {
802         RenderedServicePathKey renderedServicePathKey =
803                 new RenderedServicePathKey(RspName.getDefaultInstance(rspName));
804         InstanceIdentifier<RenderedServicePath> path =
805                 InstanceIdentifier.create(RenderedServicePaths.class)
806                         .child(RenderedServicePath.class, renderedServicePathKey);
807         mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, path);
808     }
809
810     /**
811      * Test the standalone NetvirtSfc implementation
812      * NOTE: This test requires an OVS with the NSH v8 patch, otherwise it will fail miserably.
813      * @throws InterruptedException
814      */
815     @Ignore
816     @Test
817     public void testStandalone() throws InterruptedException {
818         String bridgeName = "sw1";
819         ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
820         assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
821         Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
822         assertNotNull("node is not connected", ovsdbNode);
823
824         String controllerTarget = "tcp:192.168.50.1:6653";
825         List<ControllerEntry> setControllerEntry = southboundUtils.createControllerEntry(controllerTarget);
826         Assert.assertTrue(southboundUtils.addBridge(connectionInfo, null, bridgeName, null, true,
827                 SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
828                 setControllerEntry, null, "00:00:00:00:00:00:00:01"));
829         assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
830                 + " is not connected", isControllerConnected(connectionInfo));
831
832         Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
833         assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
834         long datapathId = southbound.getDataPathId(bridgeNode);
835         String datapathIdString = southbound.getDatapathId(bridgeNode);
836         LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
837         assertNotEquals("datapathId was not found", datapathId, 0);
838
839         SfcClassifier sfcClassifier = new SfcClassifier(dataBroker, southbound, mdsalUtils);
840         //sfcClassifier.programLocalInPort(datapathId, "4096", (long)1, (short)0, (short)50, true);
841
842         NshUtils nshUtils = new NshUtils(new Ipv4Address("192.168.50.71"), new PortNumber(6633),
843                 (long)10, (short)255, (long)4096, (long)4096);
844         MatchesBuilder matchesBuilder = aclUtils.matchesBuilder(new MatchesBuilder(), 80);
845         sfcClassifier.programSfcClassiferFlows(datapathId, (short)0, "test", matchesBuilder.build(),
846                 nshUtils, (long)2, true);
847
848         //nshUtils = new NshUtils(null, null, (long)10, (short)253, 0, 0);
849         //sfcClassifier.programEgressSfcClassiferFlows(datapathId, (short)0, "test", null,
850         //        nshUtils, (long)2, (long)3, true);
851
852         //NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
853         //FlowBuilder flowBuilder = getLocalInPortFlow(datapathId, "4096", (long) 1,
854         //                                             pipelineOrchestrator.getTable(Service.CLASSIFIER));
855         //Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
856         //assertNotNull("Could not find flow in config", flow);
857         //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
858         //assertNotNull("Could not find flow in operational", flow);
859
860         //MatchBuilder matchBuilder = sfcClassifier.buildMatch(matchesBuilder.build());
861         //NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
862         //FlowBuilder flowBuilder = getSfcClassifierFlow(datapathId,
863         //        pipelineOrchestrator.getTable(Service.CLASSIFIER), "test", null,
864         //        nshUtils, (long) 2, matchBuilder);
865         //Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
866         //assertNotNull("Could not find flow in config", flow);
867         //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
868         //assertNotNull("Could not find flow in operational", flow);
869
870         //nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
871         //flowBuilder = getEgressSfcClassifierFlow(datapathId,
872                                                    //pipelineOrchestrator.getTable(Service.CLASSIFIER),
873                                                    //"test", nshUtils, (long) 2);
874         //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
875         //assertNotNull("Could not find flow in config", flow);
876         //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
877         //assertNotNull("Could not find flow in operational", flow);
878
879         LOG.info("***** Go look for flows *****");
880         Thread.sleep(30000);
881         assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
882         Thread.sleep(1000);
883         assertTrue(southboundUtils.deleteBridge(connectionInfo, INTEGRATION_BRIDGE_NAME));
884         Thread.sleep(1000);
885         assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
886     }
887
888     private InstanceIdentifier<Flow> createFlowIid(long datapathId, String flowId, short table) {
889         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
890                 FlowUtils.createNodeBuilder(datapathId);
891         FlowBuilder flowBuilder =
892                 FlowUtils.initFlowBuilder(new FlowBuilder(), flowId, table);
893         return FlowUtils.createFlowPath(flowBuilder, nodeBuilder);
894     }
895
896     private Flow getFlow (
897             FlowBuilder flowBuilder,
898             org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder,
899             LogicalDatastoreType store) throws InterruptedException {
900
901         Flow flow = null;
902         for (int i = 0; i < 10; i++) {
903             LOG.info("getFlow try {} from {}: looking for flow: {}, node: {}",
904                     i, store, flowBuilder.build(), nodeBuilder.build());
905             flow = FlowUtils.getFlow(flowBuilder, nodeBuilder, dataBroker.newReadOnlyTransaction(), store);
906             if (flow != null) {
907                 LOG.info("getFlow try {} from {}: found flow: {}", i, store, flow);
908                 break;
909             }
910             Thread.sleep(1000);
911         }
912         return flow;
913     }
914
915     private void verifyFlow(long datapathId, String flowId, short table) throws InterruptedException {
916         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
917                 FlowUtils.createNodeBuilder(datapathId);
918         FlowBuilder flowBuilder =
919                 FlowUtils.initFlowBuilder(new FlowBuilder(), flowId, table);
920         Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
921         assertNotNull("Could not find flow in config: " + flowBuilder.build() + "--" + nodeBuilder.build(), flow);
922         flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
923         assertNotNull("Could not find flow in operational: " + flowBuilder.build() + "--" + nodeBuilder.build(),
924                 flow);
925     }
926
927     private void verifyFlow(long datapathId, String flowId, Service service) throws InterruptedException {
928         verifyFlow(datapathId, flowId, pipelineOrchestrator.getTable(service));
929     }
930
931     private void readwait() {
932         if (ovsdb_wait) {
933             LOG.warn("Waiting, kill with ps -ef | grep java, kill xxx... ");
934             try {
935                 System.in.read();
936             } catch (IOException e) {
937                 e.printStackTrace();
938             }
939         }
940     }
941
942     private boolean isControllerConnected(ConnectionInfo connectionInfo) throws InterruptedException {
943         LOG.info("isControllerConnected enter");
944         Boolean connected = false;
945         ControllerEntry controllerEntry;
946         Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
947         assertNotNull("ovsdb node not found", ovsdbNode);
948
949         BridgeConfigurationManager bridgeConfigurationManager =
950                 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
951         assertNotNull("Could not find BridgeConfigurationManager Service", bridgeConfigurationManager);
952         String controllerTarget = bridgeConfigurationManager.getControllersFromOvsdbNode(ovsdbNode).get(0);
953         Assert.assertNotNull("Failed to get controller target", controllerTarget);
954
955         for (int i = 0; i < 10; i++) {
956             LOG.info("isControllerConnected try {}: looking for controller: {}", i, controllerTarget);
957             OvsdbBridgeAugmentation bridge =
958                     southboundUtils.getBridge(connectionInfo, INTEGRATION_BRIDGE_NAME);
959             Assert.assertNotNull(bridge);
960             Assert.assertNotNull(bridge.getControllerEntry());
961             controllerEntry = bridge.getControllerEntry().iterator().next();
962             Assert.assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
963             if (controllerEntry.isIsConnected()) {
964                 Assert.assertTrue("Controller is not connected", controllerEntry.isIsConnected());
965                 connected = true;
966                 break;
967             }
968             Thread.sleep(1000);
969         }
970         LOG.info("isControllerConnected exit: {} - {}", connected, controllerTarget);
971         return connected;
972     }
973
974     private List<NotifyingDataChangeListener> waitList = new ArrayList<>();
975
976     private void closeWaitFors() {
977         for (Iterator<NotifyingDataChangeListener> iterator = waitList.iterator(); iterator.hasNext();) {
978             NotifyingDataChangeListener listener = iterator.next();
979             iterator.remove();
980             try {
981                 listener.close();
982             } catch (Exception ex) {
983                 LOG.warn("Failed to close registration {}", listener, ex);
984             }
985         }
986         LOG.info("waitList size {}", waitList.size());
987     }
988
989     public class NotifyingDataChangeListener implements AutoCloseable, DataChangeListener {
990         private LogicalDatastoreType type;
991         private final Set<InstanceIdentifier<?>> createdIids = new HashSet<>();
992         private final Set<InstanceIdentifier<?>> removedIids = new HashSet<>();
993         private final Set<InstanceIdentifier<?>> updatedIids = new HashSet<>();
994         private InstanceIdentifier<?> iid;
995         private final int RETRY_WAIT = 100;
996         private final int MDSAL_TIMEOUT = 1000;
997         private ListenerRegistration<?> listenerRegistration;
998
999         private NotifyingDataChangeListener(LogicalDatastoreType type, InstanceIdentifier<?> iid) {
1000             this.type = type;
1001             this.iid = iid;
1002             waitList.add(this);
1003         }
1004
1005         private void modify(LogicalDatastoreType type, InstanceIdentifier<?> iid) throws Exception {
1006             this.close();
1007             this.clear();
1008             this.type = type;
1009             this.iid = iid;
1010         }
1011
1012         @Override
1013         public void onDataChanged(
1014                 AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent) {
1015             LOG.info("{} DataChanged: created {}", type, asyncDataChangeEvent.getCreatedData().keySet());
1016             LOG.info("{} DataChanged: updated {}", type, asyncDataChangeEvent.getUpdatedData().keySet());
1017             LOG.info("{} DataChanged: removed {}", type, asyncDataChangeEvent.getRemovedPaths());
1018             createdIids.addAll(asyncDataChangeEvent.getCreatedData().keySet());
1019             removedIids.addAll(asyncDataChangeEvent.getRemovedPaths());
1020             updatedIids.addAll(asyncDataChangeEvent.getUpdatedData().keySet());
1021             synchronized(this) {
1022                 notifyAll();
1023             }
1024         }
1025
1026         public boolean isCreated(InstanceIdentifier<?> iid) {
1027             return createdIids.remove(iid);
1028         }
1029
1030         public boolean isUpdated(InstanceIdentifier<?> iid) {
1031             return updatedIids.remove(iid);
1032         }
1033
1034         public boolean isRemoved(InstanceIdentifier<?> iid) {
1035             return removedIids.remove(iid);
1036         }
1037
1038         public void clear() {
1039             createdIids.clear();
1040             removedIids.clear();
1041             updatedIids.clear();
1042         }
1043
1044         public void registerDataChangeListener() {
1045             listenerRegistration = dataBroker.registerDataChangeListener(type, iid, this,
1046                     AsyncDataBroker.DataChangeScope.SUBTREE);
1047         }
1048
1049         public void waitForCreation() throws InterruptedException {
1050             waitForCreation(MDSAL_TIMEOUT);
1051         }
1052
1053         public void waitForCreation(long timeout) throws InterruptedException {
1054             synchronized (this) {
1055                 long _start = System.currentTimeMillis();
1056                 LOG.info("Waiting for {} DataChanged creation on {}", type, iid);
1057                 while (!isCreated(iid) && (System.currentTimeMillis() - _start) < timeout) {
1058                     wait(RETRY_WAIT);
1059                 }
1060                 LOG.info("Woke up, waited {}ms for creation of {}", (System.currentTimeMillis() - _start), iid);
1061             }
1062         }
1063
1064         public void waitForUpdate() throws InterruptedException {
1065             waitForUpdate(MDSAL_TIMEOUT);
1066         }
1067
1068         public void waitForUpdate(long timeout) throws InterruptedException {
1069             synchronized (this) {
1070                 long _start = System.currentTimeMillis();
1071                 LOG.info("Waiting for {} DataChanged update on {}", type, iid);
1072                 while (!isUpdated(iid) && (System.currentTimeMillis() - _start) < timeout) {
1073                     wait(RETRY_WAIT);
1074                 }
1075                 LOG.info("Woke up, waited {}ms for update of {}", (System.currentTimeMillis() - _start), iid);
1076             }
1077         }
1078
1079         public void waitForDeletion() throws InterruptedException {
1080             waitForDeletion(MDSAL_TIMEOUT);
1081         }
1082
1083         public void waitForDeletion(long timeout) throws InterruptedException {
1084             synchronized (this) {
1085                 long _start = System.currentTimeMillis();
1086                 LOG.info("Waiting for {} DataChanged deletion on {}", type, iid);
1087                 while (!isRemoved(iid) && (System.currentTimeMillis() - _start) < timeout) {
1088                     wait(RETRY_WAIT);
1089                 }
1090                 LOG.info("Woke up, waited {}ms for deletion of {}", (System.currentTimeMillis() - _start), iid);
1091             }
1092         }
1093
1094         @Override
1095         public void close() throws Exception {
1096             if (listenerRegistration != null) {
1097                 try {
1098                     listenerRegistration.close();
1099                 } catch (final Exception ex) {
1100                     LOG.warn("Failed to close registration {}, iid {}", listenerRegistration, iid, ex);
1101                 }
1102             }
1103             waitList.remove(this);
1104             listenerRegistration = null;
1105         }
1106     }
1107 }