2 * Copyright (c) 2014, 2015 Ericsson Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.sfc.ofrenderer.processors;
11 import java.util.HashMap;
12 import java.util.Iterator;
14 import java.util.Optional;
17 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
18 import org.opendaylight.sfc.genius.util.SfcGeniusDataUtils;
19 import org.opendaylight.sfc.genius.util.SfcGeniusRpcClient;
20 import org.opendaylight.sfc.ofrenderer.openflow.SfcOfFlowProgrammerInterface;
21 import org.opendaylight.sfc.ofrenderer.utils.SfcOfBaseProviderUtils;
22 import org.opendaylight.sfc.ofrenderer.utils.SfcSynchronizer;
23 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
24 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
25 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
26 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
27 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.base.SfDataPlaneLocator;
28 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
29 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocator;
30 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
31 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.service.function.dictionary.SffSfDataPlaneLocator;
32 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.DataPlaneLocator;
33 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.Mac;
34 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.Mpls;
35 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.Nsh;
36 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.Transport;
37 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.VxlanGpe;
38 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.DpnIdType;
39 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.service.functions.service.function.sf.data.plane.locator.locator.type.LogicalInterface;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 public class SfcOfRspProcessor {
47 public static final long SFC_FLOWS = 0xdeadbeef;
48 private static final Logger LOG = LoggerFactory.getLogger(SfcOfRspProcessor.class);
49 private SfcOfFlowProgrammerInterface sfcOfFlowProgrammer;
50 private SfcOfBaseProviderUtils sfcOfProviderUtils;
51 private SfcSynchronizer sfcSynchronizer;
52 private Map<NodeId, Boolean> sffInitialized;
53 private Map<String, Class<? extends SfcRspTransportProcessorBase>> rspTransportProcessors;
54 private static final String TRANSPORT_ENCAP_SEPARATOR_STRING = "//";
56 /* Logical SFF always assumes vxlan-gpe tunnels for inter-sff transport, and eth-encapsulated
57 * NSH for sff-sf transport. The initial "LogicalInterface" prefix is used as an
58 * identifier only (that is, it is not a true transport)
60 private static final String LOGICAL_SFF_TRANSPORT_PROCESSOR_KEY =
61 LogicalInterface.class.getName() + TRANSPORT_ENCAP_SEPARATOR_STRING + Nsh.class.getName();
63 public SfcOfRspProcessor(
64 SfcOfFlowProgrammerInterface sfcOfFlowProgrammer,
65 SfcOfBaseProviderUtils sfcOfProviderUtils,
66 SfcSynchronizer sfcSynchronizer,
67 RpcProviderRegistry rpcProviderRegistry) {
68 this.sfcOfFlowProgrammer = sfcOfFlowProgrammer;
69 this.sfcOfProviderUtils = sfcOfProviderUtils;
70 this.sfcSynchronizer = sfcSynchronizer;
71 this.sffInitialized = new HashMap<>();
73 //FIXME this is temporary. SfcGeniusRpcClient will self-initialize via blueprint injection when the module is finished
74 SfcGeniusRpcClient.getInstance().initialize(rpcProviderRegistry);
76 this.rspTransportProcessors = new HashMap<>();
77 this.rspTransportProcessors.put(
78 getTransportEncapName(VxlanGpe.class.getName(), Nsh.class.getName()),
79 SfcRspProcessorNshVxgpe.class);
80 this.rspTransportProcessors.put(
81 getTransportEncapName(Mpls.class.getName(), Transport.class.getName()),
82 SfcRspProcessorMpls.class);
83 this.rspTransportProcessors.put(
84 getTransportEncapName(Mac.class.getName(), Transport.class.getName()),
85 SfcRspProcessorVlan.class);
86 this.rspTransportProcessors.put(
87 LOGICAL_SFF_TRANSPORT_PROCESSOR_KEY,
88 SfcRspProcessorLogicalSff.class);
92 * Main entry point for processing an RSP. Orchestrates logic to call
93 * different FlowProgrammer flow creation methods.
95 * @param rsp - a newly created/updated Rendered Service Path
97 public void processRenderedServicePath(RenderedServicePath rsp) {
98 // if this method takes too long, consider launching it in a thread
100 // This call blocks until the lock is obtained
101 sfcSynchronizer.lock();
103 sfcOfProviderUtils.addRsp(rsp.getPathId());
106 // Populate the SFF Connection Graph
108 SffGraph sffGraph = populateSffGraph(rsp);
109 SfcRspTransportProcessorBase transportProcessor = getTransportProcessor(sffGraph, rsp);
112 // Populate the SFF ingress and egress DPLs from the sffGraph
114 transportProcessor.processSffDpls();
117 // Internally calculate and set the RSP transport values
119 transportProcessor.setRspTransports();
122 // Now process the entries in the SFF Graph and populate the flow tables
124 SffGraph.SffGraphEntry entry = null;
125 Iterator<SffGraph.SffGraphEntry> sffGraphIter = sffGraph.getGraphEntryIterator();
126 sfcOfFlowProgrammer.setTableIndexMapper(
127 transportProcessor.getTableIndexMapper().isPresent()
128 ? transportProcessor.getTableIndexMapper().get()
130 while (sffGraphIter.hasNext()) {
131 entry = sffGraphIter.next();
132 LOG.debug("build flows of entry: {}", entry);
133 // The flows created by initializeSff dont belong to any particular RSP
134 sfcOfFlowProgrammer.setFlowRspId(SFC_FLOWS);
135 initializeSff(entry);
136 sfcOfFlowProgrammer.setFlowRspId(rsp.getPathId());
137 configureTransportIngressFlows(entry, sffGraph, transportProcessor);
138 configurePathMapperFlows(entry, sffGraph, transportProcessor);
139 configureNextHopFlows(entry, sffGraph, transportProcessor);
140 configureTransportEgressFlows(entry, sffGraph, transportProcessor);
143 // Flush the flows to the data store
144 this.sfcOfFlowProgrammer.flushFlows();
146 LOG.info("Processing complete for RSP: name [{}] Id [{}]", rsp.getName(), rsp.getPathId());
148 } catch (RuntimeException e) {
149 LOG.error("RuntimeException in processRenderedServicePath: ", e.getMessage(), e);
151 // If there were any errors, purge any remaining flows so they're not written
152 this.sfcOfFlowProgrammer.purgeFlows();
153 sfcSynchronizer.unlock();
154 sfcOfProviderUtils.removeRsp(rsp.getPathId());
159 * Deletes the OpenFlow flows associated with this Rendered Service Path.
161 * @param rsp - the Rendered Service Path to delete
163 public void deleteRenderedServicePath(RenderedServicePath rsp) {
164 Set<NodeId> clearedSffNodeIDs = sfcOfFlowProgrammer.deleteRspFlows(rsp.getPathId());
165 for(NodeId sffNodeId : clearedSffNodeIDs){
166 setSffInitialized(sffNodeId, false);
171 * Given the RSP transport type, return an Rsp Transport Processor that
172 * will call the appropriate FlowProgrammer methods.
174 * @param sffGraph - used to inject dependencies into the newly created object.
175 * @param rsp - contains the RSP transport type
177 * @return an RSP Transport Processor for the RSP.
179 public SfcRspTransportProcessorBase getTransportProcessor(SffGraph sffGraph, RenderedServicePath rsp) {
181 String transportProcessorKey = sffGraph.isUsingLogicalSFF() ?
182 LOGICAL_SFF_TRANSPORT_PROCESSOR_KEY :
183 getTransportEncapName(
184 rsp.getTransportType().getName(),
185 rsp.getSfcEncapsulation().getName());
187 Class<? extends SfcRspTransportProcessorBase> transportClass =
188 rspTransportProcessors.get(transportProcessorKey);
189 LOG.debug("getTransportProcessor :: transport [{}] encap [{} selected transport processor [{}]]",
190 rsp.getTransportType().getName(), rsp.getSfcEncapsulation(), transportClass);
191 SfcRspTransportProcessorBase transportProcessor = transportClass.newInstance();
192 transportProcessor.setFlowProgrammer(sfcOfFlowProgrammer);
193 transportProcessor.setRsp(rsp);
194 transportProcessor.setSffGraph(sffGraph);
195 transportProcessor.setSfcProviderUtils(sfcOfProviderUtils);
197 return transportProcessor;
198 } catch(Exception e) {
199 throw new RuntimeException(
200 "getTransportProcessor no processor for transport [" +
201 rsp.getTransportType().getName() +
202 "] encap [" + rsp.getSfcEncapsulation() + "] " + e);
207 * Given an RSP, create and populate an SffGraph.
209 * @param rsp - input to create the graph
210 * @return a newly populates SffGraph
212 private SffGraph populateSffGraph(RenderedServicePath rsp) {
213 SffGraph sffGraph = new SffGraph();
215 // Setting to INGRESS for the first graph entry, which is the RSP Ingress
216 SffName prevSffName = new SffName(SffGraph.INGRESS);
217 // Set to null in the first graph entry
218 DpnIdType srcDpnId = null;
220 Iterator<RenderedServicePathHop> servicePathHopIter = rsp.getRenderedServicePathHop().iterator();
221 SfName sfName = null;
222 SfName prevSfName = null;
223 String sfgName = null;
224 SffGraph.SffGraphEntry entry = null;
225 short lastServiceIndex = rsp.getStartingIndex();
227 while (servicePathHopIter.hasNext()) {
228 RenderedServicePathHop rspHop = servicePathHopIter.next();
229 SffName curSffName = rspHop.getServiceFunctionForwarder();
230 sfName = rspHop.getServiceFunctionName();
231 sfgName = rspHop.getServiceFunctionGroupName();
232 ServiceFunction sf = sfcOfProviderUtils.getServiceFunction(sfName, rsp.getPathId());
233 entry = sffGraph.addGraphEntry(prevSffName, curSffName, sfName, sfgName, rsp.getPathId(),
234 rspHop.getServiceIndex());
235 entry.setPrevSf(prevSfName);
236 lastServiceIndex = rspHop.getServiceIndex();
238 prevSffName = curSffName;
241 if (SfcGeniusDataUtils.isSfUsingALogicalInterface(sf)) {
242 String logicalInterfaceName = sfcOfProviderUtils.getSfLogicalInterfaceName(sf);
243 LOG.debug("populateSffGraph: SF uses a logical interface -> storing id for the dataplane node (interface:{})", logicalInterfaceName);
244 Optional<DpnIdType> dpnid = SfcGeniusRpcClient.getInstance().getDpnIdFromInterfaceNameFromGeniusRPC(logicalInterfaceName);
245 if (!dpnid.isPresent()) {
246 throw new RuntimeException("populateSffGraph:failed.dpnid for interface ["
247 + logicalInterfaceName + "] was not returned by genius. "
248 + "Rendered service path cannot be generated at this time");
250 LOG.debug("populateSffGraph: retrieved dpn id for SF {} :[{}] ", sf.getName(), dpnid.get());
251 entry.setDstDpnId(dpnid.get());
253 entry.setSrcDpnId(srcDpnId);
254 LOG.debug("populateSffGraph:added graph entry: [{}]", entry);
255 srcDpnId = entry.getDstDpnId();
258 // Add the final connection, which will be the RSP Egress
259 // Using the previous sfName as the SrcSf
260 entry = sffGraph.addGraphEntry(prevSffName, SffGraph.EGRESS, sfName, sfgName, rsp.getPathId(),
261 (short) (lastServiceIndex - 1));
262 entry.setPrevSf(prevSfName);
263 entry.setSrcDpnId(srcDpnId);
265 LOG.debug("populateSffGraph: added final graph entry: [{}]", entry);
270 * Call the appropriate flow creation methods on the TransportProcessor for
271 * the TransportIngress table.
273 * @param entry - data for the current flows to be created
274 * @param sffGraph - contains data for the RSP
275 * @param transportProcessor - specific TransportProcessor to call into
277 private void configureTransportIngressFlows(SffGraph.SffGraphEntry entry,
278 SffGraph sffGraph, SfcRspTransportProcessorBase transportProcessor) {
280 if (entry.getDstSff().equals(SffGraph.EGRESS)) {
284 ServiceFunctionForwarder sffDst =
285 sfcOfProviderUtils.getServiceFunctionForwarder(entry.getDstSff(), entry.getPathId());
286 SffDataPlaneLocator sffDstIngressDpl = sfcOfProviderUtils.getSffDataPlaneLocator(sffDst,
287 sffGraph.getSffIngressDpl(entry.getDstSff(), entry.getPathId()));
289 transportProcessor.configureSffTransportIngressFlow(entry, sffDstIngressDpl);
291 // Configure the SF related flows
292 if (entry.getSf() != null) {
293 ServiceFunction sf = sfcOfProviderUtils.getServiceFunction(entry.getSf(), entry.getPathId());
294 SfDataPlaneLocator sfDpl = sfcOfProviderUtils.getSfDataPlaneLocator(sf, entry.getDstSff());
295 transportProcessor.configureSfTransportIngressFlow(entry, sfDpl);
300 * Call the appropriate flow creation methods on the TransportProcessor for
301 * the PathMapper table.
303 * @param entry - data for the current flows to be created
304 * @param sffGraph - contains data for the RSP
305 * @param transportProcessor - specific TransportProcessor to call into
307 private void configurePathMapperFlows(SffGraph.SffGraphEntry entry,
308 SffGraph sffGraph, SfcRspTransportProcessorBase transportProcessor) {
310 if(entry.getDstSff().equals(SffGraph.EGRESS)) {
314 DataPlaneLocator dstHopIngressDpl = sffGraph.getHopIngressDpl(entry.getDstSff(), entry.getPathId());
316 // configure SFF-SFF-SF ingress -OR- Ingress-SFF-SF ingress flow using dstHopIngressDpl
317 transportProcessor.configureSffPathMapperFlow(entry, dstHopIngressDpl);
319 // configure the SF Ingress Flow
320 if (entry.getSf() != null) {
321 ServiceFunction sf = sfcOfProviderUtils.getServiceFunction(entry.getSf(), entry.getPathId());
322 SfDataPlaneLocator sfDpl = sfcOfProviderUtils.getSfDataPlaneLocator(sf, entry.getDstSff());
323 transportProcessor.configureSfPathMapperFlow(entry, sfDpl);
328 * Call the appropriate flow creation methods on the TransportProcessor for
331 * @param entry - data for the current flows to be created
332 * @param sffGraph - contains data for the RSP
333 * @param transportProcessor - specific TransportProcessor to call into
335 private void configureNextHopFlows(SffGraph.SffGraphEntry entry,
336 SffGraph sffGraph, SfcRspTransportProcessorBase transportProcessor) {
338 ServiceFunction sfDst = sfcOfProviderUtils.getServiceFunction(entry.getSf(), entry.getPathId());
339 SfDataPlaneLocator sfDstDpl = (sfDst == null) ? null : sfcOfProviderUtils.getSfDataPlaneLocator(sfDst, entry.getDstSff());
340 if (sfDstDpl != null) {
341 if (entry.getSrcSff().equals(SffGraph.INGRESS)) {
342 // Configure the GW-SFF-SF NextHop using sfDpl
343 transportProcessor.configureNextHopFlow(entry, (SffDataPlaneLocator) null, sfDstDpl);
345 // If its Ingress, nothing else to be done
348 ServiceFunctionForwarder sffSrc =
349 sfcOfProviderUtils.getServiceFunctionForwarder(entry.getSrcSff(), entry.getPathId());
350 SffDataPlaneLocator sffSrcEgressDpl = sfcOfProviderUtils.getSffDataPlaneLocator(sffSrc,
351 sffGraph.getSffEgressDpl(entry.getSrcSff(), entry.getPathId()));
352 // Configure the SFF-SFF-SF NextHop using sfDpl
353 transportProcessor.configureNextHopFlow(entry, sffSrcEgressDpl, sfDstDpl);
357 if (entry.getDstSff().equals(SffGraph.EGRESS)) {
358 // If dstSff is EGRESS, the SF is actually on the srcSff
359 SfDataPlaneLocator sfSrcDpl = sfcOfProviderUtils.getSfDataPlaneLocator(sfDst, entry.getSrcSff());
361 // Configure the SF-SFF-GW NextHop, we dont have the DstDpl, leaving it blank
362 transportProcessor.configureNextHopFlow(entry, sfSrcDpl, (SffDataPlaneLocator) null);
366 SfDataPlaneLocator sfSrcDpl = null;
367 if (entry.getPrevSf() != null) {
368 sfSrcDpl = sfcOfProviderUtils.getSfDataPlaneLocator(
369 sfcOfProviderUtils.getServiceFunction(entry.getPrevSf(), entry.getPathId()), entry.getSrcSff());
372 // Configure the SFF-SFF NextHop using the sfDpl and sffDstIngressDpl
373 if (sfSrcDpl != null) {
374 if ( (entry.getSrcSff().getValue().equals(entry.getDstSff().getValue()))
375 && !((entry.isIntraLogicalSFFEntry() && (!entry.getSrcDpnId().equals(entry.getDstDpnId()))))) {
376 // If the next hop is on this SFF then go straight to the next SF
377 // Also used in logical SFF, but only when both dpnids are the same (two SFs in the same compute node)
378 // Configure SF-SFF-SF NextHop on the same SFF
379 transportProcessor.configureNextHopFlow(entry, sfSrcDpl, sfDstDpl);
381 // Configure the SFF-SFF NextHop using the sfDpl and sffDstIngressDpl
382 ServiceFunctionForwarder sffDst =
383 sfcOfProviderUtils.getServiceFunctionForwarder(entry.getDstSff(), entry.getPathId());
384 SffDataPlaneLocator sffDstIngressDpl = sfcOfProviderUtils.getSffDataPlaneLocator(sffDst,
385 sffGraph.getSffIngressDpl(entry.getDstSff(), entry.getPathId()));
386 transportProcessor.configureNextHopFlow(entry, sfSrcDpl, sffDstIngressDpl);
392 * Call the appropriate flow creation methods on the TransportProcessor for
393 * the TransportEgress table.
395 * @param entry - data for the current flows to be created
396 * @param sffGraph - contains data for the RSP
397 * @param transportProcessor - specific TransportProcessor to call into
399 private void configureTransportEgressFlows(SffGraph.SffGraphEntry entry,
400 SffGraph sffGraph, SfcRspTransportProcessorBase transportProcessor) {
402 // Configure the SFF-Egress Transport Egress
403 ServiceFunctionForwarder sffSrc =
404 sfcOfProviderUtils.getServiceFunctionForwarder(entry.getSrcSff(), entry.getPathId());
405 if (entry.getDstSff().equals(SffGraph.EGRESS)) {
406 SffDataPlaneLocator sffSrcEgressDpl = sfcOfProviderUtils.getSffDataPlaneLocator(sffSrc,
407 sffGraph.getSffEgressDpl(entry.getSrcSff(), entry.getPathId()));
409 transportProcessor.configureSffTransportEgressFlow(
410 entry, sffSrcEgressDpl, null,
411 sffGraph.getPathEgressDpl(entry.getPathId()));
416 // Configure the SFF-SF Transport Egress using sfDpl
417 ServiceFunction sfDst = sfcOfProviderUtils.getServiceFunction(entry.getSf(), entry.getPathId());
418 SfDataPlaneLocator sfDstDpl = sfcOfProviderUtils.getSfDataPlaneLocator(sfDst, entry.getDstSff());
419 ServiceFunctionForwarder sffDst =
420 sfcOfProviderUtils.getServiceFunctionForwarder(entry.getDstSff(), entry.getPathId());
422 if (sfDstDpl != null) {
423 SffDataPlaneLocator sffDstDpl = null;
424 SffSfDataPlaneLocator sffSfDpl = sfcOfProviderUtils
425 .getSffSfDataPlaneLocator(sffDst, entry.getSf());
426 if (sffSfDpl != null) {
427 sffDstDpl = sfcOfProviderUtils
428 .getSffDataPlaneLocator(sffDst, sffSfDpl.getSffDplName());
430 transportProcessor.configureSfTransportEgressFlow(entry, sffDstDpl,
434 // Nothing else to be done for Ingress
435 if (entry.getSrcSff().equals(SffGraph.INGRESS)) {
439 // Configure the SFF-SFF Transport Egress using the sffDstIngressDpl
440 if ((! entry.getSrcSff().getValue().equals(entry.getDstSff().getValue()))
441 || ((entry.isIntraLogicalSFFEntry()) && (entry.getSrcDpnId() != entry.getDstDpnId()))) {
442 SffDataPlaneLocator sffDstIngressDpl = sfcOfProviderUtils.getSffDataPlaneLocator(sffDst,
443 sffGraph.getSffIngressDpl(entry.getDstSff(), entry.getPathId()));
444 SffDataPlaneLocator sffSrcEgressDpl = sfcOfProviderUtils.getSffDataPlaneLocator(sffSrc,
445 sffGraph.getSffEgressDpl(entry.getSrcSff(), entry.getPathId()));
446 // This is the HOP DPL details between srcSFF and dstSFF, for example: VLAN ID 100
447 DataPlaneLocator dstHopIngressDpl = sffGraph.getHopIngressDpl(entry.getDstSff(), entry.getPathId());
449 transportProcessor.configureSffTransportEgressFlow(
450 entry, sffSrcEgressDpl, sffDstIngressDpl, dstHopIngressDpl);
454 /* TODO what about SFG??
455 * Currently there is nobody available to maintain the Service
456 * Function Groups (SFGs) code, nor are there any tests available
458 private void configureSffEgressForGroup(SffGraph.SffGraphEntry entry, SffGraph sffGraph) {
461 private void configureGroupNextHopFlow(final SffName sffName, SffDataPlaneLocator srcSffDpl, long groupId,
462 String groupName, final long pathId, final short serviceIndex) {
469 * Initialize the SFF by creating the match any flows, if not already created.
471 * @param entry - contains the SFF and RSP id
473 private void initializeSff(SffGraph.SffGraphEntry entry) {
474 if (entry.getDstSff().equals(SffGraph.EGRESS)) {
478 String sffNodeName = sfcOfProviderUtils.getSffOpenFlowNodeName(entry.getDstSff(), entry.getPathId(), entry.getDstDpnId());
479 if (sffNodeName == null) {
480 throw new RuntimeException("initializeSff SFF [" + entry.getDstSff().getValue() + "] does not exist");
483 NodeId sffNodeId = new NodeId(sffNodeName);
484 if (!getSffInitialized(sffNodeId)) {
485 LOG.debug("Initializing SFF [{}] node [{}]", entry.getDstSff().getValue(), sffNodeName);
486 this.sfcOfFlowProgrammer.configureClassifierTableMatchAny(sffNodeName);
487 this.sfcOfFlowProgrammer.configureTransportIngressTableMatchAny(sffNodeName);
488 this.sfcOfFlowProgrammer.configurePathMapperTableMatchAny(sffNodeName);
489 this.sfcOfFlowProgrammer.configurePathMapperAclTableMatchAny(sffNodeName);
490 this.sfcOfFlowProgrammer.configureNextHopTableMatchAny(sffNodeName);
491 this.sfcOfFlowProgrammer.configureTransportEgressTableMatchAny(sffNodeName);
493 setSffInitialized(sffNodeId, true);
499 // Internal util methods
504 * Given an SFF name, determine if its been initialized yet or not.
505 * Called by initializeSff()
507 * @param sffNodeId The SFF node ID to check
508 * @return true if its been initialized, false otherwise
510 private boolean getSffInitialized(final NodeId sffNodeId) {
511 Boolean isInitialized = sffInitialized.get(sffNodeId);
513 if (isInitialized == null) {
517 return isInitialized;
521 * Set a given SFF as initialized.
522 * Called by initializeSff()
524 * @param sffNodeId - the SFF to set
525 * @param initialized - boolean value to set the SFF as
527 private void setSffInitialized(final NodeId sffNodeId, boolean initialized) {
528 // If the value is already in the map, its value will be replaced
529 sffInitialized.put(new NodeId(sffNodeId), initialized);
532 private String getTransportEncapName(final String transportName, final String encapName) {
534 new StringBuffer(transportName).
535 append(TRANSPORT_ENCAP_SEPARATOR_STRING).
537 LOG.info("getTransportEncapName :: transport [{}] encap [{}] result [{}]", transportName, encapName, sb.toString());
538 return sb.toString();