27dce01e0f514192965eb9a0510b2ce9f63f6055
[sfc.git] /
1 /**
2  * Copyright (c) 2017 Ericsson Spain 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.sfc.sfc_ovs.provider.listener;
10
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;
15
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;
66
67 /**
68  * Test suite for OVS SFF data listeners.
69  *
70  * @author ebrjohn
71  *
72  */
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);
79
80     // class under test
81     SfcOvsSffEntryDataListener sfcOvsSffEntryDataListener;
82
83     @SuppressWarnings("unchecked")
84     @Before
85     public void before() throws Exception {
86         setupSfc();
87         dataTreeModification = mock(DataTreeModification.class);
88         dataObjectModification = mock(DataObjectModification.class);
89         sfcOvsSffEntryDataListener = new SfcOvsSffEntryDataListener(getDataBroker());
90     }
91
92     @After
93     public void after() throws Exception {
94         sfcOvsSffEntryDataListener.close();
95         close();
96     }
97
98     @Test
99     public void testAddSff_NoDpl() {
100         final ServiceFunctionForwarder sff = buildServiceFunctionForwarderNoDPL();
101         createOvsdbNodeForSff(testIpAddress, testPort);
102
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);
107
108         // This will call sfcOvsSffEntryDataListener.add()
109         collection.add(dataTreeModification);
110         sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
111
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));
117     }
118
119     @Test
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
123         // SffDpl
124         IpPortLocator ipLocator = (IpPortLocator) sff.getSffDataPlaneLocator().get(0).getDataPlaneLocator()
125                 .getLocatorType();
126         createOvsdbNodeForSff(ipLocator.getIp(), ipLocator.getPort());
127
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);
132
133         // This will call sfcOvsSffEntryDataListener.add()
134         collection.add(dataTreeModification);
135         sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
136
137         NodeId ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(sff);
138         assertNotNull(ovsdbBridgeId);
139         assertNotNull(getSffTerminationPoint(ovsdbBridgeId, sff));
140     }
141
142     @Test
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
146         // get deleted
147
148         //
149         // Add the SFF
150         //
151         ServiceFunctionForwarder sff = build_service_function_forwarder_withDpl();
152         // For this test, If there's a DPL, there will only ever be just 1
153         // SffDpl
154         IpPortLocator ipLocator = (IpPortLocator) sff.getSffDataPlaneLocator().get(0).getDataPlaneLocator()
155                 .getLocatorType();
156         createOvsdbNodeForSff(ipLocator.getIp(), ipLocator.getPort());
157
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);
162
163         // This will call sfcOvsSffEntryDataListener.add()
164         collection.add(dataTreeModification);
165         sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
166
167         NodeId ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(sff);
168         assertNotNull(ovsdbBridgeId);
169         assertNotNull(getSffTerminationPoint(ovsdbBridgeId, sff));
170
171         //
172         // Now delete the SFF
173         //
174
175         when(dataTreeModification.getRootNode()).thenReturn(dataObjectModification);
176         when(dataObjectModification.getModificationType()).thenReturn(ModificationType.DELETE);
177         when(dataObjectModification.getDataBefore()).thenReturn(sff);
178
179         // This will call sfcOvsSffEntryDataListener.remove()
180         collection.add(dataTreeModification);
181         sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
182
183         ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(sff);
184         assertNull(getSffTerminationPoint(ovsdbBridgeId, sff));
185     }
186
187     @Test
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
191         // point get created
192
193         //
194         // Create an SFF with no DPL
195         //
196         final ServiceFunctionForwarder originalSff = buildServiceFunctionForwarderNoDPL();
197         createOvsdbNodeForSff(testIpAddress, testPort);
198
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);
203
204         // This will call sfcOvsSffEntryDataListener.add()
205         collection.add(dataTreeModification);
206         sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
207
208         NodeId ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(originalSff);
209         assertNull(ovsdbBridgeId);
210         assertNull(getSffTerminationPoint(ovsdbBridgeId, originalSff));
211
212         //
213         // Now update the SFF, adding a DPL
214         //
215         ServiceFunctionForwarder updatedSff = build_service_function_forwarder_withDpl();
216         // For this test, If there's a DPL, there will only ever be just 1
217         // SffDpl
218         IpPortLocator ipLocator = (IpPortLocator) updatedSff.getSffDataPlaneLocator().get(0).getDataPlaneLocator()
219                 .getLocatorType();
220         createOvsdbNodeForSff(ipLocator.getIp(), ipLocator.getPort());
221
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);
226
227         // This will call sfcOvsSffEntryDataListener.update()
228         collection.add(dataTreeModification);
229         sfcOvsSffEntryDataListener.onDataTreeChanged(collection);
230
231         ovsdbBridgeId = SfcOvsUtil.getOvsdbAugmentationNodeIdBySff(updatedSff);
232         assertNotNull(ovsdbBridgeId);
233         assertNotNull(getSffTerminationPoint(ovsdbBridgeId, updatedSff));
234     }
235
236     private void createOvsdbNodeForSff(IpAddress remoteIp, PortNumber remotePort) {
237         ConnectionInfoBuilder connInfoBuilder = new ConnectionInfoBuilder();
238         connInfoBuilder.setRemoteIp(remoteIp);
239         connInfoBuilder.setRemotePort(remotePort);
240
241         OvsdbNodeAugmentationBuilder ovsdbNodeAugBuilder = new OvsdbNodeAugmentationBuilder();
242         ovsdbNodeAugBuilder.setConnectionInfo(connInfoBuilder.build());
243
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());
248
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);
253     }
254
255     private ServiceFunctionForwarder buildServiceFunctionForwarderNoDPL() {
256         ServiceFunctionForwarderBuilder sffBuilder = build_sff_common();
257
258         // Notice: putting the sff now will cause the listener to execute,
259         // before all test setup is completed
260         // assertTrue(SfcProviderServiceForwarderAPI.putServiceFunctionForwarder(sff));
261
262         return sffBuilder.build();
263     }
264
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());
274
275         IpBuilder ipBuilder = new IpBuilder();
276         ipBuilder.setIp(testIpAddress).setPort(testPort);
277
278         DataPlaneLocatorBuilder sffLocatorBuilder = new DataPlaneLocatorBuilder();
279         sffLocatorBuilder.setLocatorType(ipBuilder.build()).setTransport(VxlanGpe.class);
280
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());
286
287         List<SffDataPlaneLocator> locatorList = new ArrayList<>();
288         locatorList.add(locatorBuilder.build());
289
290         ServiceFunctionForwarderBuilder sffBuilder = build_sff_common();
291         sffBuilder.setSffDataPlaneLocator(locatorList);
292
293         // Notice: putting the sff now will cause the listener to execute,
294         // before all test setup is completed
295         // assertTrue(SfcProviderServiceForwarderAPI.putServiceFunctionForwarder(sff));
296
297         return sffBuilder.build();
298     }
299
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());
308
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());
315
316         return sffBuilder;
317     }
318
319     private OvsdbTerminationPointAugmentation getSffTerminationPoint(NodeId ovsdbBridgeId,
320             ServiceFunctionForwarder sff) {
321         if (sff.getSffDataPlaneLocator() == null) {
322             return null;
323         }
324
325         InstanceIdentifier<TerminationPoint> termPointIID = SfcOvsUtil.buildOvsdbTerminationPointIID(ovsdbBridgeId,
326                 sff.getSffDataPlaneLocator().get(0).getName().getValue());
327         TerminationPoint termPoint = SfcDataStoreAPI.readTransactionAPI(termPointIID,
328                 LogicalDatastoreType.CONFIGURATION);
329
330         if (termPoint == null) {
331             return null;
332         }
333
334         return termPoint.getAugmentation(OvsdbTerminationPointAugmentation.class);
335     }
336 }