blob: 7351476258d68ab4f8c570493faf38efc6f1d8ed [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.provider.of.device.impl;
tomb5a46e62014-08-26 14:20:00 -070017
Thomas Vachuskaf0397b52015-05-29 13:50:17 -070018import com.google.common.base.Strings;
Thomas Vachuska893bf4b2015-05-29 18:13:18 -070019import com.google.common.collect.Lists;
sangho538108b2015-04-08 14:29:20 -070020import com.google.common.collect.Maps;
21import com.google.common.collect.Sets;
tomb5a46e62014-08-26 14:20:00 -070022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
Thomas Vachuskaf0397b52015-05-29 13:50:17 -070027import org.onlab.packet.ChassisId;
Thomas Vachuskab52a0142015-04-21 17:48:15 -070028import org.onosproject.net.AnnotationKeys;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.net.DefaultAnnotations;
30import org.onosproject.net.Device;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.MastershipRole;
33import org.onosproject.net.Port;
34import org.onosproject.net.PortNumber;
35import org.onosproject.net.SparseAnnotations;
36import org.onosproject.net.device.DefaultDeviceDescription;
37import org.onosproject.net.device.DefaultPortDescription;
sangho538108b2015-04-08 14:29:20 -070038import org.onosproject.net.device.DefaultPortStatistics;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.device.DeviceDescription;
40import org.onosproject.net.device.DeviceProvider;
41import org.onosproject.net.device.DeviceProviderRegistry;
42import org.onosproject.net.device.DeviceProviderService;
43import org.onosproject.net.device.PortDescription;
sangho538108b2015-04-08 14:29:20 -070044import org.onosproject.net.device.PortStatistics;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.provider.AbstractProvider;
46import org.onosproject.net.provider.ProviderId;
47import org.onosproject.openflow.controller.Dpid;
48import org.onosproject.openflow.controller.OpenFlowController;
sangho538108b2015-04-08 14:29:20 -070049import org.onosproject.openflow.controller.OpenFlowEventListener;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070050import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
Brian O'Connorabafb502014-12-02 22:26:20 -080051import org.onosproject.openflow.controller.OpenFlowSwitch;
52import org.onosproject.openflow.controller.OpenFlowSwitchListener;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070053import org.onosproject.openflow.controller.PortDescPropertyType;
Brian O'Connorabafb502014-12-02 22:26:20 -080054import org.onosproject.openflow.controller.RoleState;
Ayaka Koshibee8708e32014-10-22 13:40:18 -070055import org.projectfloodlight.openflow.protocol.OFFactory;
sangho538108b2015-04-08 14:29:20 -070056import org.projectfloodlight.openflow.protocol.OFMessage;
alshabib4680bb62014-09-04 17:15:08 -070057import org.projectfloodlight.openflow.protocol.OFPortConfig;
alshabib25c8eec2014-09-04 16:41:31 -070058import org.projectfloodlight.openflow.protocol.OFPortDesc;
Thomas Vachuskad16ce182014-10-29 17:25:29 -070059import org.projectfloodlight.openflow.protocol.OFPortFeatures;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070060import org.projectfloodlight.openflow.protocol.OFPortOptical;
alshabibafc514a2014-12-01 14:44:05 -080061import org.projectfloodlight.openflow.protocol.OFPortReason;
alshabib4680bb62014-09-04 17:15:08 -070062import org.projectfloodlight.openflow.protocol.OFPortState;
sangho538108b2015-04-08 14:29:20 -070063import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
64import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
alshabiba14f3642014-09-05 09:31:31 -070065import org.projectfloodlight.openflow.protocol.OFPortStatus;
sangho538108b2015-04-08 14:29:20 -070066import org.projectfloodlight.openflow.protocol.OFStatsReply;
Thomas Vachuska893bf4b2015-05-29 18:13:18 -070067import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
sangho538108b2015-04-08 14:29:20 -070068import org.projectfloodlight.openflow.protocol.OFStatsType;
Thomas Vachuskad16ce182014-10-29 17:25:29 -070069import org.projectfloodlight.openflow.protocol.OFVersion;
70import org.projectfloodlight.openflow.types.PortSpeed;
tomb5a46e62014-08-26 14:20:00 -070071import org.slf4j.Logger;
tom5f38b3a2014-08-27 23:50:54 -070072
tom782a7cf2014-09-11 23:58:38 -070073import java.util.ArrayList;
sangho538108b2015-04-08 14:29:20 -070074import java.util.Collection;
75import java.util.Collections;
76import java.util.HashMap;
77import java.util.HashSet;
tom782a7cf2014-09-11 23:58:38 -070078import java.util.List;
79
Brian O'Connorabafb502014-12-02 22:26:20 -080080import static org.onosproject.net.DeviceId.deviceId;
81import static org.onosproject.net.Port.Type.COPPER;
82import static org.onosproject.net.Port.Type.FIBER;
83import static org.onosproject.openflow.controller.Dpid.dpid;
84import static org.onosproject.openflow.controller.Dpid.uri;
tom782a7cf2014-09-11 23:58:38 -070085import static org.slf4j.LoggerFactory.getLogger;
86
tomb5a46e62014-08-26 14:20:00 -070087/**
tomb1260e42014-08-26 18:39:57 -070088 * Provider which uses an OpenFlow controller to detect network
tome06f8552014-08-26 16:58:42 -070089 * infrastructure devices.
tomb5a46e62014-08-26 14:20:00 -070090 */
tomb1260e42014-08-26 18:39:57 -070091@Component(immediate = true)
tomab21e7c2014-08-26 15:23:08 -070092public class OpenFlowDeviceProvider extends AbstractProvider implements DeviceProvider {
tomb5a46e62014-08-26 14:20:00 -070093
alshabiba89cc582014-09-09 16:43:00 -070094 private static final Logger LOG = getLogger(OpenFlowDeviceProvider.class);
Thomas Vachuskad16ce182014-10-29 17:25:29 -070095 private static final long MBPS = 1_000 * 1_000;
tomb5a46e62014-08-26 14:20:00 -070096
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom96dfcab2014-08-28 09:26:03 -070098 protected DeviceProviderRegistry providerRegistry;
tomab21e7c2014-08-26 15:23:08 -070099
tom5f38b3a2014-08-27 23:50:54 -0700100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected OpenFlowController controller;
102
tomab21e7c2014-08-26 15:23:08 -0700103 private DeviceProviderService providerService;
tomb5a46e62014-08-26 14:20:00 -0700104
sangho538108b2015-04-08 14:29:20 -0700105 private final InternalDeviceProvider listener = new InternalDeviceProvider();
106
107 // TODO: We need to make the poll interval configurable.
108 static final int POLL_INTERVAL = 10;
109
110 private HashMap<Dpid, PortStatsCollector> collectors = Maps.newHashMap();
tomd40fc7a2014-09-04 16:41:10 -0700111
tomab21e7c2014-08-26 15:23:08 -0700112 /**
113 * Creates an OpenFlow device provider.
114 */
115 public OpenFlowDeviceProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800116 super(new ProviderId("of", "org.onosproject.provider.openflow"));
tomab21e7c2014-08-26 15:23:08 -0700117 }
118
tomb5a46e62014-08-26 14:20:00 -0700119 @Activate
120 public void activate() {
tom96dfcab2014-08-28 09:26:03 -0700121 providerService = providerRegistry.register(this);
tomd40fc7a2014-09-04 16:41:10 -0700122 controller.addListener(listener);
sangho538108b2015-04-08 14:29:20 -0700123 controller.addEventListener(listener);
alshabibc944fd02014-09-10 17:55:17 -0700124 for (OpenFlowSwitch sw : controller.getSwitches()) {
Yuta HIGUCHIac2972a2014-11-18 12:58:52 -0800125 try {
126 listener.switchAdded(new Dpid(sw.getId()));
127 } catch (Exception e) {
128 LOG.warn("Failed initially adding {} : {}", sw.getStringId(), e.getMessage());
129 LOG.debug("Error details:", e);
130 // disconnect to trigger switch-add later
131 sw.disconnectSwitch();
132 }
sangho538108b2015-04-08 14:29:20 -0700133 PortStatsCollector psc = new PortStatsCollector(sw, POLL_INTERVAL);
134 psc.start();
135 collectors.put(new Dpid(sw.getId()), psc);
alshabibc944fd02014-09-10 17:55:17 -0700136 }
alshabiba89cc582014-09-09 16:43:00 -0700137 LOG.info("Started");
tomb5a46e62014-08-26 14:20:00 -0700138 }
139
140 @Deactivate
141 public void deactivate() {
tom96dfcab2014-08-28 09:26:03 -0700142 providerRegistry.unregister(this);
tomd40fc7a2014-09-04 16:41:10 -0700143 controller.removeListener(listener);
tomab21e7c2014-08-26 15:23:08 -0700144 providerService = null;
alshabibc944fd02014-09-10 17:55:17 -0700145
alshabiba89cc582014-09-09 16:43:00 -0700146 LOG.info("Stopped");
tomb5a46e62014-08-26 14:20:00 -0700147 }
148
Ayaka Koshibee60d4522014-10-28 15:07:00 -0700149
150 @Override
Yuta HIGUCHI54815322014-10-31 23:17:08 -0700151 public boolean isReachable(DeviceId deviceId) {
152 OpenFlowSwitch sw = controller.getSwitch(dpid(deviceId.uri()));
Yuta HIGUCHI69a27352014-10-31 15:48:37 -0700153 if (sw == null || !sw.isConnected()) {
Ayaka Koshibee60d4522014-10-28 15:07:00 -0700154 return false;
155 }
156 return true;
Ayaka Koshibee60d4522014-10-28 15:07:00 -0700157 }
158
tomab21e7c2014-08-26 15:23:08 -0700159 @Override
Ayaka Koshibe78bcbc12014-11-19 14:28:58 -0800160 public void triggerProbe(DeviceId deviceId) {
Yuta HIGUCHI802d0e82014-10-31 16:07:37 -0700161 LOG.info("Triggering probe on device {}", deviceId);
Ayaka Koshibee8708e32014-10-22 13:40:18 -0700162
Yuta HIGUCHI802d0e82014-10-31 16:07:37 -0700163 final Dpid dpid = dpid(deviceId.uri());
164 OpenFlowSwitch sw = controller.getSwitch(dpid);
165 if (sw == null || !sw.isConnected()) {
Ayaka Koshibe78bcbc12014-11-19 14:28:58 -0800166 LOG.error("Failed to probe device {} on sw={}", deviceId, sw);
Yuta HIGUCHI802d0e82014-10-31 16:07:37 -0700167 providerService.deviceDisconnected(deviceId);
168 } else {
Ayaka Koshibe78bcbc12014-11-19 14:28:58 -0800169 LOG.trace("Confirmed device {} connection", deviceId);
Yuta HIGUCHI802d0e82014-10-31 16:07:37 -0700170 }
Ayaka Koshibee8708e32014-10-22 13:40:18 -0700171
Ayaka Koshibee60d4522014-10-28 15:07:00 -0700172 // Prompt an update of port information. We can use any XID for this.
Ayaka Koshibee8708e32014-10-22 13:40:18 -0700173 OFFactory fact = sw.factory();
174 switch (fact.getVersion()) {
175 case OF_10:
176 sw.sendMsg(fact.buildFeaturesRequest().setXid(0).build());
177 break;
178 case OF_13:
179 sw.sendMsg(fact.buildPortDescStatsRequest().setXid(0).build());
180 break;
181 default:
182 LOG.warn("Unhandled protocol version");
183 }
tomab21e7c2014-08-26 15:23:08 -0700184 }
185
186 @Override
Yuta HIGUCHI54815322014-10-31 23:17:08 -0700187 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
alshabibf1216ed2014-09-03 11:53:54 -0700188 switch (newRole) {
tom782a7cf2014-09-11 23:58:38 -0700189 case MASTER:
Yuta HIGUCHI54815322014-10-31 23:17:08 -0700190 controller.setRole(dpid(deviceId.uri()), RoleState.MASTER);
tom782a7cf2014-09-11 23:58:38 -0700191 break;
192 case STANDBY:
Yuta HIGUCHI54815322014-10-31 23:17:08 -0700193 controller.setRole(dpid(deviceId.uri()), RoleState.EQUAL);
tom782a7cf2014-09-11 23:58:38 -0700194 break;
195 case NONE:
Yuta HIGUCHI54815322014-10-31 23:17:08 -0700196 controller.setRole(dpid(deviceId.uri()), RoleState.SLAVE);
tom782a7cf2014-09-11 23:58:38 -0700197 break;
198 default:
199 LOG.error("Unknown Mastership state : {}", newRole);
alshabibf1216ed2014-09-03 11:53:54 -0700200
201 }
Yuta HIGUCHI54815322014-10-31 23:17:08 -0700202 LOG.info("Accepting mastership role change for device {}", deviceId);
tomab21e7c2014-08-26 15:23:08 -0700203 }
204
Thomas Vachuska893bf4b2015-05-29 18:13:18 -0700205 private void pushPortMetrics(Dpid dpid, List<OFPortStatsEntry> portStatsEntries) {
sangho538108b2015-04-08 14:29:20 -0700206 DeviceId deviceId = DeviceId.deviceId(dpid.uri(dpid));
Thomas Vachuska893bf4b2015-05-29 18:13:18 -0700207 Collection<PortStatistics> stats = buildPortStatistics(deviceId, portStatsEntries);
sangho538108b2015-04-08 14:29:20 -0700208 providerService.updatePortStatistics(deviceId, stats);
209 }
210
Thomas Vachuska893bf4b2015-05-29 18:13:18 -0700211 private Collection<PortStatistics> buildPortStatistics(DeviceId deviceId,
212 List<OFPortStatsEntry> entries) {
sangho538108b2015-04-08 14:29:20 -0700213 HashSet<PortStatistics> stats = Sets.newHashSet();
214
Thomas Vachuska893bf4b2015-05-29 18:13:18 -0700215 for (OFPortStatsEntry entry : entries) {
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700216 try {
217 if (entry.getPortNo().getPortNumber() < 0) {
218 continue;
219 }
220 DefaultPortStatistics.Builder builder = DefaultPortStatistics.builder();
221 DefaultPortStatistics stat = builder.setDeviceId(deviceId)
222 .setPort(entry.getPortNo().getPortNumber())
223 .setPacketsReceived(entry.getRxPackets().getValue())
224 .setPacketsSent(entry.getTxPackets().getValue())
225 .setBytesReceived(entry.getRxBytes().getValue())
226 .setBytesSent(entry.getTxBytes().getValue())
227 .setPacketsRxDropped(entry.getRxDropped().getValue())
228 .setPacketsTxDropped(entry.getTxDropped().getValue())
229 .setPacketsRxErrors(entry.getRxErrors().getValue())
230 .setPacketsTxErrors(entry.getTxErrors().getValue())
231 .setDurationSec(entry.getVersion() == OFVersion.OF_10 ? 0 : entry.getDurationSec())
232 .setDurationNano(entry.getVersion() == OFVersion.OF_10 ? 0 : entry.getDurationNsec())
233 .build();
sangho538108b2015-04-08 14:29:20 -0700234
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700235 stats.add(stat);
236 } catch (Exception e) {
237 LOG.warn("Unable to process port stats", e);
238 }
sangho538108b2015-04-08 14:29:20 -0700239 }
240
241 return Collections.unmodifiableSet(stats);
242
243 }
244
245 private class InternalDeviceProvider implements OpenFlowSwitchListener, OpenFlowEventListener {
Thomas Vachuska893bf4b2015-05-29 18:13:18 -0700246
247 private List<OFPortStatsEntry> portStatsReplies = Lists.newArrayList();
248
alshabibf1216ed2014-09-03 11:53:54 -0700249 @Override
tomd1900f32014-09-03 14:08:16 -0700250 public void switchAdded(Dpid dpid) {
alshabib6f5460b2014-09-03 14:46:17 -0700251 if (providerService == null) {
252 return;
253 }
tom782a7cf2014-09-11 23:58:38 -0700254 DeviceId did = deviceId(uri(dpid));
alshabib6f5460b2014-09-03 14:46:17 -0700255 OpenFlowSwitch sw = controller.getSwitch(dpid);
256
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700257 Device.Type deviceType = sw.isOptical() ? Device.Type.ROADM :
258 Device.Type.SWITCH;
alshabib7911a052014-10-16 17:49:37 -0700259 ChassisId cId = new ChassisId(dpid.value());
Ray Milkeye53f1712015-01-16 09:17:16 -0800260
Thomas Vachuska82041f52014-11-30 22:14:02 -0800261 SparseAnnotations annotations = DefaultAnnotations.builder()
Ray Milkeye53f1712015-01-16 09:17:16 -0800262 .set("protocol", sw.factory().getVersion().toString())
263 .set("channelId", sw.channelId())
264 .build();
265
tomd1900f32014-09-03 14:08:16 -0700266 DeviceDescription description =
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700267 new DefaultDeviceDescription(did.uri(), deviceType,
Ray Milkeyd3edd032015-01-16 11:38:58 -0800268 sw.manufacturerDescription(),
tom782a7cf2014-09-11 23:58:38 -0700269 sw.hardwareDescription(),
270 sw.softwareDescription(),
alshabib7911a052014-10-16 17:49:37 -0700271 sw.serialNumber(),
Thomas Vachuska82041f52014-11-30 22:14:02 -0800272 cId, annotations);
tom782a7cf2014-09-11 23:58:38 -0700273 providerService.deviceConnected(did, description);
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700274 providerService.updatePorts(did, buildPortDescriptions(sw));
sangho538108b2015-04-08 14:29:20 -0700275
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700276 PortStatsCollector psc =
277 new PortStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL);
sangho538108b2015-04-08 14:29:20 -0700278 psc.start();
279 collectors.put(dpid, psc);
alshabib25c8eec2014-09-04 16:41:31 -0700280 }
281
alshabibf1216ed2014-09-03 11:53:54 -0700282 @Override
283 public void switchRemoved(Dpid dpid) {
alshabib6f5460b2014-09-03 14:46:17 -0700284 if (providerService == null) {
285 return;
286 }
tom782a7cf2014-09-11 23:58:38 -0700287 providerService.deviceDisconnected(deviceId(uri(dpid)));
alshabibf1216ed2014-09-03 11:53:54 -0700288
sangho538108b2015-04-08 14:29:20 -0700289 PortStatsCollector collector = collectors.remove(dpid);
290 if (collector != null) {
291 collector.stop();
292 }
293 }
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700294
295 @Override
296 public void switchChanged(Dpid dpid) {
297 if (providerService == null) {
298 return;
299 }
300 DeviceId did = deviceId(uri(dpid));
301 OpenFlowSwitch sw = controller.getSwitch(dpid);
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700302 providerService.updatePorts(did, buildPortDescriptions(sw));
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700303 }
304
alshabiba14f3642014-09-05 09:31:31 -0700305 @Override
306 public void portChanged(Dpid dpid, OFPortStatus status) {
alshabibafc514a2014-12-01 14:44:05 -0800307 PortDescription portDescription = buildPortDescription(status);
tom782a7cf2014-09-11 23:58:38 -0700308 providerService.portStatusChanged(deviceId(uri(dpid)), portDescription);
alshabibf1216ed2014-09-03 11:53:54 -0700309 }
310
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700311 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700312 public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
313 MastershipRole request = roleOf(requested);
314 MastershipRole reply = roleOf(response);
315
316 providerService.receivedRoleReply(deviceId(uri(dpid)), request, reply);
317 }
318
319 /**
320 * Translates a RoleState to the corresponding MastershipRole.
321 *
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700322 * @param response role state
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700323 * @return a MastershipRole
324 */
325 private MastershipRole roleOf(RoleState response) {
326 switch (response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700327 case MASTER:
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700328 return MastershipRole.MASTER;
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700329 case EQUAL:
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700330 return MastershipRole.STANDBY;
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700331 case SLAVE:
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700332 return MastershipRole.NONE;
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700333 default:
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700334 LOG.warn("unknown role {}", response);
335 return null;
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700336 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700337 }
338
alshabiba14f3642014-09-05 09:31:31 -0700339 /**
340 * Builds a list of port descriptions for a given list of ports.
tomff7eb7c2014-09-08 12:49:03 -0700341 *
alshabiba14f3642014-09-05 09:31:31 -0700342 * @return list of portdescriptions
343 */
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700344 private List<PortDescription> buildPortDescriptions(OpenFlowSwitch sw) {
345 final List<PortDescription> portDescs = new ArrayList<>(sw.getPorts().size());
346 sw.getPorts().forEach(port -> portDescs.add(buildPortDescription(port)));
347 if (sw.isOptical()) {
348 OpenFlowOpticalSwitch opsw = (OpenFlowOpticalSwitch) sw;
349 opsw.getPortTypes().forEach(type -> {
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700350 opsw.getPortsOf(type).forEach(
351 op -> {
352 portDescs.add(buildPortDescription(type, (OFPortOptical) op));
353 }
354 );
355 });
alshabib4680bb62014-09-04 17:15:08 -0700356 }
357 return portDescs;
358 }
359
alshabiba14f3642014-09-05 09:31:31 -0700360 /**
Ray Milkeye0fade72015-01-15 13:29:47 -0800361 * Creates an annotation for the port name if one is available.
362 *
363 * @param port description of the port
364 * @return annotation containing the port name if one is found,
365 * null otherwise
366 */
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700367 private SparseAnnotations makePortNameAnnotation(String port) {
Ray Milkeye0fade72015-01-15 13:29:47 -0800368 SparseAnnotations annotations = null;
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700369 String portName = Strings.emptyToNull(port);
Ray Milkeye0fade72015-01-15 13:29:47 -0800370 if (portName != null) {
371 annotations = DefaultAnnotations.builder()
Thomas Vachuskab52a0142015-04-21 17:48:15 -0700372 .set(AnnotationKeys.PORT_NAME, portName).build();
Ray Milkeye0fade72015-01-15 13:29:47 -0800373 }
374 return annotations;
375 }
376
377 /**
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700378 * Build a portDescription from a given Ethernet port description.
tomff7eb7c2014-09-08 12:49:03 -0700379 *
alshabiba14f3642014-09-05 09:31:31 -0700380 * @param port the port to build from.
381 * @return portDescription for the port.
382 */
383 private PortDescription buildPortDescription(OFPortDesc port) {
Thomas Vachuskad16ce182014-10-29 17:25:29 -0700384 PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
385 boolean enabled =
386 !port.getState().contains(OFPortState.LINK_DOWN) &&
387 !port.getConfig().contains(OFPortConfig.PORT_DOWN);
388 Port.Type type = port.getCurr().contains(OFPortFeatures.PF_FIBER) ? FIBER : COPPER;
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700389 SparseAnnotations annotations = makePortNameAnnotation(port.getName());
Ray Milkeye0fade72015-01-15 13:29:47 -0800390 return new DefaultPortDescription(portNo, enabled, type,
391 portSpeed(port), annotations);
alshabiba14f3642014-09-05 09:31:31 -0700392 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700393
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700394 /**
395 * Build a portDescription from a given a port description describing some
396 * Optical port.
397 *
398 * @param port description property type.
399 * @param port the port to build from.
400 * @return portDescription for the port.
401 */
402 private PortDescription buildPortDescription(PortDescPropertyType ptype, OFPortOptical port) {
403 // Minimally functional fixture. This needs to be fixed as we add better support.
404 PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
Ayaka Koshibe74b55272015-05-28 15:16:04 -0700405
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700406 boolean enabled = !port.getState().contains(OFPortState.LINK_DOWN)
407 && !port.getConfig().contains(OFPortConfig.PORT_DOWN);
408 SparseAnnotations annotations = makePortNameAnnotation(port.getName());
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700409
410 if (port.getVersion() == OFVersion.OF_13
411 && ptype == PortDescPropertyType.OPTICAL_TRANSPORT) {
412 // At this point, not much is carried in the optical port message.
Ayaka Koshibeae541732015-05-19 13:37:27 -0700413 LOG.debug("Optical transport port message {}", port.toString());
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700414 } else {
415 // removable once 1.4+ support complete.
Ayaka Koshibeae541732015-05-19 13:37:27 -0700416 LOG.debug("Unsupported optical port properties");
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700417 }
Ayaka Koshibe74b55272015-05-28 15:16:04 -0700418 return new DefaultPortDescription(portNo, enabled, FIBER, 0, annotations);
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700419 }
420
alshabibafc514a2014-12-01 14:44:05 -0800421 private PortDescription buildPortDescription(OFPortStatus status) {
422 OFPortDesc port = status.getDesc();
423 if (status.getReason() != OFPortReason.DELETE) {
424 return buildPortDescription(port);
425 } else {
426 PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
427 Port.Type type = port.getCurr().contains(OFPortFeatures.PF_FIBER) ? FIBER : COPPER;
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700428 SparseAnnotations annotations = makePortNameAnnotation(port.getName());
Ray Milkeye0fade72015-01-15 13:29:47 -0800429 return new DefaultPortDescription(portNo, false, type,
430 portSpeed(port), annotations);
alshabibafc514a2014-12-01 14:44:05 -0800431 }
432 }
433
Thomas Vachuskad16ce182014-10-29 17:25:29 -0700434 private long portSpeed(OFPortDesc port) {
435 if (port.getVersion() == OFVersion.OF_13) {
436 return port.getCurrSpeed() / MBPS;
437 }
438
439 PortSpeed portSpeed = PortSpeed.SPEED_NONE;
440 for (OFPortFeatures feat : port.getCurr()) {
441 portSpeed = PortSpeed.max(portSpeed, feat.getPortSpeed());
442 }
Thomas Vachuska98eda532014-10-29 17:31:02 -0700443 return portSpeed.getSpeedBps() / MBPS;
Thomas Vachuskad16ce182014-10-29 17:25:29 -0700444 }
sangho538108b2015-04-08 14:29:20 -0700445
446 @Override
447 public void handleMessage(Dpid dpid, OFMessage msg) {
448 switch (msg.getType()) {
449 case STATS_REPLY:
450 if (((OFStatsReply) msg).getStatsType() == OFStatsType.PORT) {
Thomas Vachuska893bf4b2015-05-29 18:13:18 -0700451 OFPortStatsReply portStatsReply = (OFPortStatsReply) msg;
452 portStatsReplies.addAll(portStatsReply.getEntries());
453 if (!portStatsReply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
454 pushPortMetrics(dpid, portStatsReplies);
455 portStatsReplies.clear();
456 }
sangho538108b2015-04-08 14:29:20 -0700457 }
458 break;
459 default:
460 break;
461 }
462 }
alshabibf1216ed2014-09-03 11:53:54 -0700463 }
464
tomb5a46e62014-08-26 14:20:00 -0700465}