blob: 88fd21c29d379390ecd7cc05178231ab52c309a7 [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 Vavilapallibb47e782014-10-09 18:16:35 -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;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -070014import java.util.concurrent.atomic.AtomicInteger;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070015
16import net.floodlightcontroller.core.IFloodlightProviderService.Role;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070017import net.floodlightcontroller.core.IOF13Switch;
18import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070019import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
20import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
21import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
22import net.floodlightcontroller.core.internal.OFSwitchImplBase;
Saurav Dase972b3a2014-09-26 15:41:06 -070023import net.floodlightcontroller.util.MACAddress;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -070024import net.floodlightcontroller.util.OrderedCollection;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070025import net.onrc.onos.core.configmanager.INetworkConfigService;
26import net.onrc.onos.core.configmanager.INetworkConfigService.NetworkConfigState;
27import net.onrc.onos.core.configmanager.INetworkConfigService.SwitchConfigStatus;
28import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -070029import net.onrc.onos.core.configmanager.NetworkConfig.SwitchConfig;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070030import net.onrc.onos.core.configmanager.NetworkConfigManager;
31import net.onrc.onos.core.configmanager.PktLinkConfig;
32import net.onrc.onos.core.configmanager.SegmentRouterConfig;
33import net.onrc.onos.core.matchaction.MatchAction;
34import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Saurav Dasbc594a42014-09-25 20:13:50 -070035import net.onrc.onos.core.matchaction.MatchActionOperations;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070036import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
37import net.onrc.onos.core.matchaction.action.Action;
38import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
39import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
40import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
41import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
42import net.onrc.onos.core.matchaction.action.GroupAction;
43import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
44import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
45import net.onrc.onos.core.matchaction.action.OutputAction;
46import net.onrc.onos.core.matchaction.action.PopMplsAction;
Saurav Dasa962a692014-10-17 14:52:38 -070047import net.onrc.onos.core.matchaction.action.PushMplsAction;
48import net.onrc.onos.core.matchaction.action.SetMplsBosAction;
49import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070050import net.onrc.onos.core.matchaction.match.Ipv4Match;
51import net.onrc.onos.core.matchaction.match.Match;
52import net.onrc.onos.core.matchaction.match.MplsMatch;
53import net.onrc.onos.core.matchaction.match.PacketMatch;
54import net.onrc.onos.core.util.Dpid;
55import net.onrc.onos.core.util.IPv4Net;
56import net.onrc.onos.core.util.PortNumber;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070057
58import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
59import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
60import org.projectfloodlight.openflow.protocol.OFBucket;
61import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
62import org.projectfloodlight.openflow.protocol.OFErrorMsg;
63import org.projectfloodlight.openflow.protocol.OFFactory;
Saurav Dase972b3a2014-09-26 15:41:06 -070064import org.projectfloodlight.openflow.protocol.OFFlowMod;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070065import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
66import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
67import org.projectfloodlight.openflow.protocol.OFGroupType;
68import org.projectfloodlight.openflow.protocol.OFMatchV3;
69import org.projectfloodlight.openflow.protocol.OFMessage;
70import org.projectfloodlight.openflow.protocol.OFOxmList;
71import org.projectfloodlight.openflow.protocol.OFPortDesc;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -070072import org.projectfloodlight.openflow.protocol.OFPortStatus;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070073import org.projectfloodlight.openflow.protocol.OFStatsReply;
74import org.projectfloodlight.openflow.protocol.action.OFAction;
75import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
Saurav Dase972b3a2014-09-26 15:41:06 -070076import org.projectfloodlight.openflow.protocol.match.Match.Builder;
77import org.projectfloodlight.openflow.protocol.match.MatchField;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070078import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
79import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
80import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
81import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
82import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
Saurav Dascc3e35f2014-10-10 15:33:32 -070083import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsBos;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070084import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
85import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
86import org.projectfloodlight.openflow.types.EthType;
87import org.projectfloodlight.openflow.types.IPv4Address;
Saurav Dase972b3a2014-09-26 15:41:06 -070088import org.projectfloodlight.openflow.types.IpProtocol;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070089import org.projectfloodlight.openflow.types.MacAddress;
Saurav Dascc3e35f2014-10-10 15:33:32 -070090import org.projectfloodlight.openflow.types.OFBooleanValue;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070091import org.projectfloodlight.openflow.types.OFBufferId;
92import org.projectfloodlight.openflow.types.OFGroup;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070093import org.projectfloodlight.openflow.types.OFPort;
94import org.projectfloodlight.openflow.types.OFVlanVidMatch;
95import org.projectfloodlight.openflow.types.TableId;
Saurav Dase972b3a2014-09-26 15:41:06 -070096import org.projectfloodlight.openflow.types.TransportPort;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070097import org.projectfloodlight.openflow.types.U32;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070098import org.projectfloodlight.openflow.util.HexString;
99
100/**
101 * OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
102 * Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
103 * Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
104 * None
105 */
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700106public class OFSwitchImplCPqD13 extends OFSwitchImplBase implements IOF13Switch {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700107 private AtomicBoolean driverHandshakeComplete;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700108 private AtomicBoolean haltStateMachine;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700109 private OFFactory factory;
110 private static final int OFPCML_NO_BUFFER = 0xffff;
111 // Configuration of asynch messages to controller. We need different
112 // asynch messages depending on role-equal or role-master.
113 // We don't want to get anything if we are slave.
114 private static final long SET_FLOW_REMOVED_MASK_MASTER = 0xf;
115 private static final long SET_PACKET_IN_MASK_MASTER = 0x7;
116 private static final long SET_PORT_STATUS_MASK_MASTER = 0x7;
117 private static final long SET_FLOW_REMOVED_MASK_EQUAL = 0x0;
118 private static final long SET_PACKET_IN_MASK_EQUAL = 0x0;
119 private static final long SET_PORT_STATUS_MASK_EQUAL = 0x7;
120 private static final long SET_ALL_SLAVE = 0x0;
121
122 private static final long TEST_FLOW_REMOVED_MASK = 0xf;
123 private static final long TEST_PACKET_IN_MASK = 0x7;
124 private static final long TEST_PORT_STATUS_MASK = 0x7;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700125
126 private static final int TABLE_VLAN = 0;
127 private static final int TABLE_TMAC = 1;
Sangho Shin01bca862014-09-12 11:18:59 -0700128 private static final int TABLE_IPv4_UNICAST = 2;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700129 private static final int TABLE_MPLS = 3;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700130 private static final int TABLE_ACL = 5;
131
132 private static final short MAX_PRIORITY = (short) 0xffff;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700133 private static final short PRIORITY_MULTIPLIER = (short) 2046;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700134 private static final short MIN_PRIORITY = 0x0;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700135
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700136 private long barrierXidToWaitFor = -1;
137 private DriverState driverState;
Jonathan Hartcb34f382014-08-12 21:11:03 -0700138 private final boolean usePipeline13;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700139 private SegmentRouterConfig srConfig;
140 private ConcurrentMap<Dpid, Set<PortNumber>> neighbors;
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700141 private ConcurrentMap<PortNumber, Dpid> portToNeighbors;
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700142 private List<Integer> segmentIds;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700143 private boolean isEdgeRouter;
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700144 private int sid;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700145 private ConcurrentMap<NeighborSet, EcmpInfo> ecmpGroups;
Sangho Shine020cc32014-10-20 13:28:02 -0700146 private ConcurrentMap<String, List<Integer>> tunnelGroups;
Srikanth Vavilapallib95e6e02014-10-02 13:56:39 -0700147 private ConcurrentMap<PortNumber, ArrayList<NeighborSet>> portNeighborSetMap;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700148 private AtomicInteger groupid;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700149
150
Jonathan Hartcb34f382014-08-12 21:11:03 -0700151
152 public OFSwitchImplCPqD13(OFDescStatsReply desc, boolean usePipeline13) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700153 super();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700154 haltStateMachine = new AtomicBoolean(false);
155 driverState = DriverState.INIT;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700156 driverHandshakeComplete = new AtomicBoolean(false);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700157 setSwitchDescription(desc);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700158 neighbors = new ConcurrentHashMap<Dpid, Set<PortNumber>>();
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700159 portToNeighbors = new ConcurrentHashMap<PortNumber, Dpid>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700160 ecmpGroups = new ConcurrentHashMap<NeighborSet, EcmpInfo>();
Srikanth Vavilapallib95e6e02014-10-02 13:56:39 -0700161 portNeighborSetMap =
162 new ConcurrentHashMap<PortNumber, ArrayList<NeighborSet>>();
Sangho Shine020cc32014-10-20 13:28:02 -0700163 tunnelGroups = new ConcurrentHashMap<String, List<Integer>>();
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700164 segmentIds = new ArrayList<Integer>();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700165 isEdgeRouter = false;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700166 groupid = new AtomicInteger(0);
Jonathan Hartcb34f382014-08-12 21:11:03 -0700167 this.usePipeline13 = usePipeline13;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700168 }
169
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700170 // *****************************
171 // OFSwitchImplBase
172 // *****************************
173
174
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700175 /* (non-Javadoc)
176 * @see java.lang.Object#toString()
177 */
178 @Override
179 public String toString() {
180 return "OFSwitchImplCPqD13 [" + ((channel != null)
181 ? channel.getRemoteAddress() : "?")
182 + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
183 }
184
185 @Override
186 public void startDriverHandshake() throws IOException {
187 log.debug("Starting driver handshake for sw {}", getStringId());
188 if (startDriverHandshakeCalled) {
189 throw new SwitchDriverSubHandshakeAlreadyStarted();
190 }
191 startDriverHandshakeCalled = true;
Jonathan Harta213bce2014-08-11 15:44:07 -0700192 factory = getFactory();
Jonathan Hartcb34f382014-08-12 21:11:03 -0700193 if (!usePipeline13) {
194 // Send packet-in to controller if a packet misses the first table
195 populateTableMissEntry(0, true, false, false, 0);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700196 driverHandshakeComplete.set(true);
Sangho Shin01bca862014-09-12 11:18:59 -0700197 } else {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700198 nextDriverState();
Sangho Shin01bca862014-09-12 11:18:59 -0700199 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700200 }
201
202 @Override
203 public boolean isDriverHandshakeComplete() {
Sangho Shin01bca862014-09-12 11:18:59 -0700204 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700205 throw new SwitchDriverSubHandshakeNotStarted();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700206 return driverHandshakeComplete.get();
207 }
208
209 @Override
210 public void processDriverHandshakeMessage(OFMessage m) {
Sangho Shin01bca862014-09-12 11:18:59 -0700211 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700212 throw new SwitchDriverSubHandshakeNotStarted();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700213 if (isDriverHandshakeComplete())
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700214 throw new SwitchDriverSubHandshakeCompleted(m);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700215 try {
216 processOFMessage(this, m);
217 } catch (IOException e) {
218 log.error("Error generated when processing OFMessage", e.getCause());
219 }
220 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700221
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700222 @Override
223 public String getSwitchDriverState() {
224 return driverState.toString();
225 }
226
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700227 public void removePortFromGroups(PortNumber port) {
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700228 /* FIX: removePortFromGroups is not working */
229
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700230 log.debug("removePortFromGroups: Remove port {} from Switch {}",
231 port, getStringId());
232 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
233 if (portNSSet == null)
234 {
235 /* No Groups are created with this port yet */
236 log.warn("removePortFromGroups: No groups exist with Switch {} port {}",
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700237 getStringId(), port);
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700238 return;
239 }
240 log.debug("removePortFromGroups: Neighborsets that the port {} is part"
241 + "of on Switch {} are {}",
242 port, getStringId(), portNSSet);
243
244 for (NeighborSet ns : portNSSet) {
245 /* Delete the first matched bucket */
246 EcmpInfo portEcmpInfo = ecmpGroups.get(ns);
247 Iterator<BucketInfo> it = portEcmpInfo.buckets.iterator();
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700248 log.debug("removePortFromGroups: Group {} on Switch {} has {} buckets",
249 portEcmpInfo.groupId, getStringId(),
250 portEcmpInfo.buckets.size());
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700251 while (it.hasNext()) {
252 BucketInfo bucket = it.next();
253 if (bucket.outport.equals(port)) {
254 it.remove();
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700255 }
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700256 }
257 log.debug("removePortFromGroups: Modifying Group on Switch {} "
258 + "and Neighborset {} with {}",
259 getStringId(), ns, portEcmpInfo);
260 modifyEcmpGroup(portEcmpInfo);
261 }
262 /* Don't delete the entry from portNeighborSetMap because
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700263 * when the port is up again this info is needed
264 */
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -0700265 return;
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700266 }
267
268 public void addPortToGroups(PortNumber port) {
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700269 log.debug("addPortToGroups: Add port {} to Switch {}",
270 port, getStringId());
271 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
272 if (portNSSet == null) {
273 /* Unknown Port */
274 log.warn("addPortToGroups: Switch {} port {} is unknown",
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700275 getStringId(), port);
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700276 return;
277 }
278 log.debug("addPortToGroups: Neighborsets that the port {} is part"
279 + "of on Switch {} are {}",
280 port, getStringId(), portNSSet);
281
282 Dpid neighborDpid = portToNeighbors.get(port);
283 for (NeighborSet ns : portNSSet) {
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700284 EcmpInfo portEcmpInfo = ecmpGroups.get(ns);
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700285 /* Find if this port is already part of any bucket
286 * in this group
287 * NOTE: This is needed because in some cases
288 * (such as for configured network nodes), both driver and
289 * application detect the network elements and creates the
290 * buckets in the same group. This check is to avoid
291 * duplicate bucket creation in such scenarios
292 */
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700293 List<BucketInfo> buckets = portEcmpInfo.buckets;
294 if (buckets == null) {
295 buckets = new ArrayList<BucketInfo>();
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700296 portEcmpInfo.buckets = buckets;
297 } else {
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700298 Iterator<BucketInfo> it = buckets.iterator();
299 boolean matchingBucketExist = false;
300 while (it.hasNext()) {
301 BucketInfo bucket = it.next();
302 if (bucket.outport.equals(port)) {
303 matchingBucketExist = true;
304 break;
305 }
306 }
307 if (matchingBucketExist) {
308 log.warn("addPortToGroups: On Switch {} duplicate "
309 + "portAdd is called for port {} with buckets {}",
310 getStringId(), port, buckets);
311 continue;
312 }
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700313 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700314 BucketInfo b = new BucketInfo(neighborDpid,
315 MacAddress.of(srConfig.getRouterMac()),
316 getNeighborRouterMacAddress(neighborDpid),
317 port,
318 ns.getEdgeLabel());
319 buckets.add(b);
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700320 log.debug("addPortToGroups: Modifying Group on Switch {} "
321 + "and Neighborset {} with {}",
322 getStringId(), ns, portEcmpInfo);
323 modifyEcmpGroup(portEcmpInfo);
324 }
325 return;
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700326 }
327
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700328 @Override
329 public OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps) {
330 OrderedCollection<PortChangeEvent> events = super.processOFPortStatus(ps);
331 for (PortChangeEvent e : events) {
332 switch (e.type) {
333 case DELETE:
334 case DOWN:
335 log.debug("processOFPortStatus: sw {} Port {} DOWN",
336 getStringId(), e.port.getPortNo().getPortNumber());
337 removePortFromGroups(PortNumber.uint32(
338 e.port.getPortNo().getPortNumber()));
339 break;
340 case UP:
341 log.debug("processOFPortStatus: sw {} Port {} UP",
342 getStringId(), e.port.getPortNo().getPortNumber());
343 addPortToGroups(PortNumber.uint32(
344 e.port.getPortNo().getPortNumber()));
345 }
346 }
347 return events;
348 }
349
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700350 // *****************************
351 // Driver handshake state-machine
352 // *****************************
353
354 enum DriverState {
355 INIT,
356 SET_TABLE_MISS_ENTRIES,
357 SET_TABLE_VLAN_TMAC,
358 SET_GROUPS,
359 VERIFY_GROUPS,
360 SET_ADJACENCY_LABELS,
361 EXIT
362 }
363
364 protected void nextDriverState() throws IOException {
365 DriverState currentState = driverState;
Saurav Das80d17392014-10-01 10:24:56 -0700366 if (haltStateMachine.get()) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700367 return;
Saurav Das80d17392014-10-01 10:24:56 -0700368 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700369 switch (currentState) {
370 case INIT:
371 driverState = DriverState.SET_TABLE_MISS_ENTRIES;
372 setTableMissEntries();
Saurav Dasd84178f2014-09-29 17:48:54 -0700373 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700374 break;
375 case SET_TABLE_MISS_ENTRIES:
376 driverState = DriverState.SET_TABLE_VLAN_TMAC;
377 getNetworkConfig();
378 populateTableVlan();
379 populateTableTMac();
Saurav Dasd84178f2014-09-29 17:48:54 -0700380 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700381 break;
382 case SET_TABLE_VLAN_TMAC:
383 driverState = DriverState.SET_GROUPS;
384 createGroups();
Saurav Dasd84178f2014-09-29 17:48:54 -0700385 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700386 break;
387 case SET_GROUPS:
388 driverState = DriverState.VERIFY_GROUPS;
389 verifyGroups();
390 break;
391 case VERIFY_GROUPS:
392 driverState = DriverState.SET_ADJACENCY_LABELS;
393 assignAdjacencyLabels();
394 break;
395 case SET_ADJACENCY_LABELS:
396 driverState = DriverState.EXIT;
397 driverHandshakeComplete.set(true);
398 break;
399 case EXIT:
400 default:
401 driverState = DriverState.EXIT;
402 log.error("Driver handshake has exited for sw: {}", getStringId());
403 }
404 }
405
406 void processOFMessage(IOFSwitch sw, OFMessage m) throws IOException {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700407 switch (m.getType()) {
408 case BARRIER_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700409 processBarrierReply(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700410 break;
411
412 case ERROR:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700413 processErrorMessage(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700414 break;
415
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700416 case GET_ASYNC_REPLY:
417 OFAsyncGetReply asrep = (OFAsyncGetReply) m;
418 decodeAsyncGetReply(asrep);
419 break;
420
421 case PACKET_IN:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700422 // not ready to handle packet-ins
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700423 break;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700424
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700425 case QUEUE_GET_CONFIG_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700426 // not doing queue config yet
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700427 break;
428
429 case STATS_REPLY:
430 processStatsReply((OFStatsReply) m);
431 break;
432
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700433 case ROLE_REPLY: // channelHandler should handle this
434 case PORT_STATUS: // channelHandler should handle this
435 case FEATURES_REPLY: // don't care
436 case FLOW_REMOVED: // don't care
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700437 default:
438 log.debug("Received message {} during switch-driver subhandshake "
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700439 + "from switch {} ... Ignoring message", m, sw.getStringId());
440 }
441 }
442
443 private void processStatsReply(OFStatsReply sr) {
444 switch (sr.getStatsType()) {
445 case AGGREGATE:
446 break;
447 case DESC:
448 break;
449 case EXPERIMENTER:
450 break;
451 case FLOW:
452 break;
453 case GROUP_DESC:
454 processGroupDesc((OFGroupDescStatsReply) sr);
455 break;
456 case GROUP_FEATURES:
457 processGroupFeatures((OFGroupFeaturesStatsReply) sr);
458 break;
459 case METER_CONFIG:
460 break;
461 case METER_FEATURES:
462 break;
463 case PORT_DESC:
464 break;
465 case TABLE_FEATURES:
466 break;
467 default:
468 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700469
470 }
471 }
472
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700473 private void processErrorMessage(OFMessage m) {
474 log.error("Switch {} Error {} in DriverState", getStringId(),
475 (OFErrorMsg) m, driverState);
476 }
477
478 private void processBarrierReply(OFMessage m) throws IOException {
479 if (m.getXid() == barrierXidToWaitFor) {
480 // Driver state-machine progresses to the next state.
481 // If Barrier messages is not received, then eventually
482 // the ChannelHandler state machine will timeout, and the switch
483 // will be disconnected.
484 nextDriverState();
485 } else {
486 log.error("Received incorrect barrier-message xid {} (expected: {}) in "
487 + "switch-driver state {} for switch {}", m, barrierXidToWaitFor,
488 driverState, getStringId());
489 }
490 }
491
492 private void processGroupDesc(OFGroupDescStatsReply gdsr) {
493 log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
494 try {
495 nextDriverState();
496 } catch (IOException e) {
497 // TODO Auto-generated catch block
498 e.printStackTrace();
499 }
500 }
501
502 // *****************************
503 // Utility methods
504 // *****************************
505
506 void setTableMissEntries() throws IOException {
507 // set all table-miss-entries
508 populateTableMissEntry(TABLE_VLAN, true, false, false, -1);
509 populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
510 populateTableMissEntry(TABLE_IPv4_UNICAST, false, true, true,
511 TABLE_ACL);
512 populateTableMissEntry(TABLE_MPLS, false, true, true,
513 TABLE_ACL);
514 populateTableMissEntry(TABLE_ACL, false, false, false, -1);
515 }
516
Saurav Dasd84178f2014-09-29 17:48:54 -0700517 private void sendHandshakeBarrier() throws IOException {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700518 long xid = getNextTransactionId();
519 barrierXidToWaitFor = xid;
520 OFBarrierRequest br = getFactory()
521 .buildBarrierRequest()
522 .setXid(xid)
523 .build();
524 write(br, null);
525 }
526
527 /**
528 * Adds a table-miss-entry to a pipeline table.
529 * <p>
530 * The table-miss-entry can be added with 'write-actions' or
531 * 'apply-actions'. It can also add a 'goto-table' instruction. By default
532 * if none of the booleans in the call are set, then the table-miss entry is
533 * added with no instructions, which means that if a packet hits the
534 * table-miss-entry, pipeline execution will stop, and the action set
535 * associated with the packet will be executed.
536 *
537 * @param tableToAdd the table to where the table-miss-entry will be added
538 * @param toControllerNow as an APPLY_ACTION instruction
539 * @param toControllerWrite as a WRITE_ACTION instruction
540 * @param toTable as a GOTO_TABLE instruction
541 * @param tableToSend the table to send as per the GOTO_TABLE instruction it
542 * needs to be set if 'toTable' is true. Ignored of 'toTable' is
543 * false.
544 * @throws IOException
545 */
546 @SuppressWarnings("unchecked")
547 private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
548 boolean toControllerWrite,
549 boolean toTable, int tableToSend) throws IOException {
550 OFOxmList oxmList = OFOxmList.EMPTY;
551 OFMatchV3 match = factory.buildMatchV3()
552 .setOxmList(oxmList)
553 .build();
554 OFAction outc = factory.actions()
555 .buildOutput()
556 .setPort(OFPort.CONTROLLER)
557 .setMaxLen(OFPCML_NO_BUFFER)
558 .build();
559 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
560 if (toControllerNow) {
561 // table-miss instruction to send to controller immediately
562 OFInstruction instr = factory.instructions()
563 .buildApplyActions()
564 .setActions(Collections.singletonList(outc))
565 .build();
566 instructions.add(instr);
567 }
568
569 if (toControllerWrite) {
570 // table-miss instruction to write-action to send to controller
571 // this will be executed whenever the action-set gets executed
572 OFInstruction instr = factory.instructions()
573 .buildWriteActions()
574 .setActions(Collections.singletonList(outc))
575 .build();
576 instructions.add(instr);
577 }
578
579 if (toTable) {
580 // table-miss instruction to goto-table x
581 OFInstruction instr = factory.instructions()
582 .gotoTable(TableId.of(tableToSend));
583 instructions.add(instr);
584 }
585
586 if (!toControllerNow && !toControllerWrite && !toTable) {
587 // table-miss has no instruction - at which point action-set will be
588 // executed - if there is an action to output/group in the action
589 // set
590 // the packet will be sent there, otherwise it will be dropped.
591 instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
592 }
593
594 OFMessage tableMissEntry = factory.buildFlowAdd()
595 .setTableId(TableId.of(tableToAdd))
596 .setMatch(match) // match everything
597 .setInstructions(instructions)
598 .setPriority(MIN_PRIORITY)
599 .setBufferId(OFBufferId.NO_BUFFER)
600 .setIdleTimeout(0)
601 .setHardTimeout(0)
602 .setXid(getNextTransactionId())
603 .build();
604 write(tableMissEntry, null);
605 }
606
607 private void getNetworkConfig() {
608 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
609 SwitchConfigStatus scs = ncs.checkSwitchConfig(new Dpid(getId()));
610 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
611 srConfig = (SegmentRouterConfig) scs.getSwitchConfig();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700612 isEdgeRouter = srConfig.isEdgeRouter();
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700613 sid = srConfig.getNodeSid();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700614 } else {
615 log.error("Switch not configured as Segment-Router");
616 }
617
618 List<LinkConfig> linkConfigList = ncs.getConfiguredAllowedLinks();
619 setNeighbors(linkConfigList);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700620
621 if (isEdgeRouter) {
622 List<SwitchConfig> switchList = ncs.getConfiguredAllowedSwitches();
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700623 getAllNodeSegmentIds(switchList);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700624 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700625 }
626
627 private void populateTableVlan() throws IOException {
628 List<OFMessage> msglist = new ArrayList<OFMessage>();
629 for (OFPortDesc p : getPorts()) {
630 int pnum = p.getPortNo().getPortNumber();
631 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
632 OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
633 OFOxmVlanVid oxv = factory.oxms()
634 .vlanVid(OFVlanVidMatch.UNTAGGED);
635 OFOxmList oxmList = OFOxmList.of(oxp, oxv);
636 OFMatchV3 match = factory.buildMatchV3()
637 .setOxmList(oxmList).build();
638
639 // TODO: match on vlan-tagged packets for vlans configured on
640 // subnet ports and strip-vlan
641
642 // Do not need to add vlans
643 /*int vlanid = getVlanConfig(pnum);
644 OFOxmVlanVid vidToSet = factory.oxms()
645 .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
646 OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
647 OFAction setVlan = factory.actions().setField(vidToSet);
648 List<OFAction> actionlist = new ArrayList<OFAction>();
649 actionlist.add(pushVlan);
650 actionlist.add(setVlan);
651 OFInstruction appAction = factory.instructions().buildApplyActions()
652 .setActions(actionlist).build();*/
653
654 OFInstruction gotoTbl = factory.instructions().buildGotoTable()
655 .setTableId(TableId.of(TABLE_TMAC)).build();
656 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
657 // instructions.add(appAction);
658 instructions.add(gotoTbl);
659 OFMessage flowEntry = factory.buildFlowAdd()
660 .setTableId(TableId.of(TABLE_VLAN))
661 .setMatch(match)
662 .setInstructions(instructions)
663 .setPriority(1000) // does not matter - all rules
664 // exclusive
665 .setBufferId(OFBufferId.NO_BUFFER)
666 .setIdleTimeout(0)
667 .setHardTimeout(0)
668 .setXid(getNextTransactionId())
669 .build();
670 msglist.add(flowEntry);
671 }
672 }
673 write(msglist);
674 log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId());
675 }
676
677 private void populateTableTMac() throws IOException {
678 // match for router-mac and ip-packets
679 OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
680 OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr());
681 OFOxmList oxmListIp = OFOxmList.of(dmac, oxe);
682 OFMatchV3 matchIp = factory.buildMatchV3()
683 .setOxmList(oxmListIp).build();
684 OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
685 .setTableId(TableId.of(TABLE_IPv4_UNICAST)).build();
686 List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
687 OFMessage ipEntry = factory.buildFlowAdd()
688 .setTableId(TableId.of(TABLE_TMAC))
689 .setMatch(matchIp)
690 .setInstructions(instructionsIp)
691 .setPriority(1000) // strict priority required lower than
692 // multicastMac
693 .setBufferId(OFBufferId.NO_BUFFER)
694 .setIdleTimeout(0)
695 .setHardTimeout(0)
696 .setXid(getNextTransactionId())
697 .build();
698
699 // match for router-mac and mpls packets
700 OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
701 OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls);
702 OFMatchV3 matchMpls = factory.buildMatchV3()
703 .setOxmList(oxmListMpls).build();
704 OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
705 .setTableId(TableId.of(TABLE_MPLS)).build();
706 List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
707 OFMessage mplsEntry = factory.buildFlowAdd()
708 .setTableId(TableId.of(TABLE_TMAC))
709 .setMatch(matchMpls)
710 .setInstructions(instructionsMpls)
711 .setPriority(1001) // strict priority required lower than
712 // multicastMac
713 .setBufferId(OFBufferId.NO_BUFFER)
714 .setIdleTimeout(0)
715 .setHardTimeout(0)
716 .setXid(getNextTransactionId())
717 .build();
718
719 log.debug("Adding termination-mac-rules in sw {}", getStringId());
720 List<OFMessage> msglist = new ArrayList<OFMessage>(2);
721 msglist.add(ipEntry);
722 msglist.add(mplsEntry);
723 write(msglist);
724 }
725
726 private MacAddress getRouterMacAddr() {
727 if (srConfig != null) {
728 return MacAddress.of(srConfig.getRouterMac());
729 } else {
730 // return a dummy mac address - it will not be used
731 return MacAddress.of("00:00:00:00:00:00");
732 }
733 }
734
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700735 private boolean isEdgeRouter(Dpid ndpid) {
736 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
737 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
738 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
739 return ((SegmentRouterConfig) scs.getSwitchConfig()).isEdgeRouter();
740 } else {
741 // TODO: return false if router not allowed
742 return false;
743 }
744 }
745
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700746 private MacAddress getNeighborRouterMacAddress(Dpid ndpid) {
747 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
748 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
749 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
750 return MacAddress.of(((SegmentRouterConfig) scs.getSwitchConfig())
751 .getRouterMac());
752 } else {
753 // return a dummy mac address - it will not be used
754 return MacAddress.of("00:00:00:00:00:00");
755 }
756 }
757
758 private void setNeighbors(List<LinkConfig> linkConfigList) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700759 for (LinkConfig lg : linkConfigList) {
760 if (!lg.getType().equals(NetworkConfigManager.PKT_LINK)) {
Saurav Das80d17392014-10-01 10:24:56 -0700761 continue;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700762 }
763 PktLinkConfig plg = (PktLinkConfig) lg;
764 if (plg.getDpid1() == getId()) {
765 addNeighborAtPort(new Dpid(plg.getDpid2()),
766 PortNumber.uint32(plg.getPort1()));
767 } else if (plg.getDpid2() == getId()) {
768 addNeighborAtPort(new Dpid(plg.getDpid1()),
769 PortNumber.uint32(plg.getPort2()));
770 }
771 }
772 }
773
774 private void addNeighborAtPort(Dpid neighborDpid, PortNumber portToNeighbor) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700775 /* Update NeighborToPort database */
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700776 if (neighbors.get(neighborDpid) != null) {
777 neighbors.get(neighborDpid).add(portToNeighbor);
778 } else {
779 Set<PortNumber> ports = new HashSet<PortNumber>();
780 ports.add(portToNeighbor);
781 neighbors.put(neighborDpid, ports);
782 }
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700783
784 /* Update portToNeighbors database */
785 if (portToNeighbors.get(portToNeighbor) == null)
786 portToNeighbors.put(portToNeighbor, neighborDpid);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700787 }
788
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700789 private void getAllNodeSegmentIds(List<SwitchConfig> switchList) {
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700790 for (SwitchConfig sc : switchList) {
791 /* TODO: Do we need to check if the SwitchConfig is of
792 * type SegmentRouter?
793 */
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700794 if (sc.getDpid() == getId()) {
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700795 continue;
796 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700797 segmentIds.add(((SegmentRouterConfig) sc).getNodeSid());
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700798 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700799 log.debug("getAllNodeSegmentIds: at sw {} are {}",
800 getStringId(), segmentIds);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700801 }
802
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700803 private boolean isSegmentIdSameAsNodeSegmentId(Dpid dpid, int sId) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700804 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
805 SwitchConfigStatus scs = ncs.checkSwitchConfig(dpid);
806 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
807 return (((SegmentRouterConfig) scs.getSwitchConfig()).
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700808 getNodeSid() == sId);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700809 } else {
810 // TODO: return false if router not allowed
811 return false;
812 }
813 }
814
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700815 private Set<Set<Dpid>> getAllNeighborSets(Set<Dpid> neighbors) {
816 List<Dpid> list = new ArrayList<Dpid>(neighbors);
817 Set<Set<Dpid>> sets = new HashSet<Set<Dpid>>();
818 /* get the number of elements in the neighbors */
819 int elements = list.size();
820 /* the number of members of a power set is 2^n
821 * including the empty set
822 */
823 int powerElements = (1 << elements);
824
825 /* run a binary counter for the number of power elements */
826 for (long i = 1; i < powerElements; i++) {
827 Set<Dpid> dpidSubSet = new HashSet<Dpid>();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700828 for (int j = 0; j < elements; j++) {
829 if ((i >> j) % 2 == 1) {
830 dpidSubSet.add(list.get(j));
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700831 }
832 }
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700833 /* NOTE: Avoid any pairings of edge routers only
834 * at a backbone router */
835 boolean avoidEdgeRouterPairing = true;
836 if ((!isEdgeRouter) && (dpidSubSet.size() > 1)) {
Srikanth Vavilapalli696010f2014-10-08 17:00:17 -0700837 for (Dpid dpid : dpidSubSet) {
838 if (!isEdgeRouter(dpid)) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700839 avoidEdgeRouterPairing = false;
Srikanth Vavilapalli696010f2014-10-08 17:00:17 -0700840 break;
841 }
842 }
843 }
844 else
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700845 avoidEdgeRouterPairing = false;
Srikanth Vavilapalli696010f2014-10-08 17:00:17 -0700846
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700847 if (!avoidEdgeRouterPairing)
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700848 sets.add(dpidSubSet);
849 }
850 return sets;
851 }
852
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700853 private void createGroupForANeighborSet(NeighborSet ns, int groupId) {
854 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
855 for (Dpid d : ns.getDpids()) {
856 for (PortNumber sp : neighbors.get(d)) {
857 BucketInfo b = new BucketInfo(d,
858 MacAddress.of(srConfig.getRouterMac()),
859 getNeighborRouterMacAddress(d), sp,
860 ns.getEdgeLabel());
861 buckets.add(b);
862
863 /* Update Port Neighborset map */
864 ArrayList<NeighborSet> portNeighborSets =
865 portNeighborSetMap.get(sp);
866 if (portNeighborSets == null) {
867 portNeighborSets = new ArrayList<NeighborSet>();
868 portNeighborSets.add(ns);
869 portNeighborSetMap.put(sp, portNeighborSets);
870 }
871 else
872 portNeighborSets.add(ns);
873 }
874 }
875 EcmpInfo ecmpInfo = new EcmpInfo(groupId, buckets);
876 setEcmpGroup(ecmpInfo);
877 ecmpGroups.put(ns, ecmpInfo);
878 log.debug(
879 "createGroupForANeighborSet: Creating ecmp group {} in sw {} "
880 + "for neighbor set {} with: {}",
881 groupId, getStringId(), ns, ecmpInfo);
882 return;
883 }
884
Sangho Shin15273b62014-10-16 22:22:05 -0700885 private void createGroupForMplsLabel(int groupId, String nodeId,
886 int nextGroupId, boolean bos) {
887 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
888 BucketInfo bucket = new BucketInfo(nextGroupId,
889 Integer.parseInt(nodeId), bos);
890 buckets.add(bucket);
891 EcmpInfo ecmpInfo = new EcmpInfo(groupId, buckets);
892 setPolicyEcmpGroup(ecmpInfo);
893// ecmpGroups.put(ns, ecmpInfo);
894 log.debug(
895 "createGroupForANeighborSet: Creating ecmp group {} in sw {} "
896 + "for pushing label {} and group to {}",
897 groupId, getStringId(), nodeId, nextGroupId);
898 return;
899 }
900
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700901 /**
902 * createGroups creates ECMP groups for all ports on this router connected
903 * to other routers (in the OF network). The information for ports is
904 * gleaned from the configured links. If no links are configured no groups
905 * will be created, and it is up to the caller of the IOF13Switch API to
906 * create groups.
907 * <p>
908 * By default all ports connected to the same neighbor router will be part
909 * of the same ECMP group. In addition, groups will be created for all
910 * possible combinations of neighbor routers.
911 * <p>
912 * For example, consider this router (R0) connected to 3 neighbors (R1, R2,
913 * and R3). The following groups will be created in R0:
914 * <li>1) all ports to R1,
915 * <li>2) all ports to R2,
916 * <li>3) all ports to R3,
917 * <li>4) all ports to R1 and R2
918 * <li>5) all ports to R1 and R3
919 * <li>6) all ports to R2 and R3
920 * <li>7) all ports to R1, R2, and R3
921 */
922 private void createGroups() {
Sangho Shin15273b62014-10-16 22:22:05 -0700923
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700924 Set<Dpid> dpids = neighbors.keySet();
925 if (dpids == null || dpids.isEmpty()) {
926 return;
927 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700928 /* Create all possible Neighbor sets from this router
929 * NOTE: Avoid any pairings of edge routers only
930 */
931 Set<Set<Dpid>> powerSet = getAllNeighborSets(dpids);
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700932 log.debug("createGroups: The size of neighbor powerset for sw {} is {}",
Srikanth Vavilapallica2263c2014-10-09 15:19:11 -0700933 getStringId(), powerSet.size());
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700934 Set<NeighborSet> nsSet = new HashSet<NeighborSet>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700935 for (Set<Dpid> combo : powerSet) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700936 if (combo.isEmpty())
937 continue;
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700938 if (isEdgeRouter && !segmentIds.isEmpty()) {
939 for (Integer sId : segmentIds) {
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700940 NeighborSet ns = new NeighborSet();
941 ns.addDpids(combo);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700942 /* Check if the edge label being set is of the
943 * same node in the Neighbor set
944 */
945 if ((combo.size() != 1) ||
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700946 (!isSegmentIdSameAsNodeSegmentId(
947 combo.iterator().next(), sId))) {
948 ns.setEdgeLabel(sId);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700949 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700950 nsSet.add(ns);
951 }
952 } else {
953 NeighborSet ns = new NeighborSet();
954 ns.addDpids(combo);
955 nsSet.add(ns);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700956 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700957 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700958 log.debug("createGroups: The neighborset with label for sw {} is {}",
Srikanth Vavilapallica2263c2014-10-09 15:19:11 -0700959 getStringId(), nsSet);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700960
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700961 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700962 createGroupForANeighborSet(ns, groupid.incrementAndGet());
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700963 }
964 }
965
966 private class EcmpInfo {
967 int groupId;
968 List<BucketInfo> buckets;
969
970 EcmpInfo(int gid, List<BucketInfo> bucketInfos) {
971 groupId = gid;
972 buckets = bucketInfos;
973 }
974
975 @Override
976 public String toString() {
977 return "groupId: " + groupId + ", buckets: " + buckets;
978 }
979 }
980
981 private class BucketInfo {
982 Dpid neighborDpid;
983 MacAddress srcMac;
984 MacAddress dstMac;
985 PortNumber outport;
Sangho Shin15273b62014-10-16 22:22:05 -0700986 int groupNo;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700987 int mplsLabel;
Sangho Shin15273b62014-10-16 22:22:05 -0700988 boolean bos;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700989
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700990 BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac,
991 PortNumber p, int label) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700992 neighborDpid = nDpid;
993 srcMac = smac;
994 dstMac = dmac;
995 outport = p;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700996 mplsLabel = label;
Sangho Shin15273b62014-10-16 22:22:05 -0700997 groupNo = -1;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700998 }
999
Sangho Shin15273b62014-10-16 22:22:05 -07001000 BucketInfo(int no, int label, boolean b) {
1001 neighborDpid = null;
1002 srcMac = null;
1003 dstMac = null;
1004 outport = null;
1005 groupNo = no;
1006 mplsLabel = label;
1007 bos = b;
1008 }
1009
1010
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001011 @Override
1012 public String toString() {
1013 return " {neighborDpid: " + neighborDpid + ", dstMac: " + dstMac +
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001014 ", srcMac: " + srcMac + ", outport: " + outport +
Sangho Shin15273b62014-10-16 22:22:05 -07001015 ", groupNo: " + groupNo +
1016 ", mplsLabel: " + mplsLabel + "}";
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001017 }
1018 }
1019
1020 private void setEcmpGroup(EcmpInfo ecmpInfo) {
1021 List<OFMessage> msglist = new ArrayList<OFMessage>();
1022 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1023
1024 List<OFBucket> buckets = new ArrayList<OFBucket>();
1025 for (BucketInfo b : ecmpInfo.buckets) {
1026 OFOxmEthDst dmac = factory.oxms()
1027 .ethDst(b.dstMac);
1028 OFAction setDA = factory.actions().buildSetField()
1029 .setField(dmac).build();
Saurav Das0a344b02014-09-26 14:18:52 -07001030 OFOxmEthSrc smac = factory.oxms()
1031 .ethSrc(b.srcMac);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001032 OFAction setSA = factory.actions().buildSetField()
1033 .setField(smac).build();
1034 OFAction outp = factory.actions().buildOutput()
1035 .setPort(OFPort.of(b.outport.shortValue()))
1036 .build();
1037 List<OFAction> actions = new ArrayList<OFAction>();
1038 actions.add(setSA);
1039 actions.add(setDA);
1040 actions.add(outp);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001041 if (b.mplsLabel != -1) {
1042 OFAction pushLabel = factory.actions().buildPushMpls()
1043 .setEthertype(EthType.MPLS_UNICAST).build();
Srikanth Vavilapalli11dc6072014-10-13 13:32:11 -07001044 OFOxmMplsBos bosX = factory.oxms()
1045 .mplsBos(OFBooleanValue.TRUE);
1046 OFAction setBX = factory.actions().buildSetField()
1047 .setField(bosX).build();
Sangho Shin62ce5c12014-10-08 16:24:40 -07001048 OFOxmMplsLabel lid = factory.oxms()
1049 .mplsLabel(U32.of(b.mplsLabel));
1050 OFAction setLabel = factory.actions().buildSetField()
1051 .setField(lid).build();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001052 OFAction copyTtl = factory.actions().copyTtlOut();
1053 OFAction decrTtl = factory.actions().decMplsTtl();
1054 actions.add(pushLabel);
1055 actions.add(setLabel);
Srikanth Vavilapalli11dc6072014-10-13 13:32:11 -07001056 actions.add(setBX);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001057 actions.add(copyTtl);
1058 actions.add(decrTtl);
1059 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001060 OFBucket ofb = factory.buildBucket()
1061 .setWeight(1)
1062 .setActions(actions)
1063 .build();
1064 buckets.add(ofb);
1065 }
1066
1067 OFMessage gm = factory.buildGroupAdd()
1068 .setGroup(group)
1069 .setBuckets(buckets)
1070 .setGroupType(OFGroupType.SELECT)
1071 .setXid(getNextTransactionId())
1072 .build();
1073 msglist.add(gm);
1074 try {
1075 write(msglist);
1076 } catch (IOException e) {
1077 // TODO Auto-generated catch block
1078 e.printStackTrace();
1079 }
1080 }
1081
Sangho Shin15273b62014-10-16 22:22:05 -07001082 private void setPolicyEcmpGroup(EcmpInfo ecmpInfo) {
1083 List<OFMessage> msglist = new ArrayList<OFMessage>();
1084 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1085
1086 List<OFBucket> buckets = new ArrayList<OFBucket>();
1087 List<OFAction> actions = new ArrayList<OFAction>();
1088 for (BucketInfo b : ecmpInfo.buckets) {
1089 if (b.dstMac != null && b.srcMac != null && b.outport != null) {
1090 OFOxmEthDst dmac = factory.oxms()
1091 .ethDst(b.dstMac);
1092 OFAction setDA = factory.actions().buildSetField()
1093 .setField(dmac).build();
1094 OFOxmEthSrc smac = factory.oxms()
1095 .ethSrc(b.srcMac);
1096 OFAction setSA = factory.actions().buildSetField()
1097 .setField(smac).build();
1098 OFAction outp = factory.actions().buildOutput()
1099 .setPort(OFPort.of(b.outport.shortValue()))
1100 .build();
1101 actions.add(setSA);
1102 actions.add(setDA);
1103 actions.add(outp);
1104 }
1105 if (b.groupNo > 0) {
1106 OFAction groupTo = factory.actions().buildGroup()
1107 .setGroup(OFGroup.of(b.groupNo))
1108 .build();
1109 actions.add(groupTo);
1110 }
1111 if (b.mplsLabel != -1) {
1112 OFAction pushLabel = factory.actions().buildPushMpls()
1113 .setEthertype(EthType.MPLS_UNICAST).build();
1114
1115 OFBooleanValue bosValue = null;
1116 if (b.bos)
1117 bosValue = OFBooleanValue.TRUE;
1118 else
1119 bosValue = OFBooleanValue.FALSE;
1120 OFOxmMplsBos bosX = factory.oxms()
1121 .mplsBos(bosValue);
1122 OFAction setBX = factory.actions().buildSetField()
1123 .setField(bosX).build();
1124 OFOxmMplsLabel lid = factory.oxms()
1125 .mplsLabel(U32.of(b.mplsLabel));
1126 OFAction setLabel = factory.actions().buildSetField()
1127 .setField(lid).build();
1128 OFAction copyTtl = factory.actions().copyTtlOut();
1129 OFAction decrTtl = factory.actions().decMplsTtl();
1130 actions.add(pushLabel);
1131 actions.add(setLabel);
1132 actions.add(setBX);
1133 actions.add(copyTtl);
1134 // decrement TTL only when the first MPLS label is pushed
1135 if (b.bos)
1136 actions.add(decrTtl);
1137 }
1138 OFBucket ofb = factory.buildBucket()
1139 .setWeight(1)
1140 .setActions(actions)
1141 .build();
1142 buckets.add(ofb);
1143 }
1144
1145 OFMessage gm = factory.buildGroupAdd()
1146 .setGroup(group)
1147 .setBuckets(buckets)
1148 .setGroupType(OFGroupType.SELECT)
1149 .setXid(getNextTransactionId())
1150 .build();
1151 msglist.add(gm);
1152 try {
1153 write(msglist);
1154 } catch (IOException e) {
1155 // TODO Auto-generated catch block
1156 e.printStackTrace();
1157 }
1158 }
1159
Sangho Shin55d00e12014-10-20 12:13:07 -07001160 private void deleteGroup(int groupId) {
1161
1162 List<OFMessage> msglist = new ArrayList<OFMessage>();
1163 OFGroup group = OFGroup.of(groupId);
1164
1165 OFMessage gm = factory.buildGroupDelete()
1166 .setGroup(group)
1167 .setGroupType(OFGroupType.SELECT)
1168 .setXid(getNextTransactionId())
1169 .build();
1170 msglist.add(gm);
1171 try {
1172 write(msglist);
1173 } catch (IOException e) {
1174 // TODO Auto-generated catch block
1175 e.printStackTrace();
1176 }
1177 }
1178
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -07001179 private void modifyEcmpGroup(EcmpInfo ecmpInfo) {
1180 List<OFMessage> msglist = new ArrayList<OFMessage>();
1181 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1182
1183 List<OFBucket> buckets = new ArrayList<OFBucket>();
1184 for (BucketInfo b : ecmpInfo.buckets) {
1185 OFOxmEthDst dmac = factory.oxms()
1186 .ethDst(b.dstMac);
1187 OFAction setDA = factory.actions().buildSetField()
1188 .setField(dmac).build();
1189 OFOxmEthSrc smac = factory.oxms()
1190 .ethSrc(b.srcMac);
1191 OFAction setSA = factory.actions().buildSetField()
1192 .setField(smac).build();
1193 OFAction outp = factory.actions().buildOutput()
1194 .setPort(OFPort.of(b.outport.shortValue()))
1195 .build();
1196 List<OFAction> actions = new ArrayList<OFAction>();
1197 actions.add(setSA);
1198 actions.add(setDA);
1199 actions.add(outp);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001200 if (b.mplsLabel != -1) {
1201 OFAction pushLabel = factory.actions().buildPushMpls()
1202 .setEthertype(EthType.MPLS_UNICAST).build();
Srikanth Vavilapalli11dc6072014-10-13 13:32:11 -07001203 OFOxmMplsBos bosX = factory.oxms()
1204 .mplsBos(OFBooleanValue.TRUE);
1205 OFAction setBX = factory.actions().buildSetField()
1206 .setField(bosX).build();
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -07001207 OFOxmMplsLabel lid = factory.oxms()
1208 .mplsLabel(U32.of(b.mplsLabel));
1209 OFAction setLabel = factory.actions().buildSetField()
1210 .setField(lid).build();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001211 OFAction copyTtl = factory.actions().copyTtlOut();
1212 OFAction decrTtl = factory.actions().decMplsTtl();
1213 actions.add(pushLabel);
1214 actions.add(setLabel);
Srikanth Vavilapalli11dc6072014-10-13 13:32:11 -07001215 actions.add(setBX);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001216 actions.add(copyTtl);
1217 actions.add(decrTtl);
1218 }
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -07001219 OFBucket ofb = factory.buildBucket()
1220 .setWeight(1)
1221 .setActions(actions)
1222 .build();
1223 buckets.add(ofb);
1224 }
1225
1226 OFMessage gm = factory.buildGroupModify()
1227 .setGroup(group)
1228 .setBuckets(buckets)
1229 .setGroupType(OFGroupType.SELECT)
1230 .setXid(getNextTransactionId())
1231 .build();
1232 msglist.add(gm);
1233 try {
1234 write(msglist);
1235 } catch (IOException e) {
1236 // TODO Auto-generated catch block
1237 e.printStackTrace();
1238 }
1239 }
1240
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001241 private void verifyGroups() throws IOException {
1242 sendGroupDescRequest();
1243 }
1244
1245 private void sendGroupDescRequest() throws IOException {
1246 OFMessage gdr = factory.buildGroupDescStatsRequest()
1247 .setXid(getNextTransactionId())
1248 .build();
1249 write(gdr, null);
1250 }
1251
1252 private void assignAdjacencyLabels() {
1253 // TODO
1254 try {
1255 nextDriverState();
1256 } catch (IOException e) {
1257 // TODO Auto-generated catch block
1258 e.printStackTrace();
1259 }
1260 }
1261
Saurav Das1cd10152014-09-26 09:38:07 -07001262 private OFAction getOFAction(Action action) {
1263 OFAction ofAction = null;
1264 if (action instanceof OutputAction) {
1265 OutputAction outputAction = (OutputAction) action;
1266 OFPort port = OFPort.of((int) outputAction.getPortNumber().value());
1267 ofAction = factory.actions().output(port, Short.MAX_VALUE);
1268 } else if (action instanceof ModifyDstMacAction) {
1269 long dstMac = ((ModifyDstMacAction) action).getDstMac().toLong();
1270 OFOxmEthDst dmac = factory.oxms()
1271 .ethDst(MacAddress.of(dstMac));
1272 ofAction = factory.actions().buildSetField()
1273 .setField(dmac).build();
1274 } else if (action instanceof ModifySrcMacAction) {
1275 long srcMac = ((ModifySrcMacAction) action).getSrcMac().toLong();
1276 OFOxmEthSrc smac = factory.oxms()
1277 .ethSrc(MacAddress.of(srcMac));
1278 ofAction = factory.actions().buildSetField()
1279 .setField(smac).build();
Saurav Dasa962a692014-10-17 14:52:38 -07001280 } else if (action instanceof PushMplsAction) {
1281 ofAction = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1282 } else if (action instanceof SetMplsIdAction) {
1283 int labelid = ((SetMplsIdAction) action).getMplsId();
1284 OFOxmMplsLabel lid = factory.oxms()
1285 .mplsLabel(U32.of(labelid));
1286 ofAction = factory.actions().buildSetField()
1287 .setField(lid).build();
1288 } else if (action instanceof SetMplsBosAction) {
1289 OFBooleanValue val = OFBooleanValue.of(
1290 ((SetMplsBosAction) action).isSet());
1291 OFOxmMplsBos bos = factory.oxms().mplsBos(val);
1292 OFAction setBos = factory.actions().buildSetField()
1293 .setField(bos).build();
1294 } else if (action instanceof PopMplsAction) {
Saurav Das1cd10152014-09-26 09:38:07 -07001295 EthType ethertype = ((PopMplsAction) action).getEthType();
1296 ofAction = factory.actions().popMpls(ethertype);
1297 } else if (action instanceof GroupAction) {
Sangho Shin15273b62014-10-16 22:22:05 -07001298 // If group Id can be specified explicitly in case of policy routing.
1299 int gid = -1;
1300 GroupAction ga = (GroupAction)action;
1301 if (ga.getGroupId() > 0) {
1302 gid = ga.getGroupId();
Saurav Das1cd10152014-09-26 09:38:07 -07001303 }
Sangho Shin15273b62014-10-16 22:22:05 -07001304 else {
1305 NeighborSet ns = ((GroupAction) action).getDpids();
1306 EcmpInfo ei = ecmpGroups.get(ns);
1307 if (ei == null) {
1308 log.debug("Unable to find ecmp group for neighbors {} at "
1309 + "switch {} and hence creating it", ns, getStringId());
1310 createGroupForANeighborSet(ns, groupid.incrementAndGet());
1311 ei = ecmpGroups.get(ns);
1312 }
1313 gid = ei.groupId;
1314 }
Srikanth Vavilapalli846df292014-10-10 15:47:16 -07001315 ofAction = factory.actions().buildGroup()
1316 .setGroup(OFGroup.of(gid))
1317 .build();
Saurav Das1cd10152014-09-26 09:38:07 -07001318 } else if (action instanceof DecNwTtlAction) {
1319 ofAction = factory.actions().decNwTtl();
1320 } else if (action instanceof DecMplsTtlAction) {
1321 ofAction = factory.actions().decMplsTtl();
1322 } else if (action instanceof CopyTtlInAction) {
1323 ofAction = factory.actions().copyTtlIn();
1324 } else if (action instanceof CopyTtlOutAction) {
1325 ofAction = factory.actions().copyTtlOut();
1326 } else {
1327 log.warn("Unsupported Action type: {}", action.getClass().getName());
1328 return null;
1329 }
1330
Saurav Das1cd10152014-09-26 09:38:07 -07001331 return ofAction;
1332 }
1333
Saurav Das0a344b02014-09-26 14:18:52 -07001334 private OFMessage getIpEntry(MatchActionOperationEntry mao) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001335 MatchAction ma = mao.getTarget();
1336 Operator op = mao.getOperator();
1337 Ipv4Match ipm = (Ipv4Match) ma.getMatch();
1338
1339 // set match
1340 IPv4Net ipdst = ipm.getDestination();
1341 OFOxmEthType ethTypeIp = factory.oxms()
1342 .ethType(EthType.IPv4);
1343 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
1344 .ipv4DstMasked(
1345 IPv4Address.of(ipdst.address().value()),
1346 IPv4Address.ofCidrMaskLength(ipdst.prefixLen())
1347 );
1348 OFOxmList oxmList = OFOxmList.of(ethTypeIp, ipPrefix);
1349 OFMatchV3 match = factory.buildMatchV3()
1350 .setOxmList(oxmList).build();
1351
1352 // set actions
1353 List<OFAction> writeActions = new ArrayList<OFAction>();
1354 for (Action action : ma.getActions()) {
Saurav Das1cd10152014-09-26 09:38:07 -07001355 OFAction ofAction = getOFAction(action);
1356 if (ofAction != null) {
1357 writeActions.add(ofAction);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001358 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001359 }
1360
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001361 // set instructions
1362 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1363 .setActions(writeActions).build();
1364 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1365 .setTableId(TableId.of(TABLE_ACL)).build();
1366 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1367 instructions.add(writeInstr);
1368 instructions.add(gotoInstr);
1369
Saurav Das1cd10152014-09-26 09:38:07 -07001370 // set flow priority to emulate longest prefix match
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001371 int priority = ipdst.prefixLen() * PRIORITY_MULTIPLIER;
1372 if (ipdst.prefixLen() == (short) 32) {
1373 priority = MAX_PRIORITY;
1374 }
1375
Saurav Dasbc594a42014-09-25 20:13:50 -07001376 // set flow-mod
Saurav Dase972b3a2014-09-26 15:41:06 -07001377 OFFlowMod.Builder fmBuilder = null;
1378 switch (op) {
1379 case ADD:
1380 fmBuilder = factory.buildFlowAdd();
1381 break;
1382 case REMOVE:
1383 fmBuilder = factory.buildFlowDeleteStrict();
1384 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001385 case MODIFY: // TODO
1386 fmBuilder = factory.buildFlowModifyStrict();
1387 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001388 default:
1389 log.warn("Unsupported MatchAction Operator: {}", op);
1390 return null;
Saurav Dasbc594a42014-09-25 20:13:50 -07001391 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001392 OFMessage ipFlow = fmBuilder
1393 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
1394 .setMatch(match)
1395 .setInstructions(instructions)
1396 .setPriority(priority)
1397 .setBufferId(OFBufferId.NO_BUFFER)
1398 .setIdleTimeout(0)
1399 .setHardTimeout(0)
1400 .setXid(getNextTransactionId())
1401 .build();
Saurav Dasbc594a42014-09-25 20:13:50 -07001402 log.debug("{} ip-rule {}-{} in sw {}",
1403 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1404 match, writeActions,
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001405 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001406 return ipFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001407 }
1408
Saurav Das0a344b02014-09-26 14:18:52 -07001409 private OFMessage getMplsEntry(MatchActionOperationEntry mao) {
Saurav Das1cd10152014-09-26 09:38:07 -07001410 MatchAction ma = mao.getTarget();
1411 Operator op = mao.getOperator();
1412 MplsMatch mplsm = (MplsMatch) ma.getMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001413
Saurav Das1cd10152014-09-26 09:38:07 -07001414 // set match
1415 OFOxmEthType ethTypeMpls = factory.oxms()
1416 .ethType(EthType.MPLS_UNICAST);
1417 OFOxmMplsLabel labelid = factory.oxms()
1418 .mplsLabel(U32.of(mplsm.getMplsLabel()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001419 OFOxmMplsBos bos = factory.oxms()
1420 .mplsBos(OFBooleanValue.of(mplsm.isBos()));
1421 OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid, bos);
Saurav Das1cd10152014-09-26 09:38:07 -07001422 OFMatchV3 matchlabel = factory.buildMatchV3()
1423 .setOxmList(oxmList).build();
1424
1425 // set actions
1426 List<OFAction> writeActions = new ArrayList<OFAction>();
1427 for (Action action : ma.getActions()) {
1428 OFAction ofAction = getOFAction(action);
1429 if (ofAction != null) {
1430 writeActions.add(ofAction);
1431 }
1432 }
1433
1434 // set instructions
1435 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1436 .setActions(writeActions).build();
1437 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1438 .setTableId(TableId.of(TABLE_ACL)).build();
1439 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1440 instructions.add(writeInstr);
1441 instructions.add(gotoInstr);
1442
Saurav Dase972b3a2014-09-26 15:41:06 -07001443 // set flow-mod
1444 OFFlowMod.Builder fmBuilder = null;
1445 switch (op) {
1446 case ADD:
1447 fmBuilder = factory.buildFlowAdd();
1448 break;
1449 case REMOVE:
1450 fmBuilder = factory.buildFlowDeleteStrict();
1451 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001452 case MODIFY: // TODO
1453 fmBuilder = factory.buildFlowModifyStrict();
1454 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001455 default:
1456 log.warn("Unsupported MatchAction Operator: {}", op);
1457 return null;
Saurav Das1cd10152014-09-26 09:38:07 -07001458 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001459
1460 OFMessage mplsFlow = fmBuilder
1461 .setTableId(TableId.of(TABLE_MPLS))
1462 .setMatch(matchlabel)
1463 .setInstructions(instructions)
1464 .setPriority(MAX_PRIORITY) // exact match and exclusive
1465 .setBufferId(OFBufferId.NO_BUFFER)
1466 .setIdleTimeout(0)
1467 .setHardTimeout(0)
1468 .setXid(getNextTransactionId())
1469 .build();
Saurav Das1cd10152014-09-26 09:38:07 -07001470 log.debug("{} mpls-rule {}-{} in sw {}",
1471 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1472 matchlabel, writeActions,
1473 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001474 return mplsFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001475 }
1476
Saurav Das0a344b02014-09-26 14:18:52 -07001477 private OFMessage getAclEntry(MatchActionOperationEntry mao) {
Saurav Dase972b3a2014-09-26 15:41:06 -07001478 MatchAction ma = mao.getTarget();
1479 Operator op = mao.getOperator();
1480 PacketMatch packetMatch = (PacketMatch) ma.getMatch();
1481 Builder matchBuilder = factory.buildMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001482
Saurav Dase972b3a2014-09-26 15:41:06 -07001483 // set match
1484 int inport = 0;
1485 if (ma.getSwitchPort() != null) {
1486 inport = (int) ma.getSwitchPort().getPortNumber().value();
1487 }
1488 final MACAddress srcMac = packetMatch.getSrcMacAddress();
1489 final MACAddress dstMac = packetMatch.getDstMacAddress();
1490 final Short etherType = packetMatch.getEtherType();
1491 final IPv4Net srcIp = packetMatch.getSrcIpAddress();
1492 final IPv4Net dstIp = packetMatch.getDstIpAddress();
1493 final Byte ipProto = packetMatch.getIpProtocolNumber();
1494 final Short srcTcpPort = packetMatch.getSrcTcpPortNumber();
1495 final Short dstTcpPort = packetMatch.getDstTcpPortNumber();
1496 if (inport > 0) {
1497 matchBuilder.setExact(MatchField.IN_PORT,
1498 OFPort.of(inport));
1499 }
1500 if (srcMac != null) {
1501 matchBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(srcMac.toLong()));
1502 }
1503 if (dstMac != null) {
1504 matchBuilder.setExact(MatchField.ETH_DST, MacAddress.of(dstMac.toLong()));
1505 }
1506 if (etherType != null) {
1507 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(etherType));
1508 }
1509 if (srcIp != null) {
1510 matchBuilder.setMasked(MatchField.IPV4_SRC,
1511 IPv4Address.of(srcIp.address().value())
1512 .withMaskOfLength(srcIp.prefixLen()));
1513 }
1514 if (dstIp != null) {
1515 matchBuilder.setMasked(MatchField.IPV4_DST,
1516 IPv4Address.of(dstIp.address().value())
1517 .withMaskOfLength(dstIp.prefixLen()));
1518 }
1519 if (ipProto != null) {
1520 matchBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(ipProto));
1521 }
1522 if (srcTcpPort != null) {
1523 matchBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(srcTcpPort));
1524 }
1525 if (dstTcpPort != null) {
1526 matchBuilder.setExact(MatchField.TCP_DST, TransportPort.of(dstTcpPort));
1527 }
1528
1529 // set actions
Saurav Dascc3e35f2014-10-10 15:33:32 -07001530 List<OFAction> writeActions = new ArrayList<OFAction>();
Saurav Dase972b3a2014-09-26 15:41:06 -07001531 for (Action action : ma.getActions()) {
1532 OFAction ofAction = getOFAction(action);
1533 if (ofAction != null) {
Saurav Dascc3e35f2014-10-10 15:33:32 -07001534 writeActions.add(ofAction);
Saurav Dase972b3a2014-09-26 15:41:06 -07001535 }
1536 }
1537
1538 // set instructions
1539 OFInstruction clearInstr = factory.instructions().clearActions();
Saurav Dascc3e35f2014-10-10 15:33:32 -07001540 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1541 .setActions(writeActions).build();
Saurav Dase972b3a2014-09-26 15:41:06 -07001542 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1543 instructions.add(clearInstr);
Saurav Dascc3e35f2014-10-10 15:33:32 -07001544 instructions.add(writeInstr);
Saurav Dase972b3a2014-09-26 15:41:06 -07001545
1546 // set flow-mod
1547 OFFlowMod.Builder fmBuilder = null;
1548 switch (op) {
1549 case ADD:
1550 fmBuilder = factory.buildFlowAdd();
1551 break;
1552 case REMOVE:
1553 fmBuilder = factory.buildFlowDeleteStrict();
1554 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001555 case MODIFY: // TODO
1556 fmBuilder = factory.buildFlowModifyStrict();
1557 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001558 default:
1559 log.warn("Unsupported MatchAction Operator: {}", op);
1560 return null;
1561 }
1562
1563 OFMessage aclFlow = fmBuilder
1564 .setTableId(TableId.of(TABLE_ACL))
1565 .setMatch(matchBuilder.build())
1566 .setInstructions(instructions)
Sangho Shin6f47dd32014-10-17 23:10:39 -07001567 .setPriority(ma.getPriority()) // exact match and exclusive
Saurav Dase972b3a2014-09-26 15:41:06 -07001568 .setBufferId(OFBufferId.NO_BUFFER)
1569 .setIdleTimeout(0)
1570 .setHardTimeout(0)
1571 .setXid(getNextTransactionId())
1572 .build();
Sangho Shin15273b62014-10-16 22:22:05 -07001573
Saurav Das0a344b02014-09-26 14:18:52 -07001574 return aclFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001575 }
1576
1577 // *****************************
1578 // IOF13Switch
1579 // *****************************
1580
1581 @Override
1582 public void pushFlow(MatchActionOperationEntry matchActionOp) throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001583 OFMessage ofm = getFlow(matchActionOp);
1584 if (ofm != null) {
1585 write(Collections.singletonList(ofm));
1586 }
1587 }
1588
1589 private OFMessage getFlow(MatchActionOperationEntry matchActionOp) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001590 final MatchAction matchAction = matchActionOp.getTarget();
1591 final Match match = matchAction.getMatch();
1592 if (match instanceof Ipv4Match) {
Saurav Das0a344b02014-09-26 14:18:52 -07001593 return getIpEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001594 } else if (match instanceof MplsMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001595 return getMplsEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001596 } else if (match instanceof PacketMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001597 return getAclEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001598 } else {
1599 log.error("Unknown match type {} pushed to switch {}", match,
1600 getStringId());
1601 }
Saurav Das0a344b02014-09-26 14:18:52 -07001602 return null;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001603 }
1604
1605 @Override
1606 public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps)
1607 throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001608 List<OFMessage> flowMods = new ArrayList<OFMessage>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001609 for (MatchActionOperationEntry matchActionOp : matchActionOps) {
Saurav Das0a344b02014-09-26 14:18:52 -07001610 OFMessage ofm = getFlow(matchActionOp);
1611 if (ofm != null) {
1612 flowMods.add(ofm);
1613 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001614 }
Saurav Das0a344b02014-09-26 14:18:52 -07001615 write(flowMods);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001616 }
1617
1618 @Override
1619 public int getEcmpGroupId(NeighborSet ns) {
1620 EcmpInfo ei = ecmpGroups.get(ns);
1621 if (ei == null) {
1622 return -1;
1623 } else {
1624 return ei.groupId;
1625 }
1626 }
1627
Saurav Dascc3e35f2014-10-10 15:33:32 -07001628 @Override
1629 public TableId getTableId(String tableType) {
1630 tableType = tableType.toLowerCase();
1631 if (tableType.contentEquals("ip")) {
1632 return TableId.of(OFSwitchImplCPqD13.TABLE_IPv4_UNICAST);
1633 }
1634 else if (tableType.contentEquals("mpls")) {
1635 return TableId.of(OFSwitchImplCPqD13.TABLE_MPLS);
1636 }
1637 else if (tableType.contentEquals("acl")) {
1638 return TableId.of(OFSwitchImplCPqD13.TABLE_ACL);
1639 }
1640 else {
1641 log.warn("Invalid tableType: {}", tableType);
1642 return null;
1643 }
1644 }
1645
Sangho Shine020cc32014-10-20 13:28:02 -07001646 public int createTunnel(String tunnelId, List<String> route, NeighborSet ns) {
Sangho Shin15273b62014-10-16 22:22:05 -07001647
1648 // create a last group of the group chaining
1649 int finalGroupId = groupid.incrementAndGet();
1650 createGroupForANeighborSet(ns, finalGroupId);
1651
1652 int groupId = 0;
1653 int nextGroupId = finalGroupId;
1654 boolean bos = false;
Sangho Shine020cc32014-10-20 13:28:02 -07001655 List<Integer> groups = new ArrayList<Integer>();
Sangho Shin15273b62014-10-16 22:22:05 -07001656
Sangho Shine020cc32014-10-20 13:28:02 -07001657 // process the node ID in order
Sangho Shin15273b62014-10-16 22:22:05 -07001658 for (int i = 0; i < route.size(); i++) {
1659 String nodeId = route.get(i);
1660 groupId = groupid.incrementAndGet();
Sangho Shine020cc32014-10-20 13:28:02 -07001661 groups.add(Integer.valueOf(groupId));
Sangho Shin15273b62014-10-16 22:22:05 -07001662 if (i == route.size()-1)
1663 bos = true;
1664 createGroupForMplsLabel(groupId, nodeId, nextGroupId, bos);
1665 nextGroupId = groupId;
1666 }
1667
Sangho Shine020cc32014-10-20 13:28:02 -07001668 tunnelGroups.putIfAbsent(tunnelId, groups);
Sangho Shin15273b62014-10-16 22:22:05 -07001669 return groupId;
1670 }
1671
1672
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001673 // *****************************
Saurav Das80d17392014-10-01 10:24:56 -07001674 // Unused
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001675 // *****************************
1676
Sangho Shin15273b62014-10-16 22:22:05 -07001677
Saurav Das80d17392014-10-01 10:24:56 -07001678 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001679 private void setAsyncConfig() throws IOException {
1680 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
1681 OFMessage setAC = null;
1682
1683 if (role == Role.MASTER) {
1684 setAC = factory.buildAsyncSet()
1685 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
1686 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
1687 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
1688 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1689 .setPacketInMaskSlave(SET_ALL_SLAVE)
1690 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1691 .setXid(getNextTransactionId())
1692 .build();
1693 } else if (role == Role.EQUAL) {
1694 setAC = factory.buildAsyncSet()
1695 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
1696 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
1697 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
1698 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1699 .setPacketInMaskSlave(SET_ALL_SLAVE)
1700 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1701 .setXid(getNextTransactionId())
1702 .build();
1703 }
1704 msglist.add(setAC);
1705
1706 OFMessage br = factory.buildBarrierRequest()
1707 .setXid(getNextTransactionId())
1708 .build();
1709 msglist.add(br);
1710
1711 OFMessage getAC = factory.buildAsyncGetRequest()
1712 .setXid(getNextTransactionId())
1713 .build();
1714 msglist.add(getAC);
1715
1716 write(msglist);
1717 }
1718
Saurav Das80d17392014-10-01 10:24:56 -07001719 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001720 private void decodeAsyncGetReply(OFAsyncGetReply rep) {
1721 long frm = rep.getFlowRemovedMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001722 long frs = rep.getFlowRemovedMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001723 long pim = rep.getPacketInMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001724 long pis = rep.getPacketInMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001725 long psm = rep.getPortStatusMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001726 long pss = rep.getPortStatusMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001727
1728 if (role == Role.MASTER || role == Role.EQUAL) { // should separate
1729 log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
1730 log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
1731 log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
1732 }
1733
1734 }
1735
Saurav Das80d17392014-10-01 10:24:56 -07001736 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001737 private void getTableFeatures() throws IOException {
1738 OFMessage gtf = factory.buildTableFeaturesStatsRequest()
1739 .setXid(getNextTransactionId())
1740 .build();
1741 write(gtf, null);
1742 }
1743
Saurav Das80d17392014-10-01 10:24:56 -07001744 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001745 private void sendGroupFeaturesRequest() throws IOException {
1746 OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
1747 .setXid(getNextTransactionId())
1748 .build();
1749 write(gfr, null);
1750 }
1751
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001752 private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
1753 log.info("Sw: {} Group Features {}", getStringId(), gfsr);
1754 }
1755
Saurav Dascc3e35f2014-10-10 15:33:32 -07001756 @SuppressWarnings("unused")
1757 private void testMultipleLabels() {
1758 if (getId() == 1) {
1759 List<OFMessage> msglist = new ArrayList<OFMessage>();
1760
1761 // first all the indirect groups
1762
1763 // the group to switch 2 with outer label
1764 OFGroup g1 = OFGroup.of(201);
1765 OFOxmEthDst dmac1 = factory.oxms().ethDst(MacAddress.of("00:00:02:02:02:80"));
1766 OFAction push1 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1767 OFOxmMplsLabel lid1 = factory.oxms()
1768 .mplsLabel(U32.of(105)); // outer label
1769 OFAction setMpls1 = factory.actions().buildSetField()
1770 .setField(lid1).build();
1771 OFOxmMplsBos bos1 = factory.oxms()
1772 .mplsBos(OFBooleanValue.FALSE);
1773 OFAction setB1 = factory.actions().buildSetField()
1774 .setField(bos1).build();
1775 OFAction setDA1 = factory.actions().buildSetField()
1776 .setField(dmac1).build();
1777 OFAction outp1 = factory.actions().buildOutput()
1778 .setPort(OFPort.of(2))
1779 .build();
1780 List<OFAction> a1 = new ArrayList<OFAction>();
1781 a1.add(push1);
1782 a1.add(setMpls1);
1783 a1.add(setB1);
1784 a1.add(setDA1);
1785 a1.add(outp1);
1786 OFBucket b1 = factory.buildBucket()
1787 .setActions(a1)
1788 .build();
1789 OFMessage gm1 = factory.buildGroupAdd()
1790 .setGroup(g1)
1791 .setBuckets(Collections.singletonList(b1))
1792 .setGroupType(OFGroupType.INDIRECT)
1793 .setXid(getNextTransactionId())
1794 .build();
1795 msglist.add(gm1);
1796
1797 // the group to switch 3 with outer label
1798 OFGroup g2 = OFGroup.of(301);
1799 OFOxmEthDst dmac2 = factory.oxms().ethDst(MacAddress.of("00:00:03:03:03:80"));
1800 OFAction push2 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1801 OFOxmMplsLabel lid2 = factory.oxms()
1802 .mplsLabel(U32.of(104)); // outer label
1803 OFAction setMpls2 = factory.actions().buildSetField()
1804 .setField(lid2).build();
1805 OFOxmMplsBos bos2 = factory.oxms()
1806 .mplsBos(OFBooleanValue.FALSE);
1807 OFAction setB2 = factory.actions().buildSetField()
1808 .setField(bos2).build();
1809 OFAction setDA2 = factory.actions().buildSetField()
1810 .setField(dmac2).build();
1811 OFAction outp2 = factory.actions().buildOutput()
1812 .setPort(OFPort.of(3))
1813 .build();
1814 List<OFAction> a2 = new ArrayList<OFAction>();
1815 a2.add(push2);
1816 a2.add(setMpls2);
1817 a2.add(setB2);
1818 a2.add(setDA2);
1819 a2.add(outp2);
1820 OFBucket b2 = factory.buildBucket()
1821 .setActions(a2)
1822 .build();
1823 OFMessage gm2 = factory.buildGroupAdd()
1824 .setGroup(g2)
1825 .setBuckets(Collections.singletonList(b2))
1826 .setGroupType(OFGroupType.INDIRECT)
1827 .setXid(getNextTransactionId())
1828 .build();
1829 msglist.add(gm2);
1830
1831 // now add main ECMP group with inner labels
1832 OFGroup group = OFGroup.of(786);
1833 List<OFBucket> buckets = new ArrayList<OFBucket>();
1834 for (int i = 0; i < 2; i++) { // 2 buckets
1835
1836 List<OFAction> actions = new ArrayList<OFAction>();
1837 OFOxmEthSrc smac = factory.oxms()
1838 .ethSrc(MacAddress.of("00:00:01:01:01:80"));
1839 OFAction setSA = factory.actions().buildSetField()
1840 .setField(smac).build();
1841 actions.add(setSA);
1842
1843 if (i == 0) {
1844 // send to switch 2
1845 OFAction pushX = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1846 OFOxmMplsLabel lidX = factory.oxms()
1847 .mplsLabel(U32.of(106)); // inner label
1848 OFAction setX = factory.actions().buildSetField()
1849 .setField(lidX).build();
1850 OFOxmMplsBos bosX = factory.oxms()
1851 .mplsBos(OFBooleanValue.TRUE);
1852 OFAction setBX = factory.actions().buildSetField()
1853 .setField(bosX).build();
1854 OFAction ogX = factory.actions().buildGroup()
1855 .setGroup(g1).build();
1856 actions.add(pushX);
1857 actions.add(setX);
1858 actions.add(setBX);
1859 actions.add(ogX);
1860
1861 } else {
1862 // send to switch 3
1863 OFAction pushY = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1864 OFOxmMplsLabel lidY = factory.oxms()
1865 .mplsLabel(U32.of(106)); // inner label
1866 OFAction setY = factory.actions().buildSetField()
1867 .setField(lidY).build();
1868 OFOxmMplsBos bosY = factory.oxms()
1869 .mplsBos(OFBooleanValue.TRUE);
1870 OFAction setBY = factory.actions().buildSetField()
1871 .setField(bosY).build();
1872 OFAction ogY = factory.actions().buildGroup()
1873 .setGroup(g2).build();
1874 actions.add(pushY);
1875 actions.add(setY);
1876 actions.add(setBY);
1877 actions.add(ogY);
1878 }
1879
1880 OFBucket ofb = factory.buildBucket()
1881 .setWeight(1)
1882 .setActions(actions)
1883 .build();
1884 buckets.add(ofb);
1885 }
1886
1887 OFMessage gm = factory.buildGroupAdd()
1888 .setGroup(group)
1889 .setBuckets(buckets)
1890 .setGroupType(OFGroupType.SELECT)
1891 .setXid(getNextTransactionId())
1892 .build();
1893 msglist.add(gm);
1894
1895 // create an ACL entry to use this ecmp group
1896 Builder matchBuilder = factory.buildMatch();
1897 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(0x800));
1898 matchBuilder.setMasked(MatchField.IPV4_DST,
1899 IPv4Address.of("7.7.7.0")
1900 .withMaskOfLength(24));
1901
1902 OFAction grp = factory.actions().buildGroup()
1903 .setGroup(OFGroup.of(786))
1904 .build();
1905 List<OFAction> writeActions = Collections.singletonList(grp);
1906
1907 OFInstruction clearInstr = factory.instructions().clearActions();
1908 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1909 .setActions(writeActions).build();
1910 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1911 instructions.add(clearInstr);
1912 instructions.add(writeInstr);
1913
1914 OFFlowMod.Builder fmBuilder = factory.buildFlowAdd();
1915
1916 OFMessage aclFlow = fmBuilder
1917 .setTableId(TableId.of(TABLE_ACL))
1918 .setMatch(matchBuilder.build())
1919 .setInstructions(instructions)
1920 .setPriority(10) // TODO: wrong - should be MA
1921 // priority
1922 .setBufferId(OFBufferId.NO_BUFFER)
1923 .setIdleTimeout(0)
1924 .setHardTimeout(0)
1925 .setXid(getNextTransactionId())
1926 .build();
1927 msglist.add(aclFlow);
1928
1929 try {
1930 write(msglist);
1931 } catch (IOException e) {
1932 // TODO Auto-generated catch block
1933 e.printStackTrace();
1934 }
Fahad Naeem Khand563af62014-10-08 17:37:25 -07001935 }
1936 }
1937
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001938}