937494a85ea30544f57747df9d1ad1dba1d34304
[netvirt.git] / openstack / net-virt-sfc / impl / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / sfc / workaround / NetvirtSfcWorkaroundOF13Provider.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.workaround;
10
11 import com.google.common.base.Preconditions;
12 import java.util.List;
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
15 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
16 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
17 import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbTables;
18 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
19 import org.opendaylight.ovsdb.openstack.netvirt.sfc.INetvirtSfcOF13Provider;
20 import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
21 import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
22 import org.opendaylight.ovsdb.openstack.netvirt.sfc.SfcUtils;
23 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
24 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
25 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
26 import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
27 import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI;
28 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.Ip;
29 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
30 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
31 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
32 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
33 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
34 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
35 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
36 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.Bridges;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
51 import org.osgi.framework.ServiceReference;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider {
56     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcWorkaroundOF13Provider.class);
57     private volatile NodeCacheManager nodeCacheManager;
58     private volatile Southbound southbound;
59     private volatile ISfcClassifierService sfcClassifierService;
60     private static final short SFC_TABLE = 150;
61     private MdsalUtils mdsalUtils;
62     private SfcUtils sfcUtils;
63     private DataBroker dataBroker;
64     private static final String VXGPE = "vxgpe";
65     public static final String TUNNEL_ENDPOINT_KEY = "local_ip";
66
67     public NetvirtSfcWorkaroundOF13Provider(final DataBroker dataBroker, MdsalUtils mdsalUtils, SfcUtils sfcUtils) {
68         Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
69         Preconditions.checkNotNull(mdsalUtils, "Input mdsalUtils cannot be NULL!");
70         Preconditions.checkNotNull(sfcUtils, "Input sfcUtils cannot be NULL!");
71
72         this.dataBroker = dataBroker;
73         this.mdsalUtils = mdsalUtils;
74         this.sfcUtils = sfcUtils;
75     }
76
77     public void setSfcClassifierService(ISfcClassifierService sfcClassifierService) {
78         this.sfcClassifierService = sfcClassifierService;
79     }
80
81     @Override
82     public void addClassifierRules(Bridge bridge, Acl acl) {
83
84     }
85
86     @Override
87     public void addClassifierRules(Bridges bridges, Acl acl) {
88         Preconditions.checkNotNull(bridges, "Input bridges cannot be NULL!");
89         Preconditions.checkNotNull(acl, "Input acl cannot be NULL!");
90     }
91
92     @Override
93     public void removeClassifierRules(Sff sff, Acl acl) {
94
95     }
96
97     @Override
98     public void addClassifierRules(Acl acl) {
99         for (Ace ace : acl.getAccessListEntries().getAce()) {
100             processAclEntry(ace);
101         }
102     }
103
104     @Override
105     public void removeClassifierRules(Acl acl) {
106         for (Ace ace : acl.getAccessListEntries().getAce()) {
107             RenderedServicePath rsp = getRenderedServicePath(ace);
108             if (rsp == null) {
109                 LOG.warn("Failed to get renderedServicePatch for entry: {}", ace);
110                 return;
111             }
112             sfcClassifierService.clearFlows(dataBroker, rsp.getName().getValue());
113         }
114     }
115
116     @Override
117     public void removeRsp(RenderedServicePath change) {
118         sfcClassifierService.clearFlows(dataBroker, change.getName().getValue());
119     }
120
121     @Override
122     public void addRsp(RenderedServicePath change) {
123         handleRenderedServicePath(change);
124     }
125
126     @Override
127     public void updateRsp(RenderedServicePath change) {
128         LOG.info("updateRsp not implemented yet");
129     }
130
131     private void processAclEntry(Ace entry) {
132         Matches matches = entry.getMatches();
133         Preconditions.checkNotNull(matches, "ACL Entry cannot be null!");
134
135         RenderedServicePath rsp = getRenderedServicePath(entry);
136         if (rsp == null) {
137             LOG.warn("Failed to get renderedServicePatch for entry: {}", entry);
138             return;
139         }
140
141         handleRenderedServicePath(rsp, entry);
142     }
143
144     private void handleRenderedServicePath(RenderedServicePath rsp) {
145         LOG.info("handleRenderedServicePath: RSP: {}", rsp);
146         Ace entry = getAceFromRenderedServicePath(rsp);
147         if (entry == null) {
148             LOG.warn("handleRenderedServicePath: failed to get acl entry");
149             return;
150         }
151
152         handleRenderedServicePath(rsp, entry);
153     }
154
155     private void handleRenderedServicePath(RenderedServicePath rsp, Ace entry) {
156         LOG.info("handleRenderedServicePath: RSP: {}, Ace: {}", rsp, entry);
157
158         Matches matches = entry.getMatches();
159         if (matches == null) {
160             LOG.warn("processAclEntry: matches not found");
161             return;
162         }
163
164         List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
165         if (pathHopList.isEmpty()) {
166             LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
167             return;
168         }
169         LOG.info("handleRenderedServicePath: pathHopList: {}", pathHopList);
170
171         RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
172                 .readRenderedServicePathFirstHop(rsp.getName());
173         LOG.info("handleRenderedServicePath: firstRspHop: {}", firstRspHop);
174
175         RenderedServicePathHop firstHop = pathHopList.get(0);
176         RenderedServicePathHop lastHop = pathHopList.get(pathHopList.size()-1);
177
178         final List<Node> bridgeNodes = nodeCacheManager.getBridgeNodes();
179         if (bridgeNodes == null || bridgeNodes.isEmpty()) {
180             LOG.warn("handleRenderedServicePath: There are no bridges to process");
181             return;
182         }
183         for (RenderedServicePathHop hop : pathHopList) {
184             for (Node bridgeNode : bridgeNodes) {
185                 // ignore bridges other than br-int
186                 // TODO: Get bridge name from DPL, rework this loop to use DPL list
187                 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(bridgeNode, "br-int");
188                 if (ovsdbBridgeAugmentation == null) {
189                     continue;
190                 }
191                 // TODO: Get port name from the DPL
192                 long vxGpeOfPort = getOFPort(bridgeNode, VXGPE);
193                 if (vxGpeOfPort == 0L) {
194                     LOG.warn("handleRenderedServicePath: Could not identify gpe vtep {} -> OF ({}) on {}",
195                             VXGPE, vxGpeOfPort, bridgeNode);
196                     continue;
197                 }
198                 long dataPathId = southbound.getDataPathId(bridgeNode);
199                 if (dataPathId == 0L) {
200                     LOG.warn("handleRenderedServicePath: Could not identify datapathId on {}", bridgeNode);
201                     continue;
202                 }
203
204                 ServiceFunction serviceFunction =
205                         SfcProviderServiceFunctionAPI.readServiceFunction(firstHop.getServiceFunctionName());
206                 if (serviceFunction == null) {
207                     LOG.warn("handleRenderedServicePath: Could not identify ServiceFunction {} on {}",
208                             firstHop.getServiceFunctionName().getValue(), bridgeNode);
209                     continue;
210                 }
211                 ServiceFunctionForwarder serviceFunctionForwarder =
212                         SfcProviderServiceForwarderAPI
213                                 .readServiceFunctionForwarder(hop.getServiceFunctionForwarder());
214                 if (serviceFunctionForwarder == null) {
215                     LOG.warn("handleRenderedServicePath: Could not identify ServiceFunctionForwarder {} on {}",
216                             firstHop.getServiceFunctionName().getValue(), bridgeNode);
217                     continue;
218                 }
219
220                 handleSf(bridgeNode, serviceFunction, rsp);
221                 handleSff(bridgeNode, serviceFunctionForwarder, serviceFunction, hop, firstHop, lastHop,
222                         entry.getRuleName(), matches, vxGpeOfPort, rsp);
223                 if (firstHop == lastHop) {
224                     handleSff(bridgeNode, serviceFunctionForwarder, serviceFunction, hop, null, lastHop,
225                             entry.getRuleName(), matches, vxGpeOfPort, rsp);
226                 }
227             }
228         }
229     }
230
231     private void handleSff(Node bridgeNode, ServiceFunctionForwarder serviceFunctionForwarder,
232                            ServiceFunction serviceFunction,
233                            RenderedServicePathHop hop,
234                            RenderedServicePathHop firstHop,
235                            RenderedServicePathHop lastHop,
236                            String ruleName, Matches matches,
237                            long vxGpeOfPort, RenderedServicePath rsp) {
238         long dataPathId = southbound.getDataPathId(bridgeNode);
239
240         if (hop == firstHop) {
241             LOG.info("handleSff: first hop processing {} - {}",
242                     bridgeNode.getNodeId().getValue(), serviceFunctionForwarder.getName().getValue());
243             NshUtils nshHeader = new NshUtils();
244             nshHeader.setNshNsp(rsp.getPathId());
245             nshHeader.setNshNsi(firstHop.getServiceIndex());
246             Ip sffIp = sfcUtils.getSffIp(lastHop.getServiceFunctionForwarder());
247             nshHeader.setNshMetaC1(NshUtils.convertIpAddressToLong(sffIp.getIp().getIpv4Address()));
248             if (isSffOnBridge(bridgeNode, serviceFunctionForwarder)) {
249                 LOG.info("handleSff: sff and bridge are the same: {} - {}, skipping first sff",
250                         bridgeNode.getNodeId().getValue(), serviceFunctionForwarder.getName().getValue());
251                 Ip ip = sfcUtils.getSfIp(serviceFunction);
252                 nshHeader.setNshTunIpDst(ip.getIp().getIpv4Address());
253                 nshHeader.setNshTunUdpPort(ip.getPort());
254             } else {
255                 LOG.info("handleSff: sff and bridge are not the same: {} - {}, sending to first sff",
256                         bridgeNode.getNodeId().getValue(), serviceFunctionForwarder.getName().getValue());
257                 Ip ip = sfcUtils.getSffIp(serviceFunctionForwarder);
258                 nshHeader.setNshTunIpDst(ip.getIp().getIpv4Address());
259                 nshHeader.setNshTunUdpPort(ip.getPort());
260             }
261             sfcClassifierService.programIngressClassifier(dataPathId, ruleName, matches,
262                     rsp.getPathId(), rsp.getStartingIndex(),
263                     nshHeader, vxGpeOfPort, rsp.getName().getValue(), true);
264         } else if (hop == lastHop) {
265             LOG.info("handleSff: last hop processing {} - {}",
266                     bridgeNode.getNodeId().getValue(), serviceFunctionForwarder.getName().getValue());
267             short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
268             String sfDplName = sfcUtils.getSfDplName(serviceFunction);
269             long sfOfPort = getSfPort(bridgeNode, sfDplName);
270             // TODO: Coexistence: SFC flows should take this using new egressTable REST
271             sfcClassifierService.programEgressClassifier(dataPathId, vxGpeOfPort, rsp.getPathId(),
272                     lastServiceindex, sfOfPort, 0, rsp.getName().getValue(), true);
273             // TODO: Coexistence: This flow should like like one above, change port, add reg0=1, resubmit
274             sfcClassifierService.programEgressClassifierBypass(dataPathId, vxGpeOfPort, rsp.getPathId(),
275                     lastServiceindex, sfOfPort, 0, rsp.getName().getValue(), true);
276         } else {
277             // add typical sff flows
278         }
279
280         // TODO: Coexistence: SFC flows should take this using new tableOffset REST
281         //sfcClassifierService.programSfcTable(dataPathId, vxGpeOfPort, SFC_TABLE, true);
282     }
283
284     void handleSf(Node bridgeNode, ServiceFunction serviceFunction, RenderedServicePath rsp) {
285         if (isSfOnBridge(bridgeNode, serviceFunction)) {
286             LOG.info("handleSf: sf and bridge are on the same node: {} - {}, adding workaround and arp",
287                     bridgeNode.getNodeId().getValue(), serviceFunction.getName().getValue());
288             long dataPathId = southbound.getDataPathId(bridgeNode);
289             Ip ip = sfcUtils.getSfIp(serviceFunction);
290             String sfIpAddr = String.valueOf(ip.getIp().getValue());
291             int sfIpPort = ip.getPort().getValue(); //GPE_PORT
292             String sfDplName = sfcUtils.getSfDplName(serviceFunction);
293             long sfOfPort = getSfPort(bridgeNode, sfDplName);
294             String sfMac = getMacFromExternalIds(bridgeNode, sfDplName);
295             if (sfMac == null) {
296                 LOG.warn("handleSff: could not find mac for {} on {}", sfDplName, bridgeNode);
297                 return;
298             }
299             //should be sffdplport, but they should all be the same 6633/4790
300             // TODO: Coexistence: SFC flows should take this using new sf dpl augmentation
301             //sfcClassifierService.program_sfEgress(dataPathId, sfIpPort, true);
302             //sfcClassifierService.program_sfIngress(dataPathId, sfIpPort, sfOfPort, sfIpAddr, sfDplName, true);
303             sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpAddr,
304                     rsp.getName().getValue(), true);
305         } else {
306             LOG.info("handleSf: sf and bridge are not on the same node: {} - {}, do nothing",
307                     bridgeNode.getNodeId().getValue(), serviceFunction.getName().getValue());
308         }
309     }
310
311     private boolean isSffOnBridge(Node bridgeNode, ServiceFunctionForwarder serviceFunctionForwarder) {
312         String localIp = "";
313         Ip ip = sfcUtils.getSffIp(serviceFunctionForwarder);
314         Node ovsdbNode = southbound.readOvsdbNode(bridgeNode);
315         if (ovsdbNode != null) {
316             localIp = getLocalip(ovsdbNode);
317         }
318         LOG.info("isSffOnBridge: {}: {}, localIp: {}, sff ip: {}",
319                 bridgeNode.getNodeId().getValue(),
320                 localIp.equals(String.valueOf(ip.getIp().getValue())),
321                 localIp, ip.getIp().getValue());
322         return localIp.equals(String.valueOf(ip.getIp().getValue()));
323     }
324
325     private String getLocalip(Node ovsdbNode) {
326         Preconditions.checkNotNull(ovsdbNode, "The ovsdbNode was null");
327         String localIp = null;
328         if (ovsdbNode != null) {
329             OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
330             if (ovsdbNodeAugmentation != null && ovsdbNodeAugmentation.getOpenvswitchOtherConfigs() != null) {
331                 localIp = southbound.getOtherConfig(ovsdbNode, OvsdbTables.OPENVSWITCH, TUNNEL_ENDPOINT_KEY);
332             }
333         }
334         if (localIp == null) {
335             LOG.warn("local_ip was not found for node: {}", ovsdbNode);
336             localIp = "";
337         }
338         return localIp;
339     }
340
341     private boolean isSfOnBridge(Node bridgeNode, ServiceFunction serviceFunction) {
342         String sfDplName = sfcUtils.getSfDplName(serviceFunction);
343         long sfOfPort = getSfPort(bridgeNode, sfDplName);
344         LOG.info("isSfOnBridge: {}: {}, sfOfPort: {}", bridgeNode.getNodeId().getValue(), sfOfPort != 0L, sfOfPort);
345         return sfOfPort != 0L;
346     }
347
348     private Ace getAceFromRenderedServicePath(RenderedServicePath rsp) {
349         Preconditions.checkNotNull(rsp, "RSP cannot be null");
350         Ace ace;
351         //String rspName = rsp.getName().getValue();
352         //String rspNameSuffix = "_rsp";
353         //String sfcName = rspName.substring(0, rspName.length() - rspNameSuffix.length());
354         //String sfcName = rsp.getServiceChainName().getValue()
355         //LOG.info("getAceFromRenderedServicePath: rsp: {}, sfcName: {}", rsp, sfcName);
356         ace = sfcUtils.getAce(rsp);
357
358         return ace;
359     }
360
361     private RenderedServicePath getRenderedServicePath (Ace entry) {
362         RenderedServicePath rsp = null;
363         RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
364         LOG.debug("getRenderedServicePath: Processing ACL entry = {} sfcRedirect = {}",
365                 entry.getRuleName(), sfcRedirect);
366         if (sfcRedirect == null) {
367             LOG.warn("getRenderedServicePath: sfcRedirect is null");
368             return null;
369         }
370
371         if (sfcRedirect.getRspName() != null) {
372             rsp = getRenderedServicePathFromRsp(sfcRedirect.getRspName());
373         } else if (sfcRedirect.getSfpName() != null) {
374             LOG.warn("getRenderedServicePath: by sfp not handled yet");
375         } else {
376             rsp = getRenderedServicePathFromSfc(entry);
377         }
378         LOG.info("getRenderedServicePath: rsp: {}", rsp);
379         return rsp;
380     }
381
382     private RenderedServicePath getRenderedServicePathFromRsp(String rspName) {
383         return sfcUtils.getRsp(rspName);
384     }
385
386     private RenderedServicePath getRenderedServicePathFromSfc (Ace entry) {
387         RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
388         LOG.debug("getRenderedServicePathFromSfc: Processing ACL entry = {} sfcRedirect = {}",
389                 entry.getRuleName(), sfcRedirect);
390         if (sfcRedirect == null) {
391             LOG.warn("getRenderedServicePathFromSfc: sfcRedirect is null");
392             return null;
393         }
394
395         String sfcName = sfcRedirect.getSfcName();
396         ServiceFunctionPath sfp = sfcUtils.getSfp(sfcName);
397         if (sfp == null || sfp.getName() == null) {
398             LOG.warn("There is no configured SFP with sfcName = {}; so skip installing the ACL entry!!", sfcName);
399             return null;
400         }
401
402         LOG.debug("getRenderedServicePathFromSfc: Processing Redirect to SFC = {}, SFP = {}", sfcName, sfp);
403         // If RSP doesn't exist, create an RSP.
404         String sfpName = sfp.getName().getValue();
405         RenderedServicePath rsp = sfcUtils.getRspforSfp(sfpName);
406         String rspName = sfp.getName().getValue() + "_rsp";
407         if (rsp == null) {
408             if (!sfcRedirect.isRenderRsp()) {
409                 LOG.info("getRenderedServicePathFromSfc: will not create RSP");
410                 return null;
411             }
412             LOG.info("getRenderedServicePathFromSfc: No configured RSP corresponding to SFP = {}, "
413                     + "Creating new RSP = {}", sfpName, rspName);
414             CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder()
415                     .setParentServiceFunctionPath(sfpName)
416                     .setName(rspName)
417                     .setSymmetric(sfp.isSymmetric())
418                     .build();
419             rsp = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, rspInput);
420             if (rsp == null) {
421                 LOG.warn("getRenderedServicePathFromSfc: failed to add RSP");
422                 return null;
423             }
424
425             // If SFP is symmetric, create RSP in the reverse direction.
426             if (sfp.isSymmetric()) {
427                 LOG.warn("getRenderedServicePathFromSfc: symmetric RSP is not supported yet");
428                 /*LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName);
429                 String rspNameRev = rspName + "-Reverse";
430                 RenderedServicePath rspReverse = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
431                         sfcUtils.getRspId(rspNameRev));
432                 if (rspReverse == null) {
433                     rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
434                     if (rspReverse == null) {
435                         LOG.warn("failed to add reverse RSP");
436                         return null;
437                     }
438                 }*/
439             }
440         }
441         return rsp;
442     }
443
444     private long getSfPort(Node bridgeNode, String sfPortName) {
445         return getOFPort(bridgeNode, sfPortName);
446     }
447
448     private long getOFPort(Node bridgeNode, String portName) {
449         long ofPort = 0L;
450         OvsdbTerminationPointAugmentation port =
451                 southbound.extractTerminationPointAugmentation(bridgeNode, portName);
452         if (port != null) {
453             ofPort = southbound.getOFPort(port);
454         }
455         if (ofPort == 0L) {
456             for (int i = 0; i < 5; i++) {
457                 LOG.info("Looking for ofPort {}, try: {}", portName, i);
458                 TerminationPoint tp = southbound.readTerminationPoint(bridgeNode, null, portName);
459                 if (tp != null) {
460                     port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
461                     if (port != null) {
462                         ofPort = southbound.getOFPort(port);
463                         LOG.info("found ofPort {} - {}, try: {}", portName, ofPort, i);
464                         break;
465                     }
466                 }
467                 try {
468                     Thread.sleep(1000);
469                 } catch (InterruptedException e) {
470                     LOG.error("Interrupted while waiting for ofPort {}", portName, e);
471                 }
472             }
473         }
474         return ofPort;
475     }
476
477     private String getMacFromExternalIds(Node bridgeNode, String portName) {
478         String mac = null;
479         OvsdbTerminationPointAugmentation port = southbound.getTerminationPointOfBridge(bridgeNode, portName);
480         LOG.info("getMac: portName: {}, bridgeNode: {},,, port: {}", portName, bridgeNode, port);
481         if (port != null && port.getInterfaceExternalIds() != null) {
482             mac = southbound.getInterfaceExternalIdsValue(port, Constants.EXTERNAL_ID_VM_MAC);
483         }
484         return mac;
485     }
486
487     @Override
488     public void setDependencies(ServiceReference serviceReference) {
489         nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
490         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
491         sfcClassifierService =
492                 (ISfcClassifierService) ServiceHelper.getGlobalInstance(ISfcClassifierService.class, this);
493         LOG.info("sfcClassifierService= {}", sfcClassifierService);
494     }
495 }