blob: 287d4fa29fcefd8129f675b09b09b9a511cd4059 [file] [log] [blame]
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -07001package net.onrc.onos.core.drivermanager;
2
3import java.io.IOException;
4import java.util.ArrayList;
5import java.util.Collection;
6import java.util.Collections;
7import java.util.HashMap;
8import java.util.HashSet;
9import java.util.Iterator;
10import java.util.List;
11import java.util.Map;
12import java.util.Set;
13import java.util.concurrent.ConcurrentHashMap;
14import java.util.concurrent.ConcurrentMap;
15import java.util.concurrent.atomic.AtomicBoolean;
16import java.util.concurrent.atomic.AtomicInteger;
17
18import net.floodlightcontroller.core.IFloodlightProviderService.Role;
19import net.floodlightcontroller.core.IOF13Switch;
20import net.floodlightcontroller.core.IOFSwitch;
21import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
22import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
23import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
24import net.floodlightcontroller.core.internal.OFSwitchImplBase;
25import net.floodlightcontroller.util.MACAddress;
26import net.floodlightcontroller.util.OrderedCollection;
27import net.onrc.onos.core.configmanager.INetworkConfigService;
28import net.onrc.onos.core.configmanager.INetworkConfigService.NetworkConfigState;
29import net.onrc.onos.core.configmanager.INetworkConfigService.SwitchConfigStatus;
30import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
31import net.onrc.onos.core.configmanager.NetworkConfig.SwitchConfig;
32import net.onrc.onos.core.configmanager.NetworkConfigManager;
33import net.onrc.onos.core.configmanager.PktLinkConfig;
34import net.onrc.onos.core.configmanager.SegmentRouterConfig;
35import net.onrc.onos.core.configmanager.SegmentRouterConfig.AdjacencySid;
36import net.onrc.onos.core.matchaction.MatchAction;
37import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
38import net.onrc.onos.core.matchaction.MatchActionOperations;
39import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
40import net.onrc.onos.core.matchaction.action.Action;
41import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
42import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
43import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
44import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
45import net.onrc.onos.core.matchaction.action.GroupAction;
46import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
47import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
48import net.onrc.onos.core.matchaction.action.OutputAction;
49import net.onrc.onos.core.matchaction.action.PopMplsAction;
50import net.onrc.onos.core.matchaction.action.PushMplsAction;
51import net.onrc.onos.core.matchaction.action.SetDAAction;
52import net.onrc.onos.core.matchaction.action.SetMplsBosAction;
53import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
54import net.onrc.onos.core.matchaction.action.SetSAAction;
55import net.onrc.onos.core.matchaction.match.Ipv4Match;
56import net.onrc.onos.core.matchaction.match.Match;
57import net.onrc.onos.core.matchaction.match.MplsMatch;
58import net.onrc.onos.core.matchaction.match.PacketMatch;
59import net.onrc.onos.core.util.Dpid;
60import net.onrc.onos.core.util.IPv4Net;
61import net.onrc.onos.core.util.PortNumber;
62
63import org.codehaus.jackson.map.ObjectMapper;
64import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
65import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
66import org.projectfloodlight.openflow.protocol.OFBucket;
67import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
68import org.projectfloodlight.openflow.protocol.OFErrorMsg;
69import org.projectfloodlight.openflow.protocol.OFFactory;
70import org.projectfloodlight.openflow.protocol.OFFlowMod;
71import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
72import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
73import org.projectfloodlight.openflow.protocol.OFGroupType;
74import org.projectfloodlight.openflow.protocol.OFMatchV3;
75import org.projectfloodlight.openflow.protocol.OFMessage;
76import org.projectfloodlight.openflow.protocol.OFOxmList;
77import org.projectfloodlight.openflow.protocol.OFPortDesc;
78import org.projectfloodlight.openflow.protocol.OFPortStatus;
79import org.projectfloodlight.openflow.protocol.OFStatsReply;
80import org.projectfloodlight.openflow.protocol.action.OFAction;
81import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
82import org.projectfloodlight.openflow.protocol.match.Match.Builder;
83import org.projectfloodlight.openflow.protocol.match.MatchField;
84import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
85import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
86import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
87import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
88import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
89import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsBos;
90import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
91import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
92import org.projectfloodlight.openflow.types.EthType;
93import org.projectfloodlight.openflow.types.IPv4Address;
94import org.projectfloodlight.openflow.types.IpProtocol;
95import org.projectfloodlight.openflow.types.MacAddress;
96import org.projectfloodlight.openflow.types.OFBooleanValue;
97import org.projectfloodlight.openflow.types.OFBufferId;
98import org.projectfloodlight.openflow.types.OFGroup;
99import org.projectfloodlight.openflow.types.OFPort;
100import org.projectfloodlight.openflow.types.OFVlanVidMatch;
101import org.projectfloodlight.openflow.types.TableId;
102import org.projectfloodlight.openflow.types.TransportPort;
103import org.projectfloodlight.openflow.types.U32;
104import org.projectfloodlight.openflow.util.HexString;
105
106/**
107 * OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
108 * Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
109 * Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
110 * None
111 */
112public class OFSwitchImplSpringOpenTTP extends OFSwitchImplBase implements IOF13Switch {
113 private AtomicBoolean driverHandshakeComplete;
114 private AtomicBoolean haltStateMachine;
115 private OFFactory factory;
116 private static final int OFPCML_NO_BUFFER = 0xffff;
117 // Configuration of asynch messages to controller. We need different
118 // asynch messages depending on role-equal or role-master.
119 // We don't want to get anything if we are slave.
120 private static final long SET_FLOW_REMOVED_MASK_MASTER = 0xf;
121 private static final long SET_PACKET_IN_MASK_MASTER = 0x7;
122 private static final long SET_PORT_STATUS_MASK_MASTER = 0x7;
123 private static final long SET_FLOW_REMOVED_MASK_EQUAL = 0x0;
124 private static final long SET_PACKET_IN_MASK_EQUAL = 0x0;
125 private static final long SET_PORT_STATUS_MASK_EQUAL = 0x7;
126 private static final long SET_ALL_SLAVE = 0x0;
127
128 private static final long TEST_FLOW_REMOVED_MASK = 0xf;
129 private static final long TEST_PACKET_IN_MASK = 0x7;
130 private static final long TEST_PORT_STATUS_MASK = 0x7;
131
132 private static final int TABLE_VLAN = 0;
133 private static final int TABLE_TMAC = 1;
134 private static final int TABLE_IPv4_UNICAST = 2;
135 private static final int TABLE_MPLS = 3;
136 private static final int TABLE_ACL = 5;
137
138 private static final short MAX_PRIORITY = (short) 0xffff;
139 private static final short PRIORITY_MULTIPLIER = (short) 2046;
140 private static final short MIN_PRIORITY = 0x0;
141
142 private long barrierXidToWaitFor = -1;
143 private DriverState driverState;
144 private final boolean usePipeline13;
145 private SegmentRouterConfig srConfig;
146 private ConcurrentMap<Dpid, Set<PortNumber>> neighbors;
147 private ConcurrentMap<PortNumber, Dpid> portToNeighbors;
148 private List<Integer> segmentIds;
149 private boolean isEdgeRouter;
150 private ConcurrentMap<NeighborSet, EcmpInfo> ecmpGroups;
151 private ConcurrentMap<Integer, EcmpInfo> userDefinedGroups;
152 private ConcurrentMap<PortNumber, ArrayList<NeighborSet>> portNeighborSetMap;
153 private AtomicInteger groupid;
154 private Map<String, String> publishAttributes;
155
156 public OFSwitchImplSpringOpenTTP(OFDescStatsReply desc, boolean usePipeline13) {
157 super();
158 haltStateMachine = new AtomicBoolean(false);
159 driverState = DriverState.INIT;
160 driverHandshakeComplete = new AtomicBoolean(false);
161 setSwitchDescription(desc);
162 neighbors = new ConcurrentHashMap<Dpid, Set<PortNumber>>();
163 portToNeighbors = new ConcurrentHashMap<PortNumber, Dpid>();
164 ecmpGroups = new ConcurrentHashMap<NeighborSet, EcmpInfo>();
165 userDefinedGroups = new ConcurrentHashMap<Integer, EcmpInfo>();
166 portNeighborSetMap =
167 new ConcurrentHashMap<PortNumber, ArrayList<NeighborSet>>();
168 segmentIds = new ArrayList<Integer>();
169 isEdgeRouter = false;
170 groupid = new AtomicInteger(0);
171 this.usePipeline13 = usePipeline13;
172 }
173
174 // *****************************
175 // OFSwitchImplBase
176 // *****************************
177
178
179 /* (non-Javadoc)
180 * @see java.lang.Object#toString()
181 */
182 @Override
183 public String toString() {
184 return "OFSwitchImplCPqD13 [" + ((channel != null)
185 ? channel.getRemoteAddress() : "?")
186 + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
187 }
188
189 @Override
190 public void startDriverHandshake() throws IOException {
191 log.debug("Starting driver handshake for sw {}", getStringId());
192 if (startDriverHandshakeCalled) {
193 throw new SwitchDriverSubHandshakeAlreadyStarted();
194 }
195 startDriverHandshakeCalled = true;
196 factory = getFactory();
197 if (!usePipeline13) {
198 // Send packet-in to controller if a packet misses the first table
199 populateTableMissEntry(0, true, false, false, 0);
200 driverHandshakeComplete.set(true);
201 } else {
202 nextDriverState();
203 }
204 }
205
206 @Override
207 public boolean isDriverHandshakeComplete() {
208 if (!startDriverHandshakeCalled)
209 throw new SwitchDriverSubHandshakeNotStarted();
210 return driverHandshakeComplete.get();
211 }
212
213 @Override
214 public void processDriverHandshakeMessage(OFMessage m) {
215 if (!startDriverHandshakeCalled)
216 throw new SwitchDriverSubHandshakeNotStarted();
217 if (isDriverHandshakeComplete())
218 throw new SwitchDriverSubHandshakeCompleted(m);
219 try {
220 processOFMessage(this, m);
221 } catch (IOException e) {
222 log.error("Error generated when processing OFMessage", e.getCause());
223 }
224 }
225
226 @Override
227 public String getSwitchDriverState() {
228 return driverState.toString();
229 }
230
231 public void removePortFromGroups(PortNumber port) {
232 log.debug("removePortFromGroups: Remove port {} from Switch {}",
233 port, getStringId());
234 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
235 if (portNSSet == null)
236 {
237 /* No Groups are created with this port yet */
238 log.warn("removePortFromGroups: No groups exist with Switch {} port {}",
239 getStringId(), port);
240 return;
241 }
242 log.debug("removePortFromGroups: Neighborsets that the port {} is part"
243 + "of on Switch {} are {}",
244 port, getStringId(), portNSSet);
245
246 for (NeighborSet ns : portNSSet) {
247 /* Delete the first matched bucket */
248 EcmpInfo portEcmpInfo = ecmpGroups.get(ns);
249 Iterator<BucketInfo> it = portEcmpInfo.buckets.iterator();
250 log.debug("removePortFromGroups: Group {} on Switch {} has {} buckets",
251 portEcmpInfo.groupId, getStringId(),
252 portEcmpInfo.buckets.size());
253 while (it.hasNext()) {
254 BucketInfo bucket = it.next();
255 if (bucket.outport.equals(port)) {
256 it.remove();
257 }
258 }
259 log.debug("removePortFromGroups: Modifying Group on Switch {} "
260 + "and Neighborset {} with {}",
261 getStringId(), ns, portEcmpInfo);
262 modifyEcmpGroup(portEcmpInfo);
263 }
264 /* Don't delete the entry from portNeighborSetMap because
265 * when the port is up again this info is needed
266 */
267 return;
268 }
269
270 public void addPortToGroups(PortNumber port) {
271 log.debug("addPortToGroups: Add port {} to Switch {}",
272 port, getStringId());
273 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
274 if (portNSSet == null) {
275 /* Unknown Port */
276 log.warn("addPortToGroups: Switch {} port {} is unknown",
277 getStringId(), port);
278 return;
279 }
280 log.debug("addPortToGroups: Neighborsets that the port {} is part"
281 + "of on Switch {} are {}",
282 port, getStringId(), portNSSet);
283
284 Dpid neighborDpid = portToNeighbors.get(port);
285 for (NeighborSet ns : portNSSet) {
286 EcmpInfo portEcmpInfo = ecmpGroups.get(ns);
287 /* Find if this port is already part of any bucket
288 * in this group
289 * NOTE: This is needed because in some cases
290 * (such as for configured network nodes), both driver and
291 * application detect the network elements and creates the
292 * buckets in the same group. This check is to avoid
293 * duplicate bucket creation in such scenarios
294 */
295 List<BucketInfo> buckets = portEcmpInfo.buckets;
296 if (buckets == null) {
297 buckets = new ArrayList<BucketInfo>();
298 portEcmpInfo.buckets = buckets;
299 } else {
300 Iterator<BucketInfo> it = buckets.iterator();
301 boolean matchingBucketExist = false;
302 while (it.hasNext()) {
303 BucketInfo bucket = it.next();
304 if (bucket.outport.equals(port)) {
305 matchingBucketExist = true;
306 break;
307 }
308 }
309 if (matchingBucketExist) {
310 log.warn("addPortToGroups: On Switch {} duplicate "
311 + "portAdd is called for port {} with buckets {}",
312 getStringId(), port, buckets);
313 continue;
314 }
315 }
316 BucketInfo b = new BucketInfo(neighborDpid,
317 MacAddress.of(srConfig.getRouterMac()),
318 getNeighborRouterMacAddress(neighborDpid),
319 port,
320 ns.getEdgeLabel(), true, -1);
321 buckets.add(b);
322 log.debug("addPortToGroups: Modifying Group on Switch {} "
323 + "and Neighborset {} with {}",
324 getStringId(), ns, portEcmpInfo);
325 modifyEcmpGroup(portEcmpInfo);
326 }
327 return;
328 }
329
330 @Override
331 public OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps) {
332 OrderedCollection<PortChangeEvent> events = super.processOFPortStatus(ps);
333 for (PortChangeEvent e : events) {
334 switch (e.type) {
335 case DELETE:
336 case DOWN:
337 log.debug("processOFPortStatus: sw {} Port {} DOWN",
338 getStringId(), e.port.getPortNo().getPortNumber());
339 removePortFromGroups(PortNumber.uint32(
340 e.port.getPortNo().getPortNumber()));
341 break;
342 case UP:
343 log.debug("processOFPortStatus: sw {} Port {} UP",
344 getStringId(), e.port.getPortNo().getPortNumber());
345 addPortToGroups(PortNumber.uint32(
346 e.port.getPortNo().getPortNumber()));
347 }
348 }
349 return events;
350 }
351
352 // *****************************
353 // Driver handshake state-machine
354 // *****************************
355
356 enum DriverState {
357 INIT,
358 SET_TABLE_MISS_ENTRIES,
359 SET_TABLE_VLAN_TMAC,
360 SET_GROUPS,
361 VERIFY_GROUPS,
362 SET_ADJACENCY_LABELS,
363 EXIT
364 }
365
366 protected void nextDriverState() throws IOException {
367 DriverState currentState = driverState;
368 if (haltStateMachine.get()) {
369 return;
370 }
371 switch (currentState) {
372 case INIT:
373 driverState = DriverState.SET_TABLE_MISS_ENTRIES;
374 setTableMissEntries();
375 sendHandshakeBarrier();
376 break;
377 case SET_TABLE_MISS_ENTRIES:
378 driverState = DriverState.SET_TABLE_VLAN_TMAC;
379 getNetworkConfig();
380 populateTableVlan();
381 populateTableTMac();
382 sendHandshakeBarrier();
383 break;
384 case SET_TABLE_VLAN_TMAC:
385 driverState = DriverState.SET_GROUPS;
386 createGroups();
387 sendHandshakeBarrier();
388 break;
389 case SET_GROUPS:
390 driverState = DriverState.VERIFY_GROUPS;
391 verifyGroups();
392 break;
393 case VERIFY_GROUPS:
394 driverState = DriverState.SET_ADJACENCY_LABELS;
395 assignAdjacencyLabels();
396 break;
397 case SET_ADJACENCY_LABELS:
398 driverState = DriverState.EXIT;
399 driverHandshakeComplete.set(true);
400 break;
401 case EXIT:
402 default:
403 driverState = DriverState.EXIT;
404 log.error("Driver handshake has exited for sw: {}", getStringId());
405 }
406 }
407
408 void processOFMessage(IOFSwitch sw, OFMessage m) throws IOException {
409 switch (m.getType()) {
410 case BARRIER_REPLY:
411 processBarrierReply(m);
412 break;
413
414 case ERROR:
415 processErrorMessage(m);
416 break;
417
418 case GET_ASYNC_REPLY:
419 OFAsyncGetReply asrep = (OFAsyncGetReply) m;
420 decodeAsyncGetReply(asrep);
421 break;
422
423 case PACKET_IN:
424 // not ready to handle packet-ins
425 break;
426
427 case QUEUE_GET_CONFIG_REPLY:
428 // not doing queue config yet
429 break;
430
431 case STATS_REPLY:
432 processStatsReply((OFStatsReply) m);
433 break;
434
435 case ROLE_REPLY: // channelHandler should handle this
436 case PORT_STATUS: // channelHandler should handle this
437 case FEATURES_REPLY: // don't care
438 case FLOW_REMOVED: // don't care
439 default:
440 log.debug("Received message {} during switch-driver subhandshake "
441 + "from switch {} ... Ignoring message", m, sw.getStringId());
442 }
443 }
444
445 private void processStatsReply(OFStatsReply sr) {
446 switch (sr.getStatsType()) {
447 case AGGREGATE:
448 break;
449 case DESC:
450 break;
451 case EXPERIMENTER:
452 break;
453 case FLOW:
454 break;
455 case GROUP_DESC:
456 processGroupDesc((OFGroupDescStatsReply) sr);
457 break;
458 case GROUP_FEATURES:
459 processGroupFeatures((OFGroupFeaturesStatsReply) sr);
460 break;
461 case METER_CONFIG:
462 break;
463 case METER_FEATURES:
464 break;
465 case PORT_DESC:
466 break;
467 case TABLE_FEATURES:
468 break;
469 default:
470 break;
471
472 }
473 }
474
475 private void processErrorMessage(OFMessage m) {
476 log.error("Switch {} Error {} in DriverState", getStringId(),
477 (OFErrorMsg) m, driverState);
478 }
479
480 private void processBarrierReply(OFMessage m) throws IOException {
481 if (m.getXid() == barrierXidToWaitFor) {
482 // Driver state-machine progresses to the next state.
483 // If Barrier messages is not received, then eventually
484 // the ChannelHandler state machine will timeout, and the switch
485 // will be disconnected.
486 nextDriverState();
487 } else {
488 log.error("Received incorrect barrier-message xid {} (expected: {}) in "
489 + "switch-driver state {} for switch {}", m, barrierXidToWaitFor,
490 driverState, getStringId());
491 }
492 }
493
494 private void processGroupDesc(OFGroupDescStatsReply gdsr) {
495 log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
496 // TODO -- actually do verification
497 try {
498 nextDriverState();
499 } catch (IOException e) {
500 // TODO Auto-generated catch block
501 e.printStackTrace();
502 }
503 }
504
505 // *****************************
506 // Utility methods
507 // *****************************
508
509 void setTableMissEntries() throws IOException {
510 // set all table-miss-entries
511 populateTableMissEntry(TABLE_VLAN, true, false, false, -1);
512 populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
513 populateTableMissEntry(TABLE_IPv4_UNICAST, false, true, true,
514 TABLE_ACL);
515 populateTableMissEntry(TABLE_MPLS, false, true, true,
516 TABLE_ACL);
517 populateTableMissEntry(TABLE_ACL, false, false, false, -1);
518 }
519
520 private void sendHandshakeBarrier() throws IOException {
521 long xid = getNextTransactionId();
522 barrierXidToWaitFor = xid;
523 OFBarrierRequest br = getFactory()
524 .buildBarrierRequest()
525 .setXid(xid)
526 .build();
527 write(br, null);
528 }
529
530 /**
531 * Adds a table-miss-entry to a pipeline table.
532 * <p>
533 * The table-miss-entry can be added with 'write-actions' or
534 * 'apply-actions'. It can also add a 'goto-table' instruction. By default
535 * if none of the booleans in the call are set, then the table-miss entry is
536 * added with no instructions, which means that if a packet hits the
537 * table-miss-entry, pipeline execution will stop, and the action set
538 * associated with the packet will be executed.
539 *
540 * @param tableToAdd the table to where the table-miss-entry will be added
541 * @param toControllerNow as an APPLY_ACTION instruction
542 * @param toControllerWrite as a WRITE_ACTION instruction
543 * @param toTable as a GOTO_TABLE instruction
544 * @param tableToSend the table to send as per the GOTO_TABLE instruction it
545 * needs to be set if 'toTable' is true. Ignored of 'toTable' is
546 * false.
547 * @throws IOException
548 */
549 @SuppressWarnings("unchecked")
550 private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
551 boolean toControllerWrite,
552 boolean toTable, int tableToSend) throws IOException {
553 OFOxmList oxmList = OFOxmList.EMPTY;
554 OFMatchV3 match = factory.buildMatchV3()
555 .setOxmList(oxmList)
556 .build();
557 OFAction outc = factory.actions()
558 .buildOutput()
559 .setPort(OFPort.CONTROLLER)
560 .setMaxLen(OFPCML_NO_BUFFER)
561 .build();
562 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
563 if (toControllerNow) {
564 // table-miss instruction to send to controller immediately
565 OFInstruction instr = factory.instructions()
566 .buildApplyActions()
567 .setActions(Collections.singletonList(outc))
568 .build();
569 instructions.add(instr);
570 }
571
572 if (toControllerWrite) {
573 // table-miss instruction to write-action to send to controller
574 // this will be executed whenever the action-set gets executed
575 OFInstruction instr = factory.instructions()
576 .buildWriteActions()
577 .setActions(Collections.singletonList(outc))
578 .build();
579 instructions.add(instr);
580 }
581
582 if (toTable) {
583 // table-miss instruction to goto-table x
584 OFInstruction instr = factory.instructions()
585 .gotoTable(TableId.of(tableToSend));
586 instructions.add(instr);
587 }
588
589 if (!toControllerNow && !toControllerWrite && !toTable) {
590 // table-miss has no instruction - at which point action-set will be
591 // executed - if there is an action to output/group in the action
592 // set
593 // the packet will be sent there, otherwise it will be dropped.
594 instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
595 }
596
597 OFMessage tableMissEntry = factory.buildFlowAdd()
598 .setTableId(TableId.of(tableToAdd))
599 .setMatch(match) // match everything
600 .setInstructions(instructions)
601 .setPriority(MIN_PRIORITY)
602 .setBufferId(OFBufferId.NO_BUFFER)
603 .setIdleTimeout(0)
604 .setHardTimeout(0)
605 .setXid(getNextTransactionId())
606 .build();
607 write(tableMissEntry, null);
608 }
609
610 private void getNetworkConfig() {
611 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
612 SwitchConfigStatus scs = ncs.checkSwitchConfig(new Dpid(getId()));
613 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
614 srConfig = (SegmentRouterConfig) scs.getSwitchConfig();
615 isEdgeRouter = srConfig.isEdgeRouter();
616 } else {
617 log.error("Switch not configured as Segment-Router");
618 }
619
620 List<LinkConfig> linkConfigList = ncs.getConfiguredAllowedLinks();
621 setNeighbors(linkConfigList);
622
623 if (isEdgeRouter) {
624 List<SwitchConfig> switchList = ncs.getConfiguredAllowedSwitches();
625 getAllNodeSegmentIds(switchList);
626 }
627 }
628
629 private void populateTableVlan() throws IOException {
630 List<OFMessage> msglist = new ArrayList<OFMessage>();
631 for (OFPortDesc p : getPorts()) {
632 int pnum = p.getPortNo().getPortNumber();
633 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
634 OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
635 OFOxmVlanVid oxv = factory.oxms()
636 .vlanVid(OFVlanVidMatch.UNTAGGED);
637 OFOxmList oxmList = OFOxmList.of(oxp, oxv);
638 OFMatchV3 match = factory.buildMatchV3()
639 .setOxmList(oxmList).build();
640
641 // TODO: match on vlan-tagged packets for vlans configured on
642 // subnet ports and strip-vlan
643
644 // Do not need to add vlans
645 /*int vlanid = getVlanConfig(pnum);
646 OFOxmVlanVid vidToSet = factory.oxms()
647 .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
648 OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
649 OFAction setVlan = factory.actions().setField(vidToSet);
650 List<OFAction> actionlist = new ArrayList<OFAction>();
651 actionlist.add(pushVlan);
652 actionlist.add(setVlan);
653 OFInstruction appAction = factory.instructions().buildApplyActions()
654 .setActions(actionlist).build();*/
655
656 OFInstruction gotoTbl = factory.instructions().buildGotoTable()
657 .setTableId(TableId.of(TABLE_TMAC)).build();
658 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
659 // instructions.add(appAction);
660 instructions.add(gotoTbl);
661 OFMessage flowEntry = factory.buildFlowAdd()
662 .setTableId(TableId.of(TABLE_VLAN))
663 .setMatch(match)
664 .setInstructions(instructions)
665 .setPriority(1000) // does not matter - all rules
666 // exclusive
667 .setBufferId(OFBufferId.NO_BUFFER)
668 .setIdleTimeout(0)
669 .setHardTimeout(0)
670 .setXid(getNextTransactionId())
671 .build();
672 msglist.add(flowEntry);
673 }
674 }
675 write(msglist);
676 log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId());
677 }
678
679 private void populateTableTMac() throws IOException {
680 // match for router-mac and ip-packets
681 OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
682 OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr());
683 OFOxmList oxmListIp = OFOxmList.of(dmac, oxe);
684 OFMatchV3 matchIp = factory.buildMatchV3()
685 .setOxmList(oxmListIp).build();
686 OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
687 .setTableId(TableId.of(TABLE_IPv4_UNICAST)).build();
688 List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
689 OFMessage ipEntry = factory.buildFlowAdd()
690 .setTableId(TableId.of(TABLE_TMAC))
691 .setMatch(matchIp)
692 .setInstructions(instructionsIp)
693 .setPriority(1000) // strict priority required lower than
694 // multicastMac
695 .setBufferId(OFBufferId.NO_BUFFER)
696 .setIdleTimeout(0)
697 .setHardTimeout(0)
698 .setXid(getNextTransactionId())
699 .build();
700
701 // match for router-mac and mpls packets
702 OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
703 OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls);
704 OFMatchV3 matchMpls = factory.buildMatchV3()
705 .setOxmList(oxmListMpls).build();
706 OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
707 .setTableId(TableId.of(TABLE_MPLS)).build();
708 List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
709 OFMessage mplsEntry = factory.buildFlowAdd()
710 .setTableId(TableId.of(TABLE_TMAC))
711 .setMatch(matchMpls)
712 .setInstructions(instructionsMpls)
713 .setPriority(1001) // strict priority required lower than
714 // multicastMac
715 .setBufferId(OFBufferId.NO_BUFFER)
716 .setIdleTimeout(0)
717 .setHardTimeout(0)
718 .setXid(getNextTransactionId())
719 .build();
720
721 log.debug("Adding termination-mac-rules in sw {}", getStringId());
722 List<OFMessage> msglist = new ArrayList<OFMessage>(2);
723 msglist.add(ipEntry);
724 msglist.add(mplsEntry);
725 write(msglist);
726 }
727
728 private MacAddress getRouterMacAddr() {
729 if (srConfig != null) {
730 return MacAddress.of(srConfig.getRouterMac());
731 } else {
732 // return a dummy mac address - it will not be used
733 return MacAddress.of("00:00:00:00:00:00");
734 }
735 }
736
737 private boolean isEdgeRouter(Dpid ndpid) {
738 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
739 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
740 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
741 return ((SegmentRouterConfig) scs.getSwitchConfig()).isEdgeRouter();
742 } else {
743 // TODO: return false if router not allowed
744 return false;
745 }
746 }
747
748 private MacAddress getNeighborRouterMacAddress(Dpid ndpid) {
749 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
750 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
751 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
752 return MacAddress.of(((SegmentRouterConfig) scs.getSwitchConfig())
753 .getRouterMac());
754 } else {
755 // return a dummy mac address - it will not be used
756 return MacAddress.of("00:00:00:00:00:00");
757 }
758 }
759
760 private void setNeighbors(List<LinkConfig> linkConfigList) {
761 for (LinkConfig lg : linkConfigList) {
762 if (!lg.getType().equals(NetworkConfigManager.PKT_LINK)) {
763 continue;
764 }
765 PktLinkConfig plg = (PktLinkConfig) lg;
766 if (plg.getDpid1() == getId()) {
767 addNeighborAtPort(new Dpid(plg.getDpid2()),
768 PortNumber.uint32(plg.getPort1()));
769 } else if (plg.getDpid2() == getId()) {
770 addNeighborAtPort(new Dpid(plg.getDpid1()),
771 PortNumber.uint32(plg.getPort2()));
772 }
773 }
774 }
775
776 private void addNeighborAtPort(Dpid neighborDpid, PortNumber portToNeighbor) {
777 /* Update NeighborToPort database */
778 if (neighbors.get(neighborDpid) != null) {
779 neighbors.get(neighborDpid).add(portToNeighbor);
780 } else {
781 Set<PortNumber> ports = new HashSet<PortNumber>();
782 ports.add(portToNeighbor);
783 neighbors.put(neighborDpid, ports);
784 }
785
786 /* Update portToNeighbors database */
787 if (portToNeighbors.get(portToNeighbor) == null)
788 portToNeighbors.put(portToNeighbor, neighborDpid);
789 }
790
791 private void getAllNodeSegmentIds(List<SwitchConfig> switchList) {
792 for (SwitchConfig sc : switchList) {
793 /* TODO: Do we need to check if the SwitchConfig is of
794 * type SegmentRouter?
795 */
796 if (sc.getDpid() == getId()) {
797 continue;
798 }
799 segmentIds.add(((SegmentRouterConfig) sc).getNodeSid());
800 }
801 log.debug("getAllNodeSegmentIds: at sw {} are {}",
802 getStringId(), segmentIds);
803 }
804
805 private boolean isSegmentIdSameAsNodeSegmentId(Dpid dpid, int sId) {
806 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
807 SwitchConfigStatus scs = ncs.checkSwitchConfig(dpid);
808 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
809 return (((SegmentRouterConfig) scs.getSwitchConfig()).
810 getNodeSid() == sId);
811 } else {
812 // TODO: return false if router not allowed
813 return false;
814 }
815 }
816
817 private Set<Set<Dpid>> getAllNeighborSets(Set<Dpid> neighbors) {
818 List<Dpid> list = new ArrayList<Dpid>(neighbors);
819 Set<Set<Dpid>> sets = new HashSet<Set<Dpid>>();
820 /* get the number of elements in the neighbors */
821 int elements = list.size();
822 /* the number of members of a power set is 2^n
823 * including the empty set
824 */
825 int powerElements = (1 << elements);
826
Srikanth Vavilapallieba65312014-10-30 15:47:20 -0700827 /* run a binary counter for the number of power elements
828 * NOTE: Exclude empty set
829 */
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -0700830 for (long i = 1; i < powerElements; i++) {
831 Set<Dpid> dpidSubSet = new HashSet<Dpid>();
832 for (int j = 0; j < elements; j++) {
833 if ((i >> j) % 2 == 1) {
834 dpidSubSet.add(list.get(j));
835 }
836 }
837 /* NOTE: Avoid any pairings of edge routers only
838 * at a backbone router */
839 boolean avoidEdgeRouterPairing = true;
840 if ((!isEdgeRouter) && (dpidSubSet.size() > 1)) {
841 for (Dpid dpid : dpidSubSet) {
842 if (!isEdgeRouter(dpid)) {
843 avoidEdgeRouterPairing = false;
844 break;
845 }
846 }
847 }
848 else
849 avoidEdgeRouterPairing = false;
850
851 if (!avoidEdgeRouterPairing)
852 sets.add(dpidSubSet);
853 }
854 return sets;
855 }
856
857 private void createGroupForANeighborSet(NeighborSet ns, int groupId) {
858 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
859 for (Dpid d : ns.getDpids()) {
860 for (PortNumber sp : neighbors.get(d)) {
861 BucketInfo b = new BucketInfo(d,
862 MacAddress.of(srConfig.getRouterMac()),
863 getNeighborRouterMacAddress(d), sp,
864 ns.getEdgeLabel(), true, -1);
865 buckets.add(b);
866
867 /* Update Port Neighborset map */
868 ArrayList<NeighborSet> portNeighborSets =
869 portNeighborSetMap.get(sp);
870 if (portNeighborSets == null) {
871 portNeighborSets = new ArrayList<NeighborSet>();
872 portNeighborSets.add(ns);
873 portNeighborSetMap.put(sp, portNeighborSets);
874 }
875 else
876 portNeighborSets.add(ns);
877 }
878 }
879 EcmpInfo ecmpInfo = new EcmpInfo(groupId, OFGroupType.SELECT, buckets);
880 setEcmpGroup(ecmpInfo);
881 ecmpGroups.put(ns, ecmpInfo);
882 log.debug(
883 "createGroupForANeighborSet: Creating ecmp group {} in sw {} "
884 + "for neighbor set {} with: {}",
885 groupId, getStringId(), ns, ecmpInfo);
886 return;
887 }
888
889 /**
890 * createGroups creates ECMP groups for all ports on this router connected
891 * to other routers (in the OF network). The information for ports is
892 * gleaned from the configured links. If no links are configured no groups
893 * will be created, and it is up to the caller of the IOF13Switch API to
894 * create groups.
895 * <p>
896 * By default all ports connected to the same neighbor router will be part
897 * of the same ECMP group. In addition, groups will be created for all
898 * possible combinations of neighbor routers.
899 * <p>
900 * For example, consider this router (R0) connected to 3 neighbors (R1, R2,
901 * and R3). The following groups will be created in R0:
902 * <li>1) all ports to R1,
903 * <li>2) all ports to R2,
904 * <li>3) all ports to R3,
905 * <li>4) all ports to R1 and R2
906 * <li>5) all ports to R1 and R3
907 * <li>6) all ports to R2 and R3
908 * <li>7) all ports to R1, R2, and R3
909 */
910 private void createGroups() {
911
912 Set<Dpid> dpids = neighbors.keySet();
913 if (dpids == null || dpids.isEmpty()) {
914 return;
915 }
916 /* Create all possible Neighbor sets from this router
917 * NOTE: Avoid any pairings of edge routers only
918 */
919 Set<Set<Dpid>> powerSet = getAllNeighborSets(dpids);
920 log.debug("createGroups: The size of neighbor powerset for sw {} is {}",
921 getStringId(), powerSet.size());
922 Set<NeighborSet> nsSet = new HashSet<NeighborSet>();
923 for (Set<Dpid> combo : powerSet) {
924 if (combo.isEmpty())
925 continue;
926 if (isEdgeRouter && !segmentIds.isEmpty()) {
Srikanth Vavilapallieba65312014-10-30 15:47:20 -0700927 /* Filter out SegmentIds matching with the
928 * nodes in the combo
929 * Add one entry for "no label" (-1) to the list
930 */
931 List<Integer> groupSegmentIds = new ArrayList<Integer>();
932 groupSegmentIds.add(-1);
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -0700933 for (Integer sId : segmentIds) {
Srikanth Vavilapallieba65312014-10-30 15:47:20 -0700934 boolean filterOut = false;
935 /* Check if the edge label being set is of
936 * any node in the Neighbor set
937 */
938 for (Dpid dpid : combo) {
939 if (isSegmentIdSameAsNodeSegmentId(dpid, sId)) {
940 filterOut = true;
941 break;
942 }
943 }
944 if (!filterOut)
945 groupSegmentIds.add(sId);
946 }
947 for (Integer sId : groupSegmentIds) {
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -0700948 NeighborSet ns = new NeighborSet();
949 ns.addDpids(combo);
Srikanth Vavilapallieba65312014-10-30 15:47:20 -0700950 ns.setEdgeLabel(sId);
951 log.debug("createGroups: sw {} combo {} sId {} ns {}",
952 getStringId(), combo, sId, ns);
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -0700953 nsSet.add(ns);
954 }
955 } else {
956 NeighborSet ns = new NeighborSet();
957 ns.addDpids(combo);
Srikanth Vavilapallieba65312014-10-30 15:47:20 -0700958 log.debug("createGroups: sw {} combo {} ns {}",
959 getStringId(), combo, ns);
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -0700960 nsSet.add(ns);
961 }
962 }
963 log.debug("createGroups: The neighborset with label for sw {} is {}",
964 getStringId(), nsSet);
965
966 for (NeighborSet ns : nsSet) {
967 createGroupForANeighborSet(ns, groupid.incrementAndGet());
968 }
969 }
970
971 private class EcmpInfo {
972 int groupId;
973 OFGroupType groupType;
974 List<BucketInfo> buckets;
975
976 EcmpInfo(int gid, OFGroupType gType, List<BucketInfo> bucketInfos) {
977 groupId = gid;
978 groupType = gType;
979 buckets = bucketInfos;
980 }
981
982 @Override
983 public String toString() {
984 return "groupId: " + groupId + ", buckets: " + buckets;
985 }
986 }
987
988 private class BucketInfo {
989 Dpid neighborDpid;
990 MacAddress srcMac;
991 MacAddress dstMac;
992 PortNumber outport;
993 int groupNo;
994 int mplsLabel;
995 boolean bos;
996
997 BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac,
998 PortNumber p, int label, boolean bos, int gotoGroupNo) {
999 neighborDpid = nDpid;
1000 srcMac = smac;
1001 dstMac = dmac;
1002 outport = p;
1003 mplsLabel = label;
1004 this.bos = bos;
1005 groupNo = gotoGroupNo;
1006 }
1007
1008
1009 @Override
1010 public String toString() {
1011 return " {neighborDpid: " + neighborDpid + ", dstMac: " + dstMac +
1012 ", srcMac: " + srcMac + ", outport: " + outport +
1013 ", groupNo: " + groupNo +
1014 ", mplsLabel: " + mplsLabel + "}";
1015 }
1016 }
1017
1018 private void setEcmpGroup(EcmpInfo ecmpInfo) {
1019 List<OFMessage> msglist = new ArrayList<OFMessage>();
1020 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1021
1022 List<OFBucket> buckets = new ArrayList<OFBucket>();
1023 for (BucketInfo b : ecmpInfo.buckets) {
1024 List<OFAction> actions = new ArrayList<OFAction>();
1025 if (b.dstMac != null) {
1026 OFOxmEthDst dmac = factory.oxms()
1027 .ethDst(b.dstMac);
1028 OFAction setDA = factory.actions().buildSetField()
1029 .setField(dmac).build();
1030 actions.add(setDA);
1031 }
1032 if (b.srcMac != null) {
1033 OFOxmEthSrc smac = factory.oxms()
1034 .ethSrc(b.srcMac);
1035 OFAction setSA = factory.actions().buildSetField()
1036 .setField(smac).build();
1037 actions.add(setSA);
1038 }
1039 if (b.outport != null) {
1040 OFAction outp = factory.actions().buildOutput()
1041 .setPort(OFPort.of(b.outport.shortValue()))
1042 .build();
1043 actions.add(outp);
1044 }
1045 if (b.mplsLabel != -1) {
1046 OFAction pushLabel = factory.actions().buildPushMpls()
1047 .setEthertype(EthType.MPLS_UNICAST).build();
1048 OFBooleanValue bosValue = null;
1049 if (b.bos)
1050 bosValue = OFBooleanValue.TRUE;
1051 else
1052 bosValue = OFBooleanValue.FALSE;
1053 OFOxmMplsBos bosX = factory.oxms()
1054 .mplsBos(bosValue);
1055 OFAction setBX = factory.actions().buildSetField()
1056 .setField(bosX).build();
1057 OFOxmMplsLabel lid = factory.oxms()
1058 .mplsLabel(U32.of(b.mplsLabel));
1059 OFAction setLabel = factory.actions().buildSetField()
1060 .setField(lid).build();
1061 OFAction copyTtl = factory.actions().copyTtlOut();
1062 OFAction decrTtl = factory.actions().decMplsTtl();
1063 actions.add(pushLabel);
1064 actions.add(setLabel);
1065 actions.add(setBX);
1066 actions.add(copyTtl);
1067 // decrement TTL only when the first MPLS label is pushed
1068 if (b.bos)
1069 actions.add(decrTtl);
1070 }
1071 if (b.groupNo > 0) {
1072 OFAction groupTo = factory.actions().buildGroup()
1073 .setGroup(OFGroup.of(b.groupNo))
1074 .build();
1075 actions.add(groupTo);
1076 }
1077 OFBucket.Builder bldr = factory.buildBucket();
1078 bldr.setActions(actions);
1079 if (ecmpInfo.groupType == OFGroupType.SELECT)
1080 bldr.setWeight(1);
1081 OFBucket ofb = bldr.build();
1082 buckets.add(ofb);
1083 }
1084
1085 OFMessage gm = factory.buildGroupAdd()
1086 .setGroup(group)
1087 .setBuckets(buckets)
1088 .setGroupType(ecmpInfo.groupType)
1089 .setXid(getNextTransactionId())
1090 .build();
1091 msglist.add(gm);
Srikanth Vavilapallieba65312014-10-30 15:47:20 -07001092 log.debug("GroupAdd in sw {} groupId {}",
1093 getStringId(), ecmpInfo.groupId);
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -07001094 try {
1095 write(msglist);
1096 } catch (IOException e) {
1097 // TODO Auto-generated catch block
1098 e.printStackTrace();
1099 }
1100 }
1101
1102 private void deleteGroup(EcmpInfo groupInfo) {
1103
1104 List<OFMessage> msglist = new ArrayList<OFMessage>();
1105 OFGroup group = OFGroup.of(groupInfo.groupId);
1106
1107 OFMessage gm = factory.buildGroupDelete()
1108 .setGroup(group)
1109 // .setGroupType(groupInfo.groupType) /* Due to a bug in CPqD
1110 // switch */
1111 .setGroupType(OFGroupType.SELECT)
1112 .setXid(getNextTransactionId())
1113 .build();
1114 msglist.add(gm);
Srikanth Vavilapallieba65312014-10-30 15:47:20 -07001115 log.debug("GroupDelete in sw {} groupId {}",
1116 getStringId(), groupInfo.groupId);
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -07001117 try {
1118 write(msglist);
1119 } catch (IOException e) {
1120 // TODO Auto-generated catch block
1121 e.printStackTrace();
1122 }
1123 }
1124
1125 private void modifyEcmpGroup(EcmpInfo ecmpInfo) {
1126 List<OFMessage> msglist = new ArrayList<OFMessage>();
1127 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1128
1129 List<OFBucket> buckets = new ArrayList<OFBucket>();
1130 for (BucketInfo b : ecmpInfo.buckets) {
1131 OFOxmEthDst dmac = factory.oxms()
1132 .ethDst(b.dstMac);
1133 OFAction setDA = factory.actions().buildSetField()
1134 .setField(dmac).build();
1135 OFOxmEthSrc smac = factory.oxms()
1136 .ethSrc(b.srcMac);
1137 OFAction setSA = factory.actions().buildSetField()
1138 .setField(smac).build();
1139 OFAction outp = factory.actions().buildOutput()
1140 .setPort(OFPort.of(b.outport.shortValue()))
1141 .build();
1142 List<OFAction> actions = new ArrayList<OFAction>();
1143 actions.add(setSA);
1144 actions.add(setDA);
1145 actions.add(outp);
1146 if (b.mplsLabel != -1) {
1147 OFAction pushLabel = factory.actions().buildPushMpls()
1148 .setEthertype(EthType.MPLS_UNICAST).build();
1149 OFOxmMplsBos bosX = factory.oxms()
1150 .mplsBos(OFBooleanValue.TRUE);
1151 OFAction setBX = factory.actions().buildSetField()
1152 .setField(bosX).build();
1153 OFOxmMplsLabel lid = factory.oxms()
1154 .mplsLabel(U32.of(b.mplsLabel));
1155 OFAction setLabel = factory.actions().buildSetField()
1156 .setField(lid).build();
1157 OFAction copyTtl = factory.actions().copyTtlOut();
1158 OFAction decrTtl = factory.actions().decMplsTtl();
1159 actions.add(pushLabel);
1160 actions.add(setLabel);
1161 actions.add(setBX);
1162 actions.add(copyTtl);
1163 actions.add(decrTtl);
1164 }
1165 OFBucket ofb = factory.buildBucket()
1166 .setWeight(1)
1167 .setActions(actions)
1168 .build();
1169 buckets.add(ofb);
1170 }
1171
1172 OFMessage gm = factory.buildGroupModify()
1173 .setGroup(group)
1174 .setBuckets(buckets)
1175 .setGroupType(OFGroupType.SELECT)
1176 .setXid(getNextTransactionId())
1177 .build();
1178 msglist.add(gm);
Srikanth Vavilapallieba65312014-10-30 15:47:20 -07001179 log.debug("GroupMod in sw {} groupId {}",
1180 getStringId(), ecmpInfo.groupId);
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -07001181 try {
1182 write(msglist);
1183 } catch (IOException e) {
1184 // TODO Auto-generated catch block
1185 e.printStackTrace();
1186 }
1187 }
1188
1189 private void verifyGroups() throws IOException {
1190 sendGroupDescRequest();
1191 }
1192
1193 private void sendGroupDescRequest() throws IOException {
1194 OFMessage gdr = factory.buildGroupDescStatsRequest()
1195 .setXid(getNextTransactionId())
1196 .build();
1197 write(gdr, null);
1198 }
1199
1200 private void assignAdjacencyLabels() {
1201 List<AdjacencySid> autogenAdjSids = new ArrayList<AdjacencySid>();
1202 publishAttributes = new HashMap<String, String>();
1203 for (OFPortDesc p : getPorts()) {
1204 int pnum = p.getPortNo().getPortNumber();
1205
1206 if (U32.ofRaw(pnum).compareTo(U32.ofRaw(OFPort.MAX.getPortNumber())) >= 1) {
1207 continue;
1208 }
1209 // create unique adj-sid assuming that operator only
1210 // enters adjSids for multiple-ports and only in the range
1211 // 1-10k XXX make sure that happens
1212 int adjSid = srConfig.getNodeSid() * 1000 + pnum;
1213 AdjacencySid as = new AdjacencySid(adjSid,
1214 Collections.singletonList(pnum));
1215 autogenAdjSids.add(as);
1216 }
1217 ObjectMapper mapper = new ObjectMapper();
1218 try {
1219 publishAttributes.put("autogenAdjSids",
1220 mapper.writeValueAsString(autogenAdjSids));
1221 } catch (IOException e1) {
1222 log.error("Error while writing adjacency labels: {}", e1.getCause());
1223 }
1224
1225 try {
1226 nextDriverState();
1227 } catch (IOException e) {
1228 // TODO Auto-generated catch block
1229 e.printStackTrace();
1230 }
1231 }
1232
1233 private OFAction getOFAction(Action action) {
1234 OFAction ofAction = null;
1235 if (action instanceof OutputAction) {
1236 OutputAction outputAction = (OutputAction) action;
1237 OFPort port = OFPort.of((int) outputAction.getPortNumber().value());
1238 ofAction = factory.actions().output(port, Short.MAX_VALUE);
1239 } else if (action instanceof ModifyDstMacAction) {
1240 long dstMac = ((ModifyDstMacAction) action).getDstMac().toLong();
1241 OFOxmEthDst dmac = factory.oxms()
1242 .ethDst(MacAddress.of(dstMac));
1243 ofAction = factory.actions().buildSetField()
1244 .setField(dmac).build();
1245 } else if (action instanceof ModifySrcMacAction) {
1246 long srcMac = ((ModifySrcMacAction) action).getSrcMac().toLong();
1247 OFOxmEthSrc smac = factory.oxms()
1248 .ethSrc(MacAddress.of(srcMac));
1249 ofAction = factory.actions().buildSetField()
1250 .setField(smac).build();
1251 } else if (action instanceof PushMplsAction) {
1252 ofAction = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1253 } else if (action instanceof SetMplsIdAction) {
1254 int labelid = ((SetMplsIdAction) action).getMplsId();
1255 OFOxmMplsLabel lid = factory.oxms()
1256 .mplsLabel(U32.of(labelid));
1257 ofAction = factory.actions().buildSetField()
1258 .setField(lid).build();
1259 } else if (action instanceof SetMplsBosAction) {
1260 OFBooleanValue val = OFBooleanValue.of(
1261 ((SetMplsBosAction) action).isSet());
1262 OFOxmMplsBos bos = factory.oxms().mplsBos(val);
1263 OFAction setBos = factory.actions().buildSetField()
1264 .setField(bos).build();
1265 } else if (action instanceof PopMplsAction) {
1266 EthType ethertype = ((PopMplsAction) action).getEthType();
1267 ofAction = factory.actions().popMpls(ethertype);
1268 } else if (action instanceof GroupAction) {
1269 int gid = -1;
1270 GroupAction ga = (GroupAction)action;
1271 if (ga.getGroupId() > 0) {
1272 gid = ga.getGroupId();
1273 }
1274 else {
1275 NeighborSet ns = ((GroupAction) action).getDpids();
1276 EcmpInfo ei = ecmpGroups.get(ns);
1277 if (ei == null) {
1278 log.debug("Unable to find ecmp group for neighbors {} at "
1279 + "switch {} and hence creating it", ns, getStringId());
1280 createGroupForANeighborSet(ns, groupid.incrementAndGet());
1281 ei = ecmpGroups.get(ns);
1282 }
1283 gid = ei.groupId;
1284 }
1285 ofAction = factory.actions().buildGroup()
1286 .setGroup(OFGroup.of(gid))
1287 .build();
1288 } else if (action instanceof DecNwTtlAction) {
1289 ofAction = factory.actions().decNwTtl();
1290 } else if (action instanceof DecMplsTtlAction) {
1291 ofAction = factory.actions().decMplsTtl();
1292 } else if (action instanceof CopyTtlInAction) {
1293 ofAction = factory.actions().copyTtlIn();
1294 } else if (action instanceof CopyTtlOutAction) {
1295 ofAction = factory.actions().copyTtlOut();
1296 } else if (action instanceof SetDAAction) {
1297 OFOxmEthDst dmac = factory.oxms()
1298 .ethDst(((SetDAAction)action).getAddress());
1299 ofAction = factory.actions().buildSetField()
1300 .setField(dmac).build();
1301 } else if (action instanceof SetSAAction) {
1302 OFOxmEthSrc smac = factory.oxms()
1303 .ethSrc(((SetSAAction)action).getAddress());
1304 ofAction = factory.actions().buildSetField()
1305 .setField(smac).build();
1306 } else {
1307 log.warn("Unsupported Action type: {}", action.getClass().getName());
1308 return null;
1309 }
1310
1311 return ofAction;
1312 }
1313
1314 private OFMessage getIpEntry(MatchActionOperationEntry mao) {
1315 MatchAction ma = mao.getTarget();
1316 Operator op = mao.getOperator();
1317 Ipv4Match ipm = (Ipv4Match) ma.getMatch();
1318
1319 // set match
1320 IPv4Net ipdst = ipm.getDestination();
1321 OFOxmEthType ethTypeIp = factory.oxms()
1322 .ethType(EthType.IPv4);
1323 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
1324 .ipv4DstMasked(
1325 IPv4Address.of(ipdst.address().value()),
1326 IPv4Address.ofCidrMaskLength(ipdst.prefixLen())
1327 );
1328 OFOxmList oxmList = OFOxmList.of(ethTypeIp, ipPrefix);
1329 OFMatchV3 match = factory.buildMatchV3()
1330 .setOxmList(oxmList).build();
1331
1332 // set actions
1333 List<OFAction> writeActions = new ArrayList<OFAction>();
1334 for (Action action : ma.getActions()) {
1335 OFAction ofAction = getOFAction(action);
1336 if (ofAction != null) {
1337 writeActions.add(ofAction);
1338 }
1339 }
1340
1341 // set instructions
1342 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1343 .setActions(writeActions).build();
1344 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1345 .setTableId(TableId.of(TABLE_ACL)).build();
1346 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1347 instructions.add(writeInstr);
1348 instructions.add(gotoInstr);
1349
1350 // set flow priority to emulate longest prefix match
1351 int priority = ipdst.prefixLen() * PRIORITY_MULTIPLIER;
1352 if (ipdst.prefixLen() == (short) 32) {
1353 priority = MAX_PRIORITY;
1354 }
1355
1356 // set flow-mod
1357 OFFlowMod.Builder fmBuilder = null;
1358 switch (op) {
1359 case ADD:
1360 fmBuilder = factory.buildFlowAdd();
1361 break;
1362 case REMOVE:
1363 fmBuilder = factory.buildFlowDeleteStrict();
1364 break;
1365 case MODIFY: // TODO
1366 fmBuilder = factory.buildFlowModifyStrict();
1367 break;
1368 default:
1369 log.warn("Unsupported MatchAction Operator: {}", op);
1370 return null;
1371 }
1372 OFMessage ipFlow = fmBuilder
1373 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
1374 .setMatch(match)
1375 .setInstructions(instructions)
1376 .setPriority(priority)
1377 .setBufferId(OFBufferId.NO_BUFFER)
1378 .setIdleTimeout(0)
1379 .setHardTimeout(0)
1380 .setXid(getNextTransactionId())
1381 .build();
1382 log.debug("{} ip-rule {}-{} in sw {}",
1383 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1384 match, writeActions,
1385 getStringId());
1386 return ipFlow;
1387 }
1388
1389 private OFMessage getMplsEntry(MatchActionOperationEntry mao) {
1390 MatchAction ma = mao.getTarget();
1391 Operator op = mao.getOperator();
1392 MplsMatch mplsm = (MplsMatch) ma.getMatch();
1393
1394 // set match
1395 OFOxmEthType ethTypeMpls = factory.oxms()
1396 .ethType(EthType.MPLS_UNICAST);
1397 OFOxmMplsLabel labelid = factory.oxms()
1398 .mplsLabel(U32.of(mplsm.getMplsLabel()));
1399 OFOxmMplsBos bos = factory.oxms()
1400 .mplsBos(OFBooleanValue.of(mplsm.isBos()));
1401 OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid, bos);
1402 OFMatchV3 matchlabel = factory.buildMatchV3()
1403 .setOxmList(oxmList).build();
1404
1405 // set actions
1406 List<OFAction> writeActions = new ArrayList<OFAction>();
1407 for (Action action : ma.getActions()) {
1408 OFAction ofAction = getOFAction(action);
1409 if (ofAction != null) {
1410 writeActions.add(ofAction);
1411 }
1412 }
1413
1414 // set instructions
1415 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1416 .setActions(writeActions).build();
1417 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1418 .setTableId(TableId.of(TABLE_ACL)).build();
1419 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1420 instructions.add(writeInstr);
1421 instructions.add(gotoInstr);
1422
1423 // set flow-mod
1424 OFFlowMod.Builder fmBuilder = null;
1425 switch (op) {
1426 case ADD:
1427 fmBuilder = factory.buildFlowAdd();
1428 break;
1429 case REMOVE:
1430 fmBuilder = factory.buildFlowDeleteStrict();
1431 break;
1432 case MODIFY: // TODO
1433 fmBuilder = factory.buildFlowModifyStrict();
1434 break;
1435 default:
1436 log.warn("Unsupported MatchAction Operator: {}", op);
1437 return null;
1438 }
1439
1440 OFMessage mplsFlow = fmBuilder
1441 .setTableId(TableId.of(TABLE_MPLS))
1442 .setMatch(matchlabel)
1443 .setInstructions(instructions)
1444 .setPriority(MAX_PRIORITY) // exact match and exclusive
1445 .setBufferId(OFBufferId.NO_BUFFER)
1446 .setIdleTimeout(0)
1447 .setHardTimeout(0)
1448 .setXid(getNextTransactionId())
1449 .build();
1450 log.debug("{} mpls-rule {}-{} in sw {}",
1451 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1452 matchlabel, writeActions,
1453 getStringId());
1454 return mplsFlow;
1455 }
1456
1457 private OFMessage getAclEntry(MatchActionOperationEntry mao) {
1458 MatchAction ma = mao.getTarget();
1459 Operator op = mao.getOperator();
1460 PacketMatch packetMatch = (PacketMatch) ma.getMatch();
1461 Builder matchBuilder = factory.buildMatch();
1462
1463 // set match
1464 int inport = 0;
1465 if (ma.getSwitchPort() != null) {
1466 inport = (int) ma.getSwitchPort().getPortNumber().value();
1467 }
1468 final MACAddress srcMac = packetMatch.getSrcMacAddress();
1469 final MACAddress dstMac = packetMatch.getDstMacAddress();
1470 final Short etherType = packetMatch.getEtherType();
1471 final IPv4Net srcIp = packetMatch.getSrcIpAddress();
1472 final IPv4Net dstIp = packetMatch.getDstIpAddress();
1473 final Byte ipProto = packetMatch.getIpProtocolNumber();
1474 final Short srcTcpPort = packetMatch.getSrcTcpPortNumber();
1475 final Short dstTcpPort = packetMatch.getDstTcpPortNumber();
1476 if (inport > 0) {
1477 matchBuilder.setExact(MatchField.IN_PORT,
1478 OFPort.of(inport));
1479 }
1480 if (srcMac != null) {
1481 matchBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(srcMac.toLong()));
1482 }
1483 if (dstMac != null) {
1484 matchBuilder.setExact(MatchField.ETH_DST, MacAddress.of(dstMac.toLong()));
1485 }
1486 if (etherType != null) {
1487 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(etherType));
1488 }
1489 if (srcIp != null) {
1490 matchBuilder.setMasked(MatchField.IPV4_SRC,
1491 IPv4Address.of(srcIp.address().value())
1492 .withMaskOfLength(srcIp.prefixLen()));
1493 }
1494 if (dstIp != null) {
1495 matchBuilder.setMasked(MatchField.IPV4_DST,
1496 IPv4Address.of(dstIp.address().value())
1497 .withMaskOfLength(dstIp.prefixLen()));
1498 }
1499 if (ipProto != null) {
1500 matchBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(ipProto));
1501 }
1502 if (srcTcpPort != null) {
1503 matchBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(srcTcpPort));
1504 }
1505 if (dstTcpPort != null) {
1506 matchBuilder.setExact(MatchField.TCP_DST, TransportPort.of(dstTcpPort));
1507 }
1508
1509 // set actions
1510 List<OFAction> writeActions = new ArrayList<OFAction>();
1511 for (Action action : ma.getActions()) {
1512 OFAction ofAction = getOFAction(action);
1513 if (ofAction != null) {
1514 writeActions.add(ofAction);
1515 }
1516 }
1517
1518 // set instructions
1519 OFInstruction clearInstr = factory.instructions().clearActions();
1520 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1521 .setActions(writeActions).build();
1522 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1523 instructions.add(clearInstr);
1524 instructions.add(writeInstr);
1525
1526 // set flow-mod
1527 OFFlowMod.Builder fmBuilder = null;
1528 switch (op) {
1529 case ADD:
1530 fmBuilder = factory.buildFlowAdd();
1531 break;
1532 case REMOVE:
1533 fmBuilder = factory.buildFlowDeleteStrict();
1534 break;
1535 case MODIFY: // TODO
1536 fmBuilder = factory.buildFlowModifyStrict();
1537 break;
1538 default:
1539 log.warn("Unsupported MatchAction Operator: {}", op);
1540 return null;
1541 }
1542
1543 OFMessage aclFlow = fmBuilder
1544 .setTableId(TableId.of(TABLE_ACL))
1545 .setMatch(matchBuilder.build())
1546 .setInstructions(instructions)
1547 .setPriority(ma.getPriority()) // exact match and exclusive
1548 .setBufferId(OFBufferId.NO_BUFFER)
1549 .setIdleTimeout(0)
1550 .setHardTimeout(0)
1551 .setXid(getNextTransactionId())
1552 .build();
1553
1554 return aclFlow;
1555 }
1556
1557 // *****************************
1558 // IOF13Switch
1559 // *****************************
1560
1561 @Override
1562 public void pushFlow(MatchActionOperationEntry matchActionOp) throws IOException {
1563 OFMessage ofm = getFlow(matchActionOp);
1564 if (ofm != null) {
1565 write(Collections.singletonList(ofm));
1566 }
1567 }
1568
1569 private OFMessage getFlow(MatchActionOperationEntry matchActionOp) {
1570 final MatchAction matchAction = matchActionOp.getTarget();
1571 final Match match = matchAction.getMatch();
1572 if (match instanceof Ipv4Match) {
1573 return getIpEntry(matchActionOp);
1574 } else if (match instanceof MplsMatch) {
1575 return getMplsEntry(matchActionOp);
1576 } else if (match instanceof PacketMatch) {
1577 return getAclEntry(matchActionOp);
1578 } else {
1579 log.error("Unknown match type {} pushed to switch {}", match,
1580 getStringId());
1581 }
1582 return null;
1583 }
1584
1585 @Override
1586 public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps)
1587 throws IOException {
1588 List<OFMessage> flowMods = new ArrayList<OFMessage>();
1589 for (MatchActionOperationEntry matchActionOp : matchActionOps) {
1590 OFMessage ofm = getFlow(matchActionOp);
1591 if (ofm != null) {
1592 flowMods.add(ofm);
1593 }
1594 }
1595 write(flowMods);
1596 }
1597
1598 @Override
1599 public int getEcmpGroupId(NeighborSet ns) {
1600 EcmpInfo ei = ecmpGroups.get(ns);
1601 if (ei == null) {
1602 return -1;
1603 } else {
1604 return ei.groupId;
1605 }
1606 }
1607
1608 @Override
1609 public TableId getTableId(String tableType) {
1610 tableType = tableType.toLowerCase();
1611 if (tableType.contentEquals("ip")) {
1612 return TableId.of(OFSwitchImplSpringOpenTTP.TABLE_IPv4_UNICAST);
1613 }
1614 else if (tableType.contentEquals("mpls")) {
1615 return TableId.of(OFSwitchImplSpringOpenTTP.TABLE_MPLS);
1616 }
1617 else if (tableType.contentEquals("acl")) {
1618 return TableId.of(OFSwitchImplSpringOpenTTP.TABLE_ACL);
1619 }
1620 else {
1621 log.warn("Invalid tableType: {}", tableType);
1622 return null;
1623 }
1624 }
1625
1626 private EcmpInfo createIndirectGroup(int groupId, MacAddress srcMac,
1627 MacAddress dstMac, PortNumber outPort, int gotoGroupNo,
1628 int mplsLabel, boolean bos) {
1629 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
1630 BucketInfo b = new BucketInfo(null, srcMac, dstMac, outPort,
1631 mplsLabel, bos, gotoGroupNo);
1632 buckets.add(b);
1633
1634 EcmpInfo ecmpInfo = new EcmpInfo(groupId, OFGroupType.INDIRECT, buckets);
1635 setEcmpGroup(ecmpInfo);
1636 log.debug(
1637 "createIndirectGroup: Creating indirect group {} in sw {} "
1638 + "with: {}", groupId, getStringId(), ecmpInfo);
1639 return ecmpInfo;
1640 }
1641
1642 private EcmpInfo createInnermostLabelGroup(int innermostGroupId,
1643 List<PortNumber> ports, int mplsLabel, boolean bos,
1644 HashMap<PortNumber, Integer> lastSetOfGroupIds) {
1645 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
1646 for (PortNumber sp : ports) {
1647 Dpid neighborDpid = portToNeighbors.get(sp);
1648 BucketInfo b = new BucketInfo(neighborDpid,
1649 MacAddress.of(srConfig.getRouterMac()),
1650 getNeighborRouterMacAddress(neighborDpid), null,
1651 mplsLabel, bos,
1652 lastSetOfGroupIds.get(sp));
1653 buckets.add(b);
1654 }
1655 EcmpInfo ecmpInfo = new EcmpInfo(innermostGroupId,
1656 OFGroupType.SELECT, buckets);
1657 setEcmpGroup(ecmpInfo);
1658 log.debug(
1659 "createInnermostLabelGroup: Creating select group {} in sw {} "
1660 + "with: {}", innermostGroupId, getStringId(), ecmpInfo);
1661 return ecmpInfo;
1662 }
1663 @Override
1664 /**
1665 * Create a group chain with the specified label stack for a given set of
1666 * ports. This API can be used by user to create groups for a tunnel based
1667 * policy routing scenario. NOTE: This API can not be used if a group to be
1668 * created with different label stacks for each port in the given set of
1669 * ports. Use XXX API for this purpose
1670 *
1671 * @param labelStack list of router segment Ids to be pushed. Can be empty.
1672 * labelStack is processed from left to right with leftmost
1673 * representing the outermost label and rightmost representing
1674 * innermost label to be pushed
1675 * @param ports List of ports on this switch to get to the first router in
1676 * the labelStack
1677 * @return group identifier
1678 */
1679 public int createGroup(List<Integer> labelStack, List<PortNumber> ports) {
1680
1681 if ((ports == null) ||
1682 ((labelStack != null) && (labelStack.size() > 3))) {
1683 log.warn("createGroup in sw {} with wrong input parameters", getStringId());
1684 }
1685 log.debug("createGroup in sw {} with labelStack {} and ports {}",
1686 getStringId(), labelStack, ports);
1687
1688 HashMap<PortNumber, Integer> lastSetOfGroupIds =
1689 new HashMap<PortNumber, Integer>();
1690 int innermostGroupId = -1;
1691 /* If it is empty label stack or label stack with only one label,
1692 * Create a single select group with buckets for each port in the list
1693 * of specified ports and specified label if any and return the
1694 * created group id
1695 */
1696 if (labelStack.size() < 2) {
1697 int curLabel = -1;
1698 boolean bos = false;
1699 if (labelStack.size()==1) {
1700 curLabel = labelStack.get(0).intValue();
1701 bos = true;
1702 }
1703
1704 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
1705 for (PortNumber sp : ports) {
1706 Dpid neighborDpid = portToNeighbors.get(sp);
1707 BucketInfo b = new BucketInfo(neighborDpid,
1708 MacAddress.of(srConfig.getRouterMac()),
1709 getNeighborRouterMacAddress(neighborDpid),
1710 sp, curLabel, bos, -1);
1711 buckets.add(b);
1712 }
1713 innermostGroupId = groupid.incrementAndGet();
1714 EcmpInfo ecmpInfo = new EcmpInfo(innermostGroupId,
1715 OFGroupType.SELECT, buckets);
1716 setEcmpGroup(ecmpInfo);
1717 userDefinedGroups.put(innermostGroupId, ecmpInfo);
1718 return innermostGroupId;
1719 }
1720
1721 /* If the label stack has two or more labels, then a chain of groups
1722 * to be created.
1723 * Step1: Create for each port in the list of specified ports,
1724 * an indirect group with the outermost label. These groups are the
1725 * end of the chain and hence don't reference to any other groups
1726 * Step2: Create for each port in the list of specified ports, an
1727 * indirect group with middle labels (if any). These groups will
1728 * have references to group ids that are created in the previous
1729 * iteration for the same ports
1730 * Step3: Create a select group with all ports and innermost label.
1731 * This group will have references to indirect group ids that are
1732 * created in the previous iteration for the same ports
1733 */
1734 for (int i = 0; i < labelStack.size(); i++) {
1735 for (PortNumber sp : ports) {
1736 if (i == 0) {
1737 /* Outermost label processing */
1738 int currGroupId = groupid.incrementAndGet();
1739 EcmpInfo indirectGroup = createIndirectGroup(currGroupId,
1740 null, null, sp, -1,
1741 labelStack.get(i).intValue(), false);
1742 lastSetOfGroupIds.put(sp, currGroupId);
1743 userDefinedGroups.put(currGroupId, indirectGroup);
1744 }
1745 else if (i == (labelStack.size() - 1)) {
1746 /* Innermost label processing */
1747 innermostGroupId = groupid.incrementAndGet();
1748 EcmpInfo topLevelGroup = createInnermostLabelGroup(
1749 innermostGroupId,
1750 ports,
1751 labelStack.get(i).intValue(), true,
1752 lastSetOfGroupIds);
1753 userDefinedGroups.put(
1754 innermostGroupId, topLevelGroup);
1755 break;
1756 }
1757 else {
1758 /* Middle label processing */
1759 int currGroupId = groupid.incrementAndGet();
1760 EcmpInfo indirectGroup = createIndirectGroup(currGroupId,
1761 null, null, null,
1762 lastSetOfGroupIds.get(sp),
1763 labelStack.get(i).intValue(), false);
1764 /* Overwrite with this iteration's group IDs */
1765 lastSetOfGroupIds.put(sp, currGroupId);
1766 userDefinedGroups.put(currGroupId, indirectGroup);
1767 }
1768 }
1769 }
1770 log.debug("createGroup in sw{}: group created with innermost group id {}",
1771 getStringId(), innermostGroupId);
1772 return innermostGroupId;
1773 }
1774
1775 /**
1776 * Remove the specified group
1777 *
1778 * @param groupId group identifier
1779 * @return success/fail
1780 */
1781 public boolean removeGroup(int groupId) {
1782 EcmpInfo group = userDefinedGroups.get(groupId);
1783 if (group == null) {
1784 log.warn("removeGroup in sw {}: with invalid group id", getStringId());
1785 return false;
1786 }
1787 deleteGroup(group);
1788 for (BucketInfo bucket : group.buckets) {
1789 int currGroupIdToBeDeleted = bucket.groupNo;
1790 while (currGroupIdToBeDeleted != -1) {
1791 /* Assuming indirect groups with single buckets */
1792 int nextGroupIdToBeDeleted =
1793 userDefinedGroups.get(currGroupIdToBeDeleted).
1794 buckets.get(0).groupNo;
1795 EcmpInfo groupToBeDeleted =
1796 userDefinedGroups.get(currGroupIdToBeDeleted);
1797 deleteGroup(groupToBeDeleted);
1798 userDefinedGroups.remove(currGroupIdToBeDeleted);
1799 currGroupIdToBeDeleted = nextGroupIdToBeDeleted;
1800 }
1801 }
1802
1803 userDefinedGroups.remove(groupId);
1804 log.debug("removeGroup in sw {}: removed group with group id {}",
1805 getStringId(), groupId);
1806 return true;
1807 }
1808
1809 @Override
1810 public Map<String, String> getPublishAttributes() {
1811 return publishAttributes;
1812 }
1813
1814 // *****************************
1815 // Unused
1816 // *****************************
1817
1818 @SuppressWarnings("unused")
1819 private void setAsyncConfig() throws IOException {
1820 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
1821 OFMessage setAC = null;
1822
1823 if (role == Role.MASTER) {
1824 setAC = factory.buildAsyncSet()
1825 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
1826 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
1827 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
1828 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1829 .setPacketInMaskSlave(SET_ALL_SLAVE)
1830 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1831 .setXid(getNextTransactionId())
1832 .build();
1833 } else if (role == Role.EQUAL) {
1834 setAC = factory.buildAsyncSet()
1835 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
1836 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
1837 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
1838 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1839 .setPacketInMaskSlave(SET_ALL_SLAVE)
1840 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1841 .setXid(getNextTransactionId())
1842 .build();
1843 }
1844 msglist.add(setAC);
1845
1846 OFMessage br = factory.buildBarrierRequest()
1847 .setXid(getNextTransactionId())
1848 .build();
1849 msglist.add(br);
1850
1851 OFMessage getAC = factory.buildAsyncGetRequest()
1852 .setXid(getNextTransactionId())
1853 .build();
1854 msglist.add(getAC);
1855
1856 write(msglist);
1857 }
1858
1859 @SuppressWarnings("unused")
1860 private void decodeAsyncGetReply(OFAsyncGetReply rep) {
1861 long frm = rep.getFlowRemovedMaskEqualMaster();
1862 long frs = rep.getFlowRemovedMaskSlave();
1863 long pim = rep.getPacketInMaskEqualMaster();
1864 long pis = rep.getPacketInMaskSlave();
1865 long psm = rep.getPortStatusMaskEqualMaster();
1866 long pss = rep.getPortStatusMaskSlave();
1867
1868 if (role == Role.MASTER || role == Role.EQUAL) { // should separate
1869 log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
1870 log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
1871 log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
1872 }
1873
1874 }
1875
1876 @SuppressWarnings("unused")
1877 private void getTableFeatures() throws IOException {
1878 OFMessage gtf = factory.buildTableFeaturesStatsRequest()
1879 .setXid(getNextTransactionId())
1880 .build();
1881 write(gtf, null);
1882 }
1883
1884 @SuppressWarnings("unused")
1885 private void sendGroupFeaturesRequest() throws IOException {
1886 OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
1887 .setXid(getNextTransactionId())
1888 .build();
1889 write(gfr, null);
1890 }
1891
1892 private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
1893 log.info("Sw: {} Group Features {}", getStringId(), gfsr);
1894 }
1895
1896 @SuppressWarnings("unused")
1897 private void testMultipleLabels() {
1898 if (getId() == 1) {
1899 List<OFMessage> msglist = new ArrayList<OFMessage>();
1900
1901 // first all the indirect groups
1902
1903 // the group to switch 2 with outer label
1904 OFGroup g1 = OFGroup.of(201);
1905 OFOxmEthDst dmac1 = factory.oxms().ethDst(MacAddress.of("00:00:02:02:02:80"));
1906 OFAction push1 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1907 OFOxmMplsLabel lid1 = factory.oxms()
1908 .mplsLabel(U32.of(105)); // outer label
1909 OFAction setMpls1 = factory.actions().buildSetField()
1910 .setField(lid1).build();
1911 OFOxmMplsBos bos1 = factory.oxms()
1912 .mplsBos(OFBooleanValue.FALSE);
1913 OFAction setB1 = factory.actions().buildSetField()
1914 .setField(bos1).build();
1915 OFAction setDA1 = factory.actions().buildSetField()
1916 .setField(dmac1).build();
1917 OFAction outp1 = factory.actions().buildOutput()
1918 .setPort(OFPort.of(2))
1919 .build();
1920 List<OFAction> a1 = new ArrayList<OFAction>();
1921 a1.add(push1);
1922 a1.add(setMpls1);
1923 a1.add(setB1);
1924 a1.add(setDA1);
1925 a1.add(outp1);
1926 OFBucket b1 = factory.buildBucket()
1927 .setActions(a1)
1928 .build();
1929 OFMessage gm1 = factory.buildGroupAdd()
1930 .setGroup(g1)
1931 .setBuckets(Collections.singletonList(b1))
1932 .setGroupType(OFGroupType.INDIRECT)
1933 .setXid(getNextTransactionId())
1934 .build();
1935 msglist.add(gm1);
1936
1937 // the group to switch 3 with outer label
1938 OFGroup g2 = OFGroup.of(301);
1939 OFOxmEthDst dmac2 = factory.oxms().ethDst(MacAddress.of("00:00:03:03:03:80"));
1940 OFAction push2 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1941 OFOxmMplsLabel lid2 = factory.oxms()
1942 .mplsLabel(U32.of(104)); // outer label
1943 OFAction setMpls2 = factory.actions().buildSetField()
1944 .setField(lid2).build();
1945 OFOxmMplsBos bos2 = factory.oxms()
1946 .mplsBos(OFBooleanValue.FALSE);
1947 OFAction setB2 = factory.actions().buildSetField()
1948 .setField(bos2).build();
1949 OFAction setDA2 = factory.actions().buildSetField()
1950 .setField(dmac2).build();
1951 OFAction outp2 = factory.actions().buildOutput()
1952 .setPort(OFPort.of(3))
1953 .build();
1954 List<OFAction> a2 = new ArrayList<OFAction>();
1955 a2.add(push2);
1956 a2.add(setMpls2);
1957 a2.add(setB2);
1958 a2.add(setDA2);
1959 a2.add(outp2);
1960 OFBucket b2 = factory.buildBucket()
1961 .setActions(a2)
1962 .build();
1963 OFMessage gm2 = factory.buildGroupAdd()
1964 .setGroup(g2)
1965 .setBuckets(Collections.singletonList(b2))
1966 .setGroupType(OFGroupType.INDIRECT)
1967 .setXid(getNextTransactionId())
1968 .build();
1969 msglist.add(gm2);
1970
1971 // now add main ECMP group with inner labels
1972 OFGroup group = OFGroup.of(786);
1973 List<OFBucket> buckets = new ArrayList<OFBucket>();
1974 for (int i = 0; i < 2; i++) { // 2 buckets
1975
1976 List<OFAction> actions = new ArrayList<OFAction>();
1977 OFOxmEthSrc smac = factory.oxms()
1978 .ethSrc(MacAddress.of("00:00:01:01:01:80"));
1979 OFAction setSA = factory.actions().buildSetField()
1980 .setField(smac).build();
1981 actions.add(setSA);
1982
1983 if (i == 0) {
1984 // send to switch 2
1985 OFAction pushX = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1986 OFOxmMplsLabel lidX = factory.oxms()
1987 .mplsLabel(U32.of(106)); // inner label
1988 OFAction setX = factory.actions().buildSetField()
1989 .setField(lidX).build();
1990 OFOxmMplsBos bosX = factory.oxms()
1991 .mplsBos(OFBooleanValue.TRUE);
1992 OFAction setBX = factory.actions().buildSetField()
1993 .setField(bosX).build();
1994 OFAction ogX = factory.actions().buildGroup()
1995 .setGroup(g1).build();
1996 actions.add(pushX);
1997 actions.add(setX);
1998 actions.add(setBX);
1999 actions.add(ogX);
2000
2001 } else {
2002 // send to switch 3
2003 OFAction pushY = factory.actions().pushMpls(EthType.MPLS_UNICAST);
2004 OFOxmMplsLabel lidY = factory.oxms()
2005 .mplsLabel(U32.of(106)); // inner label
2006 OFAction setY = factory.actions().buildSetField()
2007 .setField(lidY).build();
2008 OFOxmMplsBos bosY = factory.oxms()
2009 .mplsBos(OFBooleanValue.TRUE);
2010 OFAction setBY = factory.actions().buildSetField()
2011 .setField(bosY).build();
2012 OFAction ogY = factory.actions().buildGroup()
2013 .setGroup(g2).build();
2014 actions.add(pushY);
2015 actions.add(setY);
2016 actions.add(setBY);
2017 actions.add(ogY);
2018 }
2019
2020 OFBucket ofb = factory.buildBucket()
2021 .setWeight(1)
2022 .setActions(actions)
2023 .build();
2024 buckets.add(ofb);
2025 }
2026
2027 OFMessage gm = factory.buildGroupAdd()
2028 .setGroup(group)
2029 .setBuckets(buckets)
2030 .setGroupType(OFGroupType.SELECT)
2031 .setXid(getNextTransactionId())
2032 .build();
2033 msglist.add(gm);
2034
2035 // create an ACL entry to use this ecmp group
2036 Builder matchBuilder = factory.buildMatch();
2037 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(0x800));
2038 matchBuilder.setMasked(MatchField.IPV4_DST,
2039 IPv4Address.of("7.7.7.0")
2040 .withMaskOfLength(24));
2041
2042 OFAction grp = factory.actions().buildGroup()
2043 .setGroup(OFGroup.of(786))
2044 .build();
2045 List<OFAction> writeActions = Collections.singletonList(grp);
2046
2047 OFInstruction clearInstr = factory.instructions().clearActions();
2048 OFInstruction writeInstr = factory.instructions().buildWriteActions()
2049 .setActions(writeActions).build();
2050 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
2051 instructions.add(clearInstr);
2052 instructions.add(writeInstr);
2053
2054 OFFlowMod.Builder fmBuilder = factory.buildFlowAdd();
2055
2056 OFMessage aclFlow = fmBuilder
2057 .setTableId(TableId.of(TABLE_ACL))
2058 .setMatch(matchBuilder.build())
2059 .setInstructions(instructions)
2060 .setPriority(10) // TODO: wrong - should be MA
2061 // priority
2062 .setBufferId(OFBufferId.NO_BUFFER)
2063 .setIdleTimeout(0)
2064 .setHardTimeout(0)
2065 .setXid(getNextTransactionId())
2066 .build();
2067 msglist.add(aclFlow);
2068
2069 try {
2070 write(msglist);
2071 } catch (IOException e) {
2072 // TODO Auto-generated catch block
2073 e.printStackTrace();
2074 }
2075 }
2076 }
2077
2078
2079
2080}