Inline return values
[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.southbound.SouthboundConstants;
24 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
25 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
26 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
27 import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
28 import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI;
29 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
30 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.Ip;
31 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
32 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
34 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
35 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
36 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
37 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
38 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
41 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;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.Bridges;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
56 import org.osgi.framework.ServiceReference;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider {
61     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcWorkaroundOF13Provider.class);
62     private volatile NodeCacheManager nodeCacheManager;
63     private volatile Southbound southbound;
64     private volatile ISfcClassifierService sfcClassifierService;
65     private static final short SFC_TABLE = 150;
66     private static final int GPE_PORT = 6633;
67     private static final String NETWORK_TYPE_VXLAN = "vxlan";
68     private MdsalUtils mdsalUtils;
69     private SfcUtils sfcUtils;
70     private static final String VXGPE = "vxgpe";
71     private static final String TUNNEL_DST = "192.168.120.31";
72     private static final String TUNNEL_VNID = "10";
73     public static final String TUNNEL_ENDPOINT_KEY = "local_ip";
74
75     public NetvirtSfcWorkaroundOF13Provider(final DataBroker dataBroker, MdsalUtils mdsalUtils, SfcUtils sfcUtils) {
76         Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
77         Preconditions.checkNotNull(mdsalUtils, "Input mdsalUtils cannot be NULL!");
78         Preconditions.checkNotNull(sfcUtils, "Input sfcUtils cannot be NULL!");
79
80         this.mdsalUtils = mdsalUtils;
81         this.sfcUtils = sfcUtils;
82         //this.setDependencies(null);
83     }
84
85     public void setSfcClassifierService(ISfcClassifierService sfcClassifierService) {
86         this.sfcClassifierService = sfcClassifierService;
87     }
88
89     @Override
90     public void addClassifierRules(Bridge bridge, Acl acl) {
91
92     }
93
94     @Override
95     public void addClassifierRules(Bridges bridges, Acl acl) {
96         Preconditions.checkNotNull(bridges, "Input bridges cannot be NULL!");
97         Preconditions.checkNotNull(acl, "Input acl cannot be NULL!");
98     }
99
100     @Override
101     public void removeClassifierRules(Sff sff, Acl acl) {
102
103     }
104
105     @Override
106     public void addClassifierRules(Acl acl) {
107         String aclName = acl.getAclName();
108         Classifiers classifiers = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, sfcUtils.getClassifierIid());
109         if (classifiers == null) {
110             LOG.debug("addClassifierRules: No Classifiers found");
111             return;
112         }
113
114         LOG.debug("addClassifierRules: Classifiers: {}", classifiers);
115         for (Classifier classifier : classifiers.getClassifier()) {
116             if (classifier.getAcl().equals(aclName)) {
117                 for (Ace ace : acl.getAccessListEntries().getAce()) {
118                     processAclEntry(ace);
119                 }
120             }
121         }
122     }
123
124     @Override
125     public void removeClassifierRules(Acl acl) {
126
127     }
128
129     private void processAclEntry(Ace entry) {
130         Matches matches = entry.getMatches();
131         Preconditions.checkNotNull(matches, "Input bridges cannot be NULL!");
132
133         RenderedServicePath rsp = getRenderedServicePath(entry);
134         if (rsp == null) {
135             LOG.warn("Failed to get renderedServicePatch for entry: {}", entry);
136             return;
137         }
138
139         handleRenderedServicePath(rsp, entry);
140     }
141
142     private void handleRenderedServicePathOld(RenderedServicePath rsp, Ace entry) {
143         LOG.info("handleRenderedServicePath: RSP: {}", rsp);
144
145         Matches matches = entry.getMatches();
146         if (matches == null) {
147             LOG.warn("processAclEntry: matches not found");
148             return;
149         }
150
151         List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
152         if (pathHopList.isEmpty()) {
153             LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
154             return;
155         }
156         LOG.info("handleRenderedServicePath: pathHopList: {}", pathHopList);
157
158         final List<Node> bridgeNodes = nodeCacheManager.getBridgeNodes();
159         if (bridgeNodes == null || bridgeNodes.isEmpty()) {
160             LOG.warn("handleRenderedServicePath: There are no bridges to process");
161             return;
162         }
163         for (Node bridgeNode : bridgeNodes) {
164             OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(bridgeNode, "br-int");
165             if (ovsdbBridgeAugmentation == null) {
166                 continue;
167             }
168             long vxGpeOfPort = getOFPort(bridgeNode, VXGPE);
169             if (vxGpeOfPort == 0L) {
170                 LOG.warn("programAclEntry: Could not identify tunnel port {} -> OF ({}) on {}",
171                         VXGPE, vxGpeOfPort, bridgeNode);
172                 continue;
173             }
174             long dataPathId = southbound.getDataPathId(bridgeNode);
175             if (dataPathId == 0L) {
176                 LOG.warn("programAclEntry: Could not identify datapathId on {}", bridgeNode);
177                 continue;
178             }
179
180             // Find the first Hop within an RSP.
181             // The classifier flow needs to send all matched traffic to this first hop SFF.
182             RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
183                     .readRenderedServicePathFirstHop(rsp.getName());
184
185             LOG.info("handleRenderedServicePath: firstRspHop: {}", firstRspHop);
186             LOG.debug("handleRenderedServicePath: First Hop IPAddress = {}, Port = {}",
187                     firstRspHop.getIp().getIpv4Address().getValue(),
188                     firstRspHop.getPort().getValue());
189
190             NshUtils nshHeader = new NshUtils();
191             nshHeader.setNshMetaC1(NshUtils.convertIpAddressToLong(new Ipv4Address(TUNNEL_DST)));
192             nshHeader.setNshMetaC2(Long.parseLong(TUNNEL_VNID)); // get from register //get from
193             nshHeader.setNshNsp(rsp.getPathId());
194
195             RenderedServicePathHop firstHop = pathHopList.get(0);
196             RenderedServicePathHop lastHop = pathHopList.get(pathHopList.size()-1);
197             ServiceFunction serviceFunction =
198                     SfcProviderServiceFunctionAPI.readServiceFunction(
199                             SfName.getDefaultInstance(firstHop.getServiceFunctionName().getValue()));
200             if (serviceFunction == null) {
201                 LOG.warn("programAclEntry: Could not identify ServiceFunction {} on {}",
202                         firstHop.getServiceFunctionName().getValue(), bridgeNode);
203                 continue;
204             }
205
206             nshHeader.setNshNsi(firstHop.getServiceIndex());
207             // workaround: bypass sff and got directly to sf
208             //nshHeader.setNshTunIpDst(firstRspHop.getIp().getIpv4Address());
209             IpAddress sfIpAddress = sfcUtils.getSfIpAddress(serviceFunction);
210             String sfDplName = sfcUtils.getSfDplName(serviceFunction);
211             //sfcUtils.getSfIp(firstHop.getServiceFunctionName().getValue());
212             nshHeader.setNshTunIpDst(sfIpAddress.getIpv4Address());
213             nshHeader.setNshTunUdpPort(firstRspHop.getPort());
214             LOG.debug("handleRenderedServicePath: NSH Header = {}", nshHeader);
215
216             sfcClassifierService.programIngressClassifier(dataPathId, entry.getRuleName(), matches,
217                     nshHeader, vxGpeOfPort, true);
218
219             sfcClassifierService.program_sfEgress(dataPathId, GPE_PORT, true);
220             long sfOfPort = getSfPort(bridgeNode, sfDplName);
221
222             String sfMac = getMacFromExternalIds(bridgeNode, sfDplName);
223             String sfIpString = new String(sfIpAddress.getValue());
224             LOG.info("handleRenderedServicePath: sfDplName: {}, sfMac: {}, sfOfPort: {}, sfIpAddress: {}",
225                     sfDplName, sfMac, sfOfPort, sfIpString);
226             if (sfMac != null) { // install if the sf is on this bridge, expand when using multiple bridges
227                 sfcClassifierService.program_sfIngress(dataPathId, GPE_PORT, sfOfPort, sfIpString, sfDplName, true);
228                 sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpString, true);
229             }
230
231             short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
232             sfcClassifierService.programEgressClassifier(dataPathId, vxGpeOfPort, rsp.getPathId(),
233                     lastServiceindex, sfOfPort, 0, true);
234             sfcClassifierService.programEgressClassifierBypass(dataPathId, vxGpeOfPort, rsp.getPathId(),
235                     lastServiceindex, sfOfPort, 0, true);
236
237             sfcClassifierService.programSfcTable(dataPathId, vxGpeOfPort, SFC_TABLE, true);
238         }
239     }
240
241     private void handleRenderedServicePath(RenderedServicePath rsp, Ace entry) {
242         LOG.info("handleRenderedServicePath: RSP: {}", rsp);
243
244         Matches matches = entry.getMatches();
245         if (matches == null) {
246             LOG.warn("processAclEntry: matches not found");
247             return;
248         }
249
250         List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
251         if (pathHopList.isEmpty()) {
252             LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
253             return;
254         }
255         LOG.info("handleRenderedServicePath: pathHopList: {}", pathHopList);
256
257         RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
258                 .readRenderedServicePathFirstHop(rsp.getName());
259         LOG.info("handleRenderedServicePath: firstRspHop: {}", firstRspHop);
260
261         RenderedServicePathHop firstHop = pathHopList.get(0);
262         RenderedServicePathHop lastHop = pathHopList.get(pathHopList.size()-1);
263
264         final List<Node> bridgeNodes = nodeCacheManager.getBridgeNodes();
265         if (bridgeNodes == null || bridgeNodes.isEmpty()) {
266             LOG.warn("handleRenderedServicePath: There are no bridges to process");
267             return;
268         }
269         for (RenderedServicePathHop hop : pathHopList) {
270             for (Node bridgeNode : bridgeNodes) {
271                 // ignore bridges other than br-int
272                 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(bridgeNode, "br-int");
273                 if (ovsdbBridgeAugmentation == null) {
274                     continue;
275                 }
276                 long vxGpeOfPort = getOFPort(bridgeNode, VXGPE);
277                 if (vxGpeOfPort == 0L) {
278                     LOG.warn("programAclEntry: Could not identify gpe vtep {} -> OF ({}) on {}",
279                             VXGPE, vxGpeOfPort, bridgeNode);
280                     continue;
281                 }
282                 long dataPathId = southbound.getDataPathId(bridgeNode);
283                 if (dataPathId == 0L) {
284                     LOG.warn("programAclEntry: Could not identify datapathId on {}", bridgeNode);
285                     continue;
286                 }
287
288                 ServiceFunction serviceFunction =
289                         SfcProviderServiceFunctionAPI.readServiceFunction(firstHop.getServiceFunctionName());
290                 if (serviceFunction == null) {
291                     LOG.warn("programAclEntry: Could not identify ServiceFunction {} on {}",
292                             firstHop.getServiceFunctionName().getValue(), bridgeNode);
293                     continue;
294                 }
295                 ServiceFunctionForwarder serviceFunctionForwarder =
296                         SfcProviderServiceForwarderAPI
297                                 .readServiceFunctionForwarder(hop.getServiceFunctionForwarder());
298                 if (serviceFunctionForwarder == null) {
299                     LOG.warn("programAclEntry: Could not identify ServiceFunctionForwarder {} on {}",
300                             firstHop.getServiceFunctionName().getValue(), bridgeNode);
301                     continue;
302                 }
303
304                 handleSf(bridgeNode, serviceFunction);
305                 handleSff(bridgeNode, serviceFunctionForwarder, serviceFunction, hop, firstHop, lastHop,
306                         entry.getRuleName(), matches, vxGpeOfPort, rsp);
307                 if (firstHop == lastHop) {
308                     handleSff(bridgeNode, serviceFunctionForwarder, serviceFunction, hop, null, lastHop,
309                             entry.getRuleName(), matches, vxGpeOfPort, rsp);
310                 }
311             }
312         }
313     }
314
315     private void handleSff(Node bridgeNode, ServiceFunctionForwarder serviceFunctionForwarder,
316                            ServiceFunction serviceFunction,
317                            RenderedServicePathHop hop,
318                            RenderedServicePathHop firstHop,
319                            RenderedServicePathHop lastHop,
320                            String ruleName, Matches matches,
321                            long vxGpeOfPort, RenderedServicePath rsp) {
322         long dataPathId = southbound.getDataPathId(bridgeNode);
323
324         if (hop == firstHop) {
325             LOG.info("handleSff: first hop processing {} - {}",
326                     bridgeNode.getNodeId(), serviceFunctionForwarder.getName());
327             NshUtils nshHeader = new NshUtils();
328             nshHeader.setNshNsp(rsp.getPathId());
329             nshHeader.setNshNsi(firstHop.getServiceIndex());
330             if (isSffOnBridge(bridgeNode, serviceFunctionForwarder)) {
331                 LOG.info("handleSff: sff and bridge are the same: {} - {}, skipping first sff",
332                         bridgeNode.getNodeId(), serviceFunctionForwarder.getName());
333                 Ip ip = sfcUtils.getSfIp(serviceFunction);
334                 nshHeader.setNshTunIpDst(ip.getIp().getIpv4Address());
335                 nshHeader.setNshTunUdpPort(ip.getPort());
336             } else {
337                 LOG.info("handleSff: sff and bridge are not the same: {} - {}, sending to first sff",
338                         bridgeNode.getNodeId(), serviceFunctionForwarder.getName());
339                 Ip ip = sfcUtils.getSffIp(serviceFunctionForwarder);
340                 nshHeader.setNshTunIpDst(ip.getIp().getIpv4Address());
341                 nshHeader.setNshTunUdpPort(ip.getPort());
342             }
343             sfcClassifierService.programIngressClassifier(dataPathId, ruleName, matches,
344                     nshHeader, vxGpeOfPort, true);
345         } else if (hop == lastHop) {
346             LOG.info("handleSff: last hop processing {} - {}",
347                     bridgeNode.getNodeId(), serviceFunctionForwarder.getName());
348             short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
349             String sfDplName = sfcUtils.getSfDplName(serviceFunction);
350             long sfOfPort = getSfPort(bridgeNode, sfDplName);
351             sfcClassifierService.programEgressClassifier(dataPathId, vxGpeOfPort, rsp.getPathId(),
352                     lastServiceindex, sfOfPort, 0, true);
353             sfcClassifierService.programEgressClassifierBypass(dataPathId, vxGpeOfPort, rsp.getPathId(),
354                     lastServiceindex, sfOfPort, 0, true);
355         } else {
356             // add typical sff flows
357         }
358
359         sfcClassifierService.programSfcTable(dataPathId, vxGpeOfPort, SFC_TABLE, true);
360     }
361
362     void handleSf(Node bridgeNode, ServiceFunction serviceFunction) {
363         if (isSfOnBridge(bridgeNode, serviceFunction)) {
364             LOG.info("handleSf: sf and bridge are on the same node: {} - {}, adding workaround and arp",
365                     bridgeNode.getNodeId(), serviceFunction.getName());
366             long dataPathId = southbound.getDataPathId(bridgeNode);
367             Ip ip = sfcUtils.getSfIp(serviceFunction);
368             String sfIpAddr = String.valueOf(ip.getIp().getValue());
369             int sfIpPort = ip.getPort().getValue(); //GPE_PORT
370             String sfDplName = sfcUtils.getSfDplName(serviceFunction);
371             long sfOfPort = getSfPort(bridgeNode, sfDplName);
372             String sfMac = getMacFromExternalIds(bridgeNode, sfDplName);
373             if (sfMac == null) {
374                 LOG.warn("handleSff: could not find mac for {} on {}", sfDplName, bridgeNode);
375                 return;
376             }
377             //should be sffdplport, but they should all be the same 6633/4790
378             sfcClassifierService.program_sfEgress(dataPathId, sfIpPort, true);
379             sfcClassifierService.program_sfIngress(dataPathId, sfIpPort, sfOfPort, sfIpAddr, sfDplName, true);
380             sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpAddr, true);
381         }
382     }
383
384     private boolean isSffOnBridge(Node bridgeNode, ServiceFunctionForwarder serviceFunctionForwarder) {
385         String local_ip = "";
386         Ip ip = sfcUtils.getSffIp(serviceFunctionForwarder);
387         Node ovsdbNode = southbound.readOvsdbNode(bridgeNode);
388         if (ovsdbNode != null) {
389             OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
390             if (ovsdbNodeAugmentation != null && ovsdbNodeAugmentation.getOpenvswitchOtherConfigs() != null) {
391                 southbound.getOtherConfig(ovsdbNode, OvsdbTables.OPENVSWITCH, TUNNEL_ENDPOINT_KEY);
392             }
393
394         }
395         return local_ip.equals(String.valueOf(ip.getIp().getValue()));
396     }
397
398     private boolean isSfOnBridge(Node bridgeNode, ServiceFunction serviceFunction) {
399         String sfDplName = sfcUtils.getSfDplName(serviceFunction);
400         long sfOfPort = getSfPort(bridgeNode, sfDplName);
401         return sfOfPort != 0L;
402     }
403
404     private RenderedServicePath getRenderedServicePath (Ace entry) {
405         RenderedServicePath rsp = null;
406         RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
407         LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
408         if (sfcRedirect == null) {
409             LOG.warn("processAClEntry: sfcRedirect is null");
410             return null;
411         }
412
413         if (sfcRedirect.getRspName() != null) {
414             rsp = getRenderedServicePathFromRsp(sfcRedirect.getRspName());
415         } else if (sfcRedirect.getSfpName() != null) {
416             LOG.warn("getRenderedServicePath: sfp not handled yet");
417         } else {
418             rsp = getRenderedServicePathFromSfc(entry);
419         }
420         LOG.info("getRenderedServicePath: rsp: {}", rsp);
421         return rsp;
422     }
423
424     private RenderedServicePath getRenderedServicePathFromRsp(String rspName) {
425         return sfcUtils.getRsp(rspName);
426     }
427
428     private RenderedServicePath getRenderedServicePathFromSfc (Ace entry) {
429         RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
430         LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
431         if (sfcRedirect == null) {
432             LOG.warn("processAClEntry: sfcRedirect is null");
433             return null;
434         }
435
436         String sfcName = sfcRedirect.getSfcName();
437         ServiceFunctionPath sfp = sfcUtils.getSfp(sfcName);
438         if (sfp == null || sfp.getName() == null) {
439             LOG.warn("There is no configured SFP with sfcName = {}; so skip installing the ACL entry!!", sfcName);
440             return null;
441         }
442
443         LOG.debug("Processing Redirect to SFC = {}, SFP = {}", sfcName, sfp);
444         // If RSP doesn't exist, create an RSP.
445         String sfpName = sfp.getName().getValue();
446         RenderedServicePath rsp = sfcUtils.getRspforSfp(sfpName);
447         String rspName = sfp.getName().getValue() + "_rsp";
448         if (rsp == null) {
449             LOG.info("No configured RSP corresponding to SFP = {}, Creating new RSP = {}", sfpName, rspName);
450             CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder()
451                     .setParentServiceFunctionPath(sfpName)
452                     .setName(rspName)
453                     .setSymmetric(sfp.isSymmetric())
454                     .build();
455             rsp = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, rspInput);
456             if (rsp == null) {
457                 LOG.warn("failed to add RSP");
458                 return null;
459             }
460
461             // If SFP is symmetric, create RSP in the reverse direction.
462             if (sfp.isSymmetric()) {
463                 LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName);
464                 String rspNameRev = rspName + "-Reverse";
465                 RenderedServicePath rspReverse = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
466                         sfcUtils.getRspId(rspNameRev));
467                 if (rspReverse == null) {
468                     rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
469                     if (rspReverse == null) {
470                         LOG.warn("failed to add reverse RSP");
471                         return null;
472                     }
473                 }
474             }
475         }
476         return rsp;
477     }
478
479     // loop through all ports looking for vxlan types, skip vxgpe, keep the rest
480     // first pass we only have two tunnels: one for normal vxlan and the other for gpe
481     // so just return the first non-gpe vxlan port
482     private long getTunnelOfPort(Node bridgeNode, String vxGpePortName) {
483         long port = 0L;
484         List<OvsdbTerminationPointAugmentation> ovsdbTerminationPointAugmentations =
485                 southbound.getTerminationPointsOfBridge(bridgeNode);
486         if (!ovsdbTerminationPointAugmentations.isEmpty()) {
487             for (OvsdbTerminationPointAugmentation terminationPointAugmentation :
488                     ovsdbTerminationPointAugmentations) {
489                 if (terminationPointAugmentation.getInterfaceType() ==
490                         SouthboundConstants.OVSDB_INTERFACE_TYPE_MAP.get(NETWORK_TYPE_VXLAN)) {
491                     if (!terminationPointAugmentation.getName().equals(vxGpePortName)) {
492                         port = terminationPointAugmentation.getOfport();
493                         break;
494                     }
495                 }
496             }
497         }
498         return port;
499     }
500
501     private long getSfPort(Node bridgeNode, String sfPortName) {
502         return getOFPort(bridgeNode, sfPortName);
503     }
504
505     private long getOFPort(Node bridgeNode, String portName) {
506         long ofPort = 0L;
507         OvsdbTerminationPointAugmentation port =
508                 southbound.extractTerminationPointAugmentation(bridgeNode, portName);
509         if (port != null) {
510             ofPort = southbound.getOFPort(port);
511         }
512         if (ofPort == 0L) {
513             for (int i = 0; i < 5; i++) {
514                 LOG.info("Looking for ofPort {}, try: {}", portName, i);
515                 if (ofPort == 0L) {
516                     TerminationPoint tp = southbound.readTerminationPoint(bridgeNode, null, portName);
517                     if (tp != null) {
518                         port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
519                         if (port != null) {
520                             ofPort = southbound.getOFPort(port);
521                             break;
522                         }
523                     }
524                 }
525                 try {
526                     Thread.sleep(1000);
527                 } catch (InterruptedException e) {
528                     e.printStackTrace();
529                 }
530             }
531         }
532         return ofPort;
533     }
534
535     private String getMacFromOptions(Node bridgeNode, String portName) {
536         String mac = null;
537         OvsdbTerminationPointAugmentation port = southbound.extractTerminationPointAugmentation(bridgeNode, portName);
538         LOG.info("getMac: portName: {}, bridgeNode: {},,, port: {}", portName, bridgeNode, port);
539         if (port != null && port.getOptions() != null) {
540             //mac = southbound.getOptionsValue(port.getOptions(), EXTERNAL_ID_VM_MAC);
541             for (Options option : port.getOptions()) {
542                 LOG.info("getMac: option: {}", option);
543                 if (option.getOption().equals(Constants.EXTERNAL_ID_VM_MAC)) {
544                     mac = option.getValue();
545                     break;
546                 }
547             }
548         }
549         return mac;
550     }
551
552     private String getMacFromExternalIds(Node bridgeNode, String portName) {
553         String mac = null;
554         OvsdbTerminationPointAugmentation port = southbound.getTerminationPointOfBridge(bridgeNode, portName);
555         LOG.info("getMac: portName: {}, bridgeNode: {},,, port: {}", portName, bridgeNode, port);
556         if (port != null && port.getInterfaceExternalIds() != null) {
557             mac = southbound.getInterfaceExternalIdsValue(port, Constants.EXTERNAL_ID_VM_MAC);
558         }
559         return mac;
560     }
561
562     @Override
563     public void setDependencies(ServiceReference serviceReference) {
564         nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
565         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
566         sfcClassifierService =
567                 (ISfcClassifierService) ServiceHelper.getGlobalInstance(ISfcClassifierService.class, this);
568         LOG.info("sfcClassifierService= {}", sfcClassifierService);
569     }
570 }