blob: 5d4a9ec8070604f18717192f9556fbb5d63543c3 [file] [log] [blame]
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001package net.onrc.onos.core.drivermanager;
2
3import java.io.IOException;
4import java.util.ArrayList;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07005import java.util.Collection;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07006import java.util.Collections;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07007import java.util.HashSet;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07008import java.util.List;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07009import java.util.Set;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070010import java.util.concurrent.ConcurrentHashMap;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070011import java.util.concurrent.ConcurrentMap;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070012import java.util.concurrent.atomic.AtomicBoolean;
13
14import net.floodlightcontroller.core.IFloodlightProviderService.Role;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070015import net.floodlightcontroller.core.IOF13Switch;
16import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070017import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
18import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
19import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
20import net.floodlightcontroller.core.internal.OFSwitchImplBase;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070021import net.onrc.onos.core.configmanager.INetworkConfigService;
22import net.onrc.onos.core.configmanager.INetworkConfigService.NetworkConfigState;
23import net.onrc.onos.core.configmanager.INetworkConfigService.SwitchConfigStatus;
24import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
25import net.onrc.onos.core.configmanager.NetworkConfigManager;
26import net.onrc.onos.core.configmanager.PktLinkConfig;
27import net.onrc.onos.core.configmanager.SegmentRouterConfig;
28import net.onrc.onos.core.matchaction.MatchAction;
29import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Saurav Dasbc594a42014-09-25 20:13:50 -070030import net.onrc.onos.core.matchaction.MatchActionOperations;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070031import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
32import net.onrc.onos.core.matchaction.action.Action;
33import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
34import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
35import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
36import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
37import net.onrc.onos.core.matchaction.action.GroupAction;
38import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
39import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
40import net.onrc.onos.core.matchaction.action.OutputAction;
41import net.onrc.onos.core.matchaction.action.PopMplsAction;
42import net.onrc.onos.core.matchaction.action.PushMplsAction;
43import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
44import net.onrc.onos.core.matchaction.match.Ipv4Match;
45import net.onrc.onos.core.matchaction.match.Match;
46import net.onrc.onos.core.matchaction.match.MplsMatch;
47import net.onrc.onos.core.matchaction.match.PacketMatch;
48import net.onrc.onos.core.util.Dpid;
49import net.onrc.onos.core.util.IPv4Net;
50import net.onrc.onos.core.util.PortNumber;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070051
52import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
53import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
54import org.projectfloodlight.openflow.protocol.OFBucket;
55import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
56import org.projectfloodlight.openflow.protocol.OFErrorMsg;
57import org.projectfloodlight.openflow.protocol.OFFactory;
58import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
59import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
60import org.projectfloodlight.openflow.protocol.OFGroupType;
61import org.projectfloodlight.openflow.protocol.OFMatchV3;
62import org.projectfloodlight.openflow.protocol.OFMessage;
63import org.projectfloodlight.openflow.protocol.OFOxmList;
64import org.projectfloodlight.openflow.protocol.OFPortDesc;
65import org.projectfloodlight.openflow.protocol.OFStatsReply;
66import org.projectfloodlight.openflow.protocol.action.OFAction;
67import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
68import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
69import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
70import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
71import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
72import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070073import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
74import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
75import org.projectfloodlight.openflow.types.EthType;
76import org.projectfloodlight.openflow.types.IPv4Address;
77import org.projectfloodlight.openflow.types.MacAddress;
78import org.projectfloodlight.openflow.types.OFBufferId;
79import org.projectfloodlight.openflow.types.OFGroup;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070080import org.projectfloodlight.openflow.types.OFPort;
81import org.projectfloodlight.openflow.types.OFVlanVidMatch;
82import org.projectfloodlight.openflow.types.TableId;
83import org.projectfloodlight.openflow.types.U32;
84import org.projectfloodlight.openflow.types.U64;
85import org.projectfloodlight.openflow.util.HexString;
86
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070087import com.google.common.collect.Sets;
88
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070089/**
90 * OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
91 * Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
92 * Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
93 * None
94 */
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070095public class OFSwitchImplCPqD13 extends OFSwitchImplBase implements IOF13Switch {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070096 private static final int VLAN_ID_OFFSET = 16;
97 private AtomicBoolean driverHandshakeComplete;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070098 private AtomicBoolean haltStateMachine;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070099 private OFFactory factory;
100 private static final int OFPCML_NO_BUFFER = 0xffff;
101 // Configuration of asynch messages to controller. We need different
102 // asynch messages depending on role-equal or role-master.
103 // We don't want to get anything if we are slave.
104 private static final long SET_FLOW_REMOVED_MASK_MASTER = 0xf;
105 private static final long SET_PACKET_IN_MASK_MASTER = 0x7;
106 private static final long SET_PORT_STATUS_MASK_MASTER = 0x7;
107 private static final long SET_FLOW_REMOVED_MASK_EQUAL = 0x0;
108 private static final long SET_PACKET_IN_MASK_EQUAL = 0x0;
109 private static final long SET_PORT_STATUS_MASK_EQUAL = 0x7;
110 private static final long SET_ALL_SLAVE = 0x0;
111
112 private static final long TEST_FLOW_REMOVED_MASK = 0xf;
113 private static final long TEST_PACKET_IN_MASK = 0x7;
114 private static final long TEST_PORT_STATUS_MASK = 0x7;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700115
116 private static final int TABLE_VLAN = 0;
117 private static final int TABLE_TMAC = 1;
Sangho Shin01bca862014-09-12 11:18:59 -0700118 private static final int TABLE_IPv4_UNICAST = 2;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700119 private static final int TABLE_MPLS = 3;
120 private static final int TABLE_META = 4;
121 private static final int TABLE_ACL = 5;
122
123 private static final short MAX_PRIORITY = (short) 0xffff;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700124 private static final short PRIORITY_MULTIPLIER = (short) 2046;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700125 private static final short MIN_PRIORITY = 0x0;
126 private static final U64 METADATA_MASK = U64.of(Long.MAX_VALUE << 1 | 0x1);
127
128 ConcurrentHashMap<Integer, OFGroup> l2groups;
129
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700130 private long barrierXidToWaitFor = -1;
131 private DriverState driverState;
Jonathan Hartcb34f382014-08-12 21:11:03 -0700132 private final boolean usePipeline13;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700133 private SegmentRouterConfig srConfig;
134 private ConcurrentMap<Dpid, Set<PortNumber>> neighbors;
135 private ConcurrentMap<NeighborSet, EcmpInfo> ecmpGroups;
136
137
Jonathan Hartcb34f382014-08-12 21:11:03 -0700138
139 public OFSwitchImplCPqD13(OFDescStatsReply desc, boolean usePipeline13) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700140 super();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700141 haltStateMachine = new AtomicBoolean(false);
142 driverState = DriverState.INIT;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700143 driverHandshakeComplete = new AtomicBoolean(false);
144 l2groups = new ConcurrentHashMap<Integer, OFGroup>();
145 setSwitchDescription(desc);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700146 neighbors = new ConcurrentHashMap<Dpid, Set<PortNumber>>();
147 ecmpGroups = new ConcurrentHashMap<NeighborSet, EcmpInfo>();
Jonathan Hartcb34f382014-08-12 21:11:03 -0700148 this.usePipeline13 = usePipeline13;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700149 }
150
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700151 // *****************************
152 // OFSwitchImplBase
153 // *****************************
154
155
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700156 /* (non-Javadoc)
157 * @see java.lang.Object#toString()
158 */
159 @Override
160 public String toString() {
161 return "OFSwitchImplCPqD13 [" + ((channel != null)
162 ? channel.getRemoteAddress() : "?")
163 + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
164 }
165
166 @Override
167 public void startDriverHandshake() throws IOException {
168 log.debug("Starting driver handshake for sw {}", getStringId());
169 if (startDriverHandshakeCalled) {
170 throw new SwitchDriverSubHandshakeAlreadyStarted();
171 }
172 startDriverHandshakeCalled = true;
Jonathan Harta213bce2014-08-11 15:44:07 -0700173 factory = getFactory();
Jonathan Hartcb34f382014-08-12 21:11:03 -0700174 if (!usePipeline13) {
175 // Send packet-in to controller if a packet misses the first table
176 populateTableMissEntry(0, true, false, false, 0);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700177 driverHandshakeComplete.set(true);
Sangho Shin01bca862014-09-12 11:18:59 -0700178 } else {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700179 nextDriverState();
Sangho Shin01bca862014-09-12 11:18:59 -0700180 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700181 }
182
Sangho Shin01bca862014-09-12 11:18:59 -0700183
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700184 @Override
185 public boolean isDriverHandshakeComplete() {
Sangho Shin01bca862014-09-12 11:18:59 -0700186 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700187 throw new SwitchDriverSubHandshakeNotStarted();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700188 return driverHandshakeComplete.get();
189 }
190
191 @Override
192 public void processDriverHandshakeMessage(OFMessage m) {
Sangho Shin01bca862014-09-12 11:18:59 -0700193 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700194 throw new SwitchDriverSubHandshakeNotStarted();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700195 if (isDriverHandshakeComplete())
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700196 throw new SwitchDriverSubHandshakeCompleted(m);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700197 try {
198 processOFMessage(this, m);
199 } catch (IOException e) {
200 log.error("Error generated when processing OFMessage", e.getCause());
201 }
202 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700203
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700204 @Override
205 public String getSwitchDriverState() {
206 return driverState.toString();
207 }
208
209 // *****************************
210 // Driver handshake state-machine
211 // *****************************
212
213 enum DriverState {
214 INIT,
215 SET_TABLE_MISS_ENTRIES,
216 SET_TABLE_VLAN_TMAC,
217 SET_GROUPS,
218 VERIFY_GROUPS,
219 SET_ADJACENCY_LABELS,
220 EXIT
221 }
222
223 protected void nextDriverState() throws IOException {
224 DriverState currentState = driverState;
225 if (haltStateMachine.get())
226 return;
227 switch (currentState) {
228 case INIT:
229 driverState = DriverState.SET_TABLE_MISS_ENTRIES;
230 setTableMissEntries();
231 sendBarrier();
232 break;
233 case SET_TABLE_MISS_ENTRIES:
234 driverState = DriverState.SET_TABLE_VLAN_TMAC;
235 getNetworkConfig();
236 populateTableVlan();
237 populateTableTMac();
238 sendBarrier();
239 break;
240 case SET_TABLE_VLAN_TMAC:
241 driverState = DriverState.SET_GROUPS;
242 createGroups();
243 sendBarrier();
244 break;
245 case SET_GROUPS:
246 driverState = DriverState.VERIFY_GROUPS;
247 verifyGroups();
248 break;
249 case VERIFY_GROUPS:
250 driverState = DriverState.SET_ADJACENCY_LABELS;
251 assignAdjacencyLabels();
252 break;
253 case SET_ADJACENCY_LABELS:
254 driverState = DriverState.EXIT;
255 driverHandshakeComplete.set(true);
256 break;
257 case EXIT:
258 default:
259 driverState = DriverState.EXIT;
260 log.error("Driver handshake has exited for sw: {}", getStringId());
261 }
262 }
263
264 void processOFMessage(IOFSwitch sw, OFMessage m) throws IOException {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700265 switch (m.getType()) {
266 case BARRIER_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700267 processBarrierReply(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700268 break;
269
270 case ERROR:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700271 processErrorMessage(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700272 break;
273
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700274 case GET_ASYNC_REPLY:
275 OFAsyncGetReply asrep = (OFAsyncGetReply) m;
276 decodeAsyncGetReply(asrep);
277 break;
278
279 case PACKET_IN:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700280 // not ready to handle packet-ins
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700281 break;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700282
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700283 case QUEUE_GET_CONFIG_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700284 // not doing queue config yet
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700285 break;
286
287 case STATS_REPLY:
288 processStatsReply((OFStatsReply) m);
289 break;
290
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700291 case ROLE_REPLY: // channelHandler should handle this
292 case PORT_STATUS: // channelHandler should handle this
293 case FEATURES_REPLY: // don't care
294 case FLOW_REMOVED: // don't care
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700295 default:
296 log.debug("Received message {} during switch-driver subhandshake "
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700297 + "from switch {} ... Ignoring message", m, sw.getStringId());
298 }
299 }
300
301 private void processStatsReply(OFStatsReply sr) {
302 switch (sr.getStatsType()) {
303 case AGGREGATE:
304 break;
305 case DESC:
306 break;
307 case EXPERIMENTER:
308 break;
309 case FLOW:
310 break;
311 case GROUP_DESC:
312 processGroupDesc((OFGroupDescStatsReply) sr);
313 break;
314 case GROUP_FEATURES:
315 processGroupFeatures((OFGroupFeaturesStatsReply) sr);
316 break;
317 case METER_CONFIG:
318 break;
319 case METER_FEATURES:
320 break;
321 case PORT_DESC:
322 break;
323 case TABLE_FEATURES:
324 break;
325 default:
326 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700327
328 }
329 }
330
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700331 private void processErrorMessage(OFMessage m) {
332 log.error("Switch {} Error {} in DriverState", getStringId(),
333 (OFErrorMsg) m, driverState);
334 }
335
336 private void processBarrierReply(OFMessage m) throws IOException {
337 if (m.getXid() == barrierXidToWaitFor) {
338 // Driver state-machine progresses to the next state.
339 // If Barrier messages is not received, then eventually
340 // the ChannelHandler state machine will timeout, and the switch
341 // will be disconnected.
342 nextDriverState();
343 } else {
344 log.error("Received incorrect barrier-message xid {} (expected: {}) in "
345 + "switch-driver state {} for switch {}", m, barrierXidToWaitFor,
346 driverState, getStringId());
347 }
348 }
349
350 private void processGroupDesc(OFGroupDescStatsReply gdsr) {
351 log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
352 try {
353 nextDriverState();
354 } catch (IOException e) {
355 // TODO Auto-generated catch block
356 e.printStackTrace();
357 }
358 }
359
360 // *****************************
361 // Utility methods
362 // *****************************
363
364 void setTableMissEntries() throws IOException {
365 // set all table-miss-entries
366 populateTableMissEntry(TABLE_VLAN, true, false, false, -1);
367 populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
368 populateTableMissEntry(TABLE_IPv4_UNICAST, false, true, true,
369 TABLE_ACL);
370 populateTableMissEntry(TABLE_MPLS, false, true, true,
371 TABLE_ACL);
372 populateTableMissEntry(TABLE_ACL, false, false, false, -1);
373 }
374
375 private void sendBarrier() throws IOException {
376 long xid = getNextTransactionId();
377 barrierXidToWaitFor = xid;
378 OFBarrierRequest br = getFactory()
379 .buildBarrierRequest()
380 .setXid(xid)
381 .build();
382 write(br, null);
383 }
384
385 /**
386 * Adds a table-miss-entry to a pipeline table.
387 * <p>
388 * The table-miss-entry can be added with 'write-actions' or
389 * 'apply-actions'. It can also add a 'goto-table' instruction. By default
390 * if none of the booleans in the call are set, then the table-miss entry is
391 * added with no instructions, which means that if a packet hits the
392 * table-miss-entry, pipeline execution will stop, and the action set
393 * associated with the packet will be executed.
394 *
395 * @param tableToAdd the table to where the table-miss-entry will be added
396 * @param toControllerNow as an APPLY_ACTION instruction
397 * @param toControllerWrite as a WRITE_ACTION instruction
398 * @param toTable as a GOTO_TABLE instruction
399 * @param tableToSend the table to send as per the GOTO_TABLE instruction it
400 * needs to be set if 'toTable' is true. Ignored of 'toTable' is
401 * false.
402 * @throws IOException
403 */
404 @SuppressWarnings("unchecked")
405 private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
406 boolean toControllerWrite,
407 boolean toTable, int tableToSend) throws IOException {
408 OFOxmList oxmList = OFOxmList.EMPTY;
409 OFMatchV3 match = factory.buildMatchV3()
410 .setOxmList(oxmList)
411 .build();
412 OFAction outc = factory.actions()
413 .buildOutput()
414 .setPort(OFPort.CONTROLLER)
415 .setMaxLen(OFPCML_NO_BUFFER)
416 .build();
417 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
418 if (toControllerNow) {
419 // table-miss instruction to send to controller immediately
420 OFInstruction instr = factory.instructions()
421 .buildApplyActions()
422 .setActions(Collections.singletonList(outc))
423 .build();
424 instructions.add(instr);
425 }
426
427 if (toControllerWrite) {
428 // table-miss instruction to write-action to send to controller
429 // this will be executed whenever the action-set gets executed
430 OFInstruction instr = factory.instructions()
431 .buildWriteActions()
432 .setActions(Collections.singletonList(outc))
433 .build();
434 instructions.add(instr);
435 }
436
437 if (toTable) {
438 // table-miss instruction to goto-table x
439 OFInstruction instr = factory.instructions()
440 .gotoTable(TableId.of(tableToSend));
441 instructions.add(instr);
442 }
443
444 if (!toControllerNow && !toControllerWrite && !toTable) {
445 // table-miss has no instruction - at which point action-set will be
446 // executed - if there is an action to output/group in the action
447 // set
448 // the packet will be sent there, otherwise it will be dropped.
449 instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
450 }
451
452 OFMessage tableMissEntry = factory.buildFlowAdd()
453 .setTableId(TableId.of(tableToAdd))
454 .setMatch(match) // match everything
455 .setInstructions(instructions)
456 .setPriority(MIN_PRIORITY)
457 .setBufferId(OFBufferId.NO_BUFFER)
458 .setIdleTimeout(0)
459 .setHardTimeout(0)
460 .setXid(getNextTransactionId())
461 .build();
462 write(tableMissEntry, null);
463 }
464
465 private void getNetworkConfig() {
466 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
467 SwitchConfigStatus scs = ncs.checkSwitchConfig(new Dpid(getId()));
468 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
469 srConfig = (SegmentRouterConfig) scs.getSwitchConfig();
470 } else {
471 log.error("Switch not configured as Segment-Router");
472 }
473
474 List<LinkConfig> linkConfigList = ncs.getConfiguredAllowedLinks();
475 setNeighbors(linkConfigList);
476 }
477
478 private void populateTableVlan() throws IOException {
479 List<OFMessage> msglist = new ArrayList<OFMessage>();
480 for (OFPortDesc p : getPorts()) {
481 int pnum = p.getPortNo().getPortNumber();
482 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
483 OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
484 OFOxmVlanVid oxv = factory.oxms()
485 .vlanVid(OFVlanVidMatch.UNTAGGED);
486 OFOxmList oxmList = OFOxmList.of(oxp, oxv);
487 OFMatchV3 match = factory.buildMatchV3()
488 .setOxmList(oxmList).build();
489
490 // TODO: match on vlan-tagged packets for vlans configured on
491 // subnet ports and strip-vlan
492
493 // Do not need to add vlans
494 /*int vlanid = getVlanConfig(pnum);
495 OFOxmVlanVid vidToSet = factory.oxms()
496 .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
497 OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
498 OFAction setVlan = factory.actions().setField(vidToSet);
499 List<OFAction> actionlist = new ArrayList<OFAction>();
500 actionlist.add(pushVlan);
501 actionlist.add(setVlan);
502 OFInstruction appAction = factory.instructions().buildApplyActions()
503 .setActions(actionlist).build();*/
504
505 OFInstruction gotoTbl = factory.instructions().buildGotoTable()
506 .setTableId(TableId.of(TABLE_TMAC)).build();
507 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
508 // instructions.add(appAction);
509 instructions.add(gotoTbl);
510 OFMessage flowEntry = factory.buildFlowAdd()
511 .setTableId(TableId.of(TABLE_VLAN))
512 .setMatch(match)
513 .setInstructions(instructions)
514 .setPriority(1000) // does not matter - all rules
515 // exclusive
516 .setBufferId(OFBufferId.NO_BUFFER)
517 .setIdleTimeout(0)
518 .setHardTimeout(0)
519 .setXid(getNextTransactionId())
520 .build();
521 msglist.add(flowEntry);
522 }
523 }
524 write(msglist);
525 log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId());
526 }
527
528 private void populateTableTMac() throws IOException {
529 // match for router-mac and ip-packets
530 OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
531 OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr());
532 OFOxmList oxmListIp = OFOxmList.of(dmac, oxe);
533 OFMatchV3 matchIp = factory.buildMatchV3()
534 .setOxmList(oxmListIp).build();
535 OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
536 .setTableId(TableId.of(TABLE_IPv4_UNICAST)).build();
537 List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
538 OFMessage ipEntry = factory.buildFlowAdd()
539 .setTableId(TableId.of(TABLE_TMAC))
540 .setMatch(matchIp)
541 .setInstructions(instructionsIp)
542 .setPriority(1000) // strict priority required lower than
543 // multicastMac
544 .setBufferId(OFBufferId.NO_BUFFER)
545 .setIdleTimeout(0)
546 .setHardTimeout(0)
547 .setXid(getNextTransactionId())
548 .build();
549
550 // match for router-mac and mpls packets
551 OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
552 OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls);
553 OFMatchV3 matchMpls = factory.buildMatchV3()
554 .setOxmList(oxmListMpls).build();
555 OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
556 .setTableId(TableId.of(TABLE_MPLS)).build();
557 List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
558 OFMessage mplsEntry = factory.buildFlowAdd()
559 .setTableId(TableId.of(TABLE_TMAC))
560 .setMatch(matchMpls)
561 .setInstructions(instructionsMpls)
562 .setPriority(1001) // strict priority required lower than
563 // multicastMac
564 .setBufferId(OFBufferId.NO_BUFFER)
565 .setIdleTimeout(0)
566 .setHardTimeout(0)
567 .setXid(getNextTransactionId())
568 .build();
569
570 log.debug("Adding termination-mac-rules in sw {}", getStringId());
571 List<OFMessage> msglist = new ArrayList<OFMessage>(2);
572 msglist.add(ipEntry);
573 msglist.add(mplsEntry);
574 write(msglist);
575 }
576
577 private MacAddress getRouterMacAddr() {
578 if (srConfig != null) {
579 return MacAddress.of(srConfig.getRouterMac());
580 } else {
581 // return a dummy mac address - it will not be used
582 return MacAddress.of("00:00:00:00:00:00");
583 }
584 }
585
586 private MacAddress getNeighborRouterMacAddress(Dpid ndpid) {
587 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
588 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
589 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
590 return MacAddress.of(((SegmentRouterConfig) scs.getSwitchConfig())
591 .getRouterMac());
592 } else {
593 // return a dummy mac address - it will not be used
594 return MacAddress.of("00:00:00:00:00:00");
595 }
596 }
597
598 private void setNeighbors(List<LinkConfig> linkConfigList) {
599 List<PortNumber> portlist = new ArrayList<PortNumber>();
600 for (LinkConfig lg : linkConfigList) {
601 if (!lg.getType().equals(NetworkConfigManager.PKT_LINK)) {
602 return;
603 }
604 PktLinkConfig plg = (PktLinkConfig) lg;
605 if (plg.getDpid1() == getId()) {
606 addNeighborAtPort(new Dpid(plg.getDpid2()),
607 PortNumber.uint32(plg.getPort1()));
608 } else if (plg.getDpid2() == getId()) {
609 addNeighborAtPort(new Dpid(plg.getDpid1()),
610 PortNumber.uint32(plg.getPort2()));
611 }
612 }
613 }
614
615 private void addNeighborAtPort(Dpid neighborDpid, PortNumber portToNeighbor) {
616 if (neighbors.get(neighborDpid) != null) {
617 neighbors.get(neighborDpid).add(portToNeighbor);
618 } else {
619 Set<PortNumber> ports = new HashSet<PortNumber>();
620 ports.add(portToNeighbor);
621 neighbors.put(neighborDpid, ports);
622 }
623 }
624
625 /**
626 * createGroups creates ECMP groups for all ports on this router connected
627 * to other routers (in the OF network). The information for ports is
628 * gleaned from the configured links. If no links are configured no groups
629 * will be created, and it is up to the caller of the IOF13Switch API to
630 * create groups.
631 * <p>
632 * By default all ports connected to the same neighbor router will be part
633 * of the same ECMP group. In addition, groups will be created for all
634 * possible combinations of neighbor routers.
635 * <p>
636 * For example, consider this router (R0) connected to 3 neighbors (R1, R2,
637 * and R3). The following groups will be created in R0:
638 * <li>1) all ports to R1,
639 * <li>2) all ports to R2,
640 * <li>3) all ports to R3,
641 * <li>4) all ports to R1 and R2
642 * <li>5) all ports to R1 and R3
643 * <li>6) all ports to R2 and R3
644 * <li>7) all ports to R1, R2, and R3
645 */
646 private void createGroups() {
647 Set<Dpid> dpids = neighbors.keySet();
648 if (dpids == null || dpids.isEmpty()) {
649 return;
650 }
651 // temp map of ecmp groupings
652 /* Map<NeighborSet, List<BucketInfo>> temp =
653 new HashMap<NeighborSet, List<BucketInfo>>();
654 */
655 // get all combinations of neighbors
656 Set<Set<Dpid>> powerSet = Sets.powerSet(dpids);
657 int groupid = 1;
658 for (Set<Dpid> combo : powerSet) {
659 if (combo.isEmpty()) {
660 // eliminate the empty set in the power set
661 continue;
662 }
663 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
664 NeighborSet ns = new NeighborSet();
665 for (Dpid d : combo) {
666 ns.addDpid(d);
667 for (PortNumber sp : neighbors.get(d)) {
668 BucketInfo b = new BucketInfo(d,
669 MacAddress.of(srConfig.getRouterMac()),
670 getNeighborRouterMacAddress(d), sp);
671 buckets.add(b);
672 }
673 }
674 EcmpInfo ecmpInfo = new EcmpInfo(groupid++, buckets);
675 setEcmpGroup(ecmpInfo);
676 ecmpGroups.put(ns, ecmpInfo);
677 log.debug("Creating ecmp group in sw {}: {}", getStringId(), ecmpInfo);
678 }
679 }
680
681 private class EcmpInfo {
682 int groupId;
683 List<BucketInfo> buckets;
684
685 EcmpInfo(int gid, List<BucketInfo> bucketInfos) {
686 groupId = gid;
687 buckets = bucketInfos;
688 }
689
690 @Override
691 public String toString() {
692 return "groupId: " + groupId + ", buckets: " + buckets;
693 }
694 }
695
696 private class BucketInfo {
697 Dpid neighborDpid;
698 MacAddress srcMac;
699 MacAddress dstMac;
700 PortNumber outport;
701
702 BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac, PortNumber p) {
703 neighborDpid = nDpid;
704 srcMac = smac;
705 dstMac = dmac;
706 outport = p;
707 }
708
709 @Override
710 public String toString() {
711 return " {neighborDpid: " + neighborDpid + ", dstMac: " + dstMac +
712 ", srcMac: " + srcMac + ", outport: " + outport + "}";
713 }
714 }
715
716 private void setEcmpGroup(EcmpInfo ecmpInfo) {
717 List<OFMessage> msglist = new ArrayList<OFMessage>();
718 OFGroup group = OFGroup.of(ecmpInfo.groupId);
719
720 List<OFBucket> buckets = new ArrayList<OFBucket>();
721 for (BucketInfo b : ecmpInfo.buckets) {
722 OFOxmEthDst dmac = factory.oxms()
723 .ethDst(b.dstMac);
724 OFAction setDA = factory.actions().buildSetField()
725 .setField(dmac).build();
Saurav Das0a344b02014-09-26 14:18:52 -0700726 OFOxmEthSrc smac = factory.oxms()
727 .ethSrc(b.srcMac);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700728 OFAction setSA = factory.actions().buildSetField()
729 .setField(smac).build();
730 OFAction outp = factory.actions().buildOutput()
731 .setPort(OFPort.of(b.outport.shortValue()))
732 .build();
733 List<OFAction> actions = new ArrayList<OFAction>();
734 actions.add(setSA);
735 actions.add(setDA);
736 actions.add(outp);
737 OFBucket ofb = factory.buildBucket()
738 .setWeight(1)
739 .setActions(actions)
740 .build();
741 buckets.add(ofb);
742 }
743
744 OFMessage gm = factory.buildGroupAdd()
745 .setGroup(group)
746 .setBuckets(buckets)
747 .setGroupType(OFGroupType.SELECT)
748 .setXid(getNextTransactionId())
749 .build();
750 msglist.add(gm);
751 try {
752 write(msglist);
753 } catch (IOException e) {
754 // TODO Auto-generated catch block
755 e.printStackTrace();
756 }
757 }
758
759 private void verifyGroups() throws IOException {
760 sendGroupDescRequest();
761 }
762
763 private void sendGroupDescRequest() throws IOException {
764 OFMessage gdr = factory.buildGroupDescStatsRequest()
765 .setXid(getNextTransactionId())
766 .build();
767 write(gdr, null);
768 }
769
770 private void assignAdjacencyLabels() {
771 // TODO
772 try {
773 nextDriverState();
774 } catch (IOException e) {
775 // TODO Auto-generated catch block
776 e.printStackTrace();
777 }
778 }
779
Saurav Das1cd10152014-09-26 09:38:07 -0700780 private OFAction getOFAction(Action action) {
781 OFAction ofAction = null;
782 if (action instanceof OutputAction) {
783 OutputAction outputAction = (OutputAction) action;
784 OFPort port = OFPort.of((int) outputAction.getPortNumber().value());
785 ofAction = factory.actions().output(port, Short.MAX_VALUE);
786 } else if (action instanceof ModifyDstMacAction) {
787 long dstMac = ((ModifyDstMacAction) action).getDstMac().toLong();
788 OFOxmEthDst dmac = factory.oxms()
789 .ethDst(MacAddress.of(dstMac));
790 ofAction = factory.actions().buildSetField()
791 .setField(dmac).build();
792 } else if (action instanceof ModifySrcMacAction) {
793 long srcMac = ((ModifySrcMacAction) action).getSrcMac().toLong();
794 OFOxmEthSrc smac = factory.oxms()
795 .ethSrc(MacAddress.of(srcMac));
796 ofAction = factory.actions().buildSetField()
797 .setField(smac).build();
798 } else if (action instanceof PushMplsAction) {
799 ofAction = factory.actions().pushMpls(EthType.MPLS_UNICAST);
800 } else if (action instanceof SetMplsIdAction) {
801 int labelid = ((SetMplsIdAction) action).getMplsId();
802 OFOxmMplsLabel lid = factory.oxms()
803 .mplsLabel(U32.of(labelid));
804 ofAction = factory.actions().buildSetField()
805 .setField(lid).build();
806 } else if (action instanceof PopMplsAction) {
807 EthType ethertype = ((PopMplsAction) action).getEthType();
808 ofAction = factory.actions().popMpls(ethertype);
809 } else if (action instanceof GroupAction) {
810 NeighborSet ns = ((GroupAction) action).getDpids();
811 EcmpInfo ei = ecmpGroups.get(ns);
812 if (ei != null) {
813 int gid = ei.groupId;
814 ofAction = factory.actions().buildGroup()
815 .setGroup(OFGroup.of(gid))
816 .build();
817 } else {
818 log.error("Unable to find ecmp group for neighbors {} at "
819 + "switch {}", ns, getStringId());
820 }
821 } else if (action instanceof DecNwTtlAction) {
822 ofAction = factory.actions().decNwTtl();
823 } else if (action instanceof DecMplsTtlAction) {
824 ofAction = factory.actions().decMplsTtl();
825 } else if (action instanceof CopyTtlInAction) {
826 ofAction = factory.actions().copyTtlIn();
827 } else if (action instanceof CopyTtlOutAction) {
828 ofAction = factory.actions().copyTtlOut();
829 } else {
830 log.warn("Unsupported Action type: {}", action.getClass().getName());
831 return null;
832 }
833
834 // not supported by loxigen
835 // OFAction setBos =
836 // factory.actions().buildSetField().setField(bos).build();
837
838 return ofAction;
839 }
840
Saurav Das0a344b02014-09-26 14:18:52 -0700841 private OFMessage getIpEntry(MatchActionOperationEntry mao) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700842 MatchAction ma = mao.getTarget();
843 Operator op = mao.getOperator();
844 Ipv4Match ipm = (Ipv4Match) ma.getMatch();
845
846 // set match
847 IPv4Net ipdst = ipm.getDestination();
848 OFOxmEthType ethTypeIp = factory.oxms()
849 .ethType(EthType.IPv4);
850 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
851 .ipv4DstMasked(
852 IPv4Address.of(ipdst.address().value()),
853 IPv4Address.ofCidrMaskLength(ipdst.prefixLen())
854 );
855 OFOxmList oxmList = OFOxmList.of(ethTypeIp, ipPrefix);
856 OFMatchV3 match = factory.buildMatchV3()
857 .setOxmList(oxmList).build();
858
859 // set actions
860 List<OFAction> writeActions = new ArrayList<OFAction>();
861 for (Action action : ma.getActions()) {
Saurav Das1cd10152014-09-26 09:38:07 -0700862 OFAction ofAction = getOFAction(action);
863 if (ofAction != null) {
864 writeActions.add(ofAction);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700865 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700866 }
867
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700868 // set instructions
869 OFInstruction writeInstr = factory.instructions().buildWriteActions()
870 .setActions(writeActions).build();
871 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
872 .setTableId(TableId.of(TABLE_ACL)).build();
873 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
874 instructions.add(writeInstr);
875 instructions.add(gotoInstr);
876
Saurav Das1cd10152014-09-26 09:38:07 -0700877 // set flow priority to emulate longest prefix match
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700878 int priority = ipdst.prefixLen() * PRIORITY_MULTIPLIER;
879 if (ipdst.prefixLen() == (short) 32) {
880 priority = MAX_PRIORITY;
881 }
882
Saurav Dasbc594a42014-09-25 20:13:50 -0700883 // set flow-mod
884 OFMessage ipFlow = null;
885 if (op == MatchActionOperations.Operator.ADD) {
886 ipFlow = factory.buildFlowAdd()
887 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
888 .setMatch(match)
889 .setInstructions(instructions)
890 .setPriority(priority)
891 .setBufferId(OFBufferId.NO_BUFFER)
892 .setIdleTimeout(0)
893 .setHardTimeout(0)
894 .setXid(getNextTransactionId())
895 .build();
896 } else {
897 ipFlow = factory.buildFlowDeleteStrict()
898 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
899 .setMatch(match)
900 .setInstructions(instructions)
901 .setPriority(priority)
902 .setBufferId(OFBufferId.NO_BUFFER)
903 .setIdleTimeout(0)
904 .setHardTimeout(0)
905 .setXid(getNextTransactionId())
906 .build();
907 }
Saurav Dasbc594a42014-09-25 20:13:50 -0700908 log.debug("{} ip-rule {}-{} in sw {}",
909 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
910 match, writeActions,
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700911 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -0700912 return ipFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700913 }
914
Saurav Das0a344b02014-09-26 14:18:52 -0700915 private OFMessage getMplsEntry(MatchActionOperationEntry mao) {
Saurav Das1cd10152014-09-26 09:38:07 -0700916 MatchAction ma = mao.getTarget();
917 Operator op = mao.getOperator();
918 MplsMatch mplsm = (MplsMatch) ma.getMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700919
Saurav Das1cd10152014-09-26 09:38:07 -0700920 // set match
921 OFOxmEthType ethTypeMpls = factory.oxms()
922 .ethType(EthType.MPLS_UNICAST);
923 OFOxmMplsLabel labelid = factory.oxms()
924 .mplsLabel(U32.of(mplsm.getMplsLabel()));
925 OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid);
926 OFMatchV3 matchlabel = factory.buildMatchV3()
927 .setOxmList(oxmList).build();
928
929 // set actions
930 List<OFAction> writeActions = new ArrayList<OFAction>();
931 for (Action action : ma.getActions()) {
932 OFAction ofAction = getOFAction(action);
933 if (ofAction != null) {
934 writeActions.add(ofAction);
935 }
936 }
937
938 // set instructions
939 OFInstruction writeInstr = factory.instructions().buildWriteActions()
940 .setActions(writeActions).build();
941 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
942 .setTableId(TableId.of(TABLE_ACL)).build();
943 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
944 instructions.add(writeInstr);
945 instructions.add(gotoInstr);
946
947 OFMessage mplsFlow = null;
948 if (op == MatchActionOperations.Operator.ADD) {
949 mplsFlow = factory.buildFlowAdd()
950 .setTableId(TableId.of(TABLE_MPLS))
951 .setMatch(matchlabel)
952 .setInstructions(instructions)
953 .setPriority(MAX_PRIORITY) // exact match and exclusive
954 .setBufferId(OFBufferId.NO_BUFFER)
955 .setIdleTimeout(0)
956 .setHardTimeout(0)
957 .setXid(getNextTransactionId())
958 .build();
959 } else {
960 mplsFlow = factory.buildFlowDeleteStrict()
961 .setTableId(TableId.of(TABLE_MPLS))
962 .setMatch(matchlabel)
963 .setInstructions(instructions)
964 .setPriority(MAX_PRIORITY) // exact match and exclusive
965 .setBufferId(OFBufferId.NO_BUFFER)
966 .setIdleTimeout(0)
967 .setHardTimeout(0)
968 .setXid(getNextTransactionId())
969 .build();
970 }
Saurav Das1cd10152014-09-26 09:38:07 -0700971 log.debug("{} mpls-rule {}-{} in sw {}",
972 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
973 matchlabel, writeActions,
974 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -0700975 return mplsFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700976 }
977
Saurav Das0a344b02014-09-26 14:18:52 -0700978 private OFMessage getAclEntry(MatchActionOperationEntry mao) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700979
Saurav Das0a344b02014-09-26 14:18:52 -0700980 OFMessage aclFlow = null;
981 return aclFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700982 }
983
984 // *****************************
985 // IOF13Switch
986 // *****************************
987
988 @Override
989 public void pushFlow(MatchActionOperationEntry matchActionOp) throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -0700990 OFMessage ofm = getFlow(matchActionOp);
991 if (ofm != null) {
992 write(Collections.singletonList(ofm));
993 }
994 }
995
996 private OFMessage getFlow(MatchActionOperationEntry matchActionOp) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700997 final MatchAction matchAction = matchActionOp.getTarget();
998 final Match match = matchAction.getMatch();
999 if (match instanceof Ipv4Match) {
Saurav Das0a344b02014-09-26 14:18:52 -07001000 return getIpEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001001 } else if (match instanceof MplsMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001002 return getMplsEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001003 } else if (match instanceof PacketMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001004 return getAclEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001005 } else {
1006 log.error("Unknown match type {} pushed to switch {}", match,
1007 getStringId());
1008 }
Saurav Das0a344b02014-09-26 14:18:52 -07001009 return null;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001010 }
1011
1012 @Override
1013 public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps)
1014 throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001015 List<OFMessage> flowMods = new ArrayList<OFMessage>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001016 for (MatchActionOperationEntry matchActionOp : matchActionOps) {
Saurav Das0a344b02014-09-26 14:18:52 -07001017 OFMessage ofm = getFlow(matchActionOp);
1018 if (ofm != null) {
1019 flowMods.add(ofm);
1020 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001021 }
Saurav Das0a344b02014-09-26 14:18:52 -07001022 write(flowMods);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001023 }
1024
1025 @Override
1026 public int getEcmpGroupId(NeighborSet ns) {
1027 EcmpInfo ei = ecmpGroups.get(ns);
1028 if (ei == null) {
1029 return -1;
1030 } else {
1031 return ei.groupId;
1032 }
1033 }
1034
1035 // *****************************
1036 // Old Hardcoded Stuff
1037 // *****************************
1038
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001039 private void configureSwitch() throws IOException {
1040 // setAsyncConfig();
1041 // getTableFeatures();
1042 sendGroupFeaturesRequest();
1043 setL2Groups();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001044 sendBarrier();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001045 setL3Groups();
1046 setL25Groups();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001047 // setEcmpGroup();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001048 sendGroupDescRequest();
1049 populateTableVlan();
1050 populateTableTMac();
1051 populateIpTable();
1052 populateMplsTable();
1053 populateTableMissEntry(TABLE_ACL, false, false, false, -1);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001054 sendBarrier();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001055 }
1056
1057 private void setAsyncConfig() throws IOException {
1058 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
1059 OFMessage setAC = null;
1060
1061 if (role == Role.MASTER) {
1062 setAC = factory.buildAsyncSet()
1063 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
1064 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
1065 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
1066 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1067 .setPacketInMaskSlave(SET_ALL_SLAVE)
1068 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1069 .setXid(getNextTransactionId())
1070 .build();
1071 } else if (role == Role.EQUAL) {
1072 setAC = factory.buildAsyncSet()
1073 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
1074 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
1075 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
1076 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1077 .setPacketInMaskSlave(SET_ALL_SLAVE)
1078 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1079 .setXid(getNextTransactionId())
1080 .build();
1081 }
1082 msglist.add(setAC);
1083
1084 OFMessage br = factory.buildBarrierRequest()
1085 .setXid(getNextTransactionId())
1086 .build();
1087 msglist.add(br);
1088
1089 OFMessage getAC = factory.buildAsyncGetRequest()
1090 .setXid(getNextTransactionId())
1091 .build();
1092 msglist.add(getAC);
1093
1094 write(msglist);
1095 }
1096
1097 private void decodeAsyncGetReply(OFAsyncGetReply rep) {
1098 long frm = rep.getFlowRemovedMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001099 long frs = rep.getFlowRemovedMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001100 long pim = rep.getPacketInMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001101 long pis = rep.getPacketInMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001102 long psm = rep.getPortStatusMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001103 long pss = rep.getPortStatusMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001104
1105 if (role == Role.MASTER || role == Role.EQUAL) { // should separate
1106 log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
1107 log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
1108 log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
1109 }
1110
1111 }
1112
1113 private void getTableFeatures() throws IOException {
1114 OFMessage gtf = factory.buildTableFeaturesStatsRequest()
1115 .setXid(getNextTransactionId())
1116 .build();
1117 write(gtf, null);
1118 }
1119
1120 private void sendGroupFeaturesRequest() throws IOException {
1121 OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
1122 .setXid(getNextTransactionId())
1123 .build();
1124 write(gfr, null);
1125 }
1126
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001127
1128 /*Create L2 interface groups for all physical ports
1129 Naming convention followed is the same as OF-DPA spec
1130 eg. port 1 with allowed vlan 10, is enveloped in group with id,
1131 0x0 00a 0001, where the uppermost 4 bits identify an L2 interface,
1132 the next 12 bits identify the vlan-id, and the lowermost 16 bits
1133 identify the port number.*/
1134 private void setL2Groups() throws IOException {
1135 List<OFMessage> msglist = new ArrayList<OFMessage>();
1136 for (OFPortDesc p : getPorts()) {
1137 int pnum = p.getPortNo().getPortNumber();
1138 int portVlan = getVlanConfig(pnum);
1139 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
1140 OFGroup gl2 = OFGroup.of(pnum | (portVlan << VLAN_ID_OFFSET));
1141 OFAction out = factory.actions().buildOutput()
1142 .setPort(p.getPortNo()).build();
1143 OFAction popVlan = factory.actions().popVlan();
1144 List<OFAction> actions = new ArrayList<OFAction>();
Sangho Shin01bca862014-09-12 11:18:59 -07001145 // actions.add(popVlan);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001146 actions.add(out);
1147 OFBucket bucket = factory.buildBucket()
1148 .setActions(actions).build();
1149 List<OFBucket> buckets = Collections.singletonList(bucket);
1150 OFMessage gmAdd = factory.buildGroupAdd()
1151 .setGroup(gl2)
1152 .setBuckets(buckets)
1153 .setGroupType(OFGroupType.INDIRECT)
1154 .setXid(getNextTransactionId())
1155 .build();
1156 msglist.add(gmAdd);
1157 l2groups.put(pnum, gl2);
1158 }
1159 }
1160 log.debug("Creating {} L2 groups in sw {}", msglist.size(), getStringId());
1161 write(msglist);
1162 }
1163
1164 private int getVlanConfig(int portnum) {
1165 int portVlan = 10 * portnum;
1166 if ((getId() == 0x1 && portnum == 6) ||
1167 (getId() == 0x2) ||
1168 (getId() == 0x3 && portnum == 2)) {
1169 portVlan = 192; // 0xc0
1170 }
1171 return portVlan;
1172 }
1173
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001174
1175 // only for ports connected to other routers
1176 private OFAction getDestAction(int portnum) {
1177 OFAction setDA = null;
1178 MacAddress dAddr = null;
1179 if (getId() == 0x1 && portnum == 6) { // connected to switch 2
1180 dAddr = MacAddress.of("00:00:02:02:02:80");
1181 }
Saurav Dasdf783ae2014-09-22 09:36:32 -07001182 if (getId() == 0x1 && portnum == 7) { // connected to switch 2
1183 dAddr = MacAddress.of("00:00:02:02:02:80");
1184 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001185 if (getId() == 0x2) {
1186 if (portnum == 1) { // connected to sw 1
1187 dAddr = MacAddress.of("00:00:01:01:01:80");
1188 } else if (portnum == 2) { // connected to sw 3
1189 dAddr = MacAddress.of("00:00:07:07:07:80");
1190 }
1191 }
1192 if (getId() == 0x3) {
1193 if (portnum == 2) { // connected to switch 2
1194 dAddr = MacAddress.of("00:00:02:02:02:80");
1195 }
1196 }
1197
1198 if (dAddr != null) {
1199 OFOxmEthDst dstAddr = factory.oxms().ethDst(dAddr);
1200 setDA = factory.actions().buildSetField()
1201 .setField(dstAddr).build();
1202 }
1203 return setDA;
1204 }
1205
1206 /*
1207 * L3 groups are created for all router ports and they all point to corresponding
1208 * L2 groups. Only the ports that connect to other routers will have the
1209 * DA set.
1210 */
1211 private void setL3Groups() throws IOException {
1212 List<OFMessage> msglist = new ArrayList<OFMessage>();
1213 for (OFGroup gl2 : l2groups.values()) {
1214 int gnum = gl2.getGroupNumber();
1215 int portnum = gnum & 0x0000ffff;
1216 int vlanid = ((gnum & 0x0fff0000) >> VLAN_ID_OFFSET);
1217 MacAddress sAddr = getRouterMacAddr();
1218
1219 OFGroup gl3 = OFGroup.of(0x20000000 | portnum);
1220 OFAction group = factory.actions().buildGroup()
1221 .setGroup(gl2).build();
1222 OFOxmEthSrc srcAddr = factory.oxms().ethSrc(sAddr);
1223 OFAction setSA = factory.actions().buildSetField()
1224 .setField(srcAddr).build();
1225 OFOxmVlanVid vid = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanid));
1226 OFAction setVlan = factory.actions().buildSetField()
1227 .setField(vid).build();
1228 OFAction decTtl = factory.actions().decNwTtl();
1229
1230 List<OFAction> actions = new ArrayList<OFAction>();
1231 actions.add(decTtl); // decrement the IP TTL/do-checksum/check TTL
1232 // and MTU
Sangho Shin01bca862014-09-12 11:18:59 -07001233 // actions.add(setVlan); // set the vlan-id of the exit-port (and
1234 // l2group)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001235 actions.add(setSA); // set this routers mac address
1236 // make L3Unicast group setDA for known (configured) ports
1237 // that connect to other routers
1238 OFAction setDA = getDestAction(portnum);
Sangho Shin01bca862014-09-12 11:18:59 -07001239 if (setDA != null)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001240 actions.add(setDA);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001241 actions.add(group);
1242
1243 OFBucket bucket = factory.buildBucket()
1244 .setActions(actions).build();
1245 List<OFBucket> buckets = Collections.singletonList(bucket);
1246 OFMessage gmAdd = factory.buildGroupAdd()
1247 .setGroup(gl3)
1248 .setBuckets(buckets)
1249 .setGroupType(OFGroupType.INDIRECT)
1250 .setXid(getNextTransactionId())
1251 .build();
1252 msglist.add(gmAdd);
1253 }
1254 write(msglist);
1255 log.debug("Creating {} L3 groups in sw {}", msglist.size(), getStringId());
1256 }
1257
1258 /*
1259 * L2.5 or mpls-unicast groups are only created for those router ports
1260 * connected to other router ports. They differ from the corresponding
1261 * L3-unicast group only by the fact that they decrement the MPLS TTL
1262 * instead of the IP ttl
1263 */
1264 private void setL25Groups() throws IOException {
1265 List<OFMessage> msglist = new ArrayList<OFMessage>();
1266 for (OFGroup gl2 : l2groups.values()) {
1267 int gnum = gl2.getGroupNumber();
1268 int portnum = gnum & 0x0000ffff;
1269 int vlanid = ((gnum & 0x0fff0000) >> VLAN_ID_OFFSET);
1270 MacAddress sAddr = getRouterMacAddr();
1271 OFAction setDA = getDestAction(portnum);
1272 // setDA will only be non-null for ports connected to routers
1273 if (setDA != null) {
1274 OFGroup gl3 = OFGroup.of(0xa0000000 | portnum); // different id
1275 // for mpls
1276 // group
1277 OFAction group = factory.actions().buildGroup()
1278 .setGroup(gl2).build();
1279 OFOxmEthSrc srcAddr = factory.oxms().ethSrc(sAddr);
1280 OFAction setSA = factory.actions().buildSetField()
1281 .setField(srcAddr).build();
1282 OFOxmVlanVid vid = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanid));
1283 OFAction setVlan = factory.actions().buildSetField()
1284 .setField(vid).build();
1285 OFAction decMplsTtl = factory.actions().decMplsTtl();
1286 List<OFAction> actions = new ArrayList<OFAction>();
1287 actions.add(decMplsTtl); // decrement the MPLS
1288 // TTL/do-checksum/check TTL and MTU
Sangho Shin01bca862014-09-12 11:18:59 -07001289 // actions.add(setVlan); // set the vlan-id of the exit-port
1290 // (and
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001291 // l2group)
1292 actions.add(setSA); // set this routers mac address
1293 actions.add(setDA);
1294 actions.add(group);
1295 OFBucket bucket = factory.buildBucket()
1296 .setActions(actions).build();
1297 List<OFBucket> buckets = Collections.singletonList(bucket);
1298 OFMessage gmAdd = factory.buildGroupAdd()
1299 .setGroup(gl3)
1300 .setBuckets(buckets)
1301 .setGroupType(OFGroupType.INDIRECT)
1302 .setXid(getNextTransactionId())
1303 .build();
1304 msglist.add(gmAdd);
1305 }
1306 }
1307 write(msglist);
1308 log.debug("Creating {} MPLS groups in sw {}", msglist.size(), getStringId());
1309 }
1310
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001311
1312 private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
1313 log.info("Sw: {} Group Features {}", getStringId(), gfsr);
1314 }
1315
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001316
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001317
1318 private List<String> getMyIps() { // send to controller
1319 List<String> myIps = new ArrayList<String>();
1320 if (getId() == 0x1) {
1321 myIps.add("10.0.2.128");
1322 myIps.add("10.0.3.128");
1323 myIps.add("10.0.1.128");
1324 myIps.add("192.168.0.1");
1325 }
1326 if (getId() == 0x2) {
1327 myIps.add("192.168.0.2");
1328 }
1329 if (getId() == 0x3) {
1330 myIps.add("192.168.0.3");
1331 myIps.add("7.7.7.128");
1332 }
1333 return myIps;
1334 }
1335
1336 private List<String> getMySubnetIps() { // send to controller
1337 List<String> subnetIps = new ArrayList<String>();
1338 if (getId() == 0x1) {
1339 subnetIps.add("10.0.2.0");
1340 subnetIps.add("10.0.3.0");
1341 subnetIps.add("10.0.1.0");
1342 }
Sangho Shin01bca862014-09-12 11:18:59 -07001343 if (getId() == 0x2) {
1344 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001345 if (getId() == 0x3) {
1346 subnetIps.add("7.7.7.0");
1347 }
1348 return subnetIps;
1349 }
1350
Sangho Shin01bca862014-09-12 11:18:59 -07001351 private class RouteEntry {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001352 String prefix;
1353 String mask;
1354 int nextHopPort;
1355 String dstMac;
1356 int label;
1357
1358 public RouteEntry(String prefix, String mask, int nextHopPort, int label) {
1359 this.prefix = prefix;
1360 this.mask = mask;
1361 this.nextHopPort = nextHopPort;
1362 this.label = label;
1363 }
1364
1365 public RouteEntry(String prefix, int nextHopPort, String dstMac) {
1366 this.prefix = prefix;
1367 this.nextHopPort = nextHopPort;
1368 this.dstMac = dstMac;
1369 }
1370 }
1371
1372 // send out of mpls-group where the next-hop mac-da is already set
1373 private List<RouteEntry> getRouterNextHopIps() {
1374 List<RouteEntry> routerNextHopIps = new ArrayList<RouteEntry>();
1375 if (getId() == 0x1) {
1376 routerNextHopIps
1377 .add(new RouteEntry("192.168.0.2", "255.255.255.255", 6, 102));
1378 routerNextHopIps
1379 .add(new RouteEntry("192.168.0.3", "255.255.255.255", 6, 103));
1380 routerNextHopIps.add(new RouteEntry("7.7.7.0", "255.255.255.0", 6, 103));
1381 }
Sangho Shin01bca862014-09-12 11:18:59 -07001382 if (getId() == 0x2) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001383 /* These are required for normal IP routing without labels.
1384 routerNextHopIps.add(new RouteEntry("192.168.0.1","255.255.255.255",1));
1385 routerNextHopIps.add(new RouteEntry("192.168.0.3","255.255.255.255",2));
1386 routerNextHopIps.add(new RouteEntry("10.0.1.0","255.255.255.0",1));
1387 routerNextHopIps.add(new RouteEntry("10.0.2.0","255.255.255.0",1));
1388 routerNextHopIps.add(new RouteEntry("10.0.3.0","255.255.255.0",1));
1389 routerNextHopIps.add(new RouteEntry("7.7.7.0","255.255.255.0",2));*/
Sangho Shin01bca862014-09-12 11:18:59 -07001390 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001391 if (getId() == 0x3) {
1392 routerNextHopIps
1393 .add(new RouteEntry("192.168.0.2", "255.255.255.255", 2, 102));
1394 routerNextHopIps
1395 .add(new RouteEntry("192.168.0.1", "255.255.255.255", 2, 101));
1396 routerNextHopIps.add(new RouteEntry("10.0.1.0", "255.255.255.0", 2, 101));
1397 routerNextHopIps.add(new RouteEntry("10.0.2.0", "255.255.255.0", 2, 101));
1398 routerNextHopIps.add(new RouteEntry("10.0.3.0", "255.255.255.0", 2, 101));
1399 }
1400 return routerNextHopIps;
1401 }
1402
1403 // known host mac-addr, setDA/send out of l3group
1404 private List<RouteEntry> getHostNextHopIps() {
1405 List<RouteEntry> hostNextHopIps = new ArrayList<RouteEntry>();
1406 if (getId() == 0x1) {
Sangho Shin01bca862014-09-12 11:18:59 -07001407 //hostNextHopIps.add(new RouteEntry("10.0.1.1", 1, "00:00:00:00:01:01")); // Just for Test - SSH
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001408 hostNextHopIps.add(new RouteEntry("10.0.2.1", 4, "00:00:00:00:02:01"));
1409 hostNextHopIps.add(new RouteEntry("10.0.3.1", 5, "00:00:00:00:03:01"));
1410 }
Sangho Shin01bca862014-09-12 11:18:59 -07001411 if (getId() == 0x2) {
1412 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001413 if (getId() == 0x3) {
1414 hostNextHopIps.add(new RouteEntry("7.7.7.7", 1, "00:00:07:07:07:07"));
1415 }
1416 return hostNextHopIps;
1417 }
1418
1419 private void populateIpTable() throws IOException {
Sangho Shin01bca862014-09-12 11:18:59 -07001420 // populateMyIps();
1421 // populateMySubnets();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001422 populateRoutes();
1423 populateHostRoutes();
1424
1425 // match for everything else to send to ACL table. Essentially
1426 // the table miss flow entry
Sangho Shin01bca862014-09-12 11:18:59 -07001427 populateTableMissEntry(TABLE_IPv4_UNICAST, false, true,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001428 true, TABLE_ACL);
1429 }
1430
1431 private void populateMyIps() throws IOException {
1432 List<OFMessage> msglist = new ArrayList<OFMessage>();
1433 // first all my ip's as exact-matches
1434 // write-action instruction to send to controller
1435 List<String> myIps = getMyIps();
1436 for (int i = 0; i < myIps.size(); i++) {
1437 OFOxmEthType ethTypeIp = factory.oxms()
1438 .ethType(EthType.IPv4);
1439 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
1440 .ipv4DstMasked(IPv4Address.of(myIps.get(i)), IPv4Address.NO_MASK);
1441 OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
1442 OFMatchV3 match = factory.buildMatchV3()
1443 .setOxmList(oxmListSlash32).build();
1444 OFAction outc = factory.actions().buildOutput()
1445 .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
1446 .build();
1447 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1448 .setActions(Collections.singletonList(outc)).build();
1449 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1450 .setTableId(TableId.of(TABLE_ACL)).build();
1451 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1452 instructions.add(writeInstr);
1453 instructions.add(gotoInstr);
1454 OFMessage myIpEntry = factory.buildFlowAdd()
Sangho Shin01bca862014-09-12 11:18:59 -07001455 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001456 .setMatch(match)
1457 .setInstructions(instructions)
1458 .setPriority(MAX_PRIORITY) // highest priority for exact
1459 // match
1460 .setBufferId(OFBufferId.NO_BUFFER)
1461 .setIdleTimeout(0)
1462 .setHardTimeout(0)
1463 .setXid(getNextTransactionId())
1464 .build();
1465 msglist.add(myIpEntry);
1466 }
1467 write(msglist);
1468 log.debug("Adding {} my-ip-rules in sw {}", msglist.size(), getStringId());
1469 }
1470
1471 private void populateMySubnets() throws IOException {
1472 List<OFMessage> msglist = new ArrayList<OFMessage>();
1473 // next prefix-based subnet-IP's configured on my interfaces
1474 // need to ARP for exact-IP, so write-action instruction to send to
1475 // controller
1476 // this has different mask and priority than earlier case
1477 List<String> subnetIps = getMySubnetIps();
1478 for (int i = 0; i < subnetIps.size(); i++) {
1479 OFOxmEthType ethTypeIp = factory.oxms()
1480 .ethType(EthType.IPv4);
1481 OFOxmIpv4DstMasked ipPrefix = factory.oxms().ipv4DstMasked(
1482 IPv4Address.of(subnetIps.get(i)),
1483 IPv4Address.of(0xffffff00)); // '/24' mask
1484 OFOxmList oxmListSlash24 = OFOxmList.of(ethTypeIp, ipPrefix);
1485 OFMatchV3 match = factory.buildMatchV3()
1486 .setOxmList(oxmListSlash24).build();
1487 OFAction outc = factory.actions().buildOutput()
1488 .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
1489 .build();
1490 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1491 .setActions(Collections.singletonList(outc)).build();
1492 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1493 .setTableId(TableId.of(TABLE_ACL)).build();
1494 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1495 instructions.add(writeInstr);
1496 instructions.add(gotoInstr);
1497 OFMessage myIpEntry = factory.buildFlowAdd()
Sangho Shin01bca862014-09-12 11:18:59 -07001498 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001499 .setMatch(match)
1500 .setInstructions(instructions)
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001501 .setPriority((short) 0xfff0)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001502 .setBufferId(OFBufferId.NO_BUFFER)
1503 .setIdleTimeout(0)
1504 .setHardTimeout(0)
1505 .setXid(getNextTransactionId())
1506 .build();
1507 msglist.add(myIpEntry);
1508 }
1509 write(msglist);
1510 log.debug("Adding {} subnet-ip-rules in sw {}", msglist.size(), getStringId());
1511 msglist.clear();
1512 }
1513
1514 private void populateRoutes() throws IOException {
1515 List<OFMessage> msglist = new ArrayList<OFMessage>();
1516 // addresses where I know the next-hop's mac-address because it is a
1517 // router port - so I have an L3 interface to it (and an MPLS interface)
1518 List<RouteEntry> routerNextHopIps = getRouterNextHopIps();
1519 for (int i = 0; i < routerNextHopIps.size(); i++) {
1520 OFOxmEthType ethTypeIp = factory.oxms()
1521 .ethType(EthType.IPv4);
1522 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
1523 .ipv4DstMasked(
1524 IPv4Address.of(routerNextHopIps.get(i).prefix),
1525 IPv4Address.of(routerNextHopIps.get(i).mask)
1526 );
1527 OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
1528 OFMatchV3 match = factory.buildMatchV3()
1529 .setOxmList(oxmListSlash32).build();
1530 OFAction outg = factory.actions().buildGroup()
1531 .setGroup(OFGroup.of(0xa0000000 | // mpls group id
1532 routerNextHopIps.get(i).nextHopPort))
1533 .build();
1534 // lots of actions before forwarding to mpls group, and
1535 // unfortunately
1536 // they need to be apply-actions
1537
1538 OFAction pushlabel = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1539 OFOxmMplsLabel l = factory.oxms()
1540 .mplsLabel(U32.of(routerNextHopIps.get(i).label));
1541 OFAction setlabelid = factory.actions().buildSetField()
1542 .setField(l).build();
1543 OFAction copyTtlOut = factory.actions().copyTtlOut();
1544 // OFAction setBos =
1545 // factory.actions().buildSetField().setField(bos).build();
1546
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001547 List<OFAction> writeActions = new ArrayList<OFAction>();
Sangho Shin01bca862014-09-12 11:18:59 -07001548 writeActions.add(pushlabel);
1549 writeActions.add(copyTtlOut);
1550 writeActions.add(setlabelid);
1551 // writeActions.add(setBos); no support in loxigen
1552
1553 // List<OFAction> applyActions = new ArrayList<OFAction>();
1554 // applyActions.add(pushlabel);
1555 // applyActions.add(copyTtlOut);
1556 // OFInstruction applyInstr =
1557 // factory.instructions().buildApplyActions()
1558 // .setActions(applyActions).build();
Saurav Dasdf783ae2014-09-22 09:36:32 -07001559
1560 if (getId() == 0x1) {
1561 OFAction group47 = factory.actions().buildGroup()
1562 .setGroup(OFGroup.of(47)).build();
1563 writeActions.add(group47);
1564 } else {
1565 writeActions.add(outg); // group will decr mpls-ttl, set
1566 // mac-sa/da,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001567 // vlan
Saurav Dasdf783ae2014-09-22 09:36:32 -07001568 }
1569
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001570 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1571 .setActions(writeActions).build();
Sangho Shin01bca862014-09-12 11:18:59 -07001572 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1573 .setTableId(TableId.of(TABLE_ACL)).build();
1574 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1575 instructions.add(writeInstr);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001576
1577 // necessary to match in pseudo-table to overcome cpqd 1.3 flaw
Sangho Shin01bca862014-09-12 11:18:59 -07001578 /*OFInstruction writeMeta = factory.instructions().buildWriteMetadata()
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001579 .setMetadata(U64.of(routerNextHopIps.get(i).label))
1580 .setMetadataMask(METADATA_MASK).build();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001581 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
Sangho Shin01bca862014-09-12 11:18:59 -07001582 .setTableId(TableId.of(TABLE_META)).build();*/
1583 /*instructions.add(applyInstr);
1584 instructions.add(writeMeta);*/
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001585
Sangho Shin01bca862014-09-12 11:18:59 -07001586 instructions.add(gotoInstr);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001587 int priority = -1;
Sangho Shin01bca862014-09-12 11:18:59 -07001588 if (routerNextHopIps.get(i).mask.equals("255.255.255.255"))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001589 priority = MAX_PRIORITY;
Sangho Shin01bca862014-09-12 11:18:59 -07001590 else
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001591 priority = (short) 0xfff0;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001592 OFMessage myIpEntry = factory.buildFlowAdd()
Sangho Shin01bca862014-09-12 11:18:59 -07001593 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001594 .setMatch(match)
1595 .setInstructions(instructions)
1596 .setPriority(priority)
1597 .setBufferId(OFBufferId.NO_BUFFER)
1598 .setIdleTimeout(0)
1599 .setHardTimeout(0)
1600 .setXid(getNextTransactionId())
1601 .build();
1602 msglist.add(myIpEntry);
1603
1604 // need to also handle psuedo-table entries to match-metadata and
1605 // set mpls
1606 // label-id
Sangho Shin01bca862014-09-12 11:18:59 -07001607 /*OFOxmEthType ethTypeMpls = factory.oxms()
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001608 .ethType(EthType.MPLS_UNICAST);
1609 OFOxmMetadataMasked meta = factory.oxms()
1610 .metadataMasked(
1611 OFMetadata.ofRaw(routerNextHopIps.get(i).label),
1612 OFMetadata.NO_MASK);
1613 OFOxmList oxmListMeta = OFOxmList.of(ethTypeMpls, meta);
1614 OFMatchV3 matchMeta = factory.buildMatchV3()
1615 .setOxmList(oxmListMeta).build();
1616 List<OFAction> writeActions2 = new ArrayList<OFAction>();
1617 writeActions2.add(setlabelid);
1618 OFAction outg2 = factory.actions().buildGroup()
1619 .setGroup(OFGroup.of(routerNextHopIps.get(i).nextHopPort |
Sangho Shin01bca862014-09-12 11:18:59 -07001620 (192 << VLAN_ID_OFFSET)))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001621 .build();
1622 writeActions2.add(outg2);
1623 OFInstruction writeInstr2 = factory.instructions().buildWriteActions()
1624 .setActions(writeActions2).build();
1625 OFInstruction gotoInstr2 = factory.instructions().buildGotoTable()
1626 .setTableId(TableId.of(TABLE_ACL)).build();
1627 List<OFInstruction> instructions2 = new ArrayList<OFInstruction>();
1628 // unfortunately have to apply this action too
1629 OFInstruction applyInstr2 = factory.instructions().buildApplyActions()
1630 .setActions(writeActions2).build();
Sangho Shin01bca862014-09-12 11:18:59 -07001631 instructions2.add(applyInstr2); */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001632 // instructions2.add(writeInstr2);
1633 // instructions2.add(gotoInstr2);
1634
1635 /*OFMatchV3 match3 = factory.buildMatchV3()
Sangho Shin01bca862014-09-12 11:18:59 -07001636 .setOxmList(OFOxmList.of(meta)).build();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001637 OFInstruction clearInstruction = factory.instructions().clearActions();
1638 List<OFInstruction> instructions3 = new ArrayList<OFInstruction>();
1639 OFAction outc = factory.actions().buildOutput()
Sangho Shin01bca862014-09-12 11:18:59 -07001640 .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
1641 .build();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001642 OFInstruction writec = factory.instructions()
Sangho Shin01bca862014-09-12 11:18:59 -07001643 .writeActions(Collections.singletonList(outc));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001644 instructions3.add(clearInstruction);
1645 instructions3.add(writec);
1646 instructions3.add(gotoInstr2); */
Sangho Shin01bca862014-09-12 11:18:59 -07001647 /*OFMessage myMetaEntry = factory.buildFlowAdd()
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001648 .setTableId(TableId.of(TABLE_META))
1649 .setMatch(matchMeta)
1650 .setInstructions(instructions2)
1651 .setPriority(MAX_PRIORITY)
1652 .setBufferId(OFBufferId.NO_BUFFER)
1653 .setIdleTimeout(0)
1654 .setHardTimeout(0)
1655 .setXid(getNextTransactionId())
1656 .build();
Sangho Shin01bca862014-09-12 11:18:59 -07001657 msglist.add(myMetaEntry); */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001658
1659 }
1660 write(msglist);
1661 log.debug("Adding {} next-hop-router-rules in sw {}", msglist.size(),
1662 getStringId());
1663
1664 // add a table-miss entry to table 4 for debugging - leave it out
1665 // unclear packet state - causes switch to crash
1666 // populateTableMissEntry(TABLE_META, false, true,
1667 // true, TABLE_ACL);
1668 }
1669
1670 private void populateHostRoutes() throws IOException {
1671 List<OFMessage> msglist = new ArrayList<OFMessage>();
1672 // addresses where I know the next hop's mac-address and I can set the
1673 // destination mac in the match-instruction.write-action
1674 // either I sent out arp-request or I got an arp-request from this host
1675 List<RouteEntry> hostNextHopIps = getHostNextHopIps();
1676 for (int i = 0; i < hostNextHopIps.size(); i++) {
1677 OFOxmEthType ethTypeIp = factory.oxms()
1678 .ethType(EthType.IPv4);
1679 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
1680 .ipv4DstMasked(
1681 IPv4Address.of(hostNextHopIps.get(i).prefix),
1682 IPv4Address.NO_MASK); // host addr should be /32
1683 OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
1684 OFMatchV3 match = factory.buildMatchV3()
1685 .setOxmList(oxmListSlash32).build();
1686 OFAction setDmac = null, outg = null;
1687 OFOxmEthDst dmac = factory.oxms()
1688 .ethDst(MacAddress.of(hostNextHopIps.get(i).dstMac));
1689 setDmac = factory.actions().buildSetField()
1690 .setField(dmac).build();
1691 outg = factory.actions().buildGroup()
1692 .setGroup(OFGroup.of(0x20000000 | hostNextHopIps.get(i).nextHopPort)) // l3group
1693 // id
1694 .build();
1695 List<OFAction> writeActions = new ArrayList<OFAction>();
1696 writeActions.add(setDmac);
1697 writeActions.add(outg);
1698 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1699 .setActions(writeActions).build();
1700 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1701 .setTableId(TableId.of(TABLE_ACL)).build();
1702 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1703 instructions.add(writeInstr);
1704 instructions.add(gotoInstr);
1705 OFMessage myIpEntry = factory.buildFlowAdd()
Sangho Shin01bca862014-09-12 11:18:59 -07001706 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001707 .setMatch(match)
1708 .setInstructions(instructions)
1709 .setPriority(MAX_PRIORITY) // highest priority for exact
1710 // match
1711 .setBufferId(OFBufferId.NO_BUFFER)
1712 .setIdleTimeout(0)
1713 .setHardTimeout(0)
1714 .setXid(getNextTransactionId())
1715 .build();
1716 msglist.add(myIpEntry);
1717 }
1718 write(msglist);
1719 log.debug("Adding {} next-hop-host-rules in sw {}", msglist.size(), getStringId());
1720 }
1721
Sangho Shin01bca862014-09-12 11:18:59 -07001722 private class MplsEntry {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001723 int labelid;
1724 int portnum;
1725
1726 public MplsEntry(int labelid, int portnum) {
1727 this.labelid = labelid;
1728 this.portnum = portnum;
1729 }
1730 }
1731
1732 private List<MplsEntry> getMplsEntries() {
1733 List<MplsEntry> myLabels = new ArrayList<MplsEntry>();
1734 if (getId() == 0x1) {
1735 myLabels.add(new MplsEntry(101, OFPort.CONTROLLER.getPortNumber()));
1736 myLabels.add(new MplsEntry(103, 6));
1737 }
1738 if (getId() == 0x2) {
1739 myLabels.add(new MplsEntry(103, 2));
1740 myLabels.add(new MplsEntry(102, OFPort.CONTROLLER.getPortNumber()));
1741 myLabels.add(new MplsEntry(101, 1));
1742 }
1743 if (getId() == 0x3) {
1744 myLabels.add(new MplsEntry(103, OFPort.CONTROLLER.getPortNumber()));
1745 myLabels.add(new MplsEntry(101, 2));
1746 }
1747 return myLabels;
1748 }
1749
1750 private void populateMplsTable() throws IOException {
1751 List<OFMessage> msglist = new ArrayList<OFMessage>();
1752 List<MplsEntry> lfibEntries = getMplsEntries();
1753 for (int i = 0; i < lfibEntries.size(); i++) {
1754 OFOxmEthType ethTypeMpls = factory.oxms()
1755 .ethType(EthType.MPLS_UNICAST);
1756 OFOxmMplsLabel labelid = factory.oxms()
1757 .mplsLabel(U32.of(lfibEntries.get(i).labelid));
1758 OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid);
1759 OFMatchV3 matchlabel = factory.buildMatchV3()
1760 .setOxmList(oxmList).build();
1761 OFAction poplabel = factory.actions().popMpls(EthType.IPv4);
Sangho Shin01bca862014-09-12 11:18:59 -07001762 OFAction copyttlin = factory.actions().copyTtlIn();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001763 OFAction sendTo = null;
1764 if (lfibEntries.get(i).portnum == OFPort.CONTROLLER.getPortNumber()) {
1765 sendTo = factory.actions().output(OFPort.CONTROLLER,
1766 OFPCML_NO_BUFFER);
1767 } else {
Sangho Shin01bca862014-09-12 11:18:59 -07001768 // after popping send to L3 intf, not MPLS intf
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001769 sendTo = factory.actions().group(OFGroup.of(
Sangho Shin01bca862014-09-12 11:18:59 -07001770 0x20000000 | lfibEntries.get(i).portnum));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001771 }
1772 List<OFAction> writeActions = new ArrayList<OFAction>();
Sangho Shin01bca862014-09-12 11:18:59 -07001773 writeActions.add(copyttlin);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001774 writeActions.add(poplabel);
1775 writeActions.add(sendTo);
1776 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1777 .setActions(writeActions).build();
1778 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1779 .setTableId(TableId.of(TABLE_ACL)).build();
1780 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1781 instructions.add(writeInstr);
1782 instructions.add(gotoInstr);
1783 OFMessage myMplsEntry = factory.buildFlowAdd()
1784 .setTableId(TableId.of(TABLE_MPLS))
1785 .setMatch(matchlabel)
1786 .setInstructions(instructions)
1787 .setPriority(MAX_PRIORITY) // exact match and exclusive
1788 .setBufferId(OFBufferId.NO_BUFFER)
1789 .setIdleTimeout(0)
1790 .setHardTimeout(0)
1791 .setXid(getNextTransactionId())
1792 .build();
1793 msglist.add(myMplsEntry);
1794 }
1795 write(msglist);
1796 log.debug("Adding {} mpls-forwarding-rules in sw {}", msglist.size(),
1797 getStringId());
1798
1799 // match for everything else to send to ACL table. Essentially
1800 // the table miss flow entry
1801 populateTableMissEntry(TABLE_MPLS, false, true,
1802 true, TABLE_ACL);
1803
1804 }
1805
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001806
1807}