Committed by
Gerrit Code Review
Lambdas are reinterpreted before being sent to Linc-OE switches. This includes
adding ability to intercept messages at the switch driver for modification before being sent down. Reference: ONOS-1980 Change-Id: I405b89a0fc3844555c9efa0cd9fc887a90d00280
Showing
3 changed files
with
177 additions
and
2 deletions
| ... | @@ -24,30 +24,61 @@ import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotSta | ... | @@ -24,30 +24,61 @@ import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotSta |
| 24 | import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus; | 24 | import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus; |
| 25 | import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply; | 25 | import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply; |
| 26 | import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest; | 26 | import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest; |
| 27 | +import org.projectfloodlight.openflow.protocol.OFFactories; | ||
| 28 | +import org.projectfloodlight.openflow.protocol.OFFactory; | ||
| 29 | +import org.projectfloodlight.openflow.protocol.OFFlowMod; | ||
| 30 | +import org.projectfloodlight.openflow.protocol.OFFlowModCommand; | ||
| 31 | +import org.projectfloodlight.openflow.protocol.OFInstructionType; | ||
| 27 | import org.projectfloodlight.openflow.protocol.OFMessage; | 32 | import org.projectfloodlight.openflow.protocol.OFMessage; |
| 28 | import org.projectfloodlight.openflow.protocol.OFObject; | 33 | import org.projectfloodlight.openflow.protocol.OFObject; |
| 29 | import org.projectfloodlight.openflow.protocol.OFPortDesc; | 34 | import org.projectfloodlight.openflow.protocol.OFPortDesc; |
| 30 | import org.projectfloodlight.openflow.protocol.OFStatsReply; | 35 | import org.projectfloodlight.openflow.protocol.OFStatsReply; |
| 31 | import org.projectfloodlight.openflow.protocol.OFStatsType; | 36 | import org.projectfloodlight.openflow.protocol.OFStatsType; |
| 37 | +import org.projectfloodlight.openflow.protocol.OFType; | ||
| 38 | +import org.projectfloodlight.openflow.protocol.OFVersion; | ||
| 39 | +import org.projectfloodlight.openflow.protocol.action.OFAction; | ||
| 40 | +import org.projectfloodlight.openflow.protocol.action.OFActionCircuit; | ||
| 41 | +import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; | ||
| 42 | +import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; | ||
| 43 | +import org.projectfloodlight.openflow.protocol.match.Match; | ||
| 44 | +import org.projectfloodlight.openflow.protocol.match.MatchField; | ||
| 45 | +import org.projectfloodlight.openflow.protocol.OFActionType; | ||
| 46 | +import org.projectfloodlight.openflow.types.CircuitSignalID; | ||
| 47 | +import org.projectfloodlight.openflow.types.OFPort; | ||
| 48 | +import org.projectfloodlight.openflow.types.U8; | ||
| 32 | 49 | ||
| 33 | import com.google.common.collect.ImmutableList; | 50 | import com.google.common.collect.ImmutableList; |
| 34 | import com.google.common.collect.ImmutableSet; | 51 | import com.google.common.collect.ImmutableSet; |
| 35 | 52 | ||
| 36 | import java.io.IOException; | 53 | import java.io.IOException; |
| 37 | import java.util.List; | 54 | import java.util.List; |
| 55 | +import java.util.Map; | ||
| 56 | +import java.util.ArrayList; | ||
| 38 | import java.util.Set; | 57 | import java.util.Set; |
| 58 | +import java.util.BitSet; | ||
| 59 | +import java.util.stream.Collectors; | ||
| 39 | import java.util.concurrent.atomic.AtomicBoolean; | 60 | import java.util.concurrent.atomic.AtomicBoolean; |
| 61 | +import java.util.concurrent.ConcurrentMap; | ||
| 62 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 63 | + | ||
| 64 | +import static org.projectfloodlight.openflow.protocol.OFFlowMod.Builder; | ||
| 40 | 65 | ||
| 41 | /** | 66 | /** |
| 42 | * LINC-OE Optical Emulator switch class. | 67 | * LINC-OE Optical Emulator switch class. |
| 43 | */ | 68 | */ |
| 44 | public class OFOpticalSwitchImplLINC13 | 69 | public class OFOpticalSwitchImplLINC13 |
| 45 | extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch { | 70 | extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch { |
| 71 | + // 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); | ||
| 46 | 74 | ||
| 47 | private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false); | 75 | private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false); |
| 48 | private long barrierXidToWaitFor = -1; | 76 | private long barrierXidToWaitFor = -1; |
| 49 | 77 | ||
| 50 | private OFCircuitPortsReply wPorts; | 78 | private OFCircuitPortsReply wPorts; |
| 79 | + // 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<>(); | ||
| 51 | 82 | ||
| 52 | @Override | 83 | @Override |
| 53 | public void startDriverHandshake() { | 84 | public void startDriverHandshake() { |
| ... | @@ -170,4 +201,136 @@ public class OFOpticalSwitchImplLINC13 | ... | @@ -170,4 +201,136 @@ public class OFOpticalSwitchImplLINC13 |
| 170 | return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT); | 201 | return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT); |
| 171 | } | 202 | } |
| 172 | 203 | ||
| 204 | + @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 | + } | ||
| 173 | } | 336 | } | ... | ... |
| ... | @@ -148,4 +148,16 @@ public interface OpenFlowSwitch { | ... | @@ -148,4 +148,16 @@ public interface OpenFlowSwitch { |
| 148 | * @return string representation of the connection to the device | 148 | * @return string representation of the connection to the device |
| 149 | */ | 149 | */ |
| 150 | String channelId(); | 150 | String channelId(); |
| 151 | + | ||
| 152 | + /** | ||
| 153 | + * Prepares a message to be sent, if necessary. Default is to do nothing, | ||
| 154 | + * since most Devices do not need to pre-process a message that's about to | ||
| 155 | + * be sent. | ||
| 156 | + * | ||
| 157 | + * @param msg The message to prepare for sending | ||
| 158 | + * @return the prepared OFMessage | ||
| 159 | + */ | ||
| 160 | + default OFMessage prepareMessage(OFMessage msg) { | ||
| 161 | + return msg; | ||
| 162 | + } | ||
| 151 | } | 163 | } | ... | ... |
| ... | @@ -97,7 +97,7 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour | ... | @@ -97,7 +97,7 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour |
| 97 | @Override | 97 | @Override |
| 98 | public final void sendMsg(OFMessage m) { | 98 | public final void sendMsg(OFMessage m) { |
| 99 | if (role == RoleState.MASTER && channel.isWritable()) { | 99 | if (role == RoleState.MASTER && channel.isWritable()) { |
| 100 | - channel.write(Collections.singletonList(m)); | 100 | + channel.write(Collections.singletonList(prepareMessage(m))); |
| 101 | } | 101 | } |
| 102 | } | 102 | } |
| 103 | 103 | ||
| ... | @@ -119,6 +119,7 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour | ... | @@ -119,6 +119,7 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour |
| 119 | "a non role request message"); | 119 | "a non role request message"); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | + @Override | ||
| 122 | public final void sendHandshakeMessage(OFMessage message) { | 123 | public final void sendHandshakeMessage(OFMessage message) { |
| 123 | if (!this.isDriverHandshakeComplete()) { | 124 | if (!this.isDriverHandshakeComplete()) { |
| 124 | channel.write(Collections.singletonList(message)); | 125 | channel.write(Collections.singletonList(message)); |
| ... | @@ -155,7 +156,6 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour | ... | @@ -155,7 +156,6 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour |
| 155 | return channelId; | 156 | return channelId; |
| 156 | } | 157 | } |
| 157 | 158 | ||
| 158 | - | ||
| 159 | //************************ | 159 | //************************ |
| 160 | // Switch features related | 160 | // Switch features related |
| 161 | //************************ | 161 | //************************ | ... | ... |
-
Please register or login to post a comment