blob: 23378e959345a6306aa9cbfbba67d6d5d3475140 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
alshabibb452fd72015-04-22 20:46:20 -07002 * Copyright 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 */
alshabibb452fd72015-04-22 20:46:20 -070016package org.onosproject.driver.handshaker;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070017
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070018import com.google.common.collect.ImmutableSet;
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080019import org.onosproject.net.ChannelSpacing;
20import org.onosproject.net.DefaultOchSignalComparator;
Marc De Leenheerc2999f32015-11-20 15:52:16 -080021import org.onosproject.net.Device;
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080022import org.onosproject.net.GridType;
23import org.onosproject.net.OchSignal;
24import org.onosproject.net.PortNumber;
25import org.onosproject.net.behaviour.LambdaQuery;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070026import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
27import org.onosproject.openflow.controller.PortDescPropertyType;
Brian O'Connorabafb502014-12-02 22:26:20 -080028import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
29import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
30import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
31import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070032import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070033import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply;
34import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
Marc De Leenheerc2999f32015-11-20 15:52:16 -080035import org.projectfloodlight.openflow.protocol.OFFlowMod;
36import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070037import org.projectfloodlight.openflow.protocol.OFMessage;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070038import org.projectfloodlight.openflow.protocol.OFObject;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070039import org.projectfloodlight.openflow.protocol.OFPortDesc;
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070040import org.projectfloodlight.openflow.protocol.OFPortDescPropOpticalTransport;
41import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
42import org.projectfloodlight.openflow.protocol.OFPortOptical;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070043import org.projectfloodlight.openflow.protocol.OFStatsReply;
44import org.projectfloodlight.openflow.protocol.OFStatsType;
Marc De Leenheerc2999f32015-11-20 15:52:16 -080045import org.projectfloodlight.openflow.protocol.action.OFAction;
46import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
47import org.projectfloodlight.openflow.protocol.match.Match;
48import org.projectfloodlight.openflow.protocol.match.MatchField;
49import org.projectfloodlight.openflow.protocol.oxm.OFOxmExpOchSigId;
50import org.projectfloodlight.openflow.types.CircuitSignalID;
Marc De Leenheerc2999f32015-11-20 15:52:16 -080051import org.projectfloodlight.openflow.types.U8;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070052
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070053import java.io.IOException;
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070054import java.util.ArrayList;
55import java.util.Collections;
Marc De Leenheerc2999f32015-11-20 15:52:16 -080056import java.util.LinkedList;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070057import java.util.List;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070058import java.util.Set;
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080059import java.util.SortedSet;
60import java.util.TreeSet;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070061import java.util.concurrent.atomic.AtomicBoolean;
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080062import java.util.stream.Collectors;
63import java.util.stream.IntStream;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070064
65/**
66 * LINC-OE Optical Emulator switch class.
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070067 *
68 * The LINC ROADM emulator exposes two types of ports: OCh ports connect to ports in the packet layer,
69 * while OMS ports connect to an OMS port on a neighbouring ROADM.
70 *
71 * LINC sends the tap ports (OCh for our purposes) in the regular port desc stats reply,
72 * while it sends *all* ports (both tap and WDM ports, i.e., OCh and OMS) in the experimenter port desc stats reply.
73 *
Marc De Leenheerc2999f32015-11-20 15:52:16 -080074 * As LINC implements custom OF optical extensions (in contrast to the final standard as specified in
75 * ONF TS-022 (March 15, 2015), we need to rewrite flow stat requests and flow mods in {@link #sendMsg(OFMessage)}.
76 *
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080077 * LINC exposes OchSignal resources: 80 lambdas of 50 GHz around ITU-T G.694.1 center frequency 193.1 GHz.
78 *
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070079 */
Jonathan Hartd9df7bd2015-11-10 17:10:25 -080080public class OfOpticalSwitchImplLinc13
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080081 extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch, LambdaQuery {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070082
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080083 private static final int LAMBDA_COUNT = 80;
alshabibb452fd72015-04-22 20:46:20 -070084 private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070085 private long barrierXidToWaitFor = -1;
86
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070087 private List<OFPortOptical> opticalPorts;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070088
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070089 @Override
90 public void startDriverHandshake() {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070091 log.warn("Starting driver handshake for sw {}", getStringId());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070092 if (startDriverHandshakeCalled) {
93 throw new SwitchDriverSubHandshakeAlreadyStarted();
94 }
95 startDriverHandshakeCalled = true;
96 try {
97 sendHandshakeOFExperimenterPortDescRequest();
98 } catch (IOException e) {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070099 log.error("LINC-OE exception while sending experimenter port desc:",
100 e.getMessage());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700101 e.printStackTrace();
102 }
103 }
104
105 @Override
106 public boolean isDriverHandshakeComplete() {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700107 return driverHandshakeComplete.get();
108 }
109
110 @Override
111 public void processDriverHandshakeMessage(OFMessage m) {
alshabib9af70072015-02-09 14:34:16 -0800112 if (!startDriverHandshakeCalled) {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700113 throw new SwitchDriverSubHandshakeNotStarted();
114 }
115 if (driverHandshakeComplete.get()) {
116 throw new SwitchDriverSubHandshakeCompleted(m);
117 }
118
119 switch (m.getType()) {
120 case BARRIER_REPLY:
121 if (m.getXid() == barrierXidToWaitFor) {
122 log.debug("LINC-OE Received barrier response");
123 }
124 break;
125 case ERROR:
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -0700126 log.error("Switch {} Error {}", getStringId(), m);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700127 break;
128 case FEATURES_REPLY:
129 break;
130 case FLOW_REMOVED:
131 break;
132 case GET_ASYNC_REPLY:
133 break;
134 case PACKET_IN:
135 break;
136 case PORT_STATUS:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700137 log.warn("****LINC-OE Port Status {} {}", getStringId(), m);
138 processOFPortStatus((OFCircuitPortStatus) m);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700139 break;
140 case QUEUE_GET_CONFIG_REPLY:
141 break;
142 case ROLE_REPLY:
143 break;
144 case STATS_REPLY:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700145 OFStatsReply stats = (OFStatsReply) m;
146 if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
147 log.warn("LINC-OE : Received stats reply message {}", m);
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700148 createOpticalPortList((OFCircuitPortsReply) m);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700149 driverHandshakeComplete.set(true);
150 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700151 break;
152 default:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700153 log.warn("Received message {} during switch-driver " +
154 "subhandshake " + "from switch {} ... " +
155 "Ignoring message", m,
156 getStringId());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700157
158 }
159 }
160
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700161 public void processOFPortStatus(OFCircuitPortStatus ps) {
162 log.debug("LINC-OE ..OF Port Status :", ps);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700163 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700164
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700165 private void sendHandshakeOFExperimenterPortDescRequest() throws
166 IOException {
167 // send multi part message for port description for optical switches
168 OFCircuitPortsRequest circuitPortsRequest = factory()
169 .buildCircuitPortsRequest().setXid(getNextTransactionId())
170 .build();
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700171 log.warn("LINC-OE : Sending experimented circuit port stats " +
172 "message " +
173 "{}",
174 circuitPortsRequest.toString());
alshabiba2df7b2a2015-05-06 13:57:10 -0700175 this.sendHandshakeMessage(circuitPortsRequest);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700176 }
177
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700178 @Override
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700179 /**
180 * Returns a list of standard (Ethernet) ports.
181 *
182 * @return List of ports
183 */
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700184 public List<OFPortDesc> getPorts() {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700185 return Collections.EMPTY_LIST;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700186 }
187
Marc De Leenheerc2999f32015-11-20 15:52:16 -0800188 /**
189 * Rewrite match object to use LINC OF optical extensions.
190 *
191 * @param match original match
192 * @return rewritten match
193 */
194 private Match rewriteMatch(Match match) {
195 Match.Builder mBuilder = factory().buildMatch();
196 for (MatchField mf : match.getMatchFields()) {
197 if (mf == MatchField.EXP_OCH_SIG_ID) {
198 mBuilder.setExact(MatchField.OCH_SIGID, (CircuitSignalID) match.get(mf));
199 continue;
200 }
201 if (mf == MatchField.EXP_OCH_SIGTYPE) {
202 mBuilder.setExact(MatchField.OCH_SIGTYPE, (U8) match.get(mf));
203 continue;
204 }
205 mBuilder.setExact(mf, match.get(mf));
206 }
207
208 return mBuilder.build();
209 }
210
211 /**
212 * Rewrite actions to use LINC OF optical extensions.
213 *
214 * @param actions original actions
215 * @return rewritten actions
216 */
217 private List<OFAction> rewriteActions(List<OFAction> actions) {
218 List<OFAction> newActions = new LinkedList<>();
219
220 for (OFAction action : actions) {
221 if (!(action instanceof OFActionSetField)) {
222 newActions.add(action);
223 continue;
224 }
225
226 OFActionSetField sf = (OFActionSetField) action;
227 if (!(sf instanceof OFOxmExpOchSigId)) {
228 newActions.add(action);
229 }
230
231 OFOxmExpOchSigId oxm = (OFOxmExpOchSigId) sf.getField();
232 CircuitSignalID signalId = oxm.getValue();
233
234 newActions.add(
235 factory().actions().circuit(factory().oxms().ochSigid(signalId)));
236 }
237
238 return newActions;
239 }
240
241 @Override
242 public void sendMsg(OFMessage msg) {
243 // Ignore everything but flow mods and stat requests
244 if (!(msg instanceof OFFlowMod || msg instanceof OFFlowStatsRequest)) {
245 super.sendMsg(msg);
246 return;
247 }
248
249 Match newMatch;
250 OFMessage newMsg = null;
251
252 if (msg instanceof OFFlowStatsRequest) {
253 // Rewrite match only
254 OFFlowStatsRequest fsr = (OFFlowStatsRequest) msg;
255 newMatch = rewriteMatch(fsr.getMatch());
256 newMsg = fsr.createBuilder().setMatch(newMatch).build();
257 } else if (msg instanceof OFFlowMod) {
258 // Rewrite match and actions
259 OFFlowMod fm = (OFFlowMod) msg;
260 newMatch = rewriteMatch(fm.getMatch());
261 List<OFAction> actions = rewriteActions(fm.getActions());
262
263 newMsg = fm.createBuilder().setMatch(newMatch).setActions(actions).build();
264 }
265
266 super.sendMsg(newMsg);
267 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700268
269 @Override
270 public Boolean supportNxRole() {
271 return false;
272 }
273
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700274 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -0700275 public Device.Type deviceType() {
276 return Device.Type.ROADM;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700277 }
278
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700279 /**
280 * Checks if given port is also part of the regular port desc stats, i.e., is the port a tap port.
281 *
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800282 * @param port given port number
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700283 * @return true if the port is a tap (OCh), false otherwise (OMS port)
284 */
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800285 private boolean isOChPort(long port) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700286 for (OFPortDescStatsReply reply : this.ports) {
287 for (OFPortDesc p : reply.getEntries()) {
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800288 if (p.getPortNo().getPortNumber() == port) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700289 return true;
290 }
291 }
292 }
293
294 return false;
295 }
296
297 /**
298 * Creates an OpenFlow optical port based on the given port and transport type.
299 *
300 * @param port OpenFlow optical port
301 * @param type transport type
302 * @return OpenFlow optical port
303 */
304 private OFPortOptical createOpticalPort(OFPortOptical port, short type) {
305 List<OFPortDescPropOpticalTransport> descList = new ArrayList<>(port.getDesc().size());
306
307 for (OFPortDescPropOpticalTransport desc : port.getDesc()) {
308 OFPortDescPropOpticalTransport newDesc = desc.createBuilder()
309 .setType(desc.getType())
310 .setPortSignalType(type)
311 .setPortType(desc.getPortType())
312 .setReserved(desc.getReserved())
313 .build();
314 descList.add(newDesc);
315 }
316
317 OFPortOptical newPort = port.createBuilder()
318 .setConfig(port.getConfig())
319 .setDesc(descList)
320 .setHwAddr(port.getHwAddr())
321 .setName(port.getName())
322 .setPortNo(port.getPortNo())
323 .setState(port.getState())
324 .build();
325
326 return newPort;
327 }
328
329 /**
330 * Builds list of OFPortOptical ports based on the multi-part circuit ports reply.
331 *
332 * Ensure the optical transport port's signal type is configured correctly.
333 *
334 * @param wPorts OF reply with circuit ports
335 */
336 private void createOpticalPortList(OFCircuitPortsReply wPorts) {
337 opticalPorts = new ArrayList<>(wPorts.getEntries().size());
338
339 for (OFPortOptical p : wPorts.getEntries()) {
340 short signalType;
341
342 // FIXME: use constants once loxi has full optical extensions
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800343 if (isOChPort(p.getPortNo().getPortNumber())) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700344 signalType = 5; // OCH port
345 } else {
346 signalType = 2; // OMS port
347 }
348
349 opticalPorts.add(createOpticalPort(p, signalType));
350 }
351 }
352
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700353 @Override
354 public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700355 if (!type.equals(PortDescPropertyType.OPTICAL_TRANSPORT)) {
356 return Collections.EMPTY_LIST;
357 }
358
359 return opticalPorts;
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700360 }
361
362 @Override
363 public Set<PortDescPropertyType> getPortTypes() {
364 return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
365 }
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800366
367 @Override
368 public SortedSet<OchSignal> queryLambdas(PortNumber port) {
369 // OCh ports don't have lambdas
370 if (isOChPort(port.toLong())) {
371 return Collections.emptySortedSet();
372 }
373
374 // OMS ports expose 80 lambdas of 50GHz width, centered around the ITU-T center frequency.
375 // We report these with a spacing of 12.5 GHz.
376 List<OchSignal> lambdas = IntStream.range(0, LAMBDA_COUNT)
377 .mapToObj(x -> new OchSignal(GridType.FLEX, ChannelSpacing.CHL_12P5GHZ, x - (LAMBDA_COUNT / 2), 1))
378 .collect(Collectors.toList());
379
380 SortedSet<OchSignal> result = new TreeSet<>(new DefaultOchSignalComparator());
381 result.addAll(lambdas);
382
383 return result;
384 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700385}