2 * Copyright (c) 2017 Ericsson Spain 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.sfc.sfc_ovs.provider.listener;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.mockito.Mockito.mock;
14 import static org.mockito.Mockito.when;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.List;
19 import org.junit.After;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
23 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
24 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
27 import org.opendaylight.sfc.ovs.listener.SfcOvsSffEntryDataListener;
28 import org.opendaylight.sfc.ovs.provider.SfcOvsUtil;
29 import org.opendaylight.sfc.provider.api.SfcDataStoreAPI;
30 import org.opendaylight.sfc.sfc_ovs.provider.AbstractDataStoreManager;
31 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffDataPlaneLocatorName;
32 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
33 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsBridgeAugmentation;
34 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsBridgeAugmentationBuilder;
35 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsLocatorOptionsAugmentation;
36 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsLocatorOptionsAugmentationBuilder;
37 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.bridge.OvsBridgeBuilder;
38 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.options.OvsOptionsBuilder;
39 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocator;
40 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocatorBuilder;
41 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocatorKey;
42 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.sff.data.plane.locator.DataPlaneLocatorBuilder;
43 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
44 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderBuilder;
45 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderKey;
46 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.IpPortLocator;
47 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.VxlanGpe;
48 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.IpBuilder;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentationBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 * Test suite for OVS SFF data listeners.
73 public class SfcOvsSffEntryDataListenerTest extends AbstractDataStoreManager {
74 private final Collection<DataTreeModification<ServiceFunctionForwarder>> collection = new ArrayList<>();
75 private DataTreeModification<ServiceFunctionForwarder> dataTreeModification;
76 private DataObjectModification<ServiceFunctionForwarder> dataObjectModification;
77 private static IpAddress testIpAddress = new IpAddress(new Ipv4Address("10.1.1.101"));
78 private static PortNumber testPort = new PortNumber(6633);
81 SfcOvsSffEntryDataListener sfcOvsSffEntryDataListener;
83 @SuppressWarnings("unchecked")
85 public void before() throws Exception {
87 dataTreeModification = mock(DataTreeModification.class);
88 dataObjectModification = mock(DataObjectModification.class);
89 sfcOvsSffEntryDataListener = new SfcOvsSffEntryDataListener(getDataBroker());
93 public void after() throws Exception {
94 sfcOvsSffEntryDataListener.close();
99 public void testAddSff_NoDpl() {
100 final ServiceFunctionForwarder sff = buildServiceFunctionForwarderNoDPL();
101 createOvsdbNodeForSff(testIpAddress, testPort);
103 when(dataTreeModification.getRootNode()).thenReturn(dataObjectModification);
104 when(dataObjectModification.getModificationType()).thenReturn(ModificationType.WRITE);
105 when(dataObjectModification.getDataBefore()).thenReturn(null);
106 when(dataObjectModification.getDataAfter()).thenReturn(sff);
108 // This will call sfcOvsSffEntryDataListener.add()
109 collection.add(dataTreeModification);
110 sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
112 NodeId ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(sff);
113 // The DPL is used to lookup the topology node
114 assertNull(ovsdbBridgeId);
115 // No terminationPoints should be created since the DPL is null
116 assertNull(getSffTerminationPoint(ovsdbBridgeId, sff));
120 public void testAddSff_WithDpl() {
121 ServiceFunctionForwarder sff = build_service_function_forwarder_withDpl();
122 // For this test, If there's a DPL, there will only ever be just 1
124 IpPortLocator ipLocator = (IpPortLocator) sff.getSffDataPlaneLocator().get(0).getDataPlaneLocator()
126 createOvsdbNodeForSff(ipLocator.getIp(), ipLocator.getPort());
128 when(dataTreeModification.getRootNode()).thenReturn(dataObjectModification);
129 when(dataObjectModification.getModificationType()).thenReturn(ModificationType.WRITE);
130 when(dataObjectModification.getDataBefore()).thenReturn(null);
131 when(dataObjectModification.getDataAfter()).thenReturn(sff);
133 // This will call sfcOvsSffEntryDataListener.add()
134 collection.add(dataTreeModification);
135 sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
137 NodeId ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(sff);
138 assertNotNull(ovsdbBridgeId);
139 assertNotNull(getSffTerminationPoint(ovsdbBridgeId, sff));
143 public void testRemoveSff() {
144 // First we need to create the ovsdbBridge and termination point
145 // Then remove the SFF and test the ovsdbBridge and termination point
151 ServiceFunctionForwarder sff = build_service_function_forwarder_withDpl();
152 // For this test, If there's a DPL, there will only ever be just 1
154 IpPortLocator ipLocator = (IpPortLocator) sff.getSffDataPlaneLocator().get(0).getDataPlaneLocator()
156 createOvsdbNodeForSff(ipLocator.getIp(), ipLocator.getPort());
158 when(dataTreeModification.getRootNode()).thenReturn(dataObjectModification);
159 when(dataObjectModification.getModificationType()).thenReturn(ModificationType.WRITE);
160 when(dataObjectModification.getDataBefore()).thenReturn(null);
161 when(dataObjectModification.getDataAfter()).thenReturn(sff);
163 // This will call sfcOvsSffEntryDataListener.add()
164 collection.add(dataTreeModification);
165 sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
167 NodeId ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(sff);
168 assertNotNull(ovsdbBridgeId);
169 assertNotNull(getSffTerminationPoint(ovsdbBridgeId, sff));
172 // Now delete the SFF
175 when(dataTreeModification.getRootNode()).thenReturn(dataObjectModification);
176 when(dataObjectModification.getModificationType()).thenReturn(ModificationType.DELETE);
177 when(dataObjectModification.getDataBefore()).thenReturn(sff);
179 // This will call sfcOvsSffEntryDataListener.remove()
180 collection.add(dataTreeModification);
181 sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
183 ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(sff);
184 assertNull(getSffTerminationPoint(ovsdbBridgeId, sff));
188 public void testUpdateSff() {
189 // First add an SFF with no DPL and check nothing special is created
190 // Then update the SFF and check that the ovsdbBridge and termination
194 // Create an SFF with no DPL
196 final ServiceFunctionForwarder originalSff = buildServiceFunctionForwarderNoDPL();
197 createOvsdbNodeForSff(testIpAddress, testPort);
199 when(dataTreeModification.getRootNode()).thenReturn(dataObjectModification);
200 when(dataObjectModification.getModificationType()).thenReturn(ModificationType.WRITE);
201 when(dataObjectModification.getDataBefore()).thenReturn(null);
202 when(dataObjectModification.getDataAfter()).thenReturn(originalSff);
204 // This will call sfcOvsSffEntryDataListener.add()
205 collection.add(dataTreeModification);
206 sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
208 NodeId ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(originalSff);
209 assertNull(ovsdbBridgeId);
210 assertNull(getSffTerminationPoint(ovsdbBridgeId, originalSff));
213 // Now update the SFF, adding a DPL
215 ServiceFunctionForwarder updatedSff = build_service_function_forwarder_withDpl();
216 // For this test, If there's a DPL, there will only ever be just 1
218 IpPortLocator ipLocator = (IpPortLocator) updatedSff.getSffDataPlaneLocator().get(0).getDataPlaneLocator()
220 createOvsdbNodeForSff(ipLocator.getIp(), ipLocator.getPort());
222 when(dataTreeModification.getRootNode()).thenReturn(dataObjectModification);
223 when(dataObjectModification.getModificationType()).thenReturn(ModificationType.SUBTREE_MODIFIED);
224 when(dataObjectModification.getDataBefore()).thenReturn(originalSff);
225 when(dataObjectModification.getDataAfter()).thenReturn(updatedSff);
227 // This will call sfcOvsSffEntryDataListener.update()
228 collection.add(dataTreeModification);
229 sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
231 ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(updatedSff);
232 assertNotNull(ovsdbBridgeId);
233 assertNotNull(getSffTerminationPoint(ovsdbBridgeId, updatedSff));
236 private void createOvsdbNodeForSff(IpAddress remoteIp, PortNumber remotePort) {
237 ConnectionInfoBuilder connInfoBuilder = new ConnectionInfoBuilder();
238 connInfoBuilder.setRemoteIp(remoteIp);
239 connInfoBuilder.setRemotePort(remotePort);
241 OvsdbNodeAugmentationBuilder ovsdbNodeAugBuilder = new OvsdbNodeAugmentationBuilder();
242 ovsdbNodeAugBuilder.setConnectionInfo(connInfoBuilder.build());
244 NodeBuilder nodeBuilder = new NodeBuilder();
245 nodeBuilder.setNodeId(new NodeId("testNode"));
246 nodeBuilder.setKey(new NodeKey(nodeBuilder.getNodeId()));
247 nodeBuilder.addAugmentation(OvsdbNodeAugmentation.class, ovsdbNodeAugBuilder.build());
249 InstanceIdentifier<Node> ovsdbTopologyIID = InstanceIdentifier.create(NetworkTopology.class)
250 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
251 .child(Node.class, nodeBuilder.getKey());
252 SfcDataStoreAPI.writePutTransactionAPI(ovsdbTopologyIID, nodeBuilder.build(), LogicalDatastoreType.OPERATIONAL);
255 private ServiceFunctionForwarder buildServiceFunctionForwarderNoDPL() {
256 ServiceFunctionForwarderBuilder sffBuilder = build_sff_common();
258 // Notice: putting the sff now will cause the listener to execute,
259 // before all test setup is completed
260 // assertTrue(SfcProviderServiceForwarderAPI.putServiceFunctionForwarder(sff));
262 return sffBuilder.build();
265 private ServiceFunctionForwarder build_service_function_forwarder_withDpl() {
266 OvsOptionsBuilder ovsOptionsBuilder = new OvsOptionsBuilder();
267 ovsOptionsBuilder.setExts("gpe");
268 ovsOptionsBuilder.setKey("flow");
269 ovsOptionsBuilder.setDstPort("6633");
270 ovsOptionsBuilder.setRemoteIp("flow");
271 SffOvsLocatorOptionsAugmentationBuilder sffOvsLocatorOptionsBuilder =
272 new SffOvsLocatorOptionsAugmentationBuilder();
273 sffOvsLocatorOptionsBuilder.setOvsOptions(ovsOptionsBuilder.build());
275 IpBuilder ipBuilder = new IpBuilder();
276 ipBuilder.setIp(testIpAddress).setPort(testPort);
278 DataPlaneLocatorBuilder sffLocatorBuilder = new DataPlaneLocatorBuilder();
279 sffLocatorBuilder.setLocatorType(ipBuilder.build()).setTransport(VxlanGpe.class);
281 SffDataPlaneLocatorBuilder locatorBuilder = new SffDataPlaneLocatorBuilder();
282 locatorBuilder.setName(new SffDataPlaneLocatorName("locator-1"))
283 .setKey(new SffDataPlaneLocatorKey(new SffDataPlaneLocatorName("locator-1")))
284 .setDataPlaneLocator(sffLocatorBuilder.build())
285 .addAugmentation(SffOvsLocatorOptionsAugmentation.class, sffOvsLocatorOptionsBuilder.build());
287 List<SffDataPlaneLocator> locatorList = new ArrayList<>();
288 locatorList.add(locatorBuilder.build());
290 ServiceFunctionForwarderBuilder sffBuilder = build_sff_common();
291 sffBuilder.setSffDataPlaneLocator(locatorList);
293 // Notice: putting the sff now will cause the listener to execute,
294 // before all test setup is completed
295 // assertTrue(SfcProviderServiceForwarderAPI.putServiceFunctionForwarder(sff));
297 return sffBuilder.build();
300 // Internal method called by either build_service_function_forwarder_noDpl()
301 // or build_service_function_forwarder_withDpl()
302 private ServiceFunctionForwarderBuilder build_sff_common() {
303 OvsBridgeBuilder ovsBridgeBuilder = new OvsBridgeBuilder();
304 ovsBridgeBuilder.setBridgeName("br-int");
305 ovsBridgeBuilder.setUuid(new Uuid("12345678-1234-1234-1234-123456789012"));
306 SffOvsBridgeAugmentationBuilder sffOvsBridgeAugBuilder = new SffOvsBridgeAugmentationBuilder();
307 sffOvsBridgeAugBuilder.setOvsBridge(ovsBridgeBuilder.build());
309 SffName name = new SffName("SFF1");
310 ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
311 sffBuilder.setName(name);
312 sffBuilder.setKey(new ServiceFunctionForwarderKey(name));
313 sffBuilder.setServiceNode(null);
314 sffBuilder.addAugmentation(SffOvsBridgeAugmentation.class, sffOvsBridgeAugBuilder.build());
319 private OvsdbTerminationPointAugmentation getSffTerminationPoint(NodeId ovsdbBridgeId,
320 ServiceFunctionForwarder sff) {
321 if (sff.getSffDataPlaneLocator() == null) {
325 InstanceIdentifier<TerminationPoint> termPointIID = SfcOvsUtil.buildOvsdbTerminationPointIID(ovsdbBridgeId,
326 sff.getSffDataPlaneLocator().get(0).getName().getValue());
327 TerminationPoint termPoint = SfcDataStoreAPI.readTransactionAPI(termPointIID,
328 LogicalDatastoreType.CONFIGURATION);
330 if (termPoint == null) {
334 return termPoint.getAugmentation(OvsdbTerminationPointAugmentation.class);