Merge "Added support for annotations in generated APIs."
[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.core.ContainerFlow;
27 import org.opendaylight.controller.sal.core.IContainerListener;
28 import org.opendaylight.controller.sal.core.Node;
29 import org.opendaylight.controller.sal.core.Node.NodeIDType;
30 import org.opendaylight.controller.sal.core.NodeConnector;
31 import org.opendaylight.controller.sal.core.Property;
32 import org.opendaylight.controller.sal.core.UpdateType;
33 import org.opendaylight.controller.sal.flowprogrammer.Flow;
34 import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
35 import org.opendaylight.controller.sal.match.Match;
36 import org.opendaylight.controller.sal.match.MatchType;
37 import org.opendaylight.controller.sal.utils.GlobalConstants;
38 import org.opendaylight.controller.sal.utils.HexEncode;
39 import org.opendaylight.controller.sal.utils.NodeCreator;
40 import org.opendaylight.controller.sal.utils.Status;
41 import org.opendaylight.controller.sal.utils.StatusCode;
42 import org.openflow.protocol.OFError;
43 import org.openflow.protocol.OFFlowMod;
44 import org.openflow.protocol.OFFlowRemoved;
45 import org.openflow.protocol.OFMessage;
46 import org.openflow.protocol.OFPort;
47 import org.openflow.protocol.OFType;
48 import org.openflow.protocol.action.OFAction;
49 import org.osgi.framework.BundleContext;
50 import org.osgi.framework.FrameworkUtil;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 /**
55  * Represents the openflow plugin component in charge of programming the flows
56  * the flow programming and relay them to functional modules above SAL.
57  */
58 public class FlowProgrammerService implements IPluginInFlowProgrammerService,
59         IMessageListener, IContainerListener, IInventoryShimExternalListener,
60         CommandProvider {
61     private static final Logger log = LoggerFactory
62             .getLogger(FlowProgrammerService.class);
63     private IController controller;
64     private ConcurrentMap<String, IFlowProgrammerNotifier> flowProgrammerNotifiers;
65     private Map<String, Set<NodeConnector>> containerToNc;
66     private ConcurrentMap<Long, Map<Integer, Long>> xid2rid;
67     private int barrierMessagePriorCount = getBarrierMessagePriorCount();
68
69     public FlowProgrammerService() {
70         controller = null;
71         flowProgrammerNotifiers = new ConcurrentHashMap<String, IFlowProgrammerNotifier>();
72         containerToNc = new HashMap<String, Set<NodeConnector>>();
73         xid2rid = new ConcurrentHashMap<Long, Map<Integer, Long>>();
74     }
75
76     public void setController(IController core) {
77         this.controller = core;
78     }
79
80     public void unsetController(IController core) {
81         if (this.controller == core) {
82             this.controller = null;
83         }
84     }
85
86     public void setFlowProgrammerNotifier(Map<String, ?> props,
87             IFlowProgrammerNotifier s) {
88         if (props == null || props.get("containerName") == null) {
89             log.error("Didn't receive the service correct properties");
90             return;
91         }
92         String containerName = (String) props.get("containerName");
93         this.flowProgrammerNotifiers.put(containerName, s);
94     }
95
96     public void unsetFlowProgrammerNotifier(Map<String, ?> props,
97             IFlowProgrammerNotifier s) {
98         if (props == null || props.get("containerName") == null) {
99             log.error("Didn't receive the service correct properties");
100             return;
101         }
102         String containerName = (String) props.get("containerName");
103         if (this.flowProgrammerNotifiers != null
104                 && this.flowProgrammerNotifiers.containsKey(containerName)
105                 && this.flowProgrammerNotifiers.get(containerName) == s) {
106             this.flowProgrammerNotifiers.remove(containerName);
107         }
108     }
109
110     /**
111      * Function called by the dependency manager when all the required
112      * dependencies are satisfied
113      * 
114      */
115     void init() {
116         this.controller.addMessageListener(OFType.FLOW_REMOVED, this);
117         this.controller.addMessageListener(OFType.ERROR, this);
118         registerWithOSGIConsole();
119     }
120
121     /**
122      * Function called by the dependency manager when at least one dependency
123      * become unsatisfied or when the component is shutting down because for
124      * example bundle is being stopped.
125      * 
126      */
127     void destroy() {
128     }
129
130     /**
131      * Function called by dependency manager after "init ()" is called and after
132      * the services provided by the class are registered in the service registry
133      * 
134      */
135     void start() {
136     }
137
138     /**
139      * Function called by the dependency manager before the services exported by
140      * the component are unregistered, this will be followed by a "destroy ()"
141      * calls
142      * 
143      */
144     void stop() {
145     }
146
147     @Override
148     public Status addFlow(Node node, Flow flow) {
149         return addFlowInternal(node, flow, 0);
150     }
151
152     @Override
153     public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) {
154         return modifyFlowInternal(node, oldFlow, newFlow, 0);
155     }
156
157     @Override
158     public Status removeFlow(Node node, Flow flow) {
159         return removeFlowInternal(node, flow, 0);
160     }
161
162     @Override
163     public Status addFlowAsync(Node node, Flow flow, long rid) {
164         return addFlowInternal(node, flow, rid);
165     }
166
167     @Override
168     public Status modifyFlowAsync(Node node, Flow oldFlow, Flow newFlow,
169             long rid) {
170         return modifyFlowInternal(node, oldFlow, newFlow, rid);
171     }
172
173     @Override
174     public Status removeFlowAsync(Node node, Flow flow, long rid) {
175         return removeFlowInternal(node, flow, rid);
176     }
177
178     private Status addFlowInternal(Node node, Flow flow, long rid) {
179         String action = "add";
180         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
181             return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
182                     action, "Invalid node type"));
183         }
184
185         if (controller != null) {
186             ISwitch sw = controller.getSwitch((Long) node.getID());
187             if (sw != null) {
188                 FlowConverter x = new FlowConverter(flow);
189                 OFMessage msg = x.getOFFlowMod(OFFlowMod.OFPFC_ADD, null);
190
191                 Object result;
192                 if (rid == 0) {
193                     /*
194                      * Synchronous message send. Each message is followed by a
195                      * Barrier message.
196                      */
197                     result = sw.syncSend(msg);
198                 } else {
199                     /*
200                      * Message will be sent asynchronously. A Barrier message
201                      * will be inserted automatically to synchronize the
202                      * progression.
203                      */
204                     result = asyncMsgSend(node, sw, msg, rid);  
205                 }
206                 if (result instanceof Boolean) {
207                     return ((Boolean) result == Boolean.TRUE) ? new Status(
208                             StatusCode.SUCCESS, rid) : new Status(
209                             StatusCode.TIMEOUT, errorString(null, action,
210                                     "Request Timed Out"));
211                 } else if (result instanceof OFError) {
212                     OFError res = (OFError) result;
213                     return new Status(StatusCode.INTERNALERROR, errorString(
214                             "program", action, Utils.getOFErrorString(res)));
215                 } else {
216                     return new Status(StatusCode.INTERNALERROR, errorString(
217                             "send", action, "Internal Error"));
218                 }
219             } else {
220                 return new Status(StatusCode.GONE, errorString("send", action,
221                         "Switch is not available"));
222             }
223         }
224         return new Status(StatusCode.INTERNALERROR, errorString("send", action,
225                 "Internal plugin error"));
226     }
227
228     private Status modifyFlowInternal(Node node, Flow oldFlow, Flow newFlow, long rid) {
229         String action = "modify";
230         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
231             return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
232                     action, "Invalid node type"));
233         }
234         if (controller != null) {
235             ISwitch sw = controller.getSwitch((Long) node.getID());
236             if (sw != null) {
237                 OFMessage msg1 = null, msg2 = null;
238
239                 // If priority and match portion are the same, send a
240                 // modification message
241                 if (oldFlow.getPriority() != newFlow.getPriority()
242                         || !oldFlow.getMatch().equals(newFlow.getMatch())) {
243                     msg1 = new FlowConverter(oldFlow).getOFFlowMod(
244                             OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
245                     msg2 = new FlowConverter(newFlow).getOFFlowMod(
246                             OFFlowMod.OFPFC_ADD, null);
247                 } else {
248                     msg1 = new FlowConverter(newFlow).getOFFlowMod(
249                             OFFlowMod.OFPFC_MODIFY_STRICT, null);
250                 }
251                 /*
252                  * Synchronous message send
253                  */
254                 action = (msg2 == null) ? "modify" : "delete";
255                 Object result;
256                 if (rid == 0) {
257                     /*
258                      * Synchronous message send. Each message is followed by a
259                      * Barrier message.
260                      */
261                     result = sw.syncSend(msg1);
262                 } else {
263                     /*
264                      * Message will be sent asynchronously. A Barrier message
265                      * will be inserted automatically to synchronize the
266                      * progression.
267                      */
268                     result = asyncMsgSend(node, sw, msg1, rid);
269                 }
270                 if (result instanceof Boolean) {
271                     if ((Boolean) result == Boolean.FALSE) {
272                         return new Status(StatusCode.TIMEOUT, errorString(null,
273                                 action, "Request Timed Out"));
274                     } else if (msg2 == null) {
275                         return new Status(StatusCode.SUCCESS, rid);
276                     }
277                 } else if (result instanceof OFError) {
278                     return new Status(StatusCode.INTERNALERROR, errorString(
279                             "program", action,
280                             Utils.getOFErrorString((OFError) result)));
281                 } else {
282                     return new Status(StatusCode.INTERNALERROR, errorString(
283                             "send", action, "Internal Error"));
284                 }
285
286                 if (msg2 != null) {
287                     action = "add";
288                     if (rid == 0) {
289                         /*
290                          * Synchronous message send. Each message is followed by a
291                          * Barrier message.
292                          */
293                         result = sw.syncSend(msg2);
294                     } else {
295                         /*
296                          * Message will be sent asynchronously. A Barrier message
297                          * will be inserted automatically to synchronize the
298                          * progression.
299                          */
300                         result = asyncMsgSend(node, sw, msg2, rid);
301                     }
302                     if (result instanceof Boolean) {
303                         return ((Boolean) result == Boolean.TRUE) ? new Status(
304                                 StatusCode.SUCCESS, rid) : new Status(
305                                 StatusCode.TIMEOUT, errorString(null, action,
306                                         "Request Timed Out"));
307                     } else if (result instanceof OFError) {
308                         return new Status(StatusCode.INTERNALERROR,
309                                 errorString("program", action, Utils
310                                         .getOFErrorString((OFError) result)));
311                     } else {
312                         return new Status(StatusCode.INTERNALERROR,
313                                 errorString("send", action, "Internal Error"));
314                     }
315                 }
316             } else {
317                 return new Status(StatusCode.GONE, errorString("send", action,
318                         "Switch is not available"));
319             }
320         }
321         return new Status(StatusCode.INTERNALERROR, errorString("send", action,
322                 "Internal plugin error"));
323     }
324
325     private Status removeFlowInternal(Node node, Flow flow, long rid) {
326         String action = "remove";
327         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
328             return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
329                     action, "Invalid node type"));
330         }
331         if (controller != null) {
332             ISwitch sw = controller.getSwitch((Long) node.getID());
333             if (sw != null) {
334                 OFMessage msg = new FlowConverter(flow).getOFFlowMod(
335                         OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
336                 Object result;
337                 if (rid == 0) {
338                     /*
339                      * Synchronous message send. Each message is followed by a
340                      * Barrier message.
341                      */
342                     result = sw.syncSend(msg);
343                 } else {
344                     /*
345                      * Message will be sent asynchronously. A Barrier message
346                      * will be inserted automatically to synchronize the
347                      * progression.
348                      */
349                     result = asyncMsgSend(node, sw, msg, rid);
350                 }
351                 if (result instanceof Boolean) {
352                     return ((Boolean) result == Boolean.TRUE) ? new Status(
353                             StatusCode.SUCCESS, rid) : new Status(
354                             StatusCode.TIMEOUT, errorString(null, action,
355                                     "Request Timed Out"));
356                 } else if (result instanceof OFError) {
357                     return new Status(StatusCode.INTERNALERROR, errorString(
358                             "program", action,
359                             Utils.getOFErrorString((OFError) result)));
360                 } else {
361                     return new Status(StatusCode.INTERNALERROR, errorString(
362                             "send", action, "Internal Error"));
363                 }
364             } else {
365                 return new Status(StatusCode.GONE, errorString("send", action,
366                         "Switch is not available"));
367             }
368         }
369         return new Status(StatusCode.INTERNALERROR, errorString("send", action,
370                 "Internal plugin error"));
371     }
372
373     @Override
374     public Status removeAllFlows(Node node) {
375         return new Status(StatusCode.SUCCESS, null);
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                     || this.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, 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         Set<NodeConnector> target = null;
470
471         switch (type) {
472         case ADDED:
473             if (!containerToNc.containsKey(containerName)) {
474                 containerToNc.put(containerName, new HashSet<NodeConnector>());
475             }
476             containerToNc.get(containerName).add(p);
477             break;
478         case CHANGED:
479             break;
480         case REMOVED:
481             target = containerToNc.get(containerName);
482             if (target != null) {
483                 target.remove(p);
484             }
485             break;
486         default:
487         }
488     }
489
490     @Override
491     public void containerModeUpdated(UpdateType t) {
492
493     }
494
495     @Override
496     public Status sendBarrierMessage(Node node) {
497         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
498             return new Status(StatusCode.NOTACCEPTABLE,
499                     "The node does not support Barrier message.");
500         }
501
502         if (controller != null) {
503             long swid = (Long) node.getID();
504             ISwitch sw = controller.getSwitch(swid);
505             if (sw != null) {
506                 sw.sendBarrierMessage();
507                 clearXid2Rid(swid);
508                 return (new Status(StatusCode.SUCCESS, null));
509             } else {
510                 return new Status(StatusCode.GONE,
511                         "The node does not have a valid Switch reference.");
512             }
513         }
514         return new Status(StatusCode.INTERNALERROR,
515                 "Failed to send Barrier message.");
516     }
517     
518     /**
519      * This method sends the message asynchronously until the number of messages
520      * sent reaches a threshold. Then a Barrier message is sent automatically
521      * for sync purpose. An unique Request ID associated with the message is
522      * passed down by the caller. The Request ID will be returned to the caller
523      * when an error message is received from the switch.
524      * 
525      * @param node
526      *            The node
527      * @param msg
528      *            The switch
529      * @param msg
530      *            The OF message to be sent
531      * @param rid
532      *            The Request Id
533      * @return result
534      */
535     private Object asyncMsgSend(Node node, ISwitch sw, OFMessage msg, long rid) {
536         Object result = Boolean.TRUE;
537         long swid = (Long) node.getID();
538         int xid;
539
540         xid = sw.asyncSend(msg);
541         addXid2Rid(swid, xid, rid);
542         
543         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
544         if (swxid2rid == null) {
545             return result;
546         }
547         
548         int size = swxid2rid.size();
549         if (size % barrierMessagePriorCount == 0) {
550             result = sendBarrierMessage(node);
551         }
552         
553         return result;
554     }
555     
556     /**
557      * A number of async messages are sent followed by a synchronous Barrier
558      * message. This method returns the maximum async messages that can be sent
559      * before the Barrier message.
560      * 
561      * @return The max count of async messages sent prior to Barrier message
562      */
563     private int getBarrierMessagePriorCount() {
564         String count = System.getProperty("of.barrierMessagePriorCount");
565         int rv = 100;
566
567         if (count != null) {
568             try {
569                 rv = Integer.parseInt(count);
570             } catch (Exception e) {
571             }
572         }
573
574         return rv;
575     }
576     
577     /**
578      * This method returns the message Request ID previously assigned by the
579      * caller for a given OF message xid
580      * 
581      * @param swid
582      *            The switch id
583      * @param xid
584      *            The OF message xid
585      * @return The Request ID
586      */
587     private Long getMessageRid(long swid, Integer xid) {
588         Long rid = null;
589
590         if (xid == null) {
591             return rid;
592         }
593
594         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
595         if (swxid2rid != null) {
596             rid = swxid2rid.get(xid);
597         }
598         return rid;
599     }
600
601     /**
602      * This method returns a copy of outstanding xid to rid mappings.for a given
603      * switch
604      * 
605      * @param swid
606      *            The switch id
607      * @return a copy of xid2rid mappings
608      */
609     public Map<Integer, Long> getSwXid2Rid(long swid) {
610         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
611         
612         if (swxid2rid != null) {
613             return new HashMap<Integer, Long>(swxid2rid);
614         } else {
615             return new HashMap<Integer, Long>();
616         }
617     }
618
619     /**
620      * Adds xid to rid mapping to the local DB
621      * 
622      * @param swid
623      *            The switch id
624      * @param xid
625      *            The OF message xid
626      * @param rid
627      *            The message Request ID
628      */
629     private void addXid2Rid(long swid, int xid, long rid) {
630         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
631         if (swxid2rid != null) {
632             swxid2rid.put(xid, rid);
633         }
634     }
635
636     /**
637      * When an Error message is received, this method will be invoked to remove
638      * the offending xid from the local DB.
639      * 
640      * @param swid
641      *            The switch id
642      * @param xid
643      *            The OF message xid
644      */
645     private void removeXid2Rid(long swid, int xid) {
646         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
647         if (swxid2rid != null) {
648             swxid2rid.remove(xid);
649         }
650     }
651
652     /**
653      * When a Barrier reply is received, this method will be invoked to clear
654      * the local DB
655      * 
656      * @param swid
657      *            The switch id
658      */
659     private void clearXid2Rid(long swid) {
660         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
661         if (swxid2rid != null) {
662             swxid2rid.clear();
663         }
664     }
665
666     @Override
667     public void updateNode(Node node, UpdateType type, Set<Property> props) {
668         long swid = (Long)node.getID();
669         
670         switch (type) {
671         case ADDED:
672             Map<Integer, Long> swxid2rid = new HashMap<Integer, Long>();
673             this.xid2rid.put(swid, swxid2rid);
674             break;
675         case CHANGED:
676             break;
677         case REMOVED:
678             this.xid2rid.remove(swid);
679             break;
680         default:
681         }
682     }
683
684     @Override
685     public void updateNodeConnector(NodeConnector nodeConnector,
686             UpdateType type, Set<Property> props) {
687     }
688
689     private void registerWithOSGIConsole() {
690         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
691                 .getBundleContext();
692         bundleContext.registerService(CommandProvider.class.getName(), this,
693                 null);
694     }
695
696     @Override
697     public String getHelp() {
698         StringBuffer help = new StringBuffer();
699         help.append("-- Flow Programmer Service --\n");
700         help.append("\t px2r <node id>          - Print outstanding xid2rid mappings for a given node id\n");
701         help.append("\t px2rc                   - Print max num of async msgs prior to the Barrier\n");
702         return help.toString();
703     }
704
705     public void _px2r(CommandInterpreter ci) {
706         String st = ci.nextArgument();
707         if (st == null) {
708             ci.println("Please enter a valid node id");
709             return;
710         }
711         
712         long sid;
713         try {
714             sid = HexEncode.stringToLong(st);
715         } catch (NumberFormatException e) {
716             ci.println("Please enter a valid node id");
717             return;
718         }
719         
720         Map<Integer, Long> swxid2rid = this.xid2rid.get(sid);
721         if (swxid2rid == null) {
722             ci.println("The node id entered does not exist");
723             return;
724         }
725
726         ci.println("xid             rid");
727         
728         Set<Integer> xidSet = swxid2rid.keySet();
729         if (xidSet == null) {
730             return;
731         }
732
733         for (Integer xid : xidSet) {
734             ci.println(xid + "       " + swxid2rid.get(xid));
735         }
736     }
737
738     public void _px2rc(CommandInterpreter ci) {
739         ci.println("Max num of async messages sent prior to the Barrier message is "
740                 + barrierMessagePriorCount);
741     }
742 }