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