blob: 8b27e8c8cba090ca8b720c5990c0b31f622f5dfa [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;
Sho SHIMIZU50e7d9c2015-05-22 11:35:28 -070054import java.util.Collections;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070055import java.util.List;
Ayaka Koshibe3c240772015-05-20 16:23:40 -070056import java.util.Map;
57import java.util.ArrayList;
Ayaka Koshibe5460d622015-05-14 12:19:19 -070058import java.util.Set;
Ayaka Koshibe3c240772015-05-20 16:23:40 -070059import java.util.BitSet;
60import java.util.stream.Collectors;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070061import java.util.concurrent.atomic.AtomicBoolean;
Ayaka Koshibe3c240772015-05-20 16:23:40 -070062import java.util.concurrent.ConcurrentMap;
63import java.util.concurrent.ConcurrentHashMap;
64
65import static org.projectfloodlight.openflow.protocol.OFFlowMod.Builder;
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070066
67/**
68 * LINC-OE Optical Emulator switch class.
69 */
Ayaka Koshibe5460d622015-05-14 12:19:19 -070070public class OFOpticalSwitchImplLINC13
71 extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
Ayaka Koshibe3c240772015-05-20 16:23:40 -070072 // default number of lambdas, assuming 50GHz channels.
73 private static final int NUM_CHLS = 80;
74 private final OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070075
alshabibb452fd72015-04-22 20:46:20 -070076 private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070077 private long barrierXidToWaitFor = -1;
78
Ayaka Koshibe5460d622015-05-14 12:19:19 -070079 private OFCircuitPortsReply wPorts;
Ayaka Koshibe3c240772015-05-20 16:23:40 -070080 // book-keeping maps for allocated Linc-OE lambdas
81 protected final ConcurrentMap<OFPort, BitSet> portChannelMap = new ConcurrentHashMap<>();
82 protected final ConcurrentMap<Match, Integer> matchMap = new ConcurrentHashMap<>();
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070083
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070084 @Override
85 public void startDriverHandshake() {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070086 log.warn("Starting driver handshake for sw {}", getStringId());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070087 if (startDriverHandshakeCalled) {
88 throw new SwitchDriverSubHandshakeAlreadyStarted();
89 }
90 startDriverHandshakeCalled = true;
91 try {
92 sendHandshakeOFExperimenterPortDescRequest();
93 } catch (IOException e) {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -070094 log.error("LINC-OE exception while sending experimenter port desc:",
95 e.getMessage());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -070096 e.printStackTrace();
97 }
98 }
99
100 @Override
101 public boolean isDriverHandshakeComplete() {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700102 return driverHandshakeComplete.get();
103 }
104
105 @Override
106 public void processDriverHandshakeMessage(OFMessage m) {
alshabib9af70072015-02-09 14:34:16 -0800107 if (!startDriverHandshakeCalled) {
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700108 throw new SwitchDriverSubHandshakeNotStarted();
109 }
110 if (driverHandshakeComplete.get()) {
111 throw new SwitchDriverSubHandshakeCompleted(m);
112 }
113
114 switch (m.getType()) {
115 case BARRIER_REPLY:
116 if (m.getXid() == barrierXidToWaitFor) {
117 log.debug("LINC-OE Received barrier response");
118 }
119 break;
120 case ERROR:
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -0700121 log.error("Switch {} Error {}", getStringId(), m);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700122 break;
123 case FEATURES_REPLY:
124 break;
125 case FLOW_REMOVED:
126 break;
127 case GET_ASYNC_REPLY:
128 break;
129 case PACKET_IN:
130 break;
131 case PORT_STATUS:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700132 log.warn("****LINC-OE Port Status {} {}", getStringId(), m);
133 processOFPortStatus((OFCircuitPortStatus) m);
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700134 break;
135 case QUEUE_GET_CONFIG_REPLY:
136 break;
137 case ROLE_REPLY:
138 break;
139 case STATS_REPLY:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700140 OFStatsReply stats = (OFStatsReply) m;
141 if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
142 log.warn("LINC-OE : Received stats reply message {}", m);
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700143 wPorts = (OFCircuitPortsReply) m;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700144 driverHandshakeComplete.set(true);
145 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700146 break;
147 default:
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700148 log.warn("Received message {} during switch-driver " +
149 "subhandshake " + "from switch {} ... " +
150 "Ignoring message", m,
151 getStringId());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700152
153 }
154 }
155
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700156 public void processOFPortStatus(OFCircuitPortStatus ps) {
157 log.debug("LINC-OE ..OF Port Status :", ps);
158
159 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700160
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700161 private void sendHandshakeOFExperimenterPortDescRequest() throws
162 IOException {
163 // send multi part message for port description for optical switches
164 OFCircuitPortsRequest circuitPortsRequest = factory()
165 .buildCircuitPortsRequest().setXid(getNextTransactionId())
166 .build();
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700167 log.warn("LINC-OE : Sending experimented circuit port stats " +
168 "message " +
169 "{}",
170 circuitPortsRequest.toString());
alshabiba2df7b2a2015-05-06 13:57:10 -0700171 this.sendHandshakeMessage(circuitPortsRequest);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700172 }
173
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700174 @Override
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700175 /**
176 * Returns a list of standard (Ethernet) ports.
177 *
178 * @return List of ports
179 */
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700180 public List<OFPortDesc> getPorts() {
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700181 return ImmutableList.copyOf(super.getPorts());
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700182 }
183
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700184
185 @Override
186 public Boolean supportNxRole() {
187 return false;
188 }
189
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700190 @Override
191 public boolean isOptical() {
192 return true;
193 }
194
Ayaka Koshibe5460d622015-05-14 12:19:19 -0700195 @Override
196 public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
197 return ImmutableList.copyOf(wPorts.getEntries());
198 }
199
200 @Override
201 public Set<PortDescPropertyType> getPortTypes() {
202 return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
203 }
204
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700205 @Override
206 public OFMessage prepareMessage(OFMessage msg) {
207 if (OFVersion.OF_13 != msg.getVersion() || msg.getType() != OFType.FLOW_MOD) {
208 return msg;
209 }
210 OFFlowMod fm = (OFFlowMod) msg;
211 Match match = fm.getMatch();
212 // Don't touch FlowMods that aren't Optical-related.
213 if (match.get(MatchField.OCH_SIGTYPE) == null) {
214 return msg;
215 }
216
217 OFMessage newFM;
218 Builder builder = null;
219 List<OFAction> actions = new ArrayList<>();
220 if (fm.getCommand() == OFFlowModCommand.ADD) {
221 builder = factory.buildFlowAdd();
222 int lambda = allocateLambda(match.get(MatchField.IN_PORT), match);
223 CircuitSignalID sigid = new CircuitSignalID((byte) 1, (byte) 2, (short) lambda, (short) 1);
224 List<OFInstruction> instructions = fm.getInstructions();
225
226 newFM = buildFlowMod(builder, fm, buildMatch(match, sigid), buildActions(instructions, sigid));
227 } else if (fm.getCommand() == OFFlowModCommand.DELETE) {
228 builder = factory.buildFlowDelete();
229 int lambda = freeLambda(match.get(MatchField.IN_PORT), match);
230 CircuitSignalID sigid = new CircuitSignalID((byte) 1, (byte) 2, (short) lambda, (short) 1);
231
232 newFM = buildFlowMod(builder, fm, buildMatch(match, sigid), actions);
233 } else {
234 newFM = msg;
235 }
236 log.debug("new FM = {}", newFM);
237 return newFM;
238 }
239
240 // fetch the next available channel as the flat lambda value, or the lambda
241 // associated with a port/match combination
242 private int allocateLambda(OFPort port, Match match) {
243 Integer lambda = null;
244 synchronized (this) {
245 BitSet channels = portChannelMap.getOrDefault(port, new BitSet(NUM_CHLS + 1));
246 lambda = matchMap.get(match);
247 if (lambda == null) {
248 // TODO : double check behavior when bitset is full
249 // Linc lambdas start at 1.
250 lambda = channels.nextClearBit(1);
251 channels.set(lambda);
252 portChannelMap.put(port, channels);
253 matchMap.put(match, lambda);
254 }
255 }
256 return lambda;
257 }
258
259 // free lambda that was mapped to Port/Match combination and return its
260 // value to caller.
261 private int freeLambda(OFPort port, Match match) {
262 synchronized (this) {
263 Integer lambda = matchMap.get(match);
264 if (lambda != null) {
265 portChannelMap.get(port).clear(lambda);
266 return lambda;
267 }
268 // 1 is a sane-ish default for Linc.
269 return 1;
270 }
271 }
272
273 // build matches - *tons of assumptions are made here based on Linc-OE's behavior.*
274 // gridType = 1 (DWDM)
275 // channelSpacing = 2 (50GHz)
276 // spectralWidth = 1 (fixed grid default value)
277 private Match buildMatch(Match original, CircuitSignalID sigid) {
278 Match.Builder mBuilder = factory.buildMatch();
279
280 original.getMatchFields().forEach(mf -> {
281 String name = mf.getName();
282 if (MatchField.OCH_SIGID.getName().equals(name)) {
283 mBuilder.setExact(MatchField.OCH_SIGID, sigid);
284 } else if (MatchField.OCH_SIGTYPE.getName().equals(name)) {
285 mBuilder.setExact(MatchField.OCH_SIGTYPE, U8.of((short) 1));
286 } else if (MatchField.IN_PORT.getName().equals(name)) {
287 mBuilder.setExact(MatchField.IN_PORT, original.get(MatchField.IN_PORT));
288 }
289 });
290
291 return mBuilder.build();
292 }
293
294 private List<OFAction> buildActions(List<OFInstruction> iList, CircuitSignalID sigid) {
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700295 Map<OFInstructionType, OFInstruction> instructions = iList.stream()
296 .collect(Collectors.toMap(OFInstruction::getType, inst -> inst));
297
298 OFInstruction inst = instructions.get(OFInstructionType.APPLY_ACTIONS);
Sho SHIMIZU50e7d9c2015-05-22 11:35:28 -0700299 if (inst == null) {
300 return Collections.emptyList();
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700301 }
Sho SHIMIZU50e7d9c2015-05-22 11:35:28 -0700302
303 List<OFAction> actions = new ArrayList<>();
304 OFInstructionApplyActions iaa = (OFInstructionApplyActions) inst;
305 if (iaa.getActions() == null) {
306 return actions;
307 }
308 iaa.getActions().forEach(action -> {
309 if (OFActionType.EXPERIMENTER == action.getType()) {
310 OFActionCircuit.Builder cBuilder = factory.actions().buildCircuit()
311 .setField(factory.oxms()
312 .buildOchSigid()
313 .setValue(sigid)
314 .build());
315 actions.add(cBuilder.build());
316 } else {
317 actions.add(action);
318 }
319 });
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700320 return actions;
321 }
322
323 private OFMessage buildFlowMod(Builder builder, OFFlowMod fm, Match m, List<OFAction> act) {
324 return builder
325 .setXid(fm.getXid())
326 .setCookie(fm.getCookie())
327 .setCookieMask(fm.getCookieMask())
328 .setTableId(fm.getTableId())
329 .setIdleTimeout(fm.getIdleTimeout())
330 .setHardTimeout(fm.getHardTimeout())
331 .setBufferId(fm.getBufferId())
332 .setOutPort(fm.getOutPort())
333 .setOutGroup(fm.getOutGroup())
334 .setFlags(fm.getFlags())
335 .setMatch(m)
336 .setActions(act)
337 .build();
338 }
Praseed Balakrishnane48aa682014-10-08 17:31:37 -0700339}