blob: 8d5822c827869c75d4ea6d64008244466c6d47fd [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 Leenheerc2999f32015-11-20 15:52:16 -080019import org.onosproject.net.Device;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070020import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
21import org.onosproject.openflow.controller.PortDescPropertyType;
Brian O'Connorabafb502014-12-02 22:26:20 -080022import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
23import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
24import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
25import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070026import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070027import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply;
28import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
Marc De Leenheerc2999f32015-11-20 15:52:16 -080029import org.projectfloodlight.openflow.protocol.OFFlowMod;
30import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070031import org.projectfloodlight.openflow.protocol.OFMessage;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070032import org.projectfloodlight.openflow.protocol.OFObject;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070033import org.projectfloodlight.openflow.protocol.OFPortDesc;
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070034import org.projectfloodlight.openflow.protocol.OFPortDescPropOpticalTransport;
35import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
36import org.projectfloodlight.openflow.protocol.OFPortOptical;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070037import org.projectfloodlight.openflow.protocol.OFStatsReply;
38import org.projectfloodlight.openflow.protocol.OFStatsType;
Marc De Leenheerc2999f32015-11-20 15:52:16 -080039import org.projectfloodlight.openflow.protocol.action.OFAction;
40import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
41import org.projectfloodlight.openflow.protocol.match.Match;
42import org.projectfloodlight.openflow.protocol.match.MatchField;
43import org.projectfloodlight.openflow.protocol.oxm.OFOxmExpOchSigId;
44import org.projectfloodlight.openflow.types.CircuitSignalID;
Marc De Leenheerc2999f32015-11-20 15:52:16 -080045import org.projectfloodlight.openflow.types.U8;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070046
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070047import java.io.IOException;
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070048import java.util.ArrayList;
49import java.util.Collections;
Marc De Leenheerc2999f32015-11-20 15:52:16 -080050import java.util.LinkedList;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070051import java.util.List;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070052import java.util.Set;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070053import java.util.concurrent.atomic.AtomicBoolean;
54
55/**
56 * LINC-OE Optical Emulator switch class.
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070057 *
58 * The LINC ROADM emulator exposes two types of ports: OCh ports connect to ports in the packet layer,
59 * while OMS ports connect to an OMS port on a neighbouring ROADM.
60 *
61 * LINC sends the tap ports (OCh for our purposes) in the regular port desc stats reply,
62 * while it sends *all* ports (both tap and WDM ports, i.e., OCh and OMS) in the experimenter port desc stats reply.
63 *
Marc De Leenheerc2999f32015-11-20 15:52:16 -080064 * As LINC implements custom OF optical extensions (in contrast to the final standard as specified in
65 * ONF TS-022 (March 15, 2015), we need to rewrite flow stat requests and flow mods in {@link #sendMsg(OFMessage)}.
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070066 */
Marc De Leenheer622861d2015-12-15 22:52:52 -080067public class OfOpticalSwitchImplLinc13 extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070068
alshabibb452fd72015-04-22 20:46:20 -070069 private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070070 private long barrierXidToWaitFor = -1;
71
Marc De Leenheerfc913dd2015-07-30 16:04:55 -070072 private List<OFPortOptical> opticalPorts;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070073
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070074 @Override
75 public void startDriverHandshake() {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070076 log.warn("Starting driver handshake for sw {}", getStringId());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070077 if (startDriverHandshakeCalled) {
78 throw new SwitchDriverSubHandshakeAlreadyStarted();
79 }
80 startDriverHandshakeCalled = true;
81 try {
82 sendHandshakeOFExperimenterPortDescRequest();
83 } catch (IOException e) {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070084 log.error("LINC-OE exception while sending experimenter port desc:",
Ray Milkey676249c2015-12-18 09:27:03 -080085 e);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070086 }
87 }
88
89 @Override
90 public boolean isDriverHandshakeComplete() {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070091 return driverHandshakeComplete.get();
92 }
93
94 @Override
95 public void processDriverHandshakeMessage(OFMessage m) {
alshabib9af70072015-02-09 14:34:16 -080096 if (!startDriverHandshakeCalled) {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070097 throw new SwitchDriverSubHandshakeNotStarted();
98 }
99 if (driverHandshakeComplete.get()) {
100 throw new SwitchDriverSubHandshakeCompleted(m);
101 }
102
103 switch (m.getType()) {
104 case BARRIER_REPLY:
105 if (m.getXid() == barrierXidToWaitFor) {
106 log.debug("LINC-OE Received barrier response");
107 }
108 break;
109 case ERROR:
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -0700110 log.error("Switch {} Error {}", getStringId(), m);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700111 break;
112 case FEATURES_REPLY:
113 break;
114 case FLOW_REMOVED:
115 break;
116 case GET_ASYNC_REPLY:
117 break;
118 case PACKET_IN:
119 break;
120 case PORT_STATUS:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700121 log.warn("****LINC-OE Port Status {} {}", getStringId(), m);
122 processOFPortStatus((OFCircuitPortStatus) m);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700123 break;
124 case QUEUE_GET_CONFIG_REPLY:
125 break;
126 case ROLE_REPLY:
127 break;
128 case STATS_REPLY:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700129 OFStatsReply stats = (OFStatsReply) m;
130 if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
131 log.warn("LINC-OE : Received stats reply message {}", m);
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700132 createOpticalPortList((OFCircuitPortsReply) m);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700133 driverHandshakeComplete.set(true);
134 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700135 break;
136 default:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700137 log.warn("Received message {} during switch-driver " +
138 "subhandshake " + "from switch {} ... " +
139 "Ignoring message", m,
140 getStringId());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700141
142 }
143 }
144
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700145 public void processOFPortStatus(OFCircuitPortStatus ps) {
146 log.debug("LINC-OE ..OF Port Status :", ps);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700147 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700148
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700149 private void sendHandshakeOFExperimenterPortDescRequest() throws
150 IOException {
151 // send multi part message for port description for optical switches
152 OFCircuitPortsRequest circuitPortsRequest = factory()
153 .buildCircuitPortsRequest().setXid(getNextTransactionId())
154 .build();
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700155 log.warn("LINC-OE : Sending experimented circuit port stats " +
156 "message " +
157 "{}",
158 circuitPortsRequest.toString());
alshabiba2df7b2a2015-05-06 13:57:10 -0700159 this.sendHandshakeMessage(circuitPortsRequest);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700160 }
161
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700162 @Override
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700163 /**
164 * Returns a list of standard (Ethernet) ports.
165 *
166 * @return List of ports
167 */
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700168 public List<OFPortDesc> getPorts() {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700169 return Collections.EMPTY_LIST;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700170 }
171
Marc De Leenheerc2999f32015-11-20 15:52:16 -0800172 /**
173 * Rewrite match object to use LINC OF optical extensions.
174 *
175 * @param match original match
176 * @return rewritten match
177 */
178 private Match rewriteMatch(Match match) {
179 Match.Builder mBuilder = factory().buildMatch();
180 for (MatchField mf : match.getMatchFields()) {
181 if (mf == MatchField.EXP_OCH_SIG_ID) {
182 mBuilder.setExact(MatchField.OCH_SIGID, (CircuitSignalID) match.get(mf));
183 continue;
184 }
185 if (mf == MatchField.EXP_OCH_SIGTYPE) {
186 mBuilder.setExact(MatchField.OCH_SIGTYPE, (U8) match.get(mf));
187 continue;
188 }
189 mBuilder.setExact(mf, match.get(mf));
190 }
191
192 return mBuilder.build();
193 }
194
195 /**
196 * Rewrite actions to use LINC OF optical extensions.
197 *
198 * @param actions original actions
199 * @return rewritten actions
200 */
201 private List<OFAction> rewriteActions(List<OFAction> actions) {
202 List<OFAction> newActions = new LinkedList<>();
203
204 for (OFAction action : actions) {
205 if (!(action instanceof OFActionSetField)) {
206 newActions.add(action);
207 continue;
208 }
209
210 OFActionSetField sf = (OFActionSetField) action;
Marc De Leenheer2c305302015-12-07 21:37:44 -0800211 if (!(sf.getField() instanceof OFOxmExpOchSigId)) {
Marc De Leenheerc2999f32015-11-20 15:52:16 -0800212 newActions.add(action);
Marc De Leenheer2c305302015-12-07 21:37:44 -0800213 continue;
Marc De Leenheerc2999f32015-11-20 15:52:16 -0800214 }
215
216 OFOxmExpOchSigId oxm = (OFOxmExpOchSigId) sf.getField();
217 CircuitSignalID signalId = oxm.getValue();
218
219 newActions.add(
220 factory().actions().circuit(factory().oxms().ochSigid(signalId)));
221 }
222
223 return newActions;
224 }
225
226 @Override
227 public void sendMsg(OFMessage msg) {
228 // Ignore everything but flow mods and stat requests
229 if (!(msg instanceof OFFlowMod || msg instanceof OFFlowStatsRequest)) {
230 super.sendMsg(msg);
231 return;
232 }
233
234 Match newMatch;
235 OFMessage newMsg = null;
236
237 if (msg instanceof OFFlowStatsRequest) {
238 // Rewrite match only
239 OFFlowStatsRequest fsr = (OFFlowStatsRequest) msg;
240 newMatch = rewriteMatch(fsr.getMatch());
241 newMsg = fsr.createBuilder().setMatch(newMatch).build();
242 } else if (msg instanceof OFFlowMod) {
243 // Rewrite match and actions
244 OFFlowMod fm = (OFFlowMod) msg;
245 newMatch = rewriteMatch(fm.getMatch());
246 List<OFAction> actions = rewriteActions(fm.getActions());
Marc De Leenheerc2999f32015-11-20 15:52:16 -0800247 newMsg = fm.createBuilder().setMatch(newMatch).setActions(actions).build();
248 }
249
250 super.sendMsg(newMsg);
251 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700252
253 @Override
254 public Boolean supportNxRole() {
255 return false;
256 }
257
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700258 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -0700259 public Device.Type deviceType() {
260 return Device.Type.ROADM;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700261 }
262
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700263 /**
264 * Checks if given port is also part of the regular port desc stats, i.e., is the port a tap port.
265 *
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800266 * @param port given port number
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700267 * @return true if the port is a tap (OCh), false otherwise (OMS port)
268 */
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800269 private boolean isOChPort(long port) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700270 for (OFPortDescStatsReply reply : this.ports) {
271 for (OFPortDesc p : reply.getEntries()) {
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800272 if (p.getPortNo().getPortNumber() == port) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700273 return true;
274 }
275 }
276 }
277
278 return false;
279 }
280
281 /**
282 * Creates an OpenFlow optical port based on the given port and transport type.
283 *
284 * @param port OpenFlow optical port
285 * @param type transport type
286 * @return OpenFlow optical port
287 */
288 private OFPortOptical createOpticalPort(OFPortOptical port, short type) {
289 List<OFPortDescPropOpticalTransport> descList = new ArrayList<>(port.getDesc().size());
290
291 for (OFPortDescPropOpticalTransport desc : port.getDesc()) {
292 OFPortDescPropOpticalTransport newDesc = desc.createBuilder()
293 .setType(desc.getType())
294 .setPortSignalType(type)
295 .setPortType(desc.getPortType())
296 .setReserved(desc.getReserved())
297 .build();
298 descList.add(newDesc);
299 }
300
301 OFPortOptical newPort = port.createBuilder()
302 .setConfig(port.getConfig())
303 .setDesc(descList)
304 .setHwAddr(port.getHwAddr())
305 .setName(port.getName())
306 .setPortNo(port.getPortNo())
307 .setState(port.getState())
308 .build();
309
310 return newPort;
311 }
312
313 /**
314 * Builds list of OFPortOptical ports based on the multi-part circuit ports reply.
315 *
316 * Ensure the optical transport port's signal type is configured correctly.
317 *
318 * @param wPorts OF reply with circuit ports
319 */
320 private void createOpticalPortList(OFCircuitPortsReply wPorts) {
321 opticalPorts = new ArrayList<>(wPorts.getEntries().size());
322
323 for (OFPortOptical p : wPorts.getEntries()) {
324 short signalType;
325
326 // FIXME: use constants once loxi has full optical extensions
Marc De Leenheerb0fb41d2015-12-03 22:16:53 -0800327 if (isOChPort(p.getPortNo().getPortNumber())) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700328 signalType = 5; // OCH port
329 } else {
330 signalType = 2; // OMS port
331 }
332
333 opticalPorts.add(createOpticalPort(p, signalType));
334 }
335 }
336
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700337 @Override
338 public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
Marc De Leenheerfc913dd2015-07-30 16:04:55 -0700339 if (!type.equals(PortDescPropertyType.OPTICAL_TRANSPORT)) {
340 return Collections.EMPTY_LIST;
341 }
342
343 return opticalPorts;
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700344 }
345
346 @Override
347 public Set<PortDescPropertyType> getPortTypes() {
348 return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
349 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700350}