blob: 4c64940949a8f63408771a93d923114980799a83 [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
Ayaka Koshibe5460d622015-05-14 12:19:19 -070018import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
19import org.onosproject.openflow.controller.PortDescPropertyType;
Brian O'Connorabafb502014-12-02 22:26:20 -080020import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
21import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
22import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
23import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070024import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070025import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply;
26import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
Ayaka Koshibe3c240772015-05-20 16:23:40 -070027import org.projectfloodlight.openflow.protocol.OFFactories;
28import org.projectfloodlight.openflow.protocol.OFFactory;
29import org.projectfloodlight.openflow.protocol.OFFlowMod;
30import org.projectfloodlight.openflow.protocol.OFFlowModCommand;
31import org.projectfloodlight.openflow.protocol.OFInstructionType;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070032import org.projectfloodlight.openflow.protocol.OFMessage;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070033import org.projectfloodlight.openflow.protocol.OFObject;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070034import org.projectfloodlight.openflow.protocol.OFPortDesc;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070035import org.projectfloodlight.openflow.protocol.OFStatsReply;
36import org.projectfloodlight.openflow.protocol.OFStatsType;
Ayaka Koshibe3c240772015-05-20 16:23:40 -070037import org.projectfloodlight.openflow.protocol.OFType;
38import org.projectfloodlight.openflow.protocol.OFVersion;
39import org.projectfloodlight.openflow.protocol.action.OFAction;
40import org.projectfloodlight.openflow.protocol.action.OFActionCircuit;
41import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
42import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
43import org.projectfloodlight.openflow.protocol.match.Match;
44import org.projectfloodlight.openflow.protocol.match.MatchField;
45import org.projectfloodlight.openflow.protocol.OFActionType;
46import org.projectfloodlight.openflow.types.CircuitSignalID;
47import org.projectfloodlight.openflow.types.OFPort;
48import org.projectfloodlight.openflow.types.U8;
alshabib452234e2014-11-25 00:03:49 -050049
Ayaka Koshibe5460d622015-05-14 12:19:19 -070050import com.google.common.collect.ImmutableList;
51import com.google.common.collect.ImmutableSet;
52
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070053import java.io.IOException;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070054import java.util.List;
Ayaka Koshibe3c240772015-05-20 16:23:40 -070055import java.util.Map;
56import java.util.ArrayList;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070057import java.util.Set;
Ayaka Koshibe3c240772015-05-20 16:23:40 -070058import java.util.BitSet;
59import java.util.stream.Collectors;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070060import java.util.concurrent.atomic.AtomicBoolean;
Ayaka Koshibe3c240772015-05-20 16:23:40 -070061import java.util.concurrent.ConcurrentMap;
62import java.util.concurrent.ConcurrentHashMap;
63
64import static org.projectfloodlight.openflow.protocol.OFFlowMod.Builder;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070065
66/**
67 * LINC-OE Optical Emulator switch class.
68 */
Ayaka Koshibe5460d622015-05-14 12:19:19 -070069public class OFOpticalSwitchImplLINC13
70 extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
Ayaka Koshibe3c240772015-05-20 16:23:40 -070071 // default number of lambdas, assuming 50GHz channels.
72 private static final int NUM_CHLS = 80;
73 private final OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070074
alshabibb452fd72015-04-22 20:46:20 -070075 private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070076 private long barrierXidToWaitFor = -1;
77
Ayaka Koshibe5460d622015-05-14 12:19:19 -070078 private OFCircuitPortsReply wPorts;
Ayaka Koshibe3c240772015-05-20 16:23:40 -070079 // book-keeping maps for allocated Linc-OE lambdas
80 protected final ConcurrentMap<OFPort, BitSet> portChannelMap = new ConcurrentHashMap<>();
81 protected final ConcurrentMap<Match, Integer> matchMap = new ConcurrentHashMap<>();
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070082
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070083 @Override
84 public void startDriverHandshake() {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070085 log.warn("Starting driver handshake for sw {}", getStringId());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070086 if (startDriverHandshakeCalled) {
87 throw new SwitchDriverSubHandshakeAlreadyStarted();
88 }
89 startDriverHandshakeCalled = true;
90 try {
91 sendHandshakeOFExperimenterPortDescRequest();
92 } catch (IOException e) {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070093 log.error("LINC-OE exception while sending experimenter port desc:",
94 e.getMessage());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070095 e.printStackTrace();
96 }
97 }
98
99 @Override
100 public boolean isDriverHandshakeComplete() {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700101 return driverHandshakeComplete.get();
102 }
103
104 @Override
105 public void processDriverHandshakeMessage(OFMessage m) {
alshabib9af70072015-02-09 14:34:16 -0800106 if (!startDriverHandshakeCalled) {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700107 throw new SwitchDriverSubHandshakeNotStarted();
108 }
109 if (driverHandshakeComplete.get()) {
110 throw new SwitchDriverSubHandshakeCompleted(m);
111 }
112
113 switch (m.getType()) {
114 case BARRIER_REPLY:
115 if (m.getXid() == barrierXidToWaitFor) {
116 log.debug("LINC-OE Received barrier response");
117 }
118 break;
119 case ERROR:
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -0700120 log.error("Switch {} Error {}", getStringId(), m);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700121 break;
122 case FEATURES_REPLY:
123 break;
124 case FLOW_REMOVED:
125 break;
126 case GET_ASYNC_REPLY:
127 break;
128 case PACKET_IN:
129 break;
130 case PORT_STATUS:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700131 log.warn("****LINC-OE Port Status {} {}", getStringId(), m);
132 processOFPortStatus((OFCircuitPortStatus) m);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700133 break;
134 case QUEUE_GET_CONFIG_REPLY:
135 break;
136 case ROLE_REPLY:
137 break;
138 case STATS_REPLY:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700139 OFStatsReply stats = (OFStatsReply) m;
140 if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
141 log.warn("LINC-OE : Received stats reply message {}", m);
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700142 wPorts = (OFCircuitPortsReply) m;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700143 driverHandshakeComplete.set(true);
144 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700145 break;
146 default:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700147 log.warn("Received message {} during switch-driver " +
148 "subhandshake " + "from switch {} ... " +
149 "Ignoring message", m,
150 getStringId());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700151
152 }
153 }
154
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700155 public void processOFPortStatus(OFCircuitPortStatus ps) {
156 log.debug("LINC-OE ..OF Port Status :", ps);
157
158 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700159
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700160 private void sendHandshakeOFExperimenterPortDescRequest() throws
161 IOException {
162 // send multi part message for port description for optical switches
163 OFCircuitPortsRequest circuitPortsRequest = factory()
164 .buildCircuitPortsRequest().setXid(getNextTransactionId())
165 .build();
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700166 log.warn("LINC-OE : Sending experimented circuit port stats " +
167 "message " +
168 "{}",
169 circuitPortsRequest.toString());
alshabiba2df7b2a2015-05-06 13:57:10 -0700170 this.sendHandshakeMessage(circuitPortsRequest);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700171 }
172
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700173 @Override
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700174 /**
175 * Returns a list of standard (Ethernet) ports.
176 *
177 * @return List of ports
178 */
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700179 public List<OFPortDesc> getPorts() {
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700180 return ImmutableList.copyOf(super.getPorts());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700181 }
182
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700183
184 @Override
185 public Boolean supportNxRole() {
186 return false;
187 }
188
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700189 @Override
190 public boolean isOptical() {
191 return true;
192 }
193
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700194 @Override
195 public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
196 return ImmutableList.copyOf(wPorts.getEntries());
197 }
198
199 @Override
200 public Set<PortDescPropertyType> getPortTypes() {
201 return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
202 }
203
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700204 @Override
205 public OFMessage prepareMessage(OFMessage msg) {
206 if (OFVersion.OF_13 != msg.getVersion() || msg.getType() != OFType.FLOW_MOD) {
207 return msg;
208 }
209 OFFlowMod fm = (OFFlowMod) msg;
210 Match match = fm.getMatch();
211 // Don't touch FlowMods that aren't Optical-related.
212 if (match.get(MatchField.OCH_SIGTYPE) == null) {
213 return msg;
214 }
215
216 OFMessage newFM;
217 Builder builder = null;
218 List<OFAction> actions = new ArrayList<>();
219 if (fm.getCommand() == OFFlowModCommand.ADD) {
220 builder = factory.buildFlowAdd();
221 int lambda = allocateLambda(match.get(MatchField.IN_PORT), match);
222 CircuitSignalID sigid = new CircuitSignalID((byte) 1, (byte) 2, (short) lambda, (short) 1);
223 List<OFInstruction> instructions = fm.getInstructions();
224
225 newFM = buildFlowMod(builder, fm, buildMatch(match, sigid), buildActions(instructions, sigid));
226 } else if (fm.getCommand() == OFFlowModCommand.DELETE) {
227 builder = factory.buildFlowDelete();
228 int lambda = freeLambda(match.get(MatchField.IN_PORT), match);
229 CircuitSignalID sigid = new CircuitSignalID((byte) 1, (byte) 2, (short) lambda, (short) 1);
230
231 newFM = buildFlowMod(builder, fm, buildMatch(match, sigid), actions);
232 } else {
233 newFM = msg;
234 }
235 log.debug("new FM = {}", newFM);
236 return newFM;
237 }
238
239 // fetch the next available channel as the flat lambda value, or the lambda
240 // associated with a port/match combination
241 private int allocateLambda(OFPort port, Match match) {
242 Integer lambda = null;
243 synchronized (this) {
244 BitSet channels = portChannelMap.getOrDefault(port, new BitSet(NUM_CHLS + 1));
245 lambda = matchMap.get(match);
246 if (lambda == null) {
247 // TODO : double check behavior when bitset is full
248 // Linc lambdas start at 1.
249 lambda = channels.nextClearBit(1);
250 channels.set(lambda);
251 portChannelMap.put(port, channels);
252 matchMap.put(match, lambda);
253 }
254 }
255 return lambda;
256 }
257
258 // free lambda that was mapped to Port/Match combination and return its
259 // value to caller.
260 private int freeLambda(OFPort port, Match match) {
261 synchronized (this) {
262 Integer lambda = matchMap.get(match);
263 if (lambda != null) {
264 portChannelMap.get(port).clear(lambda);
265 return lambda;
266 }
267 // 1 is a sane-ish default for Linc.
268 return 1;
269 }
270 }
271
272 // build matches - *tons of assumptions are made here based on Linc-OE's behavior.*
273 // gridType = 1 (DWDM)
274 // channelSpacing = 2 (50GHz)
275 // spectralWidth = 1 (fixed grid default value)
276 private Match buildMatch(Match original, CircuitSignalID sigid) {
277 Match.Builder mBuilder = factory.buildMatch();
278
279 original.getMatchFields().forEach(mf -> {
280 String name = mf.getName();
281 if (MatchField.OCH_SIGID.getName().equals(name)) {
282 mBuilder.setExact(MatchField.OCH_SIGID, sigid);
283 } else if (MatchField.OCH_SIGTYPE.getName().equals(name)) {
284 mBuilder.setExact(MatchField.OCH_SIGTYPE, U8.of((short) 1));
285 } else if (MatchField.IN_PORT.getName().equals(name)) {
286 mBuilder.setExact(MatchField.IN_PORT, original.get(MatchField.IN_PORT));
287 }
288 });
289
290 return mBuilder.build();
291 }
292
293 private List<OFAction> buildActions(List<OFInstruction> iList, CircuitSignalID sigid) {
294 List<OFAction> actions = new ArrayList<>();
295 Map<OFInstructionType, OFInstruction> instructions = iList.stream()
296 .collect(Collectors.toMap(OFInstruction::getType, inst -> inst));
297
298 OFInstruction inst = instructions.get(OFInstructionType.APPLY_ACTIONS);
299 if (inst != null) {
300 OFInstructionApplyActions iaa = (OFInstructionApplyActions) inst;
301 if (iaa.getActions() == null) {
302 return actions;
303 }
304 iaa.getActions().forEach(action -> {
305 if (OFActionType.EXPERIMENTER == action.getType()) {
306 OFActionCircuit.Builder cBuilder = factory.actions().buildCircuit()
307 .setField(factory.oxms()
308 .buildOchSigid()
309 .setValue(sigid)
310 .build());
311 actions.add(cBuilder.build());
312 } else {
313 actions.add(action);
314 }
315 });
316 }
317 return actions;
318 }
319
320 private OFMessage buildFlowMod(Builder builder, OFFlowMod fm, Match m, List<OFAction> act) {
321 return builder
322 .setXid(fm.getXid())
323 .setCookie(fm.getCookie())
324 .setCookieMask(fm.getCookieMask())
325 .setTableId(fm.getTableId())
326 .setIdleTimeout(fm.getIdleTimeout())
327 .setHardTimeout(fm.getHardTimeout())
328 .setBufferId(fm.getBufferId())
329 .setOutPort(fm.getOutPort())
330 .setOutGroup(fm.getOutGroup())
331 .setFlags(fm.getFlags())
332 .setMatch(m)
333 .setActions(act)
334 .build();
335 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700336}