blob: f21e2934727a5f6e03f6eba6e2296f0d86866039 [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;
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -07008import java.util.Iterator;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07009import java.util.List;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070010import java.util.Set;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070011import java.util.concurrent.ConcurrentHashMap;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070012import java.util.concurrent.ConcurrentMap;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070013import java.util.concurrent.atomic.AtomicBoolean;
14
15import net.floodlightcontroller.core.IFloodlightProviderService.Role;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070016import net.floodlightcontroller.core.IOF13Switch;
17import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070018import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
19import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
20import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
21import net.floodlightcontroller.core.internal.OFSwitchImplBase;
Saurav Dase972b3a2014-09-26 15:41:06 -070022import net.floodlightcontroller.util.MACAddress;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070023import net.onrc.onos.core.configmanager.INetworkConfigService;
24import net.onrc.onos.core.configmanager.INetworkConfigService.NetworkConfigState;
25import net.onrc.onos.core.configmanager.INetworkConfigService.SwitchConfigStatus;
26import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
27import net.onrc.onos.core.configmanager.NetworkConfigManager;
28import net.onrc.onos.core.configmanager.PktLinkConfig;
29import net.onrc.onos.core.configmanager.SegmentRouterConfig;
30import net.onrc.onos.core.matchaction.MatchAction;
31import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Saurav Dasbc594a42014-09-25 20:13:50 -070032import net.onrc.onos.core.matchaction.MatchActionOperations;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070033import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
34import net.onrc.onos.core.matchaction.action.Action;
35import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
36import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
37import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
38import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
39import net.onrc.onos.core.matchaction.action.GroupAction;
40import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
41import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
42import net.onrc.onos.core.matchaction.action.OutputAction;
43import net.onrc.onos.core.matchaction.action.PopMplsAction;
44import net.onrc.onos.core.matchaction.action.PushMplsAction;
45import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
46import net.onrc.onos.core.matchaction.match.Ipv4Match;
47import net.onrc.onos.core.matchaction.match.Match;
48import net.onrc.onos.core.matchaction.match.MplsMatch;
49import net.onrc.onos.core.matchaction.match.PacketMatch;
50import net.onrc.onos.core.util.Dpid;
51import net.onrc.onos.core.util.IPv4Net;
52import net.onrc.onos.core.util.PortNumber;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070053
54import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
55import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
56import org.projectfloodlight.openflow.protocol.OFBucket;
57import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
58import org.projectfloodlight.openflow.protocol.OFErrorMsg;
59import org.projectfloodlight.openflow.protocol.OFFactory;
Saurav Dase972b3a2014-09-26 15:41:06 -070060import org.projectfloodlight.openflow.protocol.OFFlowMod;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070061import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
62import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
63import org.projectfloodlight.openflow.protocol.OFGroupType;
64import org.projectfloodlight.openflow.protocol.OFMatchV3;
65import org.projectfloodlight.openflow.protocol.OFMessage;
66import org.projectfloodlight.openflow.protocol.OFOxmList;
67import org.projectfloodlight.openflow.protocol.OFPortDesc;
68import org.projectfloodlight.openflow.protocol.OFStatsReply;
69import org.projectfloodlight.openflow.protocol.action.OFAction;
70import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
Saurav Dase972b3a2014-09-26 15:41:06 -070071import org.projectfloodlight.openflow.protocol.match.Match.Builder;
72import org.projectfloodlight.openflow.protocol.match.MatchField;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070073import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
74import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
75import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
76import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
77import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070078import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
79import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
80import org.projectfloodlight.openflow.types.EthType;
81import org.projectfloodlight.openflow.types.IPv4Address;
Saurav Dase972b3a2014-09-26 15:41:06 -070082import org.projectfloodlight.openflow.types.IpProtocol;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070083import org.projectfloodlight.openflow.types.MacAddress;
84import org.projectfloodlight.openflow.types.OFBufferId;
85import org.projectfloodlight.openflow.types.OFGroup;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070086import org.projectfloodlight.openflow.types.OFPort;
87import org.projectfloodlight.openflow.types.OFVlanVidMatch;
88import org.projectfloodlight.openflow.types.TableId;
Saurav Dase972b3a2014-09-26 15:41:06 -070089import org.projectfloodlight.openflow.types.TransportPort;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070090import org.projectfloodlight.openflow.types.U32;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070091import org.projectfloodlight.openflow.util.HexString;
92
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070093import com.google.common.collect.Sets;
94
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070095/**
96 * OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
97 * Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
98 * Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
99 * None
100 */
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700101public class OFSwitchImplCPqD13 extends OFSwitchImplBase implements IOF13Switch {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700102 private AtomicBoolean driverHandshakeComplete;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700103 private AtomicBoolean haltStateMachine;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700104 private OFFactory factory;
105 private static final int OFPCML_NO_BUFFER = 0xffff;
106 // Configuration of asynch messages to controller. We need different
107 // asynch messages depending on role-equal or role-master.
108 // We don't want to get anything if we are slave.
109 private static final long SET_FLOW_REMOVED_MASK_MASTER = 0xf;
110 private static final long SET_PACKET_IN_MASK_MASTER = 0x7;
111 private static final long SET_PORT_STATUS_MASK_MASTER = 0x7;
112 private static final long SET_FLOW_REMOVED_MASK_EQUAL = 0x0;
113 private static final long SET_PACKET_IN_MASK_EQUAL = 0x0;
114 private static final long SET_PORT_STATUS_MASK_EQUAL = 0x7;
115 private static final long SET_ALL_SLAVE = 0x0;
116
117 private static final long TEST_FLOW_REMOVED_MASK = 0xf;
118 private static final long TEST_PACKET_IN_MASK = 0x7;
119 private static final long TEST_PORT_STATUS_MASK = 0x7;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700120
121 private static final int TABLE_VLAN = 0;
122 private static final int TABLE_TMAC = 1;
Sangho Shin01bca862014-09-12 11:18:59 -0700123 private static final int TABLE_IPv4_UNICAST = 2;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700124 private static final int TABLE_MPLS = 3;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700125 private static final int TABLE_ACL = 5;
126
127 private static final short MAX_PRIORITY = (short) 0xffff;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700128 private static final short PRIORITY_MULTIPLIER = (short) 2046;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700129 private static final short MIN_PRIORITY = 0x0;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700130
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700131 private long barrierXidToWaitFor = -1;
132 private DriverState driverState;
Jonathan Hartcb34f382014-08-12 21:11:03 -0700133 private final boolean usePipeline13;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700134 private SegmentRouterConfig srConfig;
135 private ConcurrentMap<Dpid, Set<PortNumber>> neighbors;
136 private ConcurrentMap<NeighborSet, EcmpInfo> ecmpGroups;
Srikanth Vavilapallib95e6e02014-10-02 13:56:39 -0700137 private ConcurrentMap<PortNumber, ArrayList<NeighborSet>> portNeighborSetMap;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700138
139
Jonathan Hartcb34f382014-08-12 21:11:03 -0700140
141 public OFSwitchImplCPqD13(OFDescStatsReply desc, boolean usePipeline13) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700142 super();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700143 haltStateMachine = new AtomicBoolean(false);
144 driverState = DriverState.INIT;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700145 driverHandshakeComplete = new AtomicBoolean(false);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700146 setSwitchDescription(desc);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700147 neighbors = new ConcurrentHashMap<Dpid, Set<PortNumber>>();
148 ecmpGroups = new ConcurrentHashMap<NeighborSet, EcmpInfo>();
Srikanth Vavilapallib95e6e02014-10-02 13:56:39 -0700149 portNeighborSetMap =
150 new ConcurrentHashMap<PortNumber, ArrayList<NeighborSet>>();
Jonathan Hartcb34f382014-08-12 21:11:03 -0700151 this.usePipeline13 = usePipeline13;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700152 }
153
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700154 // *****************************
155 // OFSwitchImplBase
156 // *****************************
157
158
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700159 /* (non-Javadoc)
160 * @see java.lang.Object#toString()
161 */
162 @Override
163 public String toString() {
164 return "OFSwitchImplCPqD13 [" + ((channel != null)
165 ? channel.getRemoteAddress() : "?")
166 + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
167 }
168
169 @Override
170 public void startDriverHandshake() throws IOException {
171 log.debug("Starting driver handshake for sw {}", getStringId());
172 if (startDriverHandshakeCalled) {
173 throw new SwitchDriverSubHandshakeAlreadyStarted();
174 }
175 startDriverHandshakeCalled = true;
Jonathan Harta213bce2014-08-11 15:44:07 -0700176 factory = getFactory();
Jonathan Hartcb34f382014-08-12 21:11:03 -0700177 if (!usePipeline13) {
178 // Send packet-in to controller if a packet misses the first table
179 populateTableMissEntry(0, true, false, false, 0);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700180 driverHandshakeComplete.set(true);
Sangho Shin01bca862014-09-12 11:18:59 -0700181 } else {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700182 nextDriverState();
Sangho Shin01bca862014-09-12 11:18:59 -0700183 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700184 }
185
186 @Override
187 public boolean isDriverHandshakeComplete() {
Sangho Shin01bca862014-09-12 11:18:59 -0700188 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700189 throw new SwitchDriverSubHandshakeNotStarted();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700190 return driverHandshakeComplete.get();
191 }
192
193 @Override
194 public void processDriverHandshakeMessage(OFMessage m) {
Sangho Shin01bca862014-09-12 11:18:59 -0700195 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700196 throw new SwitchDriverSubHandshakeNotStarted();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700197 if (isDriverHandshakeComplete())
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700198 throw new SwitchDriverSubHandshakeCompleted(m);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700199 try {
200 processOFMessage(this, m);
201 } catch (IOException e) {
202 log.error("Error generated when processing OFMessage", e.getCause());
203 }
204 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700205
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700206 @Override
207 public String getSwitchDriverState() {
208 return driverState.toString();
209 }
210
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700211 public void removePortFromGroups(PortNumber port) {
212 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
Sangho Shin5be3e532014-10-03 17:20:58 -0700213 if (portNSSet == null)
214 return;
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700215 for (NeighborSet ns : portNSSet) {
216 /* Delete the first matched bucket */
217 Iterator<BucketInfo> it = ecmpGroups.get(ns).buckets.iterator();
218 while (it.hasNext()) {
219 BucketInfo bucket = it.next();
220 if (bucket.outport.equals(port)) {
221 it.remove();
222 /* Assuming port appears under only one bucket for
223 * a neighbor set
224 */
225 break;
226 }
227 }
228 }
229 /* Delete entry from portNeighborSetMap */
230 portNeighborSetMap.remove(port);
231 /* TODO: Update switches using GroupMod */
232 }
233
234 public void addPortToGroups(PortNumber port) {
235 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
236 if (portNSSet != null) {
237 /* Port is already part of ECMP groups */
238 return;
239 }
240 /* TODO: Not yet finished */
241 return;
242 }
243
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700244 // *****************************
245 // Driver handshake state-machine
246 // *****************************
247
248 enum DriverState {
249 INIT,
250 SET_TABLE_MISS_ENTRIES,
251 SET_TABLE_VLAN_TMAC,
252 SET_GROUPS,
253 VERIFY_GROUPS,
254 SET_ADJACENCY_LABELS,
255 EXIT
256 }
257
258 protected void nextDriverState() throws IOException {
259 DriverState currentState = driverState;
Saurav Das80d17392014-10-01 10:24:56 -0700260 if (haltStateMachine.get()) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700261 return;
Saurav Das80d17392014-10-01 10:24:56 -0700262 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700263 switch (currentState) {
264 case INIT:
265 driverState = DriverState.SET_TABLE_MISS_ENTRIES;
266 setTableMissEntries();
Saurav Dasd84178f2014-09-29 17:48:54 -0700267 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700268 break;
269 case SET_TABLE_MISS_ENTRIES:
270 driverState = DriverState.SET_TABLE_VLAN_TMAC;
271 getNetworkConfig();
272 populateTableVlan();
273 populateTableTMac();
Saurav Dasd84178f2014-09-29 17:48:54 -0700274 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700275 break;
276 case SET_TABLE_VLAN_TMAC:
277 driverState = DriverState.SET_GROUPS;
278 createGroups();
Saurav Dasd84178f2014-09-29 17:48:54 -0700279 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700280 break;
281 case SET_GROUPS:
282 driverState = DriverState.VERIFY_GROUPS;
283 verifyGroups();
284 break;
285 case VERIFY_GROUPS:
286 driverState = DriverState.SET_ADJACENCY_LABELS;
287 assignAdjacencyLabels();
288 break;
289 case SET_ADJACENCY_LABELS:
290 driverState = DriverState.EXIT;
291 driverHandshakeComplete.set(true);
292 break;
293 case EXIT:
294 default:
295 driverState = DriverState.EXIT;
296 log.error("Driver handshake has exited for sw: {}", getStringId());
297 }
298 }
299
300 void processOFMessage(IOFSwitch sw, OFMessage m) throws IOException {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700301 switch (m.getType()) {
302 case BARRIER_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700303 processBarrierReply(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700304 break;
305
306 case ERROR:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700307 processErrorMessage(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700308 break;
309
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700310 case GET_ASYNC_REPLY:
311 OFAsyncGetReply asrep = (OFAsyncGetReply) m;
312 decodeAsyncGetReply(asrep);
313 break;
314
315 case PACKET_IN:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700316 // not ready to handle packet-ins
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700317 break;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700318
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700319 case QUEUE_GET_CONFIG_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700320 // not doing queue config yet
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700321 break;
322
323 case STATS_REPLY:
324 processStatsReply((OFStatsReply) m);
325 break;
326
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700327 case ROLE_REPLY: // channelHandler should handle this
328 case PORT_STATUS: // channelHandler should handle this
329 case FEATURES_REPLY: // don't care
330 case FLOW_REMOVED: // don't care
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700331 default:
332 log.debug("Received message {} during switch-driver subhandshake "
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700333 + "from switch {} ... Ignoring message", m, sw.getStringId());
334 }
335 }
336
337 private void processStatsReply(OFStatsReply sr) {
338 switch (sr.getStatsType()) {
339 case AGGREGATE:
340 break;
341 case DESC:
342 break;
343 case EXPERIMENTER:
344 break;
345 case FLOW:
346 break;
347 case GROUP_DESC:
348 processGroupDesc((OFGroupDescStatsReply) sr);
349 break;
350 case GROUP_FEATURES:
351 processGroupFeatures((OFGroupFeaturesStatsReply) sr);
352 break;
353 case METER_CONFIG:
354 break;
355 case METER_FEATURES:
356 break;
357 case PORT_DESC:
358 break;
359 case TABLE_FEATURES:
360 break;
361 default:
362 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700363
364 }
365 }
366
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700367 private void processErrorMessage(OFMessage m) {
368 log.error("Switch {} Error {} in DriverState", getStringId(),
369 (OFErrorMsg) m, driverState);
370 }
371
372 private void processBarrierReply(OFMessage m) throws IOException {
373 if (m.getXid() == barrierXidToWaitFor) {
374 // Driver state-machine progresses to the next state.
375 // If Barrier messages is not received, then eventually
376 // the ChannelHandler state machine will timeout, and the switch
377 // will be disconnected.
378 nextDriverState();
379 } else {
380 log.error("Received incorrect barrier-message xid {} (expected: {}) in "
381 + "switch-driver state {} for switch {}", m, barrierXidToWaitFor,
382 driverState, getStringId());
383 }
384 }
385
386 private void processGroupDesc(OFGroupDescStatsReply gdsr) {
387 log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
388 try {
389 nextDriverState();
390 } catch (IOException e) {
391 // TODO Auto-generated catch block
392 e.printStackTrace();
393 }
394 }
395
396 // *****************************
397 // Utility methods
398 // *****************************
399
400 void setTableMissEntries() throws IOException {
401 // set all table-miss-entries
402 populateTableMissEntry(TABLE_VLAN, true, false, false, -1);
403 populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
404 populateTableMissEntry(TABLE_IPv4_UNICAST, false, true, true,
405 TABLE_ACL);
406 populateTableMissEntry(TABLE_MPLS, false, true, true,
407 TABLE_ACL);
408 populateTableMissEntry(TABLE_ACL, false, false, false, -1);
409 }
410
Saurav Dasd84178f2014-09-29 17:48:54 -0700411 private void sendHandshakeBarrier() throws IOException {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700412 long xid = getNextTransactionId();
413 barrierXidToWaitFor = xid;
414 OFBarrierRequest br = getFactory()
415 .buildBarrierRequest()
416 .setXid(xid)
417 .build();
418 write(br, null);
419 }
420
421 /**
422 * Adds a table-miss-entry to a pipeline table.
423 * <p>
424 * The table-miss-entry can be added with 'write-actions' or
425 * 'apply-actions'. It can also add a 'goto-table' instruction. By default
426 * if none of the booleans in the call are set, then the table-miss entry is
427 * added with no instructions, which means that if a packet hits the
428 * table-miss-entry, pipeline execution will stop, and the action set
429 * associated with the packet will be executed.
430 *
431 * @param tableToAdd the table to where the table-miss-entry will be added
432 * @param toControllerNow as an APPLY_ACTION instruction
433 * @param toControllerWrite as a WRITE_ACTION instruction
434 * @param toTable as a GOTO_TABLE instruction
435 * @param tableToSend the table to send as per the GOTO_TABLE instruction it
436 * needs to be set if 'toTable' is true. Ignored of 'toTable' is
437 * false.
438 * @throws IOException
439 */
440 @SuppressWarnings("unchecked")
441 private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
442 boolean toControllerWrite,
443 boolean toTable, int tableToSend) throws IOException {
444 OFOxmList oxmList = OFOxmList.EMPTY;
445 OFMatchV3 match = factory.buildMatchV3()
446 .setOxmList(oxmList)
447 .build();
448 OFAction outc = factory.actions()
449 .buildOutput()
450 .setPort(OFPort.CONTROLLER)
451 .setMaxLen(OFPCML_NO_BUFFER)
452 .build();
453 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
454 if (toControllerNow) {
455 // table-miss instruction to send to controller immediately
456 OFInstruction instr = factory.instructions()
457 .buildApplyActions()
458 .setActions(Collections.singletonList(outc))
459 .build();
460 instructions.add(instr);
461 }
462
463 if (toControllerWrite) {
464 // table-miss instruction to write-action to send to controller
465 // this will be executed whenever the action-set gets executed
466 OFInstruction instr = factory.instructions()
467 .buildWriteActions()
468 .setActions(Collections.singletonList(outc))
469 .build();
470 instructions.add(instr);
471 }
472
473 if (toTable) {
474 // table-miss instruction to goto-table x
475 OFInstruction instr = factory.instructions()
476 .gotoTable(TableId.of(tableToSend));
477 instructions.add(instr);
478 }
479
480 if (!toControllerNow && !toControllerWrite && !toTable) {
481 // table-miss has no instruction - at which point action-set will be
482 // executed - if there is an action to output/group in the action
483 // set
484 // the packet will be sent there, otherwise it will be dropped.
485 instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
486 }
487
488 OFMessage tableMissEntry = factory.buildFlowAdd()
489 .setTableId(TableId.of(tableToAdd))
490 .setMatch(match) // match everything
491 .setInstructions(instructions)
492 .setPriority(MIN_PRIORITY)
493 .setBufferId(OFBufferId.NO_BUFFER)
494 .setIdleTimeout(0)
495 .setHardTimeout(0)
496 .setXid(getNextTransactionId())
497 .build();
498 write(tableMissEntry, null);
499 }
500
501 private void getNetworkConfig() {
502 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
503 SwitchConfigStatus scs = ncs.checkSwitchConfig(new Dpid(getId()));
504 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
505 srConfig = (SegmentRouterConfig) scs.getSwitchConfig();
506 } else {
507 log.error("Switch not configured as Segment-Router");
508 }
509
510 List<LinkConfig> linkConfigList = ncs.getConfiguredAllowedLinks();
511 setNeighbors(linkConfigList);
512 }
513
514 private void populateTableVlan() throws IOException {
515 List<OFMessage> msglist = new ArrayList<OFMessage>();
516 for (OFPortDesc p : getPorts()) {
517 int pnum = p.getPortNo().getPortNumber();
518 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
519 OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
520 OFOxmVlanVid oxv = factory.oxms()
521 .vlanVid(OFVlanVidMatch.UNTAGGED);
522 OFOxmList oxmList = OFOxmList.of(oxp, oxv);
523 OFMatchV3 match = factory.buildMatchV3()
524 .setOxmList(oxmList).build();
525
526 // TODO: match on vlan-tagged packets for vlans configured on
527 // subnet ports and strip-vlan
528
529 // Do not need to add vlans
530 /*int vlanid = getVlanConfig(pnum);
531 OFOxmVlanVid vidToSet = factory.oxms()
532 .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
533 OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
534 OFAction setVlan = factory.actions().setField(vidToSet);
535 List<OFAction> actionlist = new ArrayList<OFAction>();
536 actionlist.add(pushVlan);
537 actionlist.add(setVlan);
538 OFInstruction appAction = factory.instructions().buildApplyActions()
539 .setActions(actionlist).build();*/
540
541 OFInstruction gotoTbl = factory.instructions().buildGotoTable()
542 .setTableId(TableId.of(TABLE_TMAC)).build();
543 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
544 // instructions.add(appAction);
545 instructions.add(gotoTbl);
546 OFMessage flowEntry = factory.buildFlowAdd()
547 .setTableId(TableId.of(TABLE_VLAN))
548 .setMatch(match)
549 .setInstructions(instructions)
550 .setPriority(1000) // does not matter - all rules
551 // exclusive
552 .setBufferId(OFBufferId.NO_BUFFER)
553 .setIdleTimeout(0)
554 .setHardTimeout(0)
555 .setXid(getNextTransactionId())
556 .build();
557 msglist.add(flowEntry);
558 }
559 }
560 write(msglist);
561 log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId());
562 }
563
564 private void populateTableTMac() throws IOException {
565 // match for router-mac and ip-packets
566 OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
567 OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr());
568 OFOxmList oxmListIp = OFOxmList.of(dmac, oxe);
569 OFMatchV3 matchIp = factory.buildMatchV3()
570 .setOxmList(oxmListIp).build();
571 OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
572 .setTableId(TableId.of(TABLE_IPv4_UNICAST)).build();
573 List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
574 OFMessage ipEntry = factory.buildFlowAdd()
575 .setTableId(TableId.of(TABLE_TMAC))
576 .setMatch(matchIp)
577 .setInstructions(instructionsIp)
578 .setPriority(1000) // strict priority required lower than
579 // multicastMac
580 .setBufferId(OFBufferId.NO_BUFFER)
581 .setIdleTimeout(0)
582 .setHardTimeout(0)
583 .setXid(getNextTransactionId())
584 .build();
585
586 // match for router-mac and mpls packets
587 OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
588 OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls);
589 OFMatchV3 matchMpls = factory.buildMatchV3()
590 .setOxmList(oxmListMpls).build();
591 OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
592 .setTableId(TableId.of(TABLE_MPLS)).build();
593 List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
594 OFMessage mplsEntry = factory.buildFlowAdd()
595 .setTableId(TableId.of(TABLE_TMAC))
596 .setMatch(matchMpls)
597 .setInstructions(instructionsMpls)
598 .setPriority(1001) // strict priority required lower than
599 // multicastMac
600 .setBufferId(OFBufferId.NO_BUFFER)
601 .setIdleTimeout(0)
602 .setHardTimeout(0)
603 .setXid(getNextTransactionId())
604 .build();
605
606 log.debug("Adding termination-mac-rules in sw {}", getStringId());
607 List<OFMessage> msglist = new ArrayList<OFMessage>(2);
608 msglist.add(ipEntry);
609 msglist.add(mplsEntry);
610 write(msglist);
611 }
612
613 private MacAddress getRouterMacAddr() {
614 if (srConfig != null) {
615 return MacAddress.of(srConfig.getRouterMac());
616 } else {
617 // return a dummy mac address - it will not be used
618 return MacAddress.of("00:00:00:00:00:00");
619 }
620 }
621
622 private MacAddress getNeighborRouterMacAddress(Dpid ndpid) {
623 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
624 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
625 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
626 return MacAddress.of(((SegmentRouterConfig) scs.getSwitchConfig())
627 .getRouterMac());
628 } else {
629 // return a dummy mac address - it will not be used
630 return MacAddress.of("00:00:00:00:00:00");
631 }
632 }
633
634 private void setNeighbors(List<LinkConfig> linkConfigList) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700635 for (LinkConfig lg : linkConfigList) {
636 if (!lg.getType().equals(NetworkConfigManager.PKT_LINK)) {
Saurav Das80d17392014-10-01 10:24:56 -0700637 continue;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700638 }
639 PktLinkConfig plg = (PktLinkConfig) lg;
640 if (plg.getDpid1() == getId()) {
641 addNeighborAtPort(new Dpid(plg.getDpid2()),
642 PortNumber.uint32(plg.getPort1()));
643 } else if (plg.getDpid2() == getId()) {
644 addNeighborAtPort(new Dpid(plg.getDpid1()),
645 PortNumber.uint32(plg.getPort2()));
646 }
647 }
648 }
649
650 private void addNeighborAtPort(Dpid neighborDpid, PortNumber portToNeighbor) {
651 if (neighbors.get(neighborDpid) != null) {
652 neighbors.get(neighborDpid).add(portToNeighbor);
653 } else {
654 Set<PortNumber> ports = new HashSet<PortNumber>();
655 ports.add(portToNeighbor);
656 neighbors.put(neighborDpid, ports);
657 }
658 }
659
660 /**
661 * createGroups creates ECMP groups for all ports on this router connected
662 * to other routers (in the OF network). The information for ports is
663 * gleaned from the configured links. If no links are configured no groups
664 * will be created, and it is up to the caller of the IOF13Switch API to
665 * create groups.
666 * <p>
667 * By default all ports connected to the same neighbor router will be part
668 * of the same ECMP group. In addition, groups will be created for all
669 * possible combinations of neighbor routers.
670 * <p>
671 * For example, consider this router (R0) connected to 3 neighbors (R1, R2,
672 * and R3). The following groups will be created in R0:
673 * <li>1) all ports to R1,
674 * <li>2) all ports to R2,
675 * <li>3) all ports to R3,
676 * <li>4) all ports to R1 and R2
677 * <li>5) all ports to R1 and R3
678 * <li>6) all ports to R2 and R3
679 * <li>7) all ports to R1, R2, and R3
680 */
681 private void createGroups() {
682 Set<Dpid> dpids = neighbors.keySet();
683 if (dpids == null || dpids.isEmpty()) {
684 return;
685 }
686 // temp map of ecmp groupings
687 /* Map<NeighborSet, List<BucketInfo>> temp =
688 new HashMap<NeighborSet, List<BucketInfo>>();
689 */
690 // get all combinations of neighbors
691 Set<Set<Dpid>> powerSet = Sets.powerSet(dpids);
692 int groupid = 1;
693 for (Set<Dpid> combo : powerSet) {
694 if (combo.isEmpty()) {
695 // eliminate the empty set in the power set
696 continue;
697 }
698 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
699 NeighborSet ns = new NeighborSet();
700 for (Dpid d : combo) {
701 ns.addDpid(d);
702 for (PortNumber sp : neighbors.get(d)) {
703 BucketInfo b = new BucketInfo(d,
704 MacAddress.of(srConfig.getRouterMac()),
705 getNeighborRouterMacAddress(d), sp);
706 buckets.add(b);
707 }
708 }
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700709
710 for (Dpid d : combo) {
711 for (PortNumber sp : neighbors.get(d)) {
712 ArrayList<NeighborSet> portNeighborSets =
713 portNeighborSetMap.get(sp);
714 if (portNeighborSets == null) {
715 portNeighborSets = new ArrayList<NeighborSet>();
716 portNeighborSets.add(ns);
717 portNeighborSetMap.put(sp, portNeighborSets);
718 }
719 else
720 portNeighborSets.add(ns);
721 }
722 }
723
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700724 EcmpInfo ecmpInfo = new EcmpInfo(groupid++, buckets);
725 setEcmpGroup(ecmpInfo);
726 ecmpGroups.put(ns, ecmpInfo);
727 log.debug("Creating ecmp group in sw {}: {}", getStringId(), ecmpInfo);
728 }
729 }
730
731 private class EcmpInfo {
732 int groupId;
733 List<BucketInfo> buckets;
734
735 EcmpInfo(int gid, List<BucketInfo> bucketInfos) {
736 groupId = gid;
737 buckets = bucketInfos;
738 }
739
740 @Override
741 public String toString() {
742 return "groupId: " + groupId + ", buckets: " + buckets;
743 }
744 }
745
746 private class BucketInfo {
747 Dpid neighborDpid;
748 MacAddress srcMac;
749 MacAddress dstMac;
750 PortNumber outport;
751
752 BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac, PortNumber p) {
753 neighborDpid = nDpid;
754 srcMac = smac;
755 dstMac = dmac;
756 outport = p;
757 }
758
759 @Override
760 public String toString() {
761 return " {neighborDpid: " + neighborDpid + ", dstMac: " + dstMac +
762 ", srcMac: " + srcMac + ", outport: " + outport + "}";
763 }
764 }
765
766 private void setEcmpGroup(EcmpInfo ecmpInfo) {
767 List<OFMessage> msglist = new ArrayList<OFMessage>();
768 OFGroup group = OFGroup.of(ecmpInfo.groupId);
769
770 List<OFBucket> buckets = new ArrayList<OFBucket>();
771 for (BucketInfo b : ecmpInfo.buckets) {
772 OFOxmEthDst dmac = factory.oxms()
773 .ethDst(b.dstMac);
774 OFAction setDA = factory.actions().buildSetField()
775 .setField(dmac).build();
Saurav Das0a344b02014-09-26 14:18:52 -0700776 OFOxmEthSrc smac = factory.oxms()
777 .ethSrc(b.srcMac);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700778 OFAction setSA = factory.actions().buildSetField()
779 .setField(smac).build();
780 OFAction outp = factory.actions().buildOutput()
781 .setPort(OFPort.of(b.outport.shortValue()))
782 .build();
783 List<OFAction> actions = new ArrayList<OFAction>();
784 actions.add(setSA);
785 actions.add(setDA);
786 actions.add(outp);
787 OFBucket ofb = factory.buildBucket()
788 .setWeight(1)
789 .setActions(actions)
790 .build();
791 buckets.add(ofb);
792 }
793
794 OFMessage gm = factory.buildGroupAdd()
795 .setGroup(group)
796 .setBuckets(buckets)
797 .setGroupType(OFGroupType.SELECT)
798 .setXid(getNextTransactionId())
799 .build();
800 msglist.add(gm);
801 try {
802 write(msglist);
803 } catch (IOException e) {
804 // TODO Auto-generated catch block
805 e.printStackTrace();
806 }
807 }
808
809 private void verifyGroups() throws IOException {
810 sendGroupDescRequest();
811 }
812
813 private void sendGroupDescRequest() throws IOException {
814 OFMessage gdr = factory.buildGroupDescStatsRequest()
815 .setXid(getNextTransactionId())
816 .build();
817 write(gdr, null);
818 }
819
820 private void assignAdjacencyLabels() {
821 // TODO
822 try {
823 nextDriverState();
824 } catch (IOException e) {
825 // TODO Auto-generated catch block
826 e.printStackTrace();
827 }
828 }
829
Saurav Das1cd10152014-09-26 09:38:07 -0700830 private OFAction getOFAction(Action action) {
831 OFAction ofAction = null;
832 if (action instanceof OutputAction) {
833 OutputAction outputAction = (OutputAction) action;
834 OFPort port = OFPort.of((int) outputAction.getPortNumber().value());
835 ofAction = factory.actions().output(port, Short.MAX_VALUE);
836 } else if (action instanceof ModifyDstMacAction) {
837 long dstMac = ((ModifyDstMacAction) action).getDstMac().toLong();
838 OFOxmEthDst dmac = factory.oxms()
839 .ethDst(MacAddress.of(dstMac));
840 ofAction = factory.actions().buildSetField()
841 .setField(dmac).build();
842 } else if (action instanceof ModifySrcMacAction) {
843 long srcMac = ((ModifySrcMacAction) action).getSrcMac().toLong();
844 OFOxmEthSrc smac = factory.oxms()
845 .ethSrc(MacAddress.of(srcMac));
846 ofAction = factory.actions().buildSetField()
847 .setField(smac).build();
848 } else if (action instanceof PushMplsAction) {
849 ofAction = factory.actions().pushMpls(EthType.MPLS_UNICAST);
850 } else if (action instanceof SetMplsIdAction) {
851 int labelid = ((SetMplsIdAction) action).getMplsId();
852 OFOxmMplsLabel lid = factory.oxms()
853 .mplsLabel(U32.of(labelid));
854 ofAction = factory.actions().buildSetField()
855 .setField(lid).build();
856 } else if (action instanceof PopMplsAction) {
857 EthType ethertype = ((PopMplsAction) action).getEthType();
858 ofAction = factory.actions().popMpls(ethertype);
859 } else if (action instanceof GroupAction) {
860 NeighborSet ns = ((GroupAction) action).getDpids();
861 EcmpInfo ei = ecmpGroups.get(ns);
862 if (ei != null) {
863 int gid = ei.groupId;
864 ofAction = factory.actions().buildGroup()
865 .setGroup(OFGroup.of(gid))
866 .build();
867 } else {
868 log.error("Unable to find ecmp group for neighbors {} at "
869 + "switch {}", ns, getStringId());
870 }
871 } else if (action instanceof DecNwTtlAction) {
872 ofAction = factory.actions().decNwTtl();
873 } else if (action instanceof DecMplsTtlAction) {
874 ofAction = factory.actions().decMplsTtl();
875 } else if (action instanceof CopyTtlInAction) {
876 ofAction = factory.actions().copyTtlIn();
877 } else if (action instanceof CopyTtlOutAction) {
878 ofAction = factory.actions().copyTtlOut();
879 } else {
880 log.warn("Unsupported Action type: {}", action.getClass().getName());
881 return null;
882 }
883
884 // not supported by loxigen
885 // OFAction setBos =
886 // factory.actions().buildSetField().setField(bos).build();
887
888 return ofAction;
889 }
890
Saurav Das0a344b02014-09-26 14:18:52 -0700891 private OFMessage getIpEntry(MatchActionOperationEntry mao) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700892 MatchAction ma = mao.getTarget();
893 Operator op = mao.getOperator();
894 Ipv4Match ipm = (Ipv4Match) ma.getMatch();
895
896 // set match
897 IPv4Net ipdst = ipm.getDestination();
898 OFOxmEthType ethTypeIp = factory.oxms()
899 .ethType(EthType.IPv4);
900 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
901 .ipv4DstMasked(
902 IPv4Address.of(ipdst.address().value()),
903 IPv4Address.ofCidrMaskLength(ipdst.prefixLen())
904 );
905 OFOxmList oxmList = OFOxmList.of(ethTypeIp, ipPrefix);
906 OFMatchV3 match = factory.buildMatchV3()
907 .setOxmList(oxmList).build();
908
909 // set actions
910 List<OFAction> writeActions = new ArrayList<OFAction>();
911 for (Action action : ma.getActions()) {
Saurav Das1cd10152014-09-26 09:38:07 -0700912 OFAction ofAction = getOFAction(action);
913 if (ofAction != null) {
914 writeActions.add(ofAction);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700915 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700916 }
917
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700918 // set instructions
919 OFInstruction writeInstr = factory.instructions().buildWriteActions()
920 .setActions(writeActions).build();
921 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
922 .setTableId(TableId.of(TABLE_ACL)).build();
923 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
924 instructions.add(writeInstr);
925 instructions.add(gotoInstr);
926
Saurav Das1cd10152014-09-26 09:38:07 -0700927 // set flow priority to emulate longest prefix match
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700928 int priority = ipdst.prefixLen() * PRIORITY_MULTIPLIER;
929 if (ipdst.prefixLen() == (short) 32) {
930 priority = MAX_PRIORITY;
931 }
932
Saurav Dasbc594a42014-09-25 20:13:50 -0700933 // set flow-mod
Saurav Dase972b3a2014-09-26 15:41:06 -0700934 OFFlowMod.Builder fmBuilder = null;
935 switch (op) {
936 case ADD:
937 fmBuilder = factory.buildFlowAdd();
938 break;
939 case REMOVE:
940 fmBuilder = factory.buildFlowDeleteStrict();
941 break;
Sangho Shin5be3e532014-10-03 17:20:58 -0700942 case MODIFY: // TODO
943 fmBuilder = factory.buildFlowModifyStrict();
944 break;
Saurav Dase972b3a2014-09-26 15:41:06 -0700945 default:
946 log.warn("Unsupported MatchAction Operator: {}", op);
947 return null;
Saurav Dasbc594a42014-09-25 20:13:50 -0700948 }
Saurav Dase972b3a2014-09-26 15:41:06 -0700949 OFMessage ipFlow = fmBuilder
950 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
951 .setMatch(match)
952 .setInstructions(instructions)
953 .setPriority(priority)
954 .setBufferId(OFBufferId.NO_BUFFER)
955 .setIdleTimeout(0)
956 .setHardTimeout(0)
957 .setXid(getNextTransactionId())
958 .build();
Saurav Dasbc594a42014-09-25 20:13:50 -0700959 log.debug("{} ip-rule {}-{} in sw {}",
960 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
961 match, writeActions,
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700962 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -0700963 return ipFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700964 }
965
Saurav Das0a344b02014-09-26 14:18:52 -0700966 private OFMessage getMplsEntry(MatchActionOperationEntry mao) {
Saurav Das1cd10152014-09-26 09:38:07 -0700967 MatchAction ma = mao.getTarget();
968 Operator op = mao.getOperator();
969 MplsMatch mplsm = (MplsMatch) ma.getMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700970
Saurav Das1cd10152014-09-26 09:38:07 -0700971 // set match
972 OFOxmEthType ethTypeMpls = factory.oxms()
973 .ethType(EthType.MPLS_UNICAST);
974 OFOxmMplsLabel labelid = factory.oxms()
975 .mplsLabel(U32.of(mplsm.getMplsLabel()));
976 OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid);
977 OFMatchV3 matchlabel = factory.buildMatchV3()
978 .setOxmList(oxmList).build();
979
980 // set actions
981 List<OFAction> writeActions = new ArrayList<OFAction>();
982 for (Action action : ma.getActions()) {
983 OFAction ofAction = getOFAction(action);
984 if (ofAction != null) {
985 writeActions.add(ofAction);
986 }
987 }
988
989 // set instructions
990 OFInstruction writeInstr = factory.instructions().buildWriteActions()
991 .setActions(writeActions).build();
992 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
993 .setTableId(TableId.of(TABLE_ACL)).build();
994 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
995 instructions.add(writeInstr);
996 instructions.add(gotoInstr);
997
Saurav Dase972b3a2014-09-26 15:41:06 -0700998 // set flow-mod
999 OFFlowMod.Builder fmBuilder = null;
1000 switch (op) {
1001 case ADD:
1002 fmBuilder = factory.buildFlowAdd();
1003 break;
1004 case REMOVE:
1005 fmBuilder = factory.buildFlowDeleteStrict();
1006 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001007 case MODIFY: // TODO
1008 fmBuilder = factory.buildFlowModifyStrict();
1009 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001010 default:
1011 log.warn("Unsupported MatchAction Operator: {}", op);
1012 return null;
Saurav Das1cd10152014-09-26 09:38:07 -07001013 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001014
1015 OFMessage mplsFlow = fmBuilder
1016 .setTableId(TableId.of(TABLE_MPLS))
1017 .setMatch(matchlabel)
1018 .setInstructions(instructions)
1019 .setPriority(MAX_PRIORITY) // exact match and exclusive
1020 .setBufferId(OFBufferId.NO_BUFFER)
1021 .setIdleTimeout(0)
1022 .setHardTimeout(0)
1023 .setXid(getNextTransactionId())
1024 .build();
Saurav Das1cd10152014-09-26 09:38:07 -07001025 log.debug("{} mpls-rule {}-{} in sw {}",
1026 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1027 matchlabel, writeActions,
1028 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001029 return mplsFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001030 }
1031
Saurav Das0a344b02014-09-26 14:18:52 -07001032 private OFMessage getAclEntry(MatchActionOperationEntry mao) {
Saurav Dase972b3a2014-09-26 15:41:06 -07001033 MatchAction ma = mao.getTarget();
1034 Operator op = mao.getOperator();
1035 PacketMatch packetMatch = (PacketMatch) ma.getMatch();
1036 Builder matchBuilder = factory.buildMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001037
Saurav Dase972b3a2014-09-26 15:41:06 -07001038 // set match
1039 int inport = 0;
1040 if (ma.getSwitchPort() != null) {
1041 inport = (int) ma.getSwitchPort().getPortNumber().value();
1042 }
1043 final MACAddress srcMac = packetMatch.getSrcMacAddress();
1044 final MACAddress dstMac = packetMatch.getDstMacAddress();
1045 final Short etherType = packetMatch.getEtherType();
1046 final IPv4Net srcIp = packetMatch.getSrcIpAddress();
1047 final IPv4Net dstIp = packetMatch.getDstIpAddress();
1048 final Byte ipProto = packetMatch.getIpProtocolNumber();
1049 final Short srcTcpPort = packetMatch.getSrcTcpPortNumber();
1050 final Short dstTcpPort = packetMatch.getDstTcpPortNumber();
1051 if (inport > 0) {
1052 matchBuilder.setExact(MatchField.IN_PORT,
1053 OFPort.of(inport));
1054 }
1055 if (srcMac != null) {
1056 matchBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(srcMac.toLong()));
1057 }
1058 if (dstMac != null) {
1059 matchBuilder.setExact(MatchField.ETH_DST, MacAddress.of(dstMac.toLong()));
1060 }
1061 if (etherType != null) {
1062 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(etherType));
1063 }
1064 if (srcIp != null) {
1065 matchBuilder.setMasked(MatchField.IPV4_SRC,
1066 IPv4Address.of(srcIp.address().value())
1067 .withMaskOfLength(srcIp.prefixLen()));
1068 }
1069 if (dstIp != null) {
1070 matchBuilder.setMasked(MatchField.IPV4_DST,
1071 IPv4Address.of(dstIp.address().value())
1072 .withMaskOfLength(dstIp.prefixLen()));
1073 }
1074 if (ipProto != null) {
1075 matchBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(ipProto));
1076 }
1077 if (srcTcpPort != null) {
1078 matchBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(srcTcpPort));
1079 }
1080 if (dstTcpPort != null) {
1081 matchBuilder.setExact(MatchField.TCP_DST, TransportPort.of(dstTcpPort));
1082 }
1083
1084 // set actions
1085 List<OFAction> applyActions = new ArrayList<OFAction>();
1086 for (Action action : ma.getActions()) {
1087 OFAction ofAction = getOFAction(action);
1088 if (ofAction != null) {
1089 applyActions.add(ofAction);
1090 }
1091 }
1092
1093 // set instructions
1094 OFInstruction clearInstr = factory.instructions().clearActions();
1095 OFInstruction applyInstr = factory.instructions().buildApplyActions()
1096 .setActions(applyActions).build();
1097 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1098 instructions.add(clearInstr);
1099 instructions.add(applyInstr);
1100
1101 // set flow-mod
1102 OFFlowMod.Builder fmBuilder = null;
1103 switch (op) {
1104 case ADD:
1105 fmBuilder = factory.buildFlowAdd();
1106 break;
1107 case REMOVE:
1108 fmBuilder = factory.buildFlowDeleteStrict();
1109 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001110 case MODIFY: // TODO
1111 fmBuilder = factory.buildFlowModifyStrict();
1112 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001113 default:
1114 log.warn("Unsupported MatchAction Operator: {}", op);
1115 return null;
1116 }
1117
1118 OFMessage aclFlow = fmBuilder
1119 .setTableId(TableId.of(TABLE_ACL))
1120 .setMatch(matchBuilder.build())
1121 .setInstructions(instructions)
1122 .setPriority(MAX_PRIORITY / 2) // TODO: wrong - should be MA
1123 // priority
1124 .setBufferId(OFBufferId.NO_BUFFER)
1125 .setIdleTimeout(0)
1126 .setHardTimeout(0)
1127 .setXid(getNextTransactionId())
1128 .build();
Saurav Das0a344b02014-09-26 14:18:52 -07001129 return aclFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001130 }
1131
1132 // *****************************
1133 // IOF13Switch
1134 // *****************************
1135
1136 @Override
1137 public void pushFlow(MatchActionOperationEntry matchActionOp) throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001138 OFMessage ofm = getFlow(matchActionOp);
1139 if (ofm != null) {
1140 write(Collections.singletonList(ofm));
1141 }
1142 }
1143
1144 private OFMessage getFlow(MatchActionOperationEntry matchActionOp) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001145 final MatchAction matchAction = matchActionOp.getTarget();
1146 final Match match = matchAction.getMatch();
1147 if (match instanceof Ipv4Match) {
Saurav Das0a344b02014-09-26 14:18:52 -07001148 return getIpEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001149 } else if (match instanceof MplsMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001150 return getMplsEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001151 } else if (match instanceof PacketMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001152 return getAclEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001153 } else {
1154 log.error("Unknown match type {} pushed to switch {}", match,
1155 getStringId());
1156 }
Saurav Das0a344b02014-09-26 14:18:52 -07001157 return null;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001158 }
1159
1160 @Override
1161 public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps)
1162 throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001163 List<OFMessage> flowMods = new ArrayList<OFMessage>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001164 for (MatchActionOperationEntry matchActionOp : matchActionOps) {
Saurav Das0a344b02014-09-26 14:18:52 -07001165 OFMessage ofm = getFlow(matchActionOp);
1166 if (ofm != null) {
1167 flowMods.add(ofm);
1168 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001169 }
Saurav Das0a344b02014-09-26 14:18:52 -07001170 write(flowMods);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001171 }
1172
1173 @Override
1174 public int getEcmpGroupId(NeighborSet ns) {
1175 EcmpInfo ei = ecmpGroups.get(ns);
1176 if (ei == null) {
1177 return -1;
1178 } else {
1179 return ei.groupId;
1180 }
1181 }
1182
1183 // *****************************
Saurav Das80d17392014-10-01 10:24:56 -07001184 // Unused
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001185 // *****************************
1186
Saurav Das80d17392014-10-01 10:24:56 -07001187 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001188 private void setAsyncConfig() throws IOException {
1189 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
1190 OFMessage setAC = null;
1191
1192 if (role == Role.MASTER) {
1193 setAC = factory.buildAsyncSet()
1194 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
1195 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
1196 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
1197 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1198 .setPacketInMaskSlave(SET_ALL_SLAVE)
1199 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1200 .setXid(getNextTransactionId())
1201 .build();
1202 } else if (role == Role.EQUAL) {
1203 setAC = factory.buildAsyncSet()
1204 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
1205 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
1206 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
1207 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1208 .setPacketInMaskSlave(SET_ALL_SLAVE)
1209 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1210 .setXid(getNextTransactionId())
1211 .build();
1212 }
1213 msglist.add(setAC);
1214
1215 OFMessage br = factory.buildBarrierRequest()
1216 .setXid(getNextTransactionId())
1217 .build();
1218 msglist.add(br);
1219
1220 OFMessage getAC = factory.buildAsyncGetRequest()
1221 .setXid(getNextTransactionId())
1222 .build();
1223 msglist.add(getAC);
1224
1225 write(msglist);
1226 }
1227
Saurav Das80d17392014-10-01 10:24:56 -07001228 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001229 private void decodeAsyncGetReply(OFAsyncGetReply rep) {
1230 long frm = rep.getFlowRemovedMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001231 long frs = rep.getFlowRemovedMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001232 long pim = rep.getPacketInMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001233 long pis = rep.getPacketInMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001234 long psm = rep.getPortStatusMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001235 long pss = rep.getPortStatusMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001236
1237 if (role == Role.MASTER || role == Role.EQUAL) { // should separate
1238 log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
1239 log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
1240 log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
1241 }
1242
1243 }
1244
Saurav Das80d17392014-10-01 10:24:56 -07001245 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001246 private void getTableFeatures() throws IOException {
1247 OFMessage gtf = factory.buildTableFeaturesStatsRequest()
1248 .setXid(getNextTransactionId())
1249 .build();
1250 write(gtf, null);
1251 }
1252
Saurav Das80d17392014-10-01 10:24:56 -07001253 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001254 private void sendGroupFeaturesRequest() throws IOException {
1255 OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
1256 .setXid(getNextTransactionId())
1257 .build();
1258 write(gfr, null);
1259 }
1260
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001261 private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
1262 log.info("Sw: {} Group Features {}", getStringId(), gfsr);
1263 }
1264
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001265}