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