Update .gitreview for new repo
[netvirt.git] / openstack / net-virt-sfc / impl / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / sfc / standalone / openflow13 / NetvirtSfcStandaloneOF13Provider.java
1 /*
2  * Copyright (c) 2015 Dell, 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.standalone.openflow13;
10
11 import com.google.common.base.Preconditions;
12
13 import com.google.common.collect.Iterables;
14 import java.util.List;
15 import java.util.StringTokenizer;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
20 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
21 import org.opendaylight.ovsdb.openstack.netvirt.sfc.INetvirtSfcOF13Provider;
22 import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
23 import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
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.SfcProviderServicePathAPI;
28 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
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.RenderedServicePaths;
32 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
33 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
34 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathKey;
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.sfp.rev140701.ServiceFunctionPaths;
37 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
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;
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.Matches;
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.ace.type.AceIp;
42 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.ace.type.ace.ip.ace.ip.version.AceIpv4;
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.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
51 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
52 import org.osgi.framework.ServiceReference;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 /**
57  * Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
58  * @author Arun Yerra
59  */
60 public class NetvirtSfcStandaloneOF13Provider implements INetvirtSfcOF13Provider {
61     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcStandaloneOF13Provider.class);
62     private static final short TABLE_0_CLASSIFIER = 0;
63     private static final short TABLE_3_INGR_ACL = 50;
64
65     private volatile NodeCacheManager nodeCacheManager;
66     private volatile Southbound southbound;
67     private MdsalUtils mdsalUtils;
68     private SfcClassifier sfcClassifier;
69
70     // TBD:: Remove these constants after integrating with openstack.
71     private static final String TUNNEL_DST = "192.168.50.75";
72     private static final String TUNNEL_VNID = "10";
73     private static final String CLIENT_PORT_NAME = "vethl-h35_2";
74     private static final String SERVER_PORT_NAME = "vethl-h35_4";
75     private static final String CLIENT_GPE_PORT_NAME = "sw1-vxlangpe-0";
76     private static final String SERVER_GPE_PORT_NAME = "sw6-vxlangpe-0";
77     private static final String INTERFACE_TYPE_VXLAN_GPE = "vxlangpe";
78
79     /**
80      * {@link NetvirtSfcStandaloneOF13Provider} constructor.
81      * @param dataBroker MdSal {@link DataBroker}
82      */
83     public NetvirtSfcStandaloneOF13Provider(final DataBroker dataBroker) {
84         Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
85         mdsalUtils = new MdsalUtils(dataBroker);
86         //this.setDependencies(null);
87         sfcClassifier = new SfcClassifier(dataBroker, southbound, mdsalUtils);
88     }
89
90     public void removeClassifierRules(Sff sff, Acl acl) {
91         // TODO Auto-generated method stub
92     }
93
94     @Override
95     public void addClassifierRules(Acl acl) {
96         String aclName = acl.getAclName();
97         Classifiers classifiers = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, getClassifierIid());
98         if (classifiers == null) {
99             LOG.debug("add: No Classifiers found");
100             return;
101         }
102
103         LOG.debug("add: Classifiers: {}", classifiers);
104         for (Classifier classifier : classifiers.getClassifier()) {
105             if (classifier.getAcl().equals(aclName)) {
106                 if (classifier.getBridges() != null) {
107                     addClassifierRules(classifier.getBridges(), acl);
108                 }
109             }
110         }
111     }
112
113     @Override
114     public void removeClassifierRules(Acl acl) {
115         String aclName = acl.getAclName();
116         Classifiers classifiers = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, getClassifierIid());
117         if (classifiers != null) {
118             for (Classifier classifier : classifiers.getClassifier()) {
119                 if (classifier.getAcl().equalsIgnoreCase(aclName)) {
120                     if (classifier.getSffs() != null) {
121                         for (Sff sff : classifier.getSffs().getSff()) {
122                             removeClassifierRules(sff, acl);
123                         }
124                     }
125                 }
126             }
127         }
128     }
129
130     @Override
131     public void setSfcClassifierService(ISfcClassifierService sfcClassifierService) {
132
133     }
134
135     @Override
136     public void addClassifierRules(Bridge bridge, Acl acl) {
137
138     }
139
140     @Override
141     public void addClassifierRules(Bridges bridges, Acl acl) {
142         Preconditions.checkNotNull(bridges, "Input bridges cannot be NULL!");
143         Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!");
144
145         for (Ace ace : acl.getAccessListEntries().getAce()) {
146             processAclEntry(ace, bridges, true);
147         }
148     }
149
150     private void processAclEntry(Ace entry, Bridges bridges, boolean write) {
151         Matches matches = entry.getMatches();
152         if (matches == null) {
153             LOG.warn("processAclEntry: matches not found");
154             return;
155         }
156
157         RenderedServicePath rsp = getRenderedServicePath(entry);
158         if (rsp == null) {
159             LOG.warn("Failed to get renderedServicePatch for entry: {}", entry);
160             return;
161         }
162
163         LOG.info("processAclEntry: RSP: {}", rsp);
164         List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
165         if (pathHopList.isEmpty()) {
166             LOG.warn("Service Path = {} has empty hops!!", rsp.getName());
167             return;
168         }
169
170         for (Bridge bridge : bridges.getBridge()) {
171             if (bridge.getDirection().getIntValue() == 0) {
172                 Node bridgeNode = getBridgeNode(bridge.getName());
173                 if (bridgeNode == null) {
174                     LOG.debug("processAclEntry: bridge {} not yet configured. Skip processing !!", bridge.getName());
175                     continue;
176                 }
177
178                 long tunnelOfPort = southbound.getOFPort(bridgeNode, CLIENT_GPE_PORT_NAME);
179                 if (tunnelOfPort == 0L) {
180                     LOG.error("programAclEntry: Could not identify tunnel port {} -> OF ({}) on {}",
181                             CLIENT_GPE_PORT_NAME, tunnelOfPort, bridgeNode);
182                     return;
183                 }
184
185                 long localOfPort = southbound.getOFPort(bridgeNode, CLIENT_PORT_NAME);
186                 if (localOfPort == 0L) {
187                     LOG.error("programAclEntry: Could not identify local port {} -> OF ({}) on {}",
188                             CLIENT_GPE_PORT_NAME, localOfPort, bridgeNode);
189                     return;
190                 }
191
192                 // Find the first Hop within an RSP.
193                 // The classifier flow needs to send all matched traffic to this first hop SFF.
194                 RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
195                         .readRenderedServicePathFirstHop(new RspName(rsp.getName()));
196
197                 LOG.debug("First Hop IPAddress = {}, Port = {}", firstRspHop.getIp().getIpv4Address().getValue(),
198                         firstRspHop.getPort().getValue());
199
200                 NshUtils nshHeader = new NshUtils();
201                 // C1 is the normal overlay dest ip and c2 is the vnid
202                 // Hardcoded for now, netvirt integration will have those values
203                 nshHeader.setNshMetaC1(NshUtils.convertIpAddressToLong(new Ipv4Address(TUNNEL_DST)));
204                 nshHeader.setNshMetaC2(Long.parseLong(TUNNEL_VNID));
205                 nshHeader.setNshNsp(rsp.getPathId());
206
207                 RenderedServicePathHop firstHop = pathHopList.get(0);
208                 nshHeader.setNshNsi(firstHop.getServiceIndex());
209                 nshHeader.setNshTunIpDst(firstRspHop.getIp().getIpv4Address());
210                 nshHeader.setNshTunUdpPort(firstRspHop.getPort());
211                 LOG.debug("The Nsh Header = {}", nshHeader);
212
213                 handleLocalInPort(southbound.getDataPathId(bridgeNode), rsp.getPathId().toString(), localOfPort,
214                         TABLE_0_CLASSIFIER, TABLE_3_INGR_ACL, matches, true);
215
216                 handleSfcClassiferFlows(southbound.getDataPathId(bridgeNode), TABLE_3_INGR_ACL, entry.getRuleName(),
217                         matches, nshHeader, tunnelOfPort, true);
218             } else {
219                 Node bridgeNode = getBridgeNode(bridge.getName());
220                 if (bridgeNode == null) {
221                     LOG.debug("processAclEntry: bridge {} not yet configured. Skip processing !!", bridge.getName());
222                     continue;
223                 }
224
225                 long tunnelOfPort = southbound.getOFPort(bridgeNode, SERVER_GPE_PORT_NAME);
226                 if (tunnelOfPort == 0L) {
227                     LOG.error("programAclEntry: Could not identify tunnel port {} -> OF ({}) on {}",
228                             CLIENT_GPE_PORT_NAME, tunnelOfPort, bridgeNode);
229                     return;
230                 }
231
232                 long localOfPort = southbound.getOFPort(bridgeNode, SERVER_PORT_NAME);
233                 if (localOfPort == 0L) {
234                     LOG.error("programAclEntry: Could not identify local port {} -> OF ({}) on {}",
235                             CLIENT_GPE_PORT_NAME, localOfPort, bridgeNode);
236                     return;
237                 }
238
239                 RenderedServicePathHop lastRspHop = Iterables.getLast(rsp.getRenderedServicePathHop());
240
241                 LOG.debug("programAclEntry: Last Hop #: {}, nsi: {}", lastRspHop.getHopNumber().intValue(),
242                         lastRspHop.getServiceIndex().intValue() - 1);
243
244                 NshUtils nshHeader = new NshUtils();
245                 nshHeader.setNshNsp(rsp.getPathId());
246                 nshHeader.setNshNsi((short)(lastRspHop.getServiceIndex().intValue() - 1));
247                 nshHeader.setNshMetaC2(Long.parseLong(TUNNEL_VNID));
248                 LOG.debug("programAclEntry: The Nsh Header = {}", nshHeader);
249
250                 //handleLocalEgressPort(southbound.getDataPathId(bridgeNode), rsp.getPathId().toString(), localOfPort,
251                 //        TABLE_0_CLASSIFIER, TABLE_3_INGR_ACL, true);
252
253                 handleEgressSfcClassiferFlows(southbound.getDataPathId(bridgeNode),
254                         TABLE_0_CLASSIFIER, entry.getRuleName(), matches, nshHeader, tunnelOfPort, localOfPort, true);
255             }
256         }
257     }
258
259     private RenderedServicePath getRenderedServicePath (Ace entry) {
260         RenderedServicePath rsp = null;
261         RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
262         LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
263         if (sfcRedirect == null) {
264             LOG.warn("processAClEntry: sfcRedirect is null");
265             return null;
266         }
267
268         if (sfcRedirect.getRspName() != null) {
269             rsp = getRenderedServicePathFromRsp(sfcRedirect.getRspName());
270         } else if (sfcRedirect.getSfpName() != null) {
271             LOG.warn("getRenderedServicePath: sfp not handled yet");
272         } else {
273             rsp = getRenderedServicePathFromSfc(entry);
274         }
275         LOG.info("getRenderedServicePath: rsp: {}", rsp);
276         return rsp;
277     }
278
279     private RenderedServicePath getRenderedServicePathFromRsp(String rspName) {
280         return null;//getRsp(rspName);
281     }
282
283     private RenderedServicePath getRenderedServicePathFromSfc (Ace entry) {
284         RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
285         LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
286         if (sfcRedirect == null) {
287             LOG.warn("processAClEntry: sfcRedirect is null");
288             return null;
289         }
290
291         String sfcName = sfcRedirect.getSfcName();
292         ServiceFunctionPath sfp = getSfp(sfcName);
293         if (sfp == null || sfp.getName() == null) {
294             LOG.warn("There is no configured SFP with sfcName = {}; so skip installing the ACL entry!!", sfcName);
295             return null;
296         }
297
298         LOG.debug("Processing Redirect to SFC = {}, SFP = {}", sfcName, sfp);
299         // If RSP doesn't exist, create an RSP.
300         String sfpName = sfp.getName().getValue();
301         RenderedServicePath rsp = getRspforSfp(sfpName);
302         String rspName = sfp.getName().getValue() + "_rsp";
303         if (rsp == null) {
304             LOG.info("No configured RSP corresponding to SFP = {}, Creating new RSP = {}", sfpName, rspName);
305             CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder()
306                     .setParentServiceFunctionPath(sfpName)
307                     .setName(rspName)
308                     .setSymmetric(sfp.isSymmetric())
309                     .build();
310             rsp = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, rspInput);
311             if (rsp == null) {
312                 LOG.warn("failed to add RSP");
313                 return null;
314             }
315
316             // If SFP is symmetric, create RSP in the reverse direction.
317             if (sfp.isSymmetric()) {
318                 LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName);
319                 String rspNameRev = rspName + "-Reverse";
320                 RenderedServicePath rspReverse = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
321                         getRspId(rspNameRev));
322                 if (rspReverse == null) {
323                     rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
324                     if (rspReverse == null) {
325                         LOG.warn("failed to add reverse RSP");
326                         return null;
327                     }
328                 }
329             }
330         }
331         return rsp;
332     }
333
334     private void handleLocalEgressPort(long dataPathId, String s, long localOfPort, short writeTable,
335                                        short gotoTable, boolean write) {
336
337     }
338
339     private void handleEgressSfcClassiferFlows(long dataPathId, short writeTable, String ruleName,
340                                                Matches matches, NshUtils nshHeader, long tunnelOfPort,
341                                                long outOfPort, boolean write) {
342         sfcClassifier.programEgressSfcClassiferFlows(dataPathId, writeTable, ruleName, matches, nshHeader,
343                 tunnelOfPort, outOfPort, write);
344     }
345
346     private void handleSfcClassiferFlows(long dataPathId, short writeTable, String ruleName,
347                                          Matches matches, NshUtils nshHeader, long tunnelOfPort,
348                                          boolean write) {
349         sfcClassifier.programSfcClassiferFlows(dataPathId, writeTable, ruleName, matches, nshHeader,
350                 tunnelOfPort, write);
351     }
352
353     private InstanceIdentifier<RenderedServicePaths> getRspsId() {
354         return InstanceIdentifier.builder(RenderedServicePaths.class).build();
355     }
356
357     private InstanceIdentifier<RenderedServicePath> getRspId(String rspName) {
358         return InstanceIdentifier.builder(RenderedServicePaths.class)
359                 .child(RenderedServicePath.class, new RenderedServicePathKey(new RspName(rspName))).build();
360     }
361
362     public Node getBridgeNode(String bridgeName) {
363         Node nodeFound = null;
364         final List<Node> nodes = nodeCacheManager.getBridgeNodes();
365         if (nodes != null && !nodes.isEmpty()) {
366             for (Node node : nodes) {
367                 if (southbound.getBridge(node, bridgeName) != null) {
368                     nodeFound = node;
369                     break;
370                 }
371             }
372         }
373         return nodeFound;
374     }
375
376     public RenderedServicePath getRspforSfp(String sfpName) {
377         RenderedServicePath rspFound = null;
378         RenderedServicePaths rsps = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, this.getRspsId());
379         if (rsps != null) {
380             for (RenderedServicePath rsp : rsps.getRenderedServicePath()) {
381                 if (rsp.getParentServiceFunctionPath() != null) {
382                     if (rsp.getParentServiceFunctionPath().getValue().equals(sfpName)) {
383                         rspFound = rsp;
384                     }
385                 }
386             }
387         }
388         return rspFound;
389     }
390
391     public ServiceFunctionPath getSfp(String redirectSfc) {
392         ServiceFunctionPath sfpFound = null;
393         ServiceFunctionPaths sfps = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
394         if (sfps != null) {
395             for (ServiceFunctionPath sfp: sfps.getServiceFunctionPath()) {
396                 if (sfp.getServiceChainName().getValue().equalsIgnoreCase(redirectSfc)) {
397                     sfpFound = sfp;
398                 }
399             }
400         }
401         return sfpFound;
402     }
403
404 /*
405  * (TABLE:0) EGRESS VM TRAFFIC TOWARDS TEP
406  * MATCH: DESTINATION ETHERNET ADDR AND OPENFLOW INPORT
407  * INSTRUCTION: SET TUNNELID AND GOTO TABLE TUNNEL TABLE (N)
408  * TABLE=0,IN_PORT=2,DL_SRC=00:00:00:00:00:01 \
409  * ACTIONS=SET_FIELD:5->TUN_ID,GOTO_TABLE=1"
410  */
411     public String getDestIp(Matches match) {
412         if (match.getAceType() instanceof AceIp) {
413             AceIp aceIp = (AceIp)match.getAceType();
414             if (aceIp.getAceIpVersion() instanceof AceIpv4) {
415                 AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
416                 if (aceIpv4.getDestinationIpv4Network() != null) {
417                     String ipAddrPrefix = aceIpv4.getDestinationIpv4Network().getValue();
418                     return new StringTokenizer(ipAddrPrefix, "/").nextToken();
419                 }
420             }
421         }
422         return null;
423     }
424
425     public String getSourceIp(Matches match) {
426         if (match.getAceType() instanceof AceIp) {
427             AceIp aceIp = (AceIp)match.getAceType();
428             if (aceIp.getAceIpVersion() instanceof AceIpv4) {
429                 AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
430                 if (aceIpv4.getSourceIpv4Network() != null) {
431                     //String ipAddr = new StringTokenizer(ipAddrPrefix, "/").nextToken();
432                     return aceIpv4.getSourceIpv4Network().getValue();
433                 }
434             }
435         }
436         return null;
437     }
438
439     private InstanceIdentifier<Classifiers> getClassifierIid() {
440         return InstanceIdentifier.create(Classifiers.class);
441     }
442
443     public void handleLocalInPort(long dpidLong, String segmentationId, Long inPort,
444                                   short writeTable, short goToTableId, Matches matches, boolean write) {
445         sfcClassifier.programLocalInPort(dpidLong, segmentationId, inPort, writeTable, goToTableId, matches, write);
446     }
447
448     @Override
449     public void setDependencies(ServiceReference serviceReference) {
450         nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
451         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
452     }
453
454     @Override
455     public void removeRsp(RenderedServicePath change) {
456         LOG.warn("removeRsp is not implemented yet");
457     }
458
459     @Override
460     public void addRsp(RenderedServicePath change) {
461         LOG.warn("addRsp is not implemented yet");
462     }
463
464     @Override
465     public void updateRsp(RenderedServicePath change) {
466         LOG.warn("updateRsp is not implemented yet");
467     }
468 }