blob: f434ca2efd83f13eeb6cf4b382db715aab2b0233 [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)
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -0700214 /* No Groups are created with this port yet */
Sangho Shin5be3e532014-10-03 17:20:58 -0700215 return;
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700216 for (NeighborSet ns : portNSSet) {
217 /* Delete the first matched bucket */
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -0700218 EcmpInfo portEcmpInfo = ecmpGroups.get(ns);
219 Iterator<BucketInfo> it = portEcmpInfo.buckets.iterator();
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700220 while (it.hasNext()) {
221 BucketInfo bucket = it.next();
222 if (bucket.outport.equals(port)) {
223 it.remove();
224 /* Assuming port appears under only one bucket for
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -0700225 * a neighbor set and hence invoking Group modify command
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700226 */
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -0700227 modifyEcmpGroup(portEcmpInfo);
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700228 break;
229 }
230 }
231 }
232 /* Delete entry from portNeighborSetMap */
233 portNeighborSetMap.remove(port);
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -0700234 return;
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700235 }
236
237 public void addPortToGroups(PortNumber port) {
238 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
239 if (portNSSet != null) {
240 /* Port is already part of ECMP groups */
241 return;
242 }
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -0700243 /* TODO:
244 * 1) Find the neighbors reached from this port
245 * 2) Compute the Neighbor sets
246 * 3) For the Neighbor set entries that are already there
247 * in the database,
248 * a) Update the ecmpGroups hashmap
249 * b) perform Group Modify on updated groups
250 * 4) For the new Neighbor set entries, add an entry in the database
251 * a) Add entry to the ecmpGroups hashmap
252 * b) perform Group Add on those groups
253 * 5) Update the portNeighborSetMap hashmap
254 * */
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700255 return;
256 }
257
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700258 // *****************************
259 // Driver handshake state-machine
260 // *****************************
261
262 enum DriverState {
263 INIT,
264 SET_TABLE_MISS_ENTRIES,
265 SET_TABLE_VLAN_TMAC,
266 SET_GROUPS,
267 VERIFY_GROUPS,
268 SET_ADJACENCY_LABELS,
269 EXIT
270 }
271
272 protected void nextDriverState() throws IOException {
273 DriverState currentState = driverState;
Saurav Das80d17392014-10-01 10:24:56 -0700274 if (haltStateMachine.get()) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700275 return;
Saurav Das80d17392014-10-01 10:24:56 -0700276 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700277 switch (currentState) {
278 case INIT:
279 driverState = DriverState.SET_TABLE_MISS_ENTRIES;
280 setTableMissEntries();
Saurav Dasd84178f2014-09-29 17:48:54 -0700281 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700282 break;
283 case SET_TABLE_MISS_ENTRIES:
284 driverState = DriverState.SET_TABLE_VLAN_TMAC;
285 getNetworkConfig();
286 populateTableVlan();
287 populateTableTMac();
Saurav Dasd84178f2014-09-29 17:48:54 -0700288 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700289 break;
290 case SET_TABLE_VLAN_TMAC:
291 driverState = DriverState.SET_GROUPS;
292 createGroups();
Saurav Dasd84178f2014-09-29 17:48:54 -0700293 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700294 break;
295 case SET_GROUPS:
296 driverState = DriverState.VERIFY_GROUPS;
297 verifyGroups();
298 break;
299 case VERIFY_GROUPS:
300 driverState = DriverState.SET_ADJACENCY_LABELS;
301 assignAdjacencyLabels();
302 break;
303 case SET_ADJACENCY_LABELS:
304 driverState = DriverState.EXIT;
305 driverHandshakeComplete.set(true);
306 break;
307 case EXIT:
308 default:
309 driverState = DriverState.EXIT;
310 log.error("Driver handshake has exited for sw: {}", getStringId());
311 }
312 }
313
314 void processOFMessage(IOFSwitch sw, OFMessage m) throws IOException {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700315 switch (m.getType()) {
316 case BARRIER_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700317 processBarrierReply(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700318 break;
319
320 case ERROR:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700321 processErrorMessage(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700322 break;
323
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700324 case GET_ASYNC_REPLY:
325 OFAsyncGetReply asrep = (OFAsyncGetReply) m;
326 decodeAsyncGetReply(asrep);
327 break;
328
329 case PACKET_IN:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700330 // not ready to handle packet-ins
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700331 break;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700332
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700333 case QUEUE_GET_CONFIG_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700334 // not doing queue config yet
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700335 break;
336
337 case STATS_REPLY:
338 processStatsReply((OFStatsReply) m);
339 break;
340
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700341 case ROLE_REPLY: // channelHandler should handle this
342 case PORT_STATUS: // channelHandler should handle this
343 case FEATURES_REPLY: // don't care
344 case FLOW_REMOVED: // don't care
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700345 default:
346 log.debug("Received message {} during switch-driver subhandshake "
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700347 + "from switch {} ... Ignoring message", m, sw.getStringId());
348 }
349 }
350
351 private void processStatsReply(OFStatsReply sr) {
352 switch (sr.getStatsType()) {
353 case AGGREGATE:
354 break;
355 case DESC:
356 break;
357 case EXPERIMENTER:
358 break;
359 case FLOW:
360 break;
361 case GROUP_DESC:
362 processGroupDesc((OFGroupDescStatsReply) sr);
363 break;
364 case GROUP_FEATURES:
365 processGroupFeatures((OFGroupFeaturesStatsReply) sr);
366 break;
367 case METER_CONFIG:
368 break;
369 case METER_FEATURES:
370 break;
371 case PORT_DESC:
372 break;
373 case TABLE_FEATURES:
374 break;
375 default:
376 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700377
378 }
379 }
380
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700381 private void processErrorMessage(OFMessage m) {
382 log.error("Switch {} Error {} in DriverState", getStringId(),
383 (OFErrorMsg) m, driverState);
384 }
385
386 private void processBarrierReply(OFMessage m) throws IOException {
387 if (m.getXid() == barrierXidToWaitFor) {
388 // Driver state-machine progresses to the next state.
389 // If Barrier messages is not received, then eventually
390 // the ChannelHandler state machine will timeout, and the switch
391 // will be disconnected.
392 nextDriverState();
393 } else {
394 log.error("Received incorrect barrier-message xid {} (expected: {}) in "
395 + "switch-driver state {} for switch {}", m, barrierXidToWaitFor,
396 driverState, getStringId());
397 }
398 }
399
400 private void processGroupDesc(OFGroupDescStatsReply gdsr) {
401 log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
402 try {
403 nextDriverState();
404 } catch (IOException e) {
405 // TODO Auto-generated catch block
406 e.printStackTrace();
407 }
408 }
409
410 // *****************************
411 // Utility methods
412 // *****************************
413
414 void setTableMissEntries() throws IOException {
415 // set all table-miss-entries
416 populateTableMissEntry(TABLE_VLAN, true, false, false, -1);
417 populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
418 populateTableMissEntry(TABLE_IPv4_UNICAST, false, true, true,
419 TABLE_ACL);
420 populateTableMissEntry(TABLE_MPLS, false, true, true,
421 TABLE_ACL);
422 populateTableMissEntry(TABLE_ACL, false, false, false, -1);
423 }
424
Saurav Dasd84178f2014-09-29 17:48:54 -0700425 private void sendHandshakeBarrier() throws IOException {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700426 long xid = getNextTransactionId();
427 barrierXidToWaitFor = xid;
428 OFBarrierRequest br = getFactory()
429 .buildBarrierRequest()
430 .setXid(xid)
431 .build();
432 write(br, null);
433 }
434
435 /**
436 * Adds a table-miss-entry to a pipeline table.
437 * <p>
438 * The table-miss-entry can be added with 'write-actions' or
439 * 'apply-actions'. It can also add a 'goto-table' instruction. By default
440 * if none of the booleans in the call are set, then the table-miss entry is
441 * added with no instructions, which means that if a packet hits the
442 * table-miss-entry, pipeline execution will stop, and the action set
443 * associated with the packet will be executed.
444 *
445 * @param tableToAdd the table to where the table-miss-entry will be added
446 * @param toControllerNow as an APPLY_ACTION instruction
447 * @param toControllerWrite as a WRITE_ACTION instruction
448 * @param toTable as a GOTO_TABLE instruction
449 * @param tableToSend the table to send as per the GOTO_TABLE instruction it
450 * needs to be set if 'toTable' is true. Ignored of 'toTable' is
451 * false.
452 * @throws IOException
453 */
454 @SuppressWarnings("unchecked")
455 private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
456 boolean toControllerWrite,
457 boolean toTable, int tableToSend) throws IOException {
458 OFOxmList oxmList = OFOxmList.EMPTY;
459 OFMatchV3 match = factory.buildMatchV3()
460 .setOxmList(oxmList)
461 .build();
462 OFAction outc = factory.actions()
463 .buildOutput()
464 .setPort(OFPort.CONTROLLER)
465 .setMaxLen(OFPCML_NO_BUFFER)
466 .build();
467 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
468 if (toControllerNow) {
469 // table-miss instruction to send to controller immediately
470 OFInstruction instr = factory.instructions()
471 .buildApplyActions()
472 .setActions(Collections.singletonList(outc))
473 .build();
474 instructions.add(instr);
475 }
476
477 if (toControllerWrite) {
478 // table-miss instruction to write-action to send to controller
479 // this will be executed whenever the action-set gets executed
480 OFInstruction instr = factory.instructions()
481 .buildWriteActions()
482 .setActions(Collections.singletonList(outc))
483 .build();
484 instructions.add(instr);
485 }
486
487 if (toTable) {
488 // table-miss instruction to goto-table x
489 OFInstruction instr = factory.instructions()
490 .gotoTable(TableId.of(tableToSend));
491 instructions.add(instr);
492 }
493
494 if (!toControllerNow && !toControllerWrite && !toTable) {
495 // table-miss has no instruction - at which point action-set will be
496 // executed - if there is an action to output/group in the action
497 // set
498 // the packet will be sent there, otherwise it will be dropped.
499 instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
500 }
501
502 OFMessage tableMissEntry = factory.buildFlowAdd()
503 .setTableId(TableId.of(tableToAdd))
504 .setMatch(match) // match everything
505 .setInstructions(instructions)
506 .setPriority(MIN_PRIORITY)
507 .setBufferId(OFBufferId.NO_BUFFER)
508 .setIdleTimeout(0)
509 .setHardTimeout(0)
510 .setXid(getNextTransactionId())
511 .build();
512 write(tableMissEntry, null);
513 }
514
515 private void getNetworkConfig() {
516 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
517 SwitchConfigStatus scs = ncs.checkSwitchConfig(new Dpid(getId()));
518 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
519 srConfig = (SegmentRouterConfig) scs.getSwitchConfig();
520 } else {
521 log.error("Switch not configured as Segment-Router");
522 }
523
524 List<LinkConfig> linkConfigList = ncs.getConfiguredAllowedLinks();
525 setNeighbors(linkConfigList);
526 }
527
528 private void populateTableVlan() throws IOException {
529 List<OFMessage> msglist = new ArrayList<OFMessage>();
530 for (OFPortDesc p : getPorts()) {
531 int pnum = p.getPortNo().getPortNumber();
532 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
533 OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
534 OFOxmVlanVid oxv = factory.oxms()
535 .vlanVid(OFVlanVidMatch.UNTAGGED);
536 OFOxmList oxmList = OFOxmList.of(oxp, oxv);
537 OFMatchV3 match = factory.buildMatchV3()
538 .setOxmList(oxmList).build();
539
540 // TODO: match on vlan-tagged packets for vlans configured on
541 // subnet ports and strip-vlan
542
543 // Do not need to add vlans
544 /*int vlanid = getVlanConfig(pnum);
545 OFOxmVlanVid vidToSet = factory.oxms()
546 .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
547 OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
548 OFAction setVlan = factory.actions().setField(vidToSet);
549 List<OFAction> actionlist = new ArrayList<OFAction>();
550 actionlist.add(pushVlan);
551 actionlist.add(setVlan);
552 OFInstruction appAction = factory.instructions().buildApplyActions()
553 .setActions(actionlist).build();*/
554
555 OFInstruction gotoTbl = factory.instructions().buildGotoTable()
556 .setTableId(TableId.of(TABLE_TMAC)).build();
557 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
558 // instructions.add(appAction);
559 instructions.add(gotoTbl);
560 OFMessage flowEntry = factory.buildFlowAdd()
561 .setTableId(TableId.of(TABLE_VLAN))
562 .setMatch(match)
563 .setInstructions(instructions)
564 .setPriority(1000) // does not matter - all rules
565 // exclusive
566 .setBufferId(OFBufferId.NO_BUFFER)
567 .setIdleTimeout(0)
568 .setHardTimeout(0)
569 .setXid(getNextTransactionId())
570 .build();
571 msglist.add(flowEntry);
572 }
573 }
574 write(msglist);
575 log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId());
576 }
577
578 private void populateTableTMac() throws IOException {
579 // match for router-mac and ip-packets
580 OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
581 OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr());
582 OFOxmList oxmListIp = OFOxmList.of(dmac, oxe);
583 OFMatchV3 matchIp = factory.buildMatchV3()
584 .setOxmList(oxmListIp).build();
585 OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
586 .setTableId(TableId.of(TABLE_IPv4_UNICAST)).build();
587 List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
588 OFMessage ipEntry = factory.buildFlowAdd()
589 .setTableId(TableId.of(TABLE_TMAC))
590 .setMatch(matchIp)
591 .setInstructions(instructionsIp)
592 .setPriority(1000) // strict priority required lower than
593 // multicastMac
594 .setBufferId(OFBufferId.NO_BUFFER)
595 .setIdleTimeout(0)
596 .setHardTimeout(0)
597 .setXid(getNextTransactionId())
598 .build();
599
600 // match for router-mac and mpls packets
601 OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
602 OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls);
603 OFMatchV3 matchMpls = factory.buildMatchV3()
604 .setOxmList(oxmListMpls).build();
605 OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
606 .setTableId(TableId.of(TABLE_MPLS)).build();
607 List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
608 OFMessage mplsEntry = factory.buildFlowAdd()
609 .setTableId(TableId.of(TABLE_TMAC))
610 .setMatch(matchMpls)
611 .setInstructions(instructionsMpls)
612 .setPriority(1001) // strict priority required lower than
613 // multicastMac
614 .setBufferId(OFBufferId.NO_BUFFER)
615 .setIdleTimeout(0)
616 .setHardTimeout(0)
617 .setXid(getNextTransactionId())
618 .build();
619
620 log.debug("Adding termination-mac-rules in sw {}", getStringId());
621 List<OFMessage> msglist = new ArrayList<OFMessage>(2);
622 msglist.add(ipEntry);
623 msglist.add(mplsEntry);
624 write(msglist);
625 }
626
627 private MacAddress getRouterMacAddr() {
628 if (srConfig != null) {
629 return MacAddress.of(srConfig.getRouterMac());
630 } else {
631 // return a dummy mac address - it will not be used
632 return MacAddress.of("00:00:00:00:00:00");
633 }
634 }
635
636 private MacAddress getNeighborRouterMacAddress(Dpid ndpid) {
637 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
638 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
639 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
640 return MacAddress.of(((SegmentRouterConfig) scs.getSwitchConfig())
641 .getRouterMac());
642 } else {
643 // return a dummy mac address - it will not be used
644 return MacAddress.of("00:00:00:00:00:00");
645 }
646 }
647
648 private void setNeighbors(List<LinkConfig> linkConfigList) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700649 for (LinkConfig lg : linkConfigList) {
650 if (!lg.getType().equals(NetworkConfigManager.PKT_LINK)) {
Saurav Das80d17392014-10-01 10:24:56 -0700651 continue;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700652 }
653 PktLinkConfig plg = (PktLinkConfig) lg;
654 if (plg.getDpid1() == getId()) {
655 addNeighborAtPort(new Dpid(plg.getDpid2()),
656 PortNumber.uint32(plg.getPort1()));
657 } else if (plg.getDpid2() == getId()) {
658 addNeighborAtPort(new Dpid(plg.getDpid1()),
659 PortNumber.uint32(plg.getPort2()));
660 }
661 }
662 }
663
664 private void addNeighborAtPort(Dpid neighborDpid, PortNumber portToNeighbor) {
665 if (neighbors.get(neighborDpid) != null) {
666 neighbors.get(neighborDpid).add(portToNeighbor);
667 } else {
668 Set<PortNumber> ports = new HashSet<PortNumber>();
669 ports.add(portToNeighbor);
670 neighbors.put(neighborDpid, ports);
671 }
672 }
673
674 /**
675 * createGroups creates ECMP groups for all ports on this router connected
676 * to other routers (in the OF network). The information for ports is
677 * gleaned from the configured links. If no links are configured no groups
678 * will be created, and it is up to the caller of the IOF13Switch API to
679 * create groups.
680 * <p>
681 * By default all ports connected to the same neighbor router will be part
682 * of the same ECMP group. In addition, groups will be created for all
683 * possible combinations of neighbor routers.
684 * <p>
685 * For example, consider this router (R0) connected to 3 neighbors (R1, R2,
686 * and R3). The following groups will be created in R0:
687 * <li>1) all ports to R1,
688 * <li>2) all ports to R2,
689 * <li>3) all ports to R3,
690 * <li>4) all ports to R1 and R2
691 * <li>5) all ports to R1 and R3
692 * <li>6) all ports to R2 and R3
693 * <li>7) all ports to R1, R2, and R3
694 */
695 private void createGroups() {
696 Set<Dpid> dpids = neighbors.keySet();
697 if (dpids == null || dpids.isEmpty()) {
698 return;
699 }
700 // temp map of ecmp groupings
701 /* Map<NeighborSet, List<BucketInfo>> temp =
702 new HashMap<NeighborSet, List<BucketInfo>>();
703 */
704 // get all combinations of neighbors
705 Set<Set<Dpid>> powerSet = Sets.powerSet(dpids);
706 int groupid = 1;
707 for (Set<Dpid> combo : powerSet) {
708 if (combo.isEmpty()) {
709 // eliminate the empty set in the power set
710 continue;
711 }
712 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
713 NeighborSet ns = new NeighborSet();
714 for (Dpid d : combo) {
715 ns.addDpid(d);
716 for (PortNumber sp : neighbors.get(d)) {
717 BucketInfo b = new BucketInfo(d,
718 MacAddress.of(srConfig.getRouterMac()),
719 getNeighborRouterMacAddress(d), sp);
720 buckets.add(b);
721 }
722 }
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700723
724 for (Dpid d : combo) {
725 for (PortNumber sp : neighbors.get(d)) {
726 ArrayList<NeighborSet> portNeighborSets =
727 portNeighborSetMap.get(sp);
728 if (portNeighborSets == null) {
729 portNeighborSets = new ArrayList<NeighborSet>();
730 portNeighborSets.add(ns);
731 portNeighborSetMap.put(sp, portNeighborSets);
732 }
733 else
734 portNeighborSets.add(ns);
735 }
736 }
737
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700738 EcmpInfo ecmpInfo = new EcmpInfo(groupid++, buckets);
739 setEcmpGroup(ecmpInfo);
740 ecmpGroups.put(ns, ecmpInfo);
741 log.debug("Creating ecmp group in sw {}: {}", getStringId(), ecmpInfo);
742 }
743 }
744
745 private class EcmpInfo {
746 int groupId;
747 List<BucketInfo> buckets;
748
749 EcmpInfo(int gid, List<BucketInfo> bucketInfos) {
750 groupId = gid;
751 buckets = bucketInfos;
752 }
753
754 @Override
755 public String toString() {
756 return "groupId: " + groupId + ", buckets: " + buckets;
757 }
758 }
759
760 private class BucketInfo {
761 Dpid neighborDpid;
762 MacAddress srcMac;
763 MacAddress dstMac;
764 PortNumber outport;
765
766 BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac, PortNumber p) {
767 neighborDpid = nDpid;
768 srcMac = smac;
769 dstMac = dmac;
770 outport = p;
771 }
772
773 @Override
774 public String toString() {
775 return " {neighborDpid: " + neighborDpid + ", dstMac: " + dstMac +
776 ", srcMac: " + srcMac + ", outport: " + outport + "}";
777 }
778 }
779
780 private void setEcmpGroup(EcmpInfo ecmpInfo) {
781 List<OFMessage> msglist = new ArrayList<OFMessage>();
782 OFGroup group = OFGroup.of(ecmpInfo.groupId);
783
784 List<OFBucket> buckets = new ArrayList<OFBucket>();
785 for (BucketInfo b : ecmpInfo.buckets) {
786 OFOxmEthDst dmac = factory.oxms()
787 .ethDst(b.dstMac);
788 OFAction setDA = factory.actions().buildSetField()
789 .setField(dmac).build();
Saurav Das0a344b02014-09-26 14:18:52 -0700790 OFOxmEthSrc smac = factory.oxms()
791 .ethSrc(b.srcMac);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700792 OFAction setSA = factory.actions().buildSetField()
793 .setField(smac).build();
794 OFAction outp = factory.actions().buildOutput()
795 .setPort(OFPort.of(b.outport.shortValue()))
796 .build();
797 List<OFAction> actions = new ArrayList<OFAction>();
798 actions.add(setSA);
799 actions.add(setDA);
800 actions.add(outp);
801 OFBucket ofb = factory.buildBucket()
802 .setWeight(1)
803 .setActions(actions)
804 .build();
805 buckets.add(ofb);
806 }
807
808 OFMessage gm = factory.buildGroupAdd()
809 .setGroup(group)
810 .setBuckets(buckets)
811 .setGroupType(OFGroupType.SELECT)
812 .setXid(getNextTransactionId())
813 .build();
814 msglist.add(gm);
815 try {
816 write(msglist);
817 } catch (IOException e) {
818 // TODO Auto-generated catch block
819 e.printStackTrace();
820 }
821 }
822
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -0700823 private void modifyEcmpGroup(EcmpInfo ecmpInfo) {
824 List<OFMessage> msglist = new ArrayList<OFMessage>();
825 OFGroup group = OFGroup.of(ecmpInfo.groupId);
826
827 List<OFBucket> buckets = new ArrayList<OFBucket>();
828 for (BucketInfo b : ecmpInfo.buckets) {
829 OFOxmEthDst dmac = factory.oxms()
830 .ethDst(b.dstMac);
831 OFAction setDA = factory.actions().buildSetField()
832 .setField(dmac).build();
833 OFOxmEthSrc smac = factory.oxms()
834 .ethSrc(b.srcMac);
835 OFAction setSA = factory.actions().buildSetField()
836 .setField(smac).build();
837 OFAction outp = factory.actions().buildOutput()
838 .setPort(OFPort.of(b.outport.shortValue()))
839 .build();
840 List<OFAction> actions = new ArrayList<OFAction>();
841 actions.add(setSA);
842 actions.add(setDA);
843 actions.add(outp);
844 OFBucket ofb = factory.buildBucket()
845 .setWeight(1)
846 .setActions(actions)
847 .build();
848 buckets.add(ofb);
849 }
850
851 OFMessage gm = factory.buildGroupModify()
852 .setGroup(group)
853 .setBuckets(buckets)
854 .setGroupType(OFGroupType.SELECT)
855 .setXid(getNextTransactionId())
856 .build();
857 msglist.add(gm);
858 try {
859 write(msglist);
860 } catch (IOException e) {
861 // TODO Auto-generated catch block
862 e.printStackTrace();
863 }
864 }
865
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700866 private void verifyGroups() throws IOException {
867 sendGroupDescRequest();
868 }
869
870 private void sendGroupDescRequest() throws IOException {
871 OFMessage gdr = factory.buildGroupDescStatsRequest()
872 .setXid(getNextTransactionId())
873 .build();
874 write(gdr, null);
875 }
876
877 private void assignAdjacencyLabels() {
878 // TODO
879 try {
880 nextDriverState();
881 } catch (IOException e) {
882 // TODO Auto-generated catch block
883 e.printStackTrace();
884 }
885 }
886
Saurav Das1cd10152014-09-26 09:38:07 -0700887 private OFAction getOFAction(Action action) {
888 OFAction ofAction = null;
889 if (action instanceof OutputAction) {
890 OutputAction outputAction = (OutputAction) action;
891 OFPort port = OFPort.of((int) outputAction.getPortNumber().value());
892 ofAction = factory.actions().output(port, Short.MAX_VALUE);
893 } else if (action instanceof ModifyDstMacAction) {
894 long dstMac = ((ModifyDstMacAction) action).getDstMac().toLong();
895 OFOxmEthDst dmac = factory.oxms()
896 .ethDst(MacAddress.of(dstMac));
897 ofAction = factory.actions().buildSetField()
898 .setField(dmac).build();
899 } else if (action instanceof ModifySrcMacAction) {
900 long srcMac = ((ModifySrcMacAction) action).getSrcMac().toLong();
901 OFOxmEthSrc smac = factory.oxms()
902 .ethSrc(MacAddress.of(srcMac));
903 ofAction = factory.actions().buildSetField()
904 .setField(smac).build();
905 } else if (action instanceof PushMplsAction) {
906 ofAction = factory.actions().pushMpls(EthType.MPLS_UNICAST);
907 } else if (action instanceof SetMplsIdAction) {
908 int labelid = ((SetMplsIdAction) action).getMplsId();
909 OFOxmMplsLabel lid = factory.oxms()
910 .mplsLabel(U32.of(labelid));
911 ofAction = factory.actions().buildSetField()
912 .setField(lid).build();
913 } else if (action instanceof PopMplsAction) {
914 EthType ethertype = ((PopMplsAction) action).getEthType();
915 ofAction = factory.actions().popMpls(ethertype);
916 } else if (action instanceof GroupAction) {
917 NeighborSet ns = ((GroupAction) action).getDpids();
918 EcmpInfo ei = ecmpGroups.get(ns);
919 if (ei != null) {
920 int gid = ei.groupId;
921 ofAction = factory.actions().buildGroup()
922 .setGroup(OFGroup.of(gid))
923 .build();
924 } else {
925 log.error("Unable to find ecmp group for neighbors {} at "
926 + "switch {}", ns, getStringId());
927 }
928 } else if (action instanceof DecNwTtlAction) {
929 ofAction = factory.actions().decNwTtl();
930 } else if (action instanceof DecMplsTtlAction) {
931 ofAction = factory.actions().decMplsTtl();
932 } else if (action instanceof CopyTtlInAction) {
933 ofAction = factory.actions().copyTtlIn();
934 } else if (action instanceof CopyTtlOutAction) {
935 ofAction = factory.actions().copyTtlOut();
936 } else {
937 log.warn("Unsupported Action type: {}", action.getClass().getName());
938 return null;
939 }
940
941 // not supported by loxigen
942 // OFAction setBos =
943 // factory.actions().buildSetField().setField(bos).build();
944
945 return ofAction;
946 }
947
Saurav Das0a344b02014-09-26 14:18:52 -0700948 private OFMessage getIpEntry(MatchActionOperationEntry mao) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700949 MatchAction ma = mao.getTarget();
950 Operator op = mao.getOperator();
951 Ipv4Match ipm = (Ipv4Match) ma.getMatch();
952
953 // set match
954 IPv4Net ipdst = ipm.getDestination();
955 OFOxmEthType ethTypeIp = factory.oxms()
956 .ethType(EthType.IPv4);
957 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
958 .ipv4DstMasked(
959 IPv4Address.of(ipdst.address().value()),
960 IPv4Address.ofCidrMaskLength(ipdst.prefixLen())
961 );
962 OFOxmList oxmList = OFOxmList.of(ethTypeIp, ipPrefix);
963 OFMatchV3 match = factory.buildMatchV3()
964 .setOxmList(oxmList).build();
965
966 // set actions
967 List<OFAction> writeActions = new ArrayList<OFAction>();
968 for (Action action : ma.getActions()) {
Saurav Das1cd10152014-09-26 09:38:07 -0700969 OFAction ofAction = getOFAction(action);
970 if (ofAction != null) {
971 writeActions.add(ofAction);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700972 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700973 }
974
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700975 // set instructions
976 OFInstruction writeInstr = factory.instructions().buildWriteActions()
977 .setActions(writeActions).build();
978 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
979 .setTableId(TableId.of(TABLE_ACL)).build();
980 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
981 instructions.add(writeInstr);
982 instructions.add(gotoInstr);
983
Saurav Das1cd10152014-09-26 09:38:07 -0700984 // set flow priority to emulate longest prefix match
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700985 int priority = ipdst.prefixLen() * PRIORITY_MULTIPLIER;
986 if (ipdst.prefixLen() == (short) 32) {
987 priority = MAX_PRIORITY;
988 }
989
Saurav Dasbc594a42014-09-25 20:13:50 -0700990 // set flow-mod
Saurav Dase972b3a2014-09-26 15:41:06 -0700991 OFFlowMod.Builder fmBuilder = null;
992 switch (op) {
993 case ADD:
994 fmBuilder = factory.buildFlowAdd();
995 break;
996 case REMOVE:
997 fmBuilder = factory.buildFlowDeleteStrict();
998 break;
Sangho Shin5be3e532014-10-03 17:20:58 -0700999 case MODIFY: // TODO
1000 fmBuilder = factory.buildFlowModifyStrict();
1001 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001002 default:
1003 log.warn("Unsupported MatchAction Operator: {}", op);
1004 return null;
Saurav Dasbc594a42014-09-25 20:13:50 -07001005 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001006 OFMessage ipFlow = fmBuilder
1007 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
1008 .setMatch(match)
1009 .setInstructions(instructions)
1010 .setPriority(priority)
1011 .setBufferId(OFBufferId.NO_BUFFER)
1012 .setIdleTimeout(0)
1013 .setHardTimeout(0)
1014 .setXid(getNextTransactionId())
1015 .build();
Saurav Dasbc594a42014-09-25 20:13:50 -07001016 log.debug("{} ip-rule {}-{} in sw {}",
1017 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1018 match, writeActions,
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001019 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001020 return ipFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001021 }
1022
Saurav Das0a344b02014-09-26 14:18:52 -07001023 private OFMessage getMplsEntry(MatchActionOperationEntry mao) {
Saurav Das1cd10152014-09-26 09:38:07 -07001024 MatchAction ma = mao.getTarget();
1025 Operator op = mao.getOperator();
1026 MplsMatch mplsm = (MplsMatch) ma.getMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001027
Saurav Das1cd10152014-09-26 09:38:07 -07001028 // set match
1029 OFOxmEthType ethTypeMpls = factory.oxms()
1030 .ethType(EthType.MPLS_UNICAST);
1031 OFOxmMplsLabel labelid = factory.oxms()
1032 .mplsLabel(U32.of(mplsm.getMplsLabel()));
1033 OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid);
1034 OFMatchV3 matchlabel = factory.buildMatchV3()
1035 .setOxmList(oxmList).build();
1036
1037 // set actions
1038 List<OFAction> writeActions = new ArrayList<OFAction>();
1039 for (Action action : ma.getActions()) {
1040 OFAction ofAction = getOFAction(action);
1041 if (ofAction != null) {
1042 writeActions.add(ofAction);
1043 }
1044 }
1045
1046 // set instructions
1047 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1048 .setActions(writeActions).build();
1049 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1050 .setTableId(TableId.of(TABLE_ACL)).build();
1051 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1052 instructions.add(writeInstr);
1053 instructions.add(gotoInstr);
1054
Saurav Dase972b3a2014-09-26 15:41:06 -07001055 // set flow-mod
1056 OFFlowMod.Builder fmBuilder = null;
1057 switch (op) {
1058 case ADD:
1059 fmBuilder = factory.buildFlowAdd();
1060 break;
1061 case REMOVE:
1062 fmBuilder = factory.buildFlowDeleteStrict();
1063 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001064 case MODIFY: // TODO
1065 fmBuilder = factory.buildFlowModifyStrict();
1066 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001067 default:
1068 log.warn("Unsupported MatchAction Operator: {}", op);
1069 return null;
Saurav Das1cd10152014-09-26 09:38:07 -07001070 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001071
1072 OFMessage mplsFlow = fmBuilder
1073 .setTableId(TableId.of(TABLE_MPLS))
1074 .setMatch(matchlabel)
1075 .setInstructions(instructions)
1076 .setPriority(MAX_PRIORITY) // exact match and exclusive
1077 .setBufferId(OFBufferId.NO_BUFFER)
1078 .setIdleTimeout(0)
1079 .setHardTimeout(0)
1080 .setXid(getNextTransactionId())
1081 .build();
Saurav Das1cd10152014-09-26 09:38:07 -07001082 log.debug("{} mpls-rule {}-{} in sw {}",
1083 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1084 matchlabel, writeActions,
1085 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001086 return mplsFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001087 }
1088
Saurav Das0a344b02014-09-26 14:18:52 -07001089 private OFMessage getAclEntry(MatchActionOperationEntry mao) {
Saurav Dase972b3a2014-09-26 15:41:06 -07001090 MatchAction ma = mao.getTarget();
1091 Operator op = mao.getOperator();
1092 PacketMatch packetMatch = (PacketMatch) ma.getMatch();
1093 Builder matchBuilder = factory.buildMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001094
Saurav Dase972b3a2014-09-26 15:41:06 -07001095 // set match
1096 int inport = 0;
1097 if (ma.getSwitchPort() != null) {
1098 inport = (int) ma.getSwitchPort().getPortNumber().value();
1099 }
1100 final MACAddress srcMac = packetMatch.getSrcMacAddress();
1101 final MACAddress dstMac = packetMatch.getDstMacAddress();
1102 final Short etherType = packetMatch.getEtherType();
1103 final IPv4Net srcIp = packetMatch.getSrcIpAddress();
1104 final IPv4Net dstIp = packetMatch.getDstIpAddress();
1105 final Byte ipProto = packetMatch.getIpProtocolNumber();
1106 final Short srcTcpPort = packetMatch.getSrcTcpPortNumber();
1107 final Short dstTcpPort = packetMatch.getDstTcpPortNumber();
1108 if (inport > 0) {
1109 matchBuilder.setExact(MatchField.IN_PORT,
1110 OFPort.of(inport));
1111 }
1112 if (srcMac != null) {
1113 matchBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(srcMac.toLong()));
1114 }
1115 if (dstMac != null) {
1116 matchBuilder.setExact(MatchField.ETH_DST, MacAddress.of(dstMac.toLong()));
1117 }
1118 if (etherType != null) {
1119 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(etherType));
1120 }
1121 if (srcIp != null) {
1122 matchBuilder.setMasked(MatchField.IPV4_SRC,
1123 IPv4Address.of(srcIp.address().value())
1124 .withMaskOfLength(srcIp.prefixLen()));
1125 }
1126 if (dstIp != null) {
1127 matchBuilder.setMasked(MatchField.IPV4_DST,
1128 IPv4Address.of(dstIp.address().value())
1129 .withMaskOfLength(dstIp.prefixLen()));
1130 }
1131 if (ipProto != null) {
1132 matchBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(ipProto));
1133 }
1134 if (srcTcpPort != null) {
1135 matchBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(srcTcpPort));
1136 }
1137 if (dstTcpPort != null) {
1138 matchBuilder.setExact(MatchField.TCP_DST, TransportPort.of(dstTcpPort));
1139 }
1140
1141 // set actions
1142 List<OFAction> applyActions = new ArrayList<OFAction>();
1143 for (Action action : ma.getActions()) {
1144 OFAction ofAction = getOFAction(action);
1145 if (ofAction != null) {
1146 applyActions.add(ofAction);
1147 }
1148 }
1149
1150 // set instructions
1151 OFInstruction clearInstr = factory.instructions().clearActions();
1152 OFInstruction applyInstr = factory.instructions().buildApplyActions()
1153 .setActions(applyActions).build();
1154 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1155 instructions.add(clearInstr);
1156 instructions.add(applyInstr);
1157
1158 // set flow-mod
1159 OFFlowMod.Builder fmBuilder = null;
1160 switch (op) {
1161 case ADD:
1162 fmBuilder = factory.buildFlowAdd();
1163 break;
1164 case REMOVE:
1165 fmBuilder = factory.buildFlowDeleteStrict();
1166 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001167 case MODIFY: // TODO
1168 fmBuilder = factory.buildFlowModifyStrict();
1169 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001170 default:
1171 log.warn("Unsupported MatchAction Operator: {}", op);
1172 return null;
1173 }
1174
1175 OFMessage aclFlow = fmBuilder
1176 .setTableId(TableId.of(TABLE_ACL))
1177 .setMatch(matchBuilder.build())
1178 .setInstructions(instructions)
1179 .setPriority(MAX_PRIORITY / 2) // TODO: wrong - should be MA
1180 // priority
1181 .setBufferId(OFBufferId.NO_BUFFER)
1182 .setIdleTimeout(0)
1183 .setHardTimeout(0)
1184 .setXid(getNextTransactionId())
1185 .build();
Saurav Das0a344b02014-09-26 14:18:52 -07001186 return aclFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001187 }
1188
1189 // *****************************
1190 // IOF13Switch
1191 // *****************************
1192
1193 @Override
1194 public void pushFlow(MatchActionOperationEntry matchActionOp) throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001195 OFMessage ofm = getFlow(matchActionOp);
1196 if (ofm != null) {
1197 write(Collections.singletonList(ofm));
1198 }
1199 }
1200
1201 private OFMessage getFlow(MatchActionOperationEntry matchActionOp) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001202 final MatchAction matchAction = matchActionOp.getTarget();
1203 final Match match = matchAction.getMatch();
1204 if (match instanceof Ipv4Match) {
Saurav Das0a344b02014-09-26 14:18:52 -07001205 return getIpEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001206 } else if (match instanceof MplsMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001207 return getMplsEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001208 } else if (match instanceof PacketMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001209 return getAclEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001210 } else {
1211 log.error("Unknown match type {} pushed to switch {}", match,
1212 getStringId());
1213 }
Saurav Das0a344b02014-09-26 14:18:52 -07001214 return null;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001215 }
1216
1217 @Override
1218 public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps)
1219 throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001220 List<OFMessage> flowMods = new ArrayList<OFMessage>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001221 for (MatchActionOperationEntry matchActionOp : matchActionOps) {
Saurav Das0a344b02014-09-26 14:18:52 -07001222 OFMessage ofm = getFlow(matchActionOp);
1223 if (ofm != null) {
1224 flowMods.add(ofm);
1225 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001226 }
Saurav Das0a344b02014-09-26 14:18:52 -07001227 write(flowMods);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001228 }
1229
1230 @Override
1231 public int getEcmpGroupId(NeighborSet ns) {
1232 EcmpInfo ei = ecmpGroups.get(ns);
1233 if (ei == null) {
1234 return -1;
1235 } else {
1236 return ei.groupId;
1237 }
1238 }
1239
1240 // *****************************
Saurav Das80d17392014-10-01 10:24:56 -07001241 // Unused
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001242 // *****************************
1243
Saurav Das80d17392014-10-01 10:24:56 -07001244 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001245 private void setAsyncConfig() throws IOException {
1246 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
1247 OFMessage setAC = null;
1248
1249 if (role == Role.MASTER) {
1250 setAC = factory.buildAsyncSet()
1251 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
1252 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
1253 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
1254 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1255 .setPacketInMaskSlave(SET_ALL_SLAVE)
1256 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1257 .setXid(getNextTransactionId())
1258 .build();
1259 } else if (role == Role.EQUAL) {
1260 setAC = factory.buildAsyncSet()
1261 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
1262 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
1263 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
1264 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1265 .setPacketInMaskSlave(SET_ALL_SLAVE)
1266 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1267 .setXid(getNextTransactionId())
1268 .build();
1269 }
1270 msglist.add(setAC);
1271
1272 OFMessage br = factory.buildBarrierRequest()
1273 .setXid(getNextTransactionId())
1274 .build();
1275 msglist.add(br);
1276
1277 OFMessage getAC = factory.buildAsyncGetRequest()
1278 .setXid(getNextTransactionId())
1279 .build();
1280 msglist.add(getAC);
1281
1282 write(msglist);
1283 }
1284
Saurav Das80d17392014-10-01 10:24:56 -07001285 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001286 private void decodeAsyncGetReply(OFAsyncGetReply rep) {
1287 long frm = rep.getFlowRemovedMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001288 long frs = rep.getFlowRemovedMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001289 long pim = rep.getPacketInMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001290 long pis = rep.getPacketInMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001291 long psm = rep.getPortStatusMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001292 long pss = rep.getPortStatusMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001293
1294 if (role == Role.MASTER || role == Role.EQUAL) { // should separate
1295 log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
1296 log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
1297 log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
1298 }
1299
1300 }
1301
Saurav Das80d17392014-10-01 10:24:56 -07001302 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001303 private void getTableFeatures() throws IOException {
1304 OFMessage gtf = factory.buildTableFeaturesStatsRequest()
1305 .setXid(getNextTransactionId())
1306 .build();
1307 write(gtf, null);
1308 }
1309
Saurav Das80d17392014-10-01 10:24:56 -07001310 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001311 private void sendGroupFeaturesRequest() throws IOException {
1312 OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
1313 .setXid(getNextTransactionId())
1314 .build();
1315 write(gfr, null);
1316 }
1317
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001318 private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
1319 log.info("Sw: {} Group Features {}", getStringId(), gfsr);
1320 }
1321
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001322}