Resolving http://bugs.opendaylight.org/show_bug.cgi?id=4
[controller.git] / opendaylight / protocol_plugins / openflow / src / main / java / org / opendaylight / controller / protocol_plugin / openflow / core / internal / SwitchHandler.java
1
2 /*
3  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9
10 package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
11
12 import java.nio.ByteBuffer;
13 import java.nio.channels.SelectionKey;
14 import java.nio.channels.Selector;
15 import java.nio.channels.SocketChannel;
16 import java.nio.channels.spi.SelectorProvider;
17 import java.util.ArrayList;
18 import java.util.Date;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.Timer;
25 import java.util.TimerTask;
26 import java.util.concurrent.Callable;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.Future;
31 import java.util.concurrent.TimeUnit;
32 import java.util.concurrent.atomic.AtomicInteger;
33
34 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
35 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
36 import org.openflow.protocol.OFBarrierReply;
37 import org.openflow.protocol.OFEchoReply;
38 import org.openflow.protocol.OFError;
39 import org.openflow.protocol.OFFeaturesReply;
40 import org.openflow.protocol.OFFlowMod;
41 import org.openflow.protocol.OFGetConfigReply;
42 import org.openflow.protocol.OFMatch;
43 import org.openflow.protocol.OFMessage;
44 import org.openflow.protocol.OFPhysicalPort;
45 import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
46 import org.openflow.protocol.OFPhysicalPort.OFPortFeatures;
47 import org.openflow.protocol.OFPhysicalPort.OFPortState;
48 import org.openflow.protocol.OFPort;
49 import org.openflow.protocol.OFPortStatus;
50 import org.openflow.protocol.OFPortStatus.OFPortReason;
51 import org.openflow.protocol.OFSetConfig;
52 import org.openflow.protocol.OFStatisticsReply;
53 import org.openflow.protocol.OFStatisticsRequest;
54 import org.openflow.protocol.OFType;
55 import org.openflow.protocol.factory.BasicFactory;
56 import org.openflow.util.HexString;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 public class SwitchHandler implements ISwitch {
61     private static final Logger logger = LoggerFactory
62             .getLogger(SwitchHandler.class);
63     private static final int SWITCH_LIVENESS_TIMER = 5000;
64     private static final int SWITCH_LIVENESS_TIMEOUT = 2 * SWITCH_LIVENESS_TIMER + 500;
65     private static final int SYNCHRONOUS_FLOW_TIMEOUT = 2000;
66     private static final int STATS_COLLECTION_TIMEOUT = 2000;
67     private static final int bufferSize = 1024 * 1024;
68
69     private String instanceName;
70     private ISwitch thisISwitch;
71     private IController core;
72     private Long sid;
73     private Integer buffers;
74     private Integer capabilities;
75     private Byte tables;
76     private Integer actions;
77     private Selector selector;
78     private SelectionKey clientSelectionKey;
79     private SocketChannel socket;
80     private ByteBuffer inBuffer;
81     private ByteBuffer outBuffer;
82     private BasicFactory factory;
83     private AtomicInteger xid;
84     private SwitchState state;
85     private Timer periodicTimer;
86     private Map<Short, OFPhysicalPort> physicalPorts;
87     private Map<Short, Integer> portBandwidth;
88     private Date connectedDate;
89     private Long lastMsgReceivedTimeStamp;
90     private Boolean probeSent;
91     private ExecutorService executor;
92     private ConcurrentHashMap<Integer, Callable<Object>> messageWaitingDone;
93     private boolean running;
94     private Thread switchHandlerThread;
95
96     private enum SwitchState {
97         NON_OPERATIONAL(0), WAIT_FEATURES_REPLY(1), WAIT_CONFIG_REPLY(2), OPERATIONAL(
98                 3);
99
100         private int value;
101
102         private SwitchState(int value) {
103             this.value = value;
104         }
105
106         @SuppressWarnings("unused")
107         public int value() {
108             return this.value;
109         }
110     }
111
112     public SwitchHandler(Controller core, SocketChannel sc, String name) {
113         this.instanceName = name;
114         this.thisISwitch = this;
115         this.sid = (long) 0;
116         this.buffers = (int)0;
117         this.capabilities = (int)0;
118         this.tables = (byte)0;
119         this.actions = (int)0;
120         this.core = core;
121         this.socket = sc;
122         this.factory = new BasicFactory();
123         this.connectedDate = new Date();
124         this.lastMsgReceivedTimeStamp = connectedDate.getTime();
125         this.physicalPorts = new HashMap<Short, OFPhysicalPort>();
126         this.portBandwidth = new HashMap<Short, Integer>();
127         this.state = SwitchState.NON_OPERATIONAL;
128         this.probeSent = false;
129         this.xid = new AtomicInteger(this.socket.hashCode());
130         this.periodicTimer = null;
131         this.executor = Executors.newFixedThreadPool(4);
132         this.messageWaitingDone = new ConcurrentHashMap<Integer, Callable<Object>>();
133         this.inBuffer = ByteBuffer.allocateDirect(bufferSize);
134         this.outBuffer = ByteBuffer.allocateDirect(bufferSize);
135     }
136
137     public void start() {
138         try {
139             this.selector = SelectorProvider.provider().openSelector();
140             this.socket.configureBlocking(false);
141             this.socket.socket().setTcpNoDelay(true);
142             this.clientSelectionKey = this.socket.register(this.selector,
143                     SelectionKey.OP_READ);
144             startHandlerThread();
145         } catch (Exception e) {
146             reportError(e);
147             return;
148         }
149     }
150
151     private void startHandlerThread() {
152         OFMessage msg = factory.getMessage(OFType.HELLO);
153         asyncSend(msg);
154         switchHandlerThread = new Thread(new Runnable() {
155             @Override
156             public void run() {
157                 running = true;
158                 while (running) {
159                     try {
160                         // wait for an incoming connection
161                         selector.select(0);
162                         Iterator<SelectionKey> selectedKeys = selector
163                                 .selectedKeys().iterator();
164                         while (selectedKeys.hasNext()) {
165                             SelectionKey skey = selectedKeys.next();
166                             selectedKeys.remove();
167                             if (skey.isValid() && skey.isWritable()) {
168                                 resumeSend();
169                             }
170                             if (skey.isValid() && skey.isReadable()) {
171                                 handleMessages();
172                             }
173                         }
174                     } catch (Exception e) {
175                         reportError(e);
176                     }
177                 }
178             }
179         }, instanceName);
180         switchHandlerThread.start();
181     }
182
183     public void stop() {
184         try {
185             running = false;
186             selector.wakeup();
187             cancelSwitchTimer();
188             this.clientSelectionKey.cancel();
189             this.socket.close();
190             executor.shutdown();
191         } catch (Exception e) {
192                 // do nothing since we are shutting down.
193                 return;
194         }
195     }
196
197     @Override
198     public int getNextXid() {
199         return this.xid.incrementAndGet();
200     }
201
202     @Override
203     public Integer asyncSend(OFMessage msg) {
204         return asyncSend(msg, getNextXid());
205     }
206
207     @Override
208     public Integer asyncSend(OFMessage msg, int xid) {
209         synchronized (outBuffer) {
210             /*
211             if ((msg.getType() != OFType.ECHO_REQUEST) &&
212                         (msg.getType() != OFType.ECHO_REPLY)) {
213                 logger.debug("sending " + msg.getType().toString() + " to " + toString());
214             }
215              */
216             msg.setXid(xid);
217             int msgLen = msg.getLengthU();
218             if (outBuffer.remaining() < msgLen) {
219                 // increase the buffer size so that it can contain this message
220                 ByteBuffer newBuffer = ByteBuffer.allocateDirect(outBuffer
221                         .capacity()
222                         + msgLen);
223                 outBuffer.flip();
224                 newBuffer.put(outBuffer);
225                 outBuffer = newBuffer;
226             }
227             msg.writeTo(outBuffer);
228             outBuffer.flip();
229             try {
230                 socket.write(outBuffer);
231                 outBuffer.compact();
232                 if (outBuffer.position() > 0) {
233                     this.clientSelectionKey = this.socket.register(
234                             this.selector, SelectionKey.OP_WRITE, this);
235                 }
236                 logger.trace("Message sent: " + msg.toString());
237             } catch (Exception e) {
238                 reportError(e);
239             }
240         }
241         return xid;
242     }
243
244     public void resumeSend() {
245         synchronized (outBuffer) {
246             try {
247                 outBuffer.flip();
248                 socket.write(outBuffer);
249                 outBuffer.compact();
250                 if (outBuffer.position() > 0) {
251                     this.clientSelectionKey = this.socket.register(
252                             this.selector, SelectionKey.OP_WRITE, this);
253                 } else {
254                     this.clientSelectionKey = this.socket.register(
255                             this.selector, SelectionKey.OP_READ, this);
256                 }
257             } catch (Exception e) {
258                 reportError(e);
259             }
260         }
261     }
262
263     public void handleMessages() {
264         List<OFMessage> msgs = readMessages();
265         if (msgs == null) {
266             logger.debug(toString() + " is down");
267             // the connection is down, inform core
268             reportSwitchStateChange(false);
269             return;
270         }
271         for (OFMessage msg : msgs) {
272             logger.trace("Message received: " + msg.toString());
273             /*
274             if  ((msg.getType() != OFType.ECHO_REQUEST) &&
275                         (msg.getType() != OFType.ECHO_REPLY)) {
276                 logger.debug(msg.getType().toString() + " received from sw " + toString());
277             }
278              */
279             this.lastMsgReceivedTimeStamp = System.currentTimeMillis();
280             OFType type = msg.getType();
281             switch (type) {
282             case HELLO:
283                 // send feature request
284                 OFMessage featureRequest = factory
285                         .getMessage(OFType.FEATURES_REQUEST);
286                 asyncSend(featureRequest);
287                 // delete all pre-existing flows
288                 OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
289                 OFFlowMod flowMod = (OFFlowMod) factory
290                         .getMessage(OFType.FLOW_MOD);
291                 flowMod.setMatch(match).setCommand(OFFlowMod.OFPFC_DELETE)
292                         .setOutPort(OFPort.OFPP_NONE).setLength(
293                                 (short) OFFlowMod.MINIMUM_LENGTH);
294                 asyncSend(flowMod);
295                 this.state = SwitchState.WAIT_FEATURES_REPLY;
296                 startSwitchTimer();
297                 break;
298             case ECHO_REQUEST:
299                 OFEchoReply echoReply = (OFEchoReply) factory
300                         .getMessage(OFType.ECHO_REPLY);
301                 asyncSend(echoReply);
302                 break;
303             case ECHO_REPLY:
304                 this.probeSent = false;
305                 break;
306             case FEATURES_REPLY:
307                 processFeaturesReply((OFFeaturesReply) msg);
308                 break;
309             case GET_CONFIG_REPLY:
310                 // make sure that the switch can send the whole packet to the controller
311                 if (((OFGetConfigReply) msg).getMissSendLength() == (short) 0xffff) {
312                     this.state = SwitchState.OPERATIONAL;
313                 }
314                 break;
315             case BARRIER_REPLY:
316                 processBarrierReply((OFBarrierReply) msg);
317                 break;
318             case ERROR:
319                 processErrorReply((OFError) msg);
320                 break;
321             case PORT_STATUS:
322                 processPortStatusMsg((OFPortStatus) msg);
323                 break;
324             case STATS_REPLY:
325                 processStatsReply((OFStatisticsReply) msg);
326                 break;
327             case PACKET_IN:
328                 break;
329             default:
330                 break;
331             } // end of switch
332             if (isOperational()) {
333                 ((Controller) core).takeSwitchEventMsg(thisISwitch, msg);
334             }
335         } // end of for
336     }
337
338     private void processPortStatusMsg(OFPortStatus msg) {
339         //short portNumber = msg.getDesc().getPortNumber();
340         OFPhysicalPort port = msg.getDesc();
341         if (msg.getReason() == (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
342             updatePhysicalPort(port);
343             //logger.debug("Port " + portNumber + " on " + toString() + " modified");
344         } else if (msg.getReason() == (byte) OFPortReason.OFPPR_ADD.ordinal()) {
345             updatePhysicalPort(port);
346             //logger.debug("Port " + portNumber + " on " + toString() + " added");
347         } else if (msg.getReason() == (byte) OFPortReason.OFPPR_DELETE
348                 .ordinal()) {
349             deletePhysicalPort(port);
350             //logger.debug("Port " + portNumber + " on " + toString() + " deleted");
351         }
352
353     }
354
355     private List<OFMessage> readMessages() {
356         List<OFMessage> msgs = null;
357         int bytesRead;
358         try {
359             bytesRead = socket.read(inBuffer);
360         } catch (Exception e) {
361             reportError(e);
362             return null;
363         }
364         if (bytesRead == -1) {
365             return null;
366         }
367         inBuffer.flip();
368         msgs = factory.parseMessages(inBuffer);
369         if (inBuffer.hasRemaining()) {
370             inBuffer.compact();
371         } else {
372             inBuffer.clear();
373         }
374         return msgs;
375     }
376
377     private void startSwitchTimer() {
378         this.periodicTimer = new Timer();
379         this.periodicTimer.scheduleAtFixedRate(new TimerTask() {
380             @Override
381             public void run() {
382                 try {
383                     Long now = System.currentTimeMillis();
384                     if ((now - lastMsgReceivedTimeStamp) > SWITCH_LIVENESS_TIMEOUT) {
385                         if (probeSent) {
386                             // switch failed to respond to our probe, consider it down
387                             logger.warn(toString()
388                                     + " is idle for too long, disconnect");
389                             reportSwitchStateChange(false);
390                         } else {
391                             // send a probe to see if the switch is still alive
392                             //logger.debug("Send idle probe (Echo Request) to " + switchName());
393                             probeSent = true;
394                             OFMessage echo = factory
395                                     .getMessage(OFType.ECHO_REQUEST);
396                             asyncSend(echo);
397                         }
398                     } else {
399                         if (state == SwitchState.WAIT_FEATURES_REPLY) {
400                             // send another features request
401                             OFMessage request = factory
402                                     .getMessage(OFType.FEATURES_REQUEST);
403                             asyncSend(request);
404                         } else {
405                             if (state == SwitchState.WAIT_CONFIG_REPLY) {
406                                 //  send another config request
407                                 OFSetConfig config = (OFSetConfig) factory
408                                         .getMessage(OFType.SET_CONFIG);
409                                 config.setMissSendLength((short) 0xffff)
410                                         .setLengthU(OFSetConfig.MINIMUM_LENGTH);
411                                 asyncSend(config);
412                                 OFMessage getConfig = factory
413                                         .getMessage(OFType.GET_CONFIG_REQUEST);
414                                 asyncSend(getConfig);
415                             }
416                         }
417                     }
418                 } catch (Exception e) {
419                     reportError(e);
420                 }
421             }
422         }, SWITCH_LIVENESS_TIMER, SWITCH_LIVENESS_TIMER);
423     }
424
425     private void cancelSwitchTimer() {
426         if (this.periodicTimer != null) {
427             this.periodicTimer.cancel();
428         }
429     }
430
431     private void reportError(Exception e) {
432         //logger.error(toString() + " caught Error " + e.toString());
433         // notify core of this error event
434         ((Controller) core).takeSwitchEventError(this);
435     }
436
437     private void reportSwitchStateChange(boolean added) {
438         if (added) {
439             ((Controller) core).takeSwtichEventAdd(this);
440         } else {
441             ((Controller) core).takeSwitchEventDelete(this);
442         }
443     }
444
445     @Override
446     public Long getId() {
447         return this.sid;
448     }
449
450     private void processFeaturesReply(OFFeaturesReply reply) {
451         if (this.state == SwitchState.WAIT_FEATURES_REPLY) {
452             this.sid = reply.getDatapathId();
453             this.buffers = reply.getBuffers();
454             this.capabilities = reply.getCapabilities();
455             this.tables = reply.getTables();
456             this.actions = reply.getActions();
457             // notify core of this error event
458             for (OFPhysicalPort port : reply.getPorts()) {
459                 updatePhysicalPort(port);
460             }
461             // config the switch to send full data packet
462             OFSetConfig config = (OFSetConfig) factory
463                     .getMessage(OFType.SET_CONFIG);
464             config.setMissSendLength((short) 0xffff).setLengthU(
465                     OFSetConfig.MINIMUM_LENGTH);
466             asyncSend(config);
467             // send config request to make sure the switch can handle the set config
468             OFMessage getConfig = factory.getMessage(OFType.GET_CONFIG_REQUEST);
469             asyncSend(getConfig);
470             this.state = SwitchState.WAIT_CONFIG_REPLY;
471             // inform core that a new switch is now operational
472             reportSwitchStateChange(true);
473         }
474     }
475
476     private void updatePhysicalPort(OFPhysicalPort port) {
477         Short portNumber = port.getPortNumber();
478         physicalPorts.put(portNumber, port);
479         portBandwidth
480                 .put(
481                         portNumber,
482                         port.getCurrentFeatures()
483                                 & (OFPortFeatures.OFPPF_10MB_FD.getValue()
484                                         | OFPortFeatures.OFPPF_10MB_HD
485                                                 .getValue()
486                                         | OFPortFeatures.OFPPF_100MB_FD
487                                                 .getValue()
488                                         | OFPortFeatures.OFPPF_100MB_HD
489                                                 .getValue()
490                                         | OFPortFeatures.OFPPF_1GB_FD
491                                                 .getValue()
492                                         | OFPortFeatures.OFPPF_1GB_HD
493                                                 .getValue() | OFPortFeatures.OFPPF_10GB_FD
494                                         .getValue()));
495     }
496
497     private void deletePhysicalPort(OFPhysicalPort port) {
498         Short portNumber = port.getPortNumber();
499         physicalPorts.remove(portNumber);
500         portBandwidth.remove(portNumber);
501     }
502
503     @Override
504     public boolean isOperational() {
505         return ((this.state == SwitchState.WAIT_CONFIG_REPLY) || (this.state == SwitchState.OPERATIONAL));
506     }
507
508     @Override
509     public String toString() {
510         return ("["
511                 + this.socket.toString()
512                 + " SWID "
513                 + (isOperational() ? HexString.toHexString(this.sid)
514                         : "unkbown") + "]");
515     }
516
517     @Override
518     public Date getConnectedDate() {
519         return this.connectedDate;
520     }
521
522     public String getInstanceName() {
523         return instanceName;
524     }
525
526     @Override
527     public Object getStatistics(OFStatisticsRequest req) {
528         int xid = getNextXid();
529         StatisticsCollector worker = new StatisticsCollector(this, xid, req);
530         messageWaitingDone.put(xid, worker);
531         Future<Object> submit = executor.submit(worker);
532         Object result = null;
533         try {
534             result = submit
535                     .get(STATS_COLLECTION_TIMEOUT, TimeUnit.MILLISECONDS);
536             return result;
537         } catch (Exception e) {
538             logger.warn("Timeout while waiting for " + req.getType()
539                     + " replies");
540             result = null; // to indicate timeout has occurred
541             return result;
542         }
543     }
544
545     @Override
546     public Object syncSend(OFMessage msg) {
547         Integer xid = getNextXid();
548         SynchronousMessage worker = new SynchronousMessage(this, xid, msg);
549         messageWaitingDone.put(xid, worker);
550         Object result = null;
551         Boolean status = false;
552         Future<Object> submit = executor.submit(worker);
553         try {
554             result = submit
555                     .get(SYNCHRONOUS_FLOW_TIMEOUT, TimeUnit.MILLISECONDS);
556             messageWaitingDone.remove(xid);
557             if (result == null) {
558                 // if result  is null, then it means the switch can handle this message successfully
559                 // convert the result into a Boolean with value true
560                 status = true;
561                 //logger.debug("Successfully send " + msg.getType().toString());
562                 result = status;
563             } else {
564                 // if result  is not null, this means the switch can't handle this message
565                 // the result if OFError already
566                 logger.debug("Send " + msg.getType().toString()
567                         + " failed --> " + ((OFError) result).toString());
568             }
569             return result;
570         } catch (Exception e) {
571             logger.warn("Timeout while waiting for " + msg.getType().toString()
572                     + " reply");
573             // convert the result into a Boolean with value false
574             status = false;
575             result = status;
576             return result;
577         }
578     }
579
580     /*
581      * Either a BarrierReply or a OFError is received. If this is a reply for an outstanding sync message,
582      * wake up associated task so that it can continue
583      */
584     private void processBarrierReply(OFBarrierReply msg) {
585         Integer xid = msg.getXid();
586         SynchronousMessage worker = (SynchronousMessage) messageWaitingDone
587                 .remove(xid);
588         if (worker == null) {
589             return;
590         }
591         worker.wakeup();
592     }
593
594     private void processErrorReply(OFError errorMsg) {
595         OFMessage offendingMsg = errorMsg.getOffendingMsg();
596         Integer xid;
597         if (offendingMsg != null) {
598             xid = offendingMsg.getXid();
599         } else {
600             xid = errorMsg.getXid();
601         }
602         /*
603          * the error can be a reply to a synchronous message or to a statistic request message
604          */
605         Callable<?> worker = messageWaitingDone.remove(xid);
606         if (worker == null) {
607             return;
608         }
609         if (worker instanceof SynchronousMessage) {
610             ((SynchronousMessage) worker).wakeup(errorMsg);
611         } else {
612             ((StatisticsCollector) worker).wakeup(errorMsg);
613         }
614     }
615
616     private void processStatsReply(OFStatisticsReply reply) {
617         Integer xid = reply.getXid();
618         StatisticsCollector worker = (StatisticsCollector) messageWaitingDone
619                 .get(xid);
620         if (worker == null) {
621             return;
622         }
623         if (worker.collect(reply)) {
624             // if all the stats records are received (collect() returns true)
625             // then we are done.
626             messageWaitingDone.remove(xid);
627             worker.wakeup();
628         }
629     }
630
631     @Override
632     public Map<Short, OFPhysicalPort> getPhysicalPorts() {
633         return this.physicalPorts;
634     }
635
636     @Override
637     public OFPhysicalPort getPhysicalPort(Short portNumber) {
638         return this.physicalPorts.get(portNumber);
639     }
640
641     @Override
642     public Integer getPortBandwidth(Short portNumber) {
643         return this.portBandwidth.get(portNumber);
644     }
645
646     @Override
647     public Set<Short> getPorts() {
648         return this.physicalPorts.keySet();
649     }
650
651     @Override
652     public Byte getTables() {
653         return this.tables;
654     }
655     
656     @Override
657     public Integer getActions() {
658         return this.actions;
659     }
660     
661     @Override
662     public Integer getCapabilities() {
663         return this.capabilities;
664     }
665
666     @Override
667     public Integer getBuffers() {
668         return this.buffers;
669     }
670
671     @Override
672     public boolean isPortEnabled(short portNumber) {
673         return isPortEnabled(physicalPorts.get(portNumber));
674     }
675
676     @Override
677     public boolean isPortEnabled(OFPhysicalPort port) {
678         if (port == null) {
679             return false;
680         }
681         int portConfig = port.getConfig();
682         int portState = port.getState();
683         if ((portConfig & OFPortConfig.OFPPC_PORT_DOWN.getValue()) > 0) {
684             return false;
685         }
686         if ((portState & OFPortState.OFPPS_LINK_DOWN.getValue()) > 0) {
687             return false;
688         }
689         if ((portState & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK
690                 .getValue()) {
691             return false;
692         }
693         return true;
694     }
695
696     @Override
697     public List<OFPhysicalPort> getEnabledPorts() {
698         List<OFPhysicalPort> result = new ArrayList<OFPhysicalPort>();
699         synchronized (this.physicalPorts) {
700             for (OFPhysicalPort port : physicalPorts.values()) {
701                 if (isPortEnabled(port)) {
702                     result.add(port);
703                 }
704             }
705         }
706         return result;
707     }
708 }