Merge changes I0f752636,Idd154499,Ic35fa3e8
[controller.git] / opendaylight / protocol_plugins / openflow / src / main / java / org / opendaylight / controller / protocol_plugin / openflow / internal / FlowProgrammerService.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, 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.controller.protocol_plugin.openflow.internal;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.Map;
15 import java.util.Set;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18
19 import org.eclipse.osgi.framework.console.CommandInterpreter;
20 import org.eclipse.osgi.framework.console.CommandProvider;
21 import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier;
22 import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
23 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
24 import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
25 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
26 import org.opendaylight.controller.sal.connection.IPluginOutConnectionService;
27 import org.opendaylight.controller.sal.core.ContainerFlow;
28 import org.opendaylight.controller.sal.core.IContainerAware;
29 import org.opendaylight.controller.sal.core.IContainerListener;
30 import org.opendaylight.controller.sal.core.Node;
31 import org.opendaylight.controller.sal.core.Node.NodeIDType;
32 import org.opendaylight.controller.sal.core.NodeConnector;
33 import org.opendaylight.controller.sal.core.Property;
34 import org.opendaylight.controller.sal.core.UpdateType;
35 import org.opendaylight.controller.sal.flowprogrammer.Flow;
36 import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
37 import org.opendaylight.controller.sal.match.Match;
38 import org.opendaylight.controller.sal.match.MatchType;
39 import org.opendaylight.controller.sal.utils.GlobalConstants;
40 import org.opendaylight.controller.sal.utils.HexEncode;
41 import org.opendaylight.controller.sal.utils.NodeCreator;
42 import org.opendaylight.controller.sal.utils.Status;
43 import org.opendaylight.controller.sal.utils.StatusCode;
44 import org.openflow.protocol.OFError;
45 import org.openflow.protocol.OFFlowMod;
46 import org.openflow.protocol.OFFlowRemoved;
47 import org.openflow.protocol.OFMessage;
48 import org.openflow.protocol.OFPort;
49 import org.openflow.protocol.OFType;
50 import org.openflow.protocol.action.OFAction;
51 import org.osgi.framework.BundleContext;
52 import org.osgi.framework.FrameworkUtil;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 /**
57  * Represents the openflow plugin component in charge of programming the flows
58  * the flow programming and relay them to functional modules above SAL.
59  */
60 public class FlowProgrammerService implements IPluginInFlowProgrammerService,
61         IMessageListener, IContainerListener, IInventoryShimExternalListener,
62         CommandProvider, IContainerAware {
63     private static final Logger log = LoggerFactory
64             .getLogger(FlowProgrammerService.class);
65     private IController controller;
66     private ConcurrentMap<String, IFlowProgrammerNotifier> flowProgrammerNotifiers;
67     private Map<String, Set<NodeConnector>> containerToNc;
68     private ConcurrentMap<Long, Map<Integer, Long>> xid2rid;
69     private int barrierMessagePriorCount = getBarrierMessagePriorCount();
70     private IPluginOutConnectionService connectionOutService;
71
72     public FlowProgrammerService() {
73         controller = null;
74         flowProgrammerNotifiers = new ConcurrentHashMap<String, IFlowProgrammerNotifier>();
75         containerToNc = new HashMap<String, Set<NodeConnector>>();
76         xid2rid = new ConcurrentHashMap<Long, Map<Integer, Long>>();
77     }
78
79     public void setController(IController core) {
80         this.controller = core;
81     }
82
83     public void unsetController(IController core) {
84         if (this.controller == core) {
85             this.controller = null;
86         }
87     }
88
89     void setIPluginOutConnectionService(IPluginOutConnectionService s) {
90         connectionOutService = s;
91     }
92
93     void unsetIPluginOutConnectionService(IPluginOutConnectionService s) {
94         if (connectionOutService == s) {
95             connectionOutService = null;
96         }
97     }
98
99     public void setFlowProgrammerNotifier(Map<String, ?> props,
100             IFlowProgrammerNotifier s) {
101         if (props == null || props.get("containerName") == null) {
102             log.error("Didn't receive the service correct properties");
103             return;
104         }
105         String containerName = (String) props.get("containerName");
106         this.flowProgrammerNotifiers.put(containerName, s);
107     }
108
109     public void unsetFlowProgrammerNotifier(Map<String, ?> props,
110             IFlowProgrammerNotifier s) {
111         if (props == null || props.get("containerName") == null) {
112             log.error("Didn't receive the service correct properties");
113             return;
114         }
115         String containerName = (String) props.get("containerName");
116         if (this.flowProgrammerNotifiers != null
117                 && this.flowProgrammerNotifiers.containsKey(containerName)
118                 && this.flowProgrammerNotifiers.get(containerName) == s) {
119             this.flowProgrammerNotifiers.remove(containerName);
120         }
121     }
122
123     /**
124      * Function called by the dependency manager when all the required
125      * dependencies are satisfied
126      *
127      */
128     void init() {
129         this.controller.addMessageListener(OFType.FLOW_REMOVED, this);
130         this.controller.addMessageListener(OFType.ERROR, this);
131         registerWithOSGIConsole();
132     }
133
134     /**
135      * Function called by the dependency manager when at least one dependency
136      * become unsatisfied or when the component is shutting down because for
137      * example bundle is being stopped.
138      *
139      */
140     void destroy() {
141     }
142
143     /**
144      * Function called by dependency manager after "init ()" is called and after
145      * the services provided by the class are registered in the service registry
146      *
147      */
148     void start() {
149     }
150
151     /**
152      * Function called by the dependency manager before the services exported by
153      * the component are unregistered, this will be followed by a "destroy ()"
154      * calls
155      *
156      */
157     void stop() {
158     }
159
160     @Override
161     public Status addFlow(Node node, Flow flow) {
162         if (!connectionOutService.isLocal(node)) {
163             log.debug("Add flow will not be processed in a non-master controller for node " + node);
164             return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node);
165         }
166
167         return addFlowInternal(node, flow, 0);
168     }
169
170     @Override
171     public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) {
172         if (!connectionOutService.isLocal(node)) {
173             log.debug("Modify flow will not be processed in a non-master controller for node " + node);
174             return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node);
175         }
176
177         return modifyFlowInternal(node, oldFlow, newFlow, 0);
178     }
179
180     @Override
181     public Status removeFlow(Node node, Flow flow) {
182         if (!connectionOutService.isLocal(node)) {
183             log.debug("Remove flow will not be processed in a non-master controller for node " + node);
184             return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node);
185         }
186
187         return removeFlowInternal(node, flow, 0);
188     }
189
190     @Override
191     public Status addFlowAsync(Node node, Flow flow, long rid) {
192         if (!connectionOutService.isLocal(node)) {
193             log.debug("Add flow Async will not be processed in a non-master controller for node " + node);
194             return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node);
195         }
196
197         return addFlowInternal(node, flow, rid);
198     }
199
200     @Override
201     public Status modifyFlowAsync(Node node, Flow oldFlow, Flow newFlow,
202             long rid) {
203         if (!connectionOutService.isLocal(node)) {
204             log.debug("Modify flow async will not be processed in a non-master controller for node " + node);
205             return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node);
206         }
207
208         return modifyFlowInternal(node, oldFlow, newFlow, rid);
209     }
210
211     @Override
212     public Status removeFlowAsync(Node node, Flow flow, long rid) {
213         if (!connectionOutService.isLocal(node)) {
214             log.debug("Remove flow async will not be processed in a non-master controller for node " + node);
215             return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node);
216         }
217
218         return removeFlowInternal(node, flow, rid);
219     }
220
221     private Status addFlowInternal(Node node, Flow flow, long rid) {
222         String action = "add";
223         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
224             return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
225                     action, "Invalid node type"));
226         }
227
228         if (controller != null) {
229             ISwitch sw = controller.getSwitch((Long) node.getID());
230             if (sw != null) {
231                 FlowConverter x = new FlowConverter(flow);
232                 OFMessage msg = x.getOFFlowMod(OFFlowMod.OFPFC_ADD, null);
233
234                 Object result;
235                 if (rid == 0) {
236                     /*
237                      * Synchronous message send. Each message is followed by a
238                      * Barrier message.
239                      */
240                     result = sw.syncSend(msg);
241                 } else {
242                     /*
243                      * Message will be sent asynchronously. A Barrier message
244                      * will be inserted automatically to synchronize the
245                      * progression.
246                      */
247                     result = asyncMsgSend(node, sw, msg, rid);
248                 }
249                 return getStatusInternal(result, action, rid);
250             } else {
251                 return new Status(StatusCode.GONE, errorString("send", action,
252                         "Switch is not available"));
253             }
254         }
255         return new Status(StatusCode.INTERNALERROR, errorString("send", action,
256                 "Internal plugin error"));
257     }
258
259     private Status modifyFlowInternal(Node node, Flow oldFlow, Flow newFlow, long rid) {
260         String action = "modify";
261         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
262             return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
263                     action, "Invalid node type"));
264         }
265         if (controller != null) {
266             ISwitch sw = controller.getSwitch((Long) node.getID());
267             if (sw != null) {
268                 OFMessage msg1 = null, msg2 = null;
269
270                 // If priority and match portion are the same, send a
271                 // modification message
272                 if (oldFlow.getPriority() != newFlow.getPriority()
273                         || !oldFlow.getMatch().equals(newFlow.getMatch())) {
274                     msg1 = new FlowConverter(oldFlow).getOFFlowMod(
275                             OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
276                     msg2 = new FlowConverter(newFlow).getOFFlowMod(
277                             OFFlowMod.OFPFC_ADD, null);
278                 } else {
279                     msg1 = new FlowConverter(newFlow).getOFFlowMod(
280                             OFFlowMod.OFPFC_MODIFY_STRICT, null);
281                 }
282                 /*
283                  * Synchronous message send
284                  */
285                 action = (msg2 == null) ? "modify" : "delete";
286                 Object result;
287                 if (rid == 0) {
288                     /*
289                      * Synchronous message send. Each message is followed by a
290                      * Barrier message.
291                      */
292                     result = sw.syncSend(msg1);
293                 } else {
294                     /*
295                      * Message will be sent asynchronously. A Barrier message
296                      * will be inserted automatically to synchronize the
297                      * progression.
298                      */
299                     result = asyncMsgSend(node, sw, msg1, rid);
300                 }
301
302                 Status rv = getStatusInternal(result, action, rid);
303                 if ((msg2 == null) || !rv.isSuccess()) {
304                     return rv;
305                 }
306
307                 action = "add";
308                 if (rid == 0) {
309                     /*
310                      * Synchronous message send. Each message is followed by a
311                      * Barrier message.
312                      */
313                     result = sw.syncSend(msg2);
314                 } else {
315                     /*
316                      * Message will be sent asynchronously. A Barrier message
317                      * will be inserted automatically to synchronize the
318                      * progression.
319                      */
320                     result = asyncMsgSend(node, sw, msg2, rid);
321                 }
322                 return getStatusInternal(result, action, rid);
323             } else {
324                 return new Status(StatusCode.GONE, errorString("send", action,
325                         "Switch is not available"));
326             }
327         }
328         return new Status(StatusCode.INTERNALERROR, errorString("send", action,
329                 "Internal plugin error"));
330     }
331
332     private Status removeFlowInternal(Node node, Flow flow, long rid) {
333         String action = "remove";
334         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
335             return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
336                     action, "Invalid node type"));
337         }
338         if (controller != null) {
339             ISwitch sw = controller.getSwitch((Long) node.getID());
340             if (sw != null) {
341                 OFMessage msg = new FlowConverter(flow).getOFFlowMod(
342                         OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
343                 Object result;
344                 if (rid == 0) {
345                     /*
346                      * Synchronous message send. Each message is followed by a
347                      * Barrier message.
348                      */
349                     result = sw.syncSend(msg);
350                 } else {
351                     /*
352                      * Message will be sent asynchronously. A Barrier message
353                      * will be inserted automatically to synchronize the
354                      * progression.
355                      */
356                     result = asyncMsgSend(node, sw, msg, rid);
357                 }
358                 return getStatusInternal(result, action, rid);
359             } else {
360                 return new Status(StatusCode.GONE, errorString("send", action,
361                         "Switch is not available"));
362             }
363         }
364         return new Status(StatusCode.INTERNALERROR, errorString("send", action,
365                 "Internal plugin error"));
366     }
367
368     @Override
369     public Status removeAllFlows(Node node) {
370         if (!connectionOutService.isLocal(node)) {
371             log.debug("Remove all flows will not be processed in a non-master controller for node " + node);
372             return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node);
373         }
374
375         return new Status(StatusCode.SUCCESS);
376     }
377
378     private String errorString(String phase, String action, String cause) {
379         return "Failed to "
380                 + ((phase != null) ? phase + " the " + action
381                         + " flow message: " : action + " the flow: ") + cause;
382     }
383
384     @Override
385     public void receive(ISwitch sw, OFMessage msg) {
386         if (msg instanceof OFFlowRemoved) {
387             handleFlowRemovedMessage(sw, (OFFlowRemoved) msg);
388         } else if (msg instanceof OFError) {
389             handleErrorMessage(sw, (OFError) msg);
390         }
391     }
392
393     private void handleFlowRemovedMessage(ISwitch sw, OFFlowRemoved msg) {
394         Node node = NodeCreator.createOFNode(sw.getId());
395         Flow flow = new FlowConverter(msg.getMatch(),
396                 new ArrayList<OFAction>(0)).getFlow(node);
397         flow.setPriority(msg.getPriority());
398         flow.setIdleTimeout(msg.getIdleTimeout());
399         flow.setId(msg.getCookie());
400
401         Match match = flow.getMatch();
402         NodeConnector inPort = match.isPresent(MatchType.IN_PORT) ? (NodeConnector) match
403                 .getField(MatchType.IN_PORT).getValue() : null;
404
405         for (Map.Entry<String, IFlowProgrammerNotifier> containerNotifier : flowProgrammerNotifiers
406                 .entrySet()) {
407             String container = containerNotifier.getKey();
408             IFlowProgrammerNotifier notifier = containerNotifier.getValue();
409             /*
410              * Switch only provide us with the match information. For now let's
411              * try to identify the container membership only from the input port
412              * match field. In any case, upper layer consumers can derive
413              * whether the notification was not for them. More sophisticated
414              * filtering can be added later on.
415              */
416             if (inPort == null
417                     || container.equals(GlobalConstants.DEFAULT.toString())
418                     || (containerToNc.containsKey(container) && containerToNc.get(container).contains(inPort))) {
419                 notifier.flowRemoved(node, flow);
420             }
421         }
422     }
423
424     private void handleErrorMessage(ISwitch sw, OFError errorMsg) {
425         Node node = NodeCreator.createOFNode(sw.getId());
426         OFMessage offendingMsg = errorMsg.getOffendingMsg();
427         Integer xid;
428         if (offendingMsg != null) {
429             xid = offendingMsg.getXid();
430         } else {
431             xid = errorMsg.getXid();
432         }
433
434         Long rid = getMessageRid(sw.getId(), xid);
435         /*
436          * Null or zero requestId indicates that the error message is meant for
437          * a sync message. It will be handled by the sync message worker thread.
438          * Hence we are done here.
439          */
440         if ((rid == null) || (rid == 0)) {
441             return;
442         }
443
444         /*
445          * Notifies the caller that error has been reported for a previous flow
446          * programming request
447          */
448         for (Map.Entry<String, IFlowProgrammerNotifier> containerNotifier : flowProgrammerNotifiers
449                 .entrySet()) {
450             IFlowProgrammerNotifier notifier = containerNotifier.getValue();
451             notifier.flowErrorReported(node, rid, Utils.getOFErrorString(errorMsg));
452         }
453     }
454
455     @Override
456     public void tagUpdated(String containerName, Node n, short oldTag,
457             short newTag, UpdateType t) {
458
459     }
460
461     @Override
462     public void containerFlowUpdated(String containerName,
463             ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
464     }
465
466     @Override
467     public void nodeConnectorUpdated(String containerName, NodeConnector p,
468             UpdateType type) {
469         switch (type) {
470         case ADDED:
471             if (!containerToNc.containsKey(containerName)) {
472                 containerToNc.put(containerName, new HashSet<NodeConnector>());
473             }
474             containerToNc.get(containerName).add(p);
475             break;
476         case CHANGED:
477             break;
478         case REMOVED:
479             Set<NodeConnector> target = containerToNc.get(containerName);
480             if (target != null) {
481                 target.remove(p);
482             }
483             break;
484         default:
485         }
486     }
487
488     @Override
489     public void containerModeUpdated(UpdateType t) {
490
491     }
492
493     @Override
494     public Status syncSendBarrierMessage(Node node) {
495         if (!connectionOutService.isLocal(node)) {
496             log.debug("Sync Send Barrier will not be processed in a non-master controller for node " + node);
497             return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node);
498         }
499
500         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
501             return new Status(StatusCode.NOTACCEPTABLE,
502                     "The node does not support Barrier message.");
503         }
504
505         if (controller != null) {
506             long swid = (Long) node.getID();
507             ISwitch sw = controller.getSwitch(swid);
508             if (sw != null) {
509                 sw.syncSendBarrierMessage();
510                 clearXid2Rid(swid);
511                 return (new Status(StatusCode.SUCCESS));
512             } else {
513                 return new Status(StatusCode.GONE,
514                         "The node does not have a valid Switch reference.");
515             }
516         }
517         return new Status(StatusCode.INTERNALERROR,
518                 "Failed to send Barrier message.");
519     }
520
521     @Override
522     public Status asyncSendBarrierMessage(Node node) {
523         if (!connectionOutService.isLocal(node)) {
524             log.debug("ASync Send Barrier will not be processed in a non-master controller for node " + node);
525             return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node);
526         }
527
528         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
529             return new Status(StatusCode.NOTACCEPTABLE,
530                     "The node does not support Barrier message.");
531         }
532
533         if (controller != null) {
534             long swid = (Long) node.getID();
535             ISwitch sw = controller.getSwitch(swid);
536             if (sw != null) {
537                 sw.asyncSendBarrierMessage();
538                 clearXid2Rid(swid);
539                 return (new Status(StatusCode.SUCCESS));
540             } else {
541                 return new Status(StatusCode.GONE,
542                         "The node does not have a valid Switch reference.");
543             }
544         }
545         return new Status(StatusCode.INTERNALERROR,
546                 "Failed to send Barrier message.");
547     }
548
549     /**
550      * This method sends the message asynchronously until the number of messages
551      * sent reaches a threshold. Then a Barrier message is sent automatically
552      * for sync purpose. An unique Request ID associated with the message is
553      * passed down by the caller. The Request ID will be returned to the caller
554      * when an error message is received from the switch.
555      *
556      * @param node
557      *            The node
558      * @param msg
559      *            The switch
560      * @param msg
561      *            The OF message to be sent
562      * @param rid
563      *            The Request Id
564      * @return result
565      */
566     private Object asyncMsgSend(Node node, ISwitch sw, OFMessage msg, long rid) {
567         Object result = Boolean.TRUE;
568         long swid = (Long) node.getID();
569         int xid;
570
571         xid = sw.asyncSend(msg);
572         addXid2Rid(swid, xid, rid);
573
574         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
575         if (swxid2rid == null) {
576             return result;
577         }
578
579         int size = swxid2rid.size();
580         if (size % barrierMessagePriorCount == 0) {
581             result = asyncSendBarrierMessage(node);
582         }
583
584         return result;
585     }
586
587     /**
588      * A number of async messages are sent followed by a synchronous Barrier
589      * message. This method returns the maximum async messages that can be sent
590      * before the Barrier message.
591      *
592      * @return The max count of async messages sent prior to Barrier message
593      */
594     private int getBarrierMessagePriorCount() {
595         String count = System.getProperty("of.barrierMessagePriorCount");
596         int rv = 100;
597
598         if (count != null) {
599             try {
600                 rv = Integer.parseInt(count);
601             } catch (Exception e) {
602             }
603         }
604
605         return rv;
606     }
607
608     /**
609      * This method returns the message Request ID previously assigned by the
610      * caller for a given OF message xid
611      *
612      * @param swid
613      *            The switch id
614      * @param xid
615      *            The OF message xid
616      * @return The Request ID
617      */
618     private Long getMessageRid(long swid, Integer xid) {
619         Long rid = null;
620
621         if (xid == null) {
622             return rid;
623         }
624
625         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
626         if (swxid2rid != null) {
627             rid = swxid2rid.get(xid);
628         }
629         return rid;
630     }
631
632     /**
633      * This method returns a copy of outstanding xid to rid mappings.for a given
634      * switch
635      *
636      * @param swid
637      *            The switch id
638      * @return a copy of xid2rid mappings
639      */
640     public Map<Integer, Long> getSwXid2Rid(long swid) {
641         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
642
643         if (swxid2rid != null) {
644             return new HashMap<Integer, Long>(swxid2rid);
645         } else {
646             return new HashMap<Integer, Long>();
647         }
648     }
649
650     /**
651      * Adds xid to rid mapping to the local DB
652      *
653      * @param swid
654      *            The switch id
655      * @param xid
656      *            The OF message xid
657      * @param rid
658      *            The message Request ID
659      */
660     private void addXid2Rid(long swid, int xid, long rid) {
661         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
662         if (swxid2rid != null) {
663             swxid2rid.put(xid, rid);
664         }
665     }
666
667     /**
668      * When an Error message is received, this method will be invoked to remove
669      * the offending xid from the local DB.
670      *
671      * @param swid
672      *            The switch id
673      * @param xid
674      *            The OF message xid
675      */
676     private void removeXid2Rid(long swid, int xid) {
677         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
678         if (swxid2rid != null) {
679             swxid2rid.remove(xid);
680         }
681     }
682
683     /**
684      * Convert various result into Status
685      *
686      * @param result
687      *            The returned result from previous action
688      * @param action
689      *            add/modify/delete flow action
690      * @param rid
691      *            The Request ID associated with the flow message
692      * @return Status
693      */
694     private Status getStatusInternal(Object result, String action, long rid) {
695         if (result instanceof Boolean) {
696             return ((Boolean) result == Boolean.TRUE) ? new Status(
697                     StatusCode.SUCCESS, rid) : new Status(
698                     StatusCode.TIMEOUT, errorString(null, action,
699                             "Request Timed Out"));
700         } else if (result instanceof Status) {
701             return (Status) result;
702         } else if (result instanceof OFError) {
703             OFError res = (OFError) result;
704             return new Status(StatusCode.INTERNALERROR, errorString(
705                     "program", action, Utils.getOFErrorString(res)));
706         } else {
707             return new Status(StatusCode.INTERNALERROR, errorString(
708                     "send", action, "Internal Error"));
709         }
710     }
711
712     /**
713      * When a Barrier reply is received, this method will be invoked to clear
714      * the local DB
715      *
716      * @param swid
717      *            The switch id
718      */
719     private void clearXid2Rid(long swid) {
720         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
721         if (swxid2rid != null) {
722             swxid2rid.clear();
723         }
724     }
725
726     @Override
727     public void updateNode(Node node, UpdateType type, Set<Property> props) {
728         long swid = (Long)node.getID();
729
730         switch (type) {
731         case ADDED:
732             Map<Integer, Long> swxid2rid = new HashMap<Integer, Long>();
733             this.xid2rid.put(swid, swxid2rid);
734             break;
735         case CHANGED:
736             break;
737         case REMOVED:
738             this.xid2rid.remove(swid);
739             break;
740         default:
741         }
742     }
743
744     @Override
745     public void updateNodeConnector(NodeConnector nodeConnector,
746             UpdateType type, Set<Property> props) {
747     }
748
749     private void registerWithOSGIConsole() {
750         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
751                 .getBundleContext();
752         bundleContext.registerService(CommandProvider.class.getName(), this,
753                 null);
754     }
755
756     @Override
757     public String getHelp() {
758         StringBuffer help = new StringBuffer();
759         help.append("-- Flow Programmer Service --\n");
760         help.append("\t px2r <node id>          - Print outstanding xid2rid mappings for a given node id\n");
761         help.append("\t px2rc                   - Print max num of async msgs prior to the Barrier\n");
762         return help.toString();
763     }
764
765     public void _px2r(CommandInterpreter ci) {
766         String st = ci.nextArgument();
767         if (st == null) {
768             ci.println("Please enter a valid node id");
769             return;
770         }
771
772         long sid;
773         try {
774             sid = HexEncode.stringToLong(st);
775         } catch (NumberFormatException e) {
776             ci.println("Please enter a valid node id");
777             return;
778         }
779
780         Map<Integer, Long> swxid2rid = this.xid2rid.get(sid);
781         if (swxid2rid == null) {
782             ci.println("The node id entered does not exist");
783             return;
784         }
785
786         ci.println("xid             rid");
787
788         Set<Integer> xidSet = swxid2rid.keySet();
789         if (xidSet == null) {
790             return;
791         }
792
793         for (Integer xid : xidSet) {
794             ci.println(xid + "       " + swxid2rid.get(xid));
795         }
796     }
797
798     public void _px2rc(CommandInterpreter ci) {
799         ci.println("Max num of async messages sent prior to the Barrier message is "
800                 + barrierMessagePriorCount);
801     }
802
803     @Override
804     public void containerCreate(String containerName) {
805         // do nothing
806     }
807
808     @Override
809     public void containerDestroy(String containerName) {
810         containerToNc.remove(containerName);
811     }
812 }