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