blob: 67a8f0e11b3387a5ca10464468c8e99035cfb831 [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 Leenheer2c305302015-12-07 21:37:44 -080062import java.util.function.Supplier;
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080063import java.util.stream.Collectors;
64import java.util.stream.IntStream;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070065
66/**
67 * LINC-OE Optical Emulator switch class.
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070068 *
69 * The LINC ROADM emulator exposes two types of ports: OCh ports connect to ports in the packet layer,
70 * while OMS ports connect to an OMS port on a neighbouring ROADM.
71 *
72 * LINC sends the tap ports (OCh for our purposes) in the regular port desc stats reply,
73 * while it sends *all* ports (both tap and WDM ports, i.e., OCh and OMS) in the experimenter port desc stats reply.
74 *
Marc De Leenheerc2999f32015-11-20 15:52:16 -080075 * As LINC implements custom OF optical extensions (in contrast to the final standard as specified in
76 * ONF TS-022 (March 15, 2015), we need to rewrite flow stat requests and flow mods in {@link #sendMsg(OFMessage)}.
77 *
Marc De Leenheer2c305302015-12-07 21:37:44 -080078 * LINC exposes OchSignal resources: 80 lambdas of 50 GHz (fixed grid) around ITU-T G.694.1 center frequency 193.1 GHz.
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080079 *
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070080 */
Jonathan Hartd9df7bd2015-11-10 17:10:25 -080081public class OfOpticalSwitchImplLinc13
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080082 extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch, LambdaQuery {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070083
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -080084 private static final int LAMBDA_COUNT = 80;
alshabibb452fd72015-04-22 20:46:20 -070085 private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070086 private long barrierXidToWaitFor = -1;
87
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070088 private List<OFPortOptical> opticalPorts;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070089
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070090 @Override
91 public void startDriverHandshake() {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070092 log.warn("Starting driver handshake for sw {}", getStringId());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070093 if (startDriverHandshakeCalled) {
94 throw new SwitchDriverSubHandshakeAlreadyStarted();
95 }
96 startDriverHandshakeCalled = true;
97 try {
98 sendHandshakeOFExperimenterPortDescRequest();
99 } catch (IOException e) {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700100 log.error("LINC-OE exception while sending experimenter port desc:",
101 e.getMessage());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700102 e.printStackTrace();
103 }
104 }
105
106 @Override
107 public boolean isDriverHandshakeComplete() {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700108 return driverHandshakeComplete.get();
109 }
110
111 @Override
112 public void processDriverHandshakeMessage(OFMessage m) {
alshabib9af70072015-02-09 14:34:16 -0800113 if (!startDriverHandshakeCalled) {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700114 throw new SwitchDriverSubHandshakeNotStarted();
115 }
116 if (driverHandshakeComplete.get()) {
117 throw new SwitchDriverSubHandshakeCompleted(m);
118 }
119
120 switch (m.getType()) {
121 case BARRIER_REPLY:
122 if (m.getXid() == barrierXidToWaitFor) {
123 log.debug("LINC-OE Received barrier response");
124 }
125 break;
126 case ERROR:
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -0700127 log.error("Switch {} Error {}", getStringId(), m);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700128 break;
129 case FEATURES_REPLY:
130 break;
131 case FLOW_REMOVED:
132 break;
133 case GET_ASYNC_REPLY:
134 break;
135 case PACKET_IN:
136 break;
137 case PORT_STATUS:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700138 log.warn("****LINC-OE Port Status {} {}", getStringId(), m);
139 processOFPortStatus((OFCircuitPortStatus) m);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700140 break;
141 case QUEUE_GET_CONFIG_REPLY:
142 break;
143 case ROLE_REPLY:
144 break;
145 case STATS_REPLY:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700146 OFStatsReply stats = (OFStatsReply) m;
147 if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
148 log.warn("LINC-OE : Received stats reply message {}", m);
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700149 createOpticalPortList((OFCircuitPortsReply) m);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700150 driverHandshakeComplete.set(true);
151 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700152 break;
153 default:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700154 log.warn("Received message {} during switch-driver " +
155 "subhandshake " + "from switch {} ... " +
156 "Ignoring message", m,
157 getStringId());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700158
159 }
160 }
161
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700162 public void processOFPortStatus(OFCircuitPortStatus ps) {
163 log.debug("LINC-OE ..OF Port Status :", ps);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700164 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700165
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700166 private void sendHandshakeOFExperimenterPortDescRequest() throws
167 IOException {
168 // send multi part message for port description for optical switches
169 OFCircuitPortsRequest circuitPortsRequest = factory()
170 .buildCircuitPortsRequest().setXid(getNextTransactionId())
171 .build();
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700172 log.warn("LINC-OE : Sending experimented circuit port stats " +
173 "message " +
174 "{}",
175 circuitPortsRequest.toString());
alshabiba2df7b2a2015-05-06 13:57:10 -0700176 this.sendHandshakeMessage(circuitPortsRequest);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700177 }
178
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700179 @Override
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700180 /**
181 * Returns a list of standard (Ethernet) ports.
182 *
183 * @return List of ports
184 */
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700185 public List<OFPortDesc> getPorts() {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700186 return Collections.EMPTY_LIST;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700187 }
188
Marc De Leenheerc2999f32015-11-20 15:52:16 -0800189 /**
190 * Rewrite match object to use LINC OF optical extensions.
191 *
192 * @param match original match
193 * @return rewritten match
194 */
195 private Match rewriteMatch(Match match) {
196 Match.Builder mBuilder = factory().buildMatch();
197 for (MatchField mf : match.getMatchFields()) {
198 if (mf == MatchField.EXP_OCH_SIG_ID) {
199 mBuilder.setExact(MatchField.OCH_SIGID, (CircuitSignalID) match.get(mf));
200 continue;
201 }
202 if (mf == MatchField.EXP_OCH_SIGTYPE) {
203 mBuilder.setExact(MatchField.OCH_SIGTYPE, (U8) match.get(mf));
204 continue;
205 }
206 mBuilder.setExact(mf, match.get(mf));
207 }
208
209 return mBuilder.build();
210 }
211
212 /**
213 * Rewrite actions to use LINC OF optical extensions.
214 *
215 * @param actions original actions
216 * @return rewritten actions
217 */
218 private List<OFAction> rewriteActions(List<OFAction> actions) {
219 List<OFAction> newActions = new LinkedList<>();
220
221 for (OFAction action : actions) {
222 if (!(action instanceof OFActionSetField)) {
223 newActions.add(action);
224 continue;
225 }
226
227 OFActionSetField sf = (OFActionSetField) action;
Marc De Leenheer2c305302015-12-07 21:37:44 -0800228 if (!(sf.getField() instanceof OFOxmExpOchSigId)) {
Marc De Leenheerc2999f32015-11-20 15:52:16 -0800229 newActions.add(action);
Marc De Leenheer2c305302015-12-07 21:37:44 -0800230 continue;
Marc De Leenheerc2999f32015-11-20 15:52:16 -0800231 }
232
233 OFOxmExpOchSigId oxm = (OFOxmExpOchSigId) sf.getField();
234 CircuitSignalID signalId = oxm.getValue();
235
236 newActions.add(
237 factory().actions().circuit(factory().oxms().ochSigid(signalId)));
238 }
239
240 return newActions;
241 }
242
243 @Override
244 public void sendMsg(OFMessage msg) {
245 // Ignore everything but flow mods and stat requests
246 if (!(msg instanceof OFFlowMod || msg instanceof OFFlowStatsRequest)) {
247 super.sendMsg(msg);
248 return;
249 }
250
251 Match newMatch;
252 OFMessage newMsg = null;
253
254 if (msg instanceof OFFlowStatsRequest) {
255 // Rewrite match only
256 OFFlowStatsRequest fsr = (OFFlowStatsRequest) msg;
257 newMatch = rewriteMatch(fsr.getMatch());
258 newMsg = fsr.createBuilder().setMatch(newMatch).build();
259 } else if (msg instanceof OFFlowMod) {
260 // Rewrite match and actions
261 OFFlowMod fm = (OFFlowMod) msg;
262 newMatch = rewriteMatch(fm.getMatch());
263 List<OFAction> actions = rewriteActions(fm.getActions());
Marc De Leenheerc2999f32015-11-20 15:52:16 -0800264 newMsg = fm.createBuilder().setMatch(newMatch).setActions(actions).build();
265 }
266
267 super.sendMsg(newMsg);
268 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700269
270 @Override
271 public Boolean supportNxRole() {
272 return false;
273 }
274
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700275 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -0700276 public Device.Type deviceType() {
277 return Device.Type.ROADM;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700278 }
279
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700280 /**
281 * Checks if given port is also part of the regular port desc stats, i.e., is the port a tap port.
282 *
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800283 * @param port given port number
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700284 * @return true if the port is a tap (OCh), false otherwise (OMS port)
285 */
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800286 private boolean isOChPort(long port) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700287 for (OFPortDescStatsReply reply : this.ports) {
288 for (OFPortDesc p : reply.getEntries()) {
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800289 if (p.getPortNo().getPortNumber() == port) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700290 return true;
291 }
292 }
293 }
294
295 return false;
296 }
297
298 /**
299 * Creates an OpenFlow optical port based on the given port and transport type.
300 *
301 * @param port OpenFlow optical port
302 * @param type transport type
303 * @return OpenFlow optical port
304 */
305 private OFPortOptical createOpticalPort(OFPortOptical port, short type) {
306 List<OFPortDescPropOpticalTransport> descList = new ArrayList<>(port.getDesc().size());
307
308 for (OFPortDescPropOpticalTransport desc : port.getDesc()) {
309 OFPortDescPropOpticalTransport newDesc = desc.createBuilder()
310 .setType(desc.getType())
311 .setPortSignalType(type)
312 .setPortType(desc.getPortType())
313 .setReserved(desc.getReserved())
314 .build();
315 descList.add(newDesc);
316 }
317
318 OFPortOptical newPort = port.createBuilder()
319 .setConfig(port.getConfig())
320 .setDesc(descList)
321 .setHwAddr(port.getHwAddr())
322 .setName(port.getName())
323 .setPortNo(port.getPortNo())
324 .setState(port.getState())
325 .build();
326
327 return newPort;
328 }
329
330 /**
331 * Builds list of OFPortOptical ports based on the multi-part circuit ports reply.
332 *
333 * Ensure the optical transport port's signal type is configured correctly.
334 *
335 * @param wPorts OF reply with circuit ports
336 */
337 private void createOpticalPortList(OFCircuitPortsReply wPorts) {
338 opticalPorts = new ArrayList<>(wPorts.getEntries().size());
339
340 for (OFPortOptical p : wPorts.getEntries()) {
341 short signalType;
342
343 // FIXME: use constants once loxi has full optical extensions
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800344 if (isOChPort(p.getPortNo().getPortNumber())) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700345 signalType = 5; // OCH port
346 } else {
347 signalType = 2; // OMS port
348 }
349
350 opticalPorts.add(createOpticalPort(p, signalType));
351 }
352 }
353
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700354 @Override
355 public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700356 if (!type.equals(PortDescPropertyType.OPTICAL_TRANSPORT)) {
357 return Collections.EMPTY_LIST;
358 }
359
360 return opticalPorts;
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700361 }
362
363 @Override
364 public Set<PortDescPropertyType> getPortTypes() {
365 return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
366 }
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800367
368 @Override
369 public SortedSet<OchSignal> queryLambdas(PortNumber port) {
370 // OCh ports don't have lambdas
371 if (isOChPort(port.toLong())) {
372 return Collections.emptySortedSet();
373 }
374
Marc De Leenheer2c305302015-12-07 21:37:44 -0800375 // OMS ports expose 80 fixed grid lambdas of 50GHz width, centered around the ITU-T center frequency 193.1 THz.
376 Supplier<SortedSet<OchSignal>> supplier = () -> new TreeSet<>(new DefaultOchSignalComparator());
377 return IntStream.range(0, LAMBDA_COUNT)
378 .mapToObj(x -> new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, x - (LAMBDA_COUNT / 2), 4))
379 .collect(Collectors.toCollection(supplier));
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800380 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700381}