blob: 8ebe8cceae5c0d05b544cf672b3d3daf5c1aa3c6 [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 Dasfc5e3eb2014-09-25 19:05:21 -070047import net.onrc.onos.core.matchaction.match.Ipv4Match;
48import net.onrc.onos.core.matchaction.match.Match;
49import net.onrc.onos.core.matchaction.match.MplsMatch;
50import net.onrc.onos.core.matchaction.match.PacketMatch;
51import net.onrc.onos.core.util.Dpid;
52import net.onrc.onos.core.util.IPv4Net;
53import net.onrc.onos.core.util.PortNumber;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070054
55import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
56import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
57import org.projectfloodlight.openflow.protocol.OFBucket;
58import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
59import org.projectfloodlight.openflow.protocol.OFErrorMsg;
60import org.projectfloodlight.openflow.protocol.OFFactory;
Saurav Dase972b3a2014-09-26 15:41:06 -070061import org.projectfloodlight.openflow.protocol.OFFlowMod;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070062import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
63import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
64import org.projectfloodlight.openflow.protocol.OFGroupType;
65import org.projectfloodlight.openflow.protocol.OFMatchV3;
66import org.projectfloodlight.openflow.protocol.OFMessage;
67import org.projectfloodlight.openflow.protocol.OFOxmList;
68import org.projectfloodlight.openflow.protocol.OFPortDesc;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -070069import org.projectfloodlight.openflow.protocol.OFPortStatus;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070070import org.projectfloodlight.openflow.protocol.OFStatsReply;
71import org.projectfloodlight.openflow.protocol.action.OFAction;
72import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
Saurav Dase972b3a2014-09-26 15:41:06 -070073import org.projectfloodlight.openflow.protocol.match.Match.Builder;
74import org.projectfloodlight.openflow.protocol.match.MatchField;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070075import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
76import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
77import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
78import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
79import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
Saurav Dascc3e35f2014-10-10 15:33:32 -070080import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsBos;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070081import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
82import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
83import org.projectfloodlight.openflow.types.EthType;
84import org.projectfloodlight.openflow.types.IPv4Address;
Saurav Dase972b3a2014-09-26 15:41:06 -070085import org.projectfloodlight.openflow.types.IpProtocol;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070086import org.projectfloodlight.openflow.types.MacAddress;
Saurav Dascc3e35f2014-10-10 15:33:32 -070087import org.projectfloodlight.openflow.types.OFBooleanValue;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070088import org.projectfloodlight.openflow.types.OFBufferId;
89import org.projectfloodlight.openflow.types.OFGroup;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070090import org.projectfloodlight.openflow.types.OFPort;
91import org.projectfloodlight.openflow.types.OFVlanVidMatch;
92import org.projectfloodlight.openflow.types.TableId;
Saurav Dase972b3a2014-09-26 15:41:06 -070093import org.projectfloodlight.openflow.types.TransportPort;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070094import org.projectfloodlight.openflow.types.U32;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070095import org.projectfloodlight.openflow.util.HexString;
96
97/**
98 * OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
99 * Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
100 * Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
101 * None
102 */
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700103public class OFSwitchImplCPqD13 extends OFSwitchImplBase implements IOF13Switch {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700104 private AtomicBoolean driverHandshakeComplete;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700105 private AtomicBoolean haltStateMachine;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700106 private OFFactory factory;
107 private static final int OFPCML_NO_BUFFER = 0xffff;
108 // Configuration of asynch messages to controller. We need different
109 // asynch messages depending on role-equal or role-master.
110 // We don't want to get anything if we are slave.
111 private static final long SET_FLOW_REMOVED_MASK_MASTER = 0xf;
112 private static final long SET_PACKET_IN_MASK_MASTER = 0x7;
113 private static final long SET_PORT_STATUS_MASK_MASTER = 0x7;
114 private static final long SET_FLOW_REMOVED_MASK_EQUAL = 0x0;
115 private static final long SET_PACKET_IN_MASK_EQUAL = 0x0;
116 private static final long SET_PORT_STATUS_MASK_EQUAL = 0x7;
117 private static final long SET_ALL_SLAVE = 0x0;
118
119 private static final long TEST_FLOW_REMOVED_MASK = 0xf;
120 private static final long TEST_PACKET_IN_MASK = 0x7;
121 private static final long TEST_PORT_STATUS_MASK = 0x7;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700122
123 private static final int TABLE_VLAN = 0;
124 private static final int TABLE_TMAC = 1;
Sangho Shin01bca862014-09-12 11:18:59 -0700125 private static final int TABLE_IPv4_UNICAST = 2;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700126 private static final int TABLE_MPLS = 3;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700127 private static final int TABLE_ACL = 5;
128
129 private static final short MAX_PRIORITY = (short) 0xffff;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700130 private static final short PRIORITY_MULTIPLIER = (short) 2046;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700131 private static final short MIN_PRIORITY = 0x0;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700132
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700133 private long barrierXidToWaitFor = -1;
134 private DriverState driverState;
Jonathan Hartcb34f382014-08-12 21:11:03 -0700135 private final boolean usePipeline13;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700136 private SegmentRouterConfig srConfig;
137 private ConcurrentMap<Dpid, Set<PortNumber>> neighbors;
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700138 private ConcurrentMap<PortNumber, Dpid> portToNeighbors;
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700139 private List<Integer> segmentIds;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700140 private boolean isEdgeRouter;
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700141 private int sid;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700142 private ConcurrentMap<NeighborSet, EcmpInfo> ecmpGroups;
Srikanth Vavilapallib95e6e02014-10-02 13:56:39 -0700143 private ConcurrentMap<PortNumber, ArrayList<NeighborSet>> portNeighborSetMap;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700144 private AtomicInteger groupid;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700145
146
Jonathan Hartcb34f382014-08-12 21:11:03 -0700147
148 public OFSwitchImplCPqD13(OFDescStatsReply desc, boolean usePipeline13) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700149 super();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700150 haltStateMachine = new AtomicBoolean(false);
151 driverState = DriverState.INIT;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700152 driverHandshakeComplete = new AtomicBoolean(false);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700153 setSwitchDescription(desc);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700154 neighbors = new ConcurrentHashMap<Dpid, Set<PortNumber>>();
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700155 portToNeighbors = new ConcurrentHashMap<PortNumber, Dpid>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700156 ecmpGroups = new ConcurrentHashMap<NeighborSet, EcmpInfo>();
Srikanth Vavilapallib95e6e02014-10-02 13:56:39 -0700157 portNeighborSetMap =
158 new ConcurrentHashMap<PortNumber, ArrayList<NeighborSet>>();
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700159 segmentIds = new ArrayList<Integer>();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700160 isEdgeRouter = false;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700161 groupid = new AtomicInteger(0);
Jonathan Hartcb34f382014-08-12 21:11:03 -0700162 this.usePipeline13 = usePipeline13;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700163 }
164
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700165 // *****************************
166 // OFSwitchImplBase
167 // *****************************
168
169
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700170 /* (non-Javadoc)
171 * @see java.lang.Object#toString()
172 */
173 @Override
174 public String toString() {
175 return "OFSwitchImplCPqD13 [" + ((channel != null)
176 ? channel.getRemoteAddress() : "?")
177 + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
178 }
179
180 @Override
181 public void startDriverHandshake() throws IOException {
182 log.debug("Starting driver handshake for sw {}", getStringId());
183 if (startDriverHandshakeCalled) {
184 throw new SwitchDriverSubHandshakeAlreadyStarted();
185 }
186 startDriverHandshakeCalled = true;
Jonathan Harta213bce2014-08-11 15:44:07 -0700187 factory = getFactory();
Jonathan Hartcb34f382014-08-12 21:11:03 -0700188 if (!usePipeline13) {
189 // Send packet-in to controller if a packet misses the first table
190 populateTableMissEntry(0, true, false, false, 0);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700191 driverHandshakeComplete.set(true);
Sangho Shin01bca862014-09-12 11:18:59 -0700192 } else {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700193 nextDriverState();
Sangho Shin01bca862014-09-12 11:18:59 -0700194 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700195 }
196
197 @Override
198 public boolean isDriverHandshakeComplete() {
Sangho Shin01bca862014-09-12 11:18:59 -0700199 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700200 throw new SwitchDriverSubHandshakeNotStarted();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700201 return driverHandshakeComplete.get();
202 }
203
204 @Override
205 public void processDriverHandshakeMessage(OFMessage m) {
Sangho Shin01bca862014-09-12 11:18:59 -0700206 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700207 throw new SwitchDriverSubHandshakeNotStarted();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700208 if (isDriverHandshakeComplete())
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700209 throw new SwitchDriverSubHandshakeCompleted(m);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700210 try {
211 processOFMessage(this, m);
212 } catch (IOException e) {
213 log.error("Error generated when processing OFMessage", e.getCause());
214 }
215 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700216
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700217 @Override
218 public String getSwitchDriverState() {
219 return driverState.toString();
220 }
221
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700222 public void removePortFromGroups(PortNumber port) {
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700223 /* FIX: removePortFromGroups is not working */
224
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700225 log.debug("removePortFromGroups: Remove port {} from Switch {}",
226 port, getStringId());
227 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
228 if (portNSSet == null)
229 {
230 /* No Groups are created with this port yet */
231 log.warn("removePortFromGroups: No groups exist with Switch {} port {}",
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700232 getStringId(), port);
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700233 return;
234 }
235 log.debug("removePortFromGroups: Neighborsets that the port {} is part"
236 + "of on Switch {} are {}",
237 port, getStringId(), portNSSet);
238
239 for (NeighborSet ns : portNSSet) {
240 /* Delete the first matched bucket */
241 EcmpInfo portEcmpInfo = ecmpGroups.get(ns);
242 Iterator<BucketInfo> it = portEcmpInfo.buckets.iterator();
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700243 log.debug("removePortFromGroups: Group {} on Switch {} has {} buckets",
244 portEcmpInfo.groupId, getStringId(),
245 portEcmpInfo.buckets.size());
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700246 while (it.hasNext()) {
247 BucketInfo bucket = it.next();
248 if (bucket.outport.equals(port)) {
249 it.remove();
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700250 }
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700251 }
252 log.debug("removePortFromGroups: Modifying Group on Switch {} "
253 + "and Neighborset {} with {}",
254 getStringId(), ns, portEcmpInfo);
255 modifyEcmpGroup(portEcmpInfo);
256 }
257 /* Don't delete the entry from portNeighborSetMap because
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700258 * when the port is up again this info is needed
259 */
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -0700260 return;
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700261 }
262
263 public void addPortToGroups(PortNumber port) {
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700264 log.debug("addPortToGroups: Add port {} to Switch {}",
265 port, getStringId());
266 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
267 if (portNSSet == null) {
268 /* Unknown Port */
269 log.warn("addPortToGroups: Switch {} port {} is unknown",
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700270 getStringId(), port);
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700271 return;
272 }
273 log.debug("addPortToGroups: Neighborsets that the port {} is part"
274 + "of on Switch {} are {}",
275 port, getStringId(), portNSSet);
276
277 Dpid neighborDpid = portToNeighbors.get(port);
278 for (NeighborSet ns : portNSSet) {
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700279 EcmpInfo portEcmpInfo = ecmpGroups.get(ns);
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700280 /* Find if this port is already part of any bucket
281 * in this group
282 * NOTE: This is needed because in some cases
283 * (such as for configured network nodes), both driver and
284 * application detect the network elements and creates the
285 * buckets in the same group. This check is to avoid
286 * duplicate bucket creation in such scenarios
287 */
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700288 List<BucketInfo> buckets = portEcmpInfo.buckets;
289 if (buckets == null) {
290 buckets = new ArrayList<BucketInfo>();
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700291 portEcmpInfo.buckets = buckets;
292 } else {
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700293 Iterator<BucketInfo> it = buckets.iterator();
294 boolean matchingBucketExist = false;
295 while (it.hasNext()) {
296 BucketInfo bucket = it.next();
297 if (bucket.outport.equals(port)) {
298 matchingBucketExist = true;
299 break;
300 }
301 }
302 if (matchingBucketExist) {
303 log.warn("addPortToGroups: On Switch {} duplicate "
304 + "portAdd is called for port {} with buckets {}",
305 getStringId(), port, buckets);
306 continue;
307 }
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700308 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700309 BucketInfo b = new BucketInfo(neighborDpid,
310 MacAddress.of(srConfig.getRouterMac()),
311 getNeighborRouterMacAddress(neighborDpid),
312 port,
313 ns.getEdgeLabel());
314 buckets.add(b);
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700315 log.debug("addPortToGroups: Modifying Group on Switch {} "
316 + "and Neighborset {} with {}",
317 getStringId(), ns, portEcmpInfo);
318 modifyEcmpGroup(portEcmpInfo);
319 }
320 return;
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700321 }
322
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700323 @Override
324 public OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps) {
325 OrderedCollection<PortChangeEvent> events = super.processOFPortStatus(ps);
326 for (PortChangeEvent e : events) {
327 switch (e.type) {
328 case DELETE:
329 case DOWN:
330 log.debug("processOFPortStatus: sw {} Port {} DOWN",
331 getStringId(), e.port.getPortNo().getPortNumber());
332 removePortFromGroups(PortNumber.uint32(
333 e.port.getPortNo().getPortNumber()));
334 break;
335 case UP:
336 log.debug("processOFPortStatus: sw {} Port {} UP",
337 getStringId(), e.port.getPortNo().getPortNumber());
338 addPortToGroups(PortNumber.uint32(
339 e.port.getPortNo().getPortNumber()));
340 }
341 }
342 return events;
343 }
344
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700345 // *****************************
346 // Driver handshake state-machine
347 // *****************************
348
349 enum DriverState {
350 INIT,
351 SET_TABLE_MISS_ENTRIES,
352 SET_TABLE_VLAN_TMAC,
353 SET_GROUPS,
354 VERIFY_GROUPS,
355 SET_ADJACENCY_LABELS,
356 EXIT
357 }
358
359 protected void nextDriverState() throws IOException {
360 DriverState currentState = driverState;
Saurav Das80d17392014-10-01 10:24:56 -0700361 if (haltStateMachine.get()) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700362 return;
Saurav Das80d17392014-10-01 10:24:56 -0700363 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700364 switch (currentState) {
365 case INIT:
366 driverState = DriverState.SET_TABLE_MISS_ENTRIES;
367 setTableMissEntries();
Saurav Dasd84178f2014-09-29 17:48:54 -0700368 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700369 break;
370 case SET_TABLE_MISS_ENTRIES:
371 driverState = DriverState.SET_TABLE_VLAN_TMAC;
372 getNetworkConfig();
373 populateTableVlan();
374 populateTableTMac();
Saurav Dasd84178f2014-09-29 17:48:54 -0700375 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700376 break;
377 case SET_TABLE_VLAN_TMAC:
378 driverState = DriverState.SET_GROUPS;
379 createGroups();
Saurav Dasd84178f2014-09-29 17:48:54 -0700380 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700381 break;
382 case SET_GROUPS:
383 driverState = DriverState.VERIFY_GROUPS;
384 verifyGroups();
385 break;
386 case VERIFY_GROUPS:
387 driverState = DriverState.SET_ADJACENCY_LABELS;
388 assignAdjacencyLabels();
389 break;
390 case SET_ADJACENCY_LABELS:
391 driverState = DriverState.EXIT;
392 driverHandshakeComplete.set(true);
393 break;
394 case EXIT:
395 default:
396 driverState = DriverState.EXIT;
397 log.error("Driver handshake has exited for sw: {}", getStringId());
398 }
399 }
400
401 void processOFMessage(IOFSwitch sw, OFMessage m) throws IOException {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700402 switch (m.getType()) {
403 case BARRIER_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700404 processBarrierReply(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700405 break;
406
407 case ERROR:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700408 processErrorMessage(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700409 break;
410
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700411 case GET_ASYNC_REPLY:
412 OFAsyncGetReply asrep = (OFAsyncGetReply) m;
413 decodeAsyncGetReply(asrep);
414 break;
415
416 case PACKET_IN:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700417 // not ready to handle packet-ins
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700418 break;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700419
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700420 case QUEUE_GET_CONFIG_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700421 // not doing queue config yet
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700422 break;
423
424 case STATS_REPLY:
425 processStatsReply((OFStatsReply) m);
426 break;
427
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700428 case ROLE_REPLY: // channelHandler should handle this
429 case PORT_STATUS: // channelHandler should handle this
430 case FEATURES_REPLY: // don't care
431 case FLOW_REMOVED: // don't care
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700432 default:
433 log.debug("Received message {} during switch-driver subhandshake "
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700434 + "from switch {} ... Ignoring message", m, sw.getStringId());
435 }
436 }
437
438 private void processStatsReply(OFStatsReply sr) {
439 switch (sr.getStatsType()) {
440 case AGGREGATE:
441 break;
442 case DESC:
443 break;
444 case EXPERIMENTER:
445 break;
446 case FLOW:
447 break;
448 case GROUP_DESC:
449 processGroupDesc((OFGroupDescStatsReply) sr);
450 break;
451 case GROUP_FEATURES:
452 processGroupFeatures((OFGroupFeaturesStatsReply) sr);
453 break;
454 case METER_CONFIG:
455 break;
456 case METER_FEATURES:
457 break;
458 case PORT_DESC:
459 break;
460 case TABLE_FEATURES:
461 break;
462 default:
463 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700464
465 }
466 }
467
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700468 private void processErrorMessage(OFMessage m) {
469 log.error("Switch {} Error {} in DriverState", getStringId(),
470 (OFErrorMsg) m, driverState);
471 }
472
473 private void processBarrierReply(OFMessage m) throws IOException {
474 if (m.getXid() == barrierXidToWaitFor) {
475 // Driver state-machine progresses to the next state.
476 // If Barrier messages is not received, then eventually
477 // the ChannelHandler state machine will timeout, and the switch
478 // will be disconnected.
479 nextDriverState();
480 } else {
481 log.error("Received incorrect barrier-message xid {} (expected: {}) in "
482 + "switch-driver state {} for switch {}", m, barrierXidToWaitFor,
483 driverState, getStringId());
484 }
485 }
486
487 private void processGroupDesc(OFGroupDescStatsReply gdsr) {
488 log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
489 try {
490 nextDriverState();
491 } catch (IOException e) {
492 // TODO Auto-generated catch block
493 e.printStackTrace();
494 }
495 }
496
497 // *****************************
498 // Utility methods
499 // *****************************
500
501 void setTableMissEntries() throws IOException {
502 // set all table-miss-entries
503 populateTableMissEntry(TABLE_VLAN, true, false, false, -1);
504 populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
505 populateTableMissEntry(TABLE_IPv4_UNICAST, false, true, true,
506 TABLE_ACL);
507 populateTableMissEntry(TABLE_MPLS, false, true, true,
508 TABLE_ACL);
509 populateTableMissEntry(TABLE_ACL, false, false, false, -1);
510 }
511
Saurav Dasd84178f2014-09-29 17:48:54 -0700512 private void sendHandshakeBarrier() throws IOException {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700513 long xid = getNextTransactionId();
514 barrierXidToWaitFor = xid;
515 OFBarrierRequest br = getFactory()
516 .buildBarrierRequest()
517 .setXid(xid)
518 .build();
519 write(br, null);
520 }
521
522 /**
523 * Adds a table-miss-entry to a pipeline table.
524 * <p>
525 * The table-miss-entry can be added with 'write-actions' or
526 * 'apply-actions'. It can also add a 'goto-table' instruction. By default
527 * if none of the booleans in the call are set, then the table-miss entry is
528 * added with no instructions, which means that if a packet hits the
529 * table-miss-entry, pipeline execution will stop, and the action set
530 * associated with the packet will be executed.
531 *
532 * @param tableToAdd the table to where the table-miss-entry will be added
533 * @param toControllerNow as an APPLY_ACTION instruction
534 * @param toControllerWrite as a WRITE_ACTION instruction
535 * @param toTable as a GOTO_TABLE instruction
536 * @param tableToSend the table to send as per the GOTO_TABLE instruction it
537 * needs to be set if 'toTable' is true. Ignored of 'toTable' is
538 * false.
539 * @throws IOException
540 */
541 @SuppressWarnings("unchecked")
542 private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
543 boolean toControllerWrite,
544 boolean toTable, int tableToSend) throws IOException {
545 OFOxmList oxmList = OFOxmList.EMPTY;
546 OFMatchV3 match = factory.buildMatchV3()
547 .setOxmList(oxmList)
548 .build();
549 OFAction outc = factory.actions()
550 .buildOutput()
551 .setPort(OFPort.CONTROLLER)
552 .setMaxLen(OFPCML_NO_BUFFER)
553 .build();
554 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
555 if (toControllerNow) {
556 // table-miss instruction to send to controller immediately
557 OFInstruction instr = factory.instructions()
558 .buildApplyActions()
559 .setActions(Collections.singletonList(outc))
560 .build();
561 instructions.add(instr);
562 }
563
564 if (toControllerWrite) {
565 // table-miss instruction to write-action to send to controller
566 // this will be executed whenever the action-set gets executed
567 OFInstruction instr = factory.instructions()
568 .buildWriteActions()
569 .setActions(Collections.singletonList(outc))
570 .build();
571 instructions.add(instr);
572 }
573
574 if (toTable) {
575 // table-miss instruction to goto-table x
576 OFInstruction instr = factory.instructions()
577 .gotoTable(TableId.of(tableToSend));
578 instructions.add(instr);
579 }
580
581 if (!toControllerNow && !toControllerWrite && !toTable) {
582 // table-miss has no instruction - at which point action-set will be
583 // executed - if there is an action to output/group in the action
584 // set
585 // the packet will be sent there, otherwise it will be dropped.
586 instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
587 }
588
589 OFMessage tableMissEntry = factory.buildFlowAdd()
590 .setTableId(TableId.of(tableToAdd))
591 .setMatch(match) // match everything
592 .setInstructions(instructions)
593 .setPriority(MIN_PRIORITY)
594 .setBufferId(OFBufferId.NO_BUFFER)
595 .setIdleTimeout(0)
596 .setHardTimeout(0)
597 .setXid(getNextTransactionId())
598 .build();
599 write(tableMissEntry, null);
600 }
601
602 private void getNetworkConfig() {
603 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
604 SwitchConfigStatus scs = ncs.checkSwitchConfig(new Dpid(getId()));
605 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
606 srConfig = (SegmentRouterConfig) scs.getSwitchConfig();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700607 isEdgeRouter = srConfig.isEdgeRouter();
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700608 sid = srConfig.getNodeSid();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700609 } else {
610 log.error("Switch not configured as Segment-Router");
611 }
612
613 List<LinkConfig> linkConfigList = ncs.getConfiguredAllowedLinks();
614 setNeighbors(linkConfigList);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700615
616 if (isEdgeRouter) {
617 List<SwitchConfig> switchList = ncs.getConfiguredAllowedSwitches();
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700618 getAllNodeSegmentIds(switchList);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700619 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700620 }
621
622 private void populateTableVlan() throws IOException {
623 List<OFMessage> msglist = new ArrayList<OFMessage>();
624 for (OFPortDesc p : getPorts()) {
625 int pnum = p.getPortNo().getPortNumber();
626 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
627 OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
628 OFOxmVlanVid oxv = factory.oxms()
629 .vlanVid(OFVlanVidMatch.UNTAGGED);
630 OFOxmList oxmList = OFOxmList.of(oxp, oxv);
631 OFMatchV3 match = factory.buildMatchV3()
632 .setOxmList(oxmList).build();
633
634 // TODO: match on vlan-tagged packets for vlans configured on
635 // subnet ports and strip-vlan
636
637 // Do not need to add vlans
638 /*int vlanid = getVlanConfig(pnum);
639 OFOxmVlanVid vidToSet = factory.oxms()
640 .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
641 OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
642 OFAction setVlan = factory.actions().setField(vidToSet);
643 List<OFAction> actionlist = new ArrayList<OFAction>();
644 actionlist.add(pushVlan);
645 actionlist.add(setVlan);
646 OFInstruction appAction = factory.instructions().buildApplyActions()
647 .setActions(actionlist).build();*/
648
649 OFInstruction gotoTbl = factory.instructions().buildGotoTable()
650 .setTableId(TableId.of(TABLE_TMAC)).build();
651 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
652 // instructions.add(appAction);
653 instructions.add(gotoTbl);
654 OFMessage flowEntry = factory.buildFlowAdd()
655 .setTableId(TableId.of(TABLE_VLAN))
656 .setMatch(match)
657 .setInstructions(instructions)
658 .setPriority(1000) // does not matter - all rules
659 // exclusive
660 .setBufferId(OFBufferId.NO_BUFFER)
661 .setIdleTimeout(0)
662 .setHardTimeout(0)
663 .setXid(getNextTransactionId())
664 .build();
665 msglist.add(flowEntry);
666 }
667 }
668 write(msglist);
669 log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId());
670 }
671
672 private void populateTableTMac() throws IOException {
673 // match for router-mac and ip-packets
674 OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
675 OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr());
676 OFOxmList oxmListIp = OFOxmList.of(dmac, oxe);
677 OFMatchV3 matchIp = factory.buildMatchV3()
678 .setOxmList(oxmListIp).build();
679 OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
680 .setTableId(TableId.of(TABLE_IPv4_UNICAST)).build();
681 List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
682 OFMessage ipEntry = factory.buildFlowAdd()
683 .setTableId(TableId.of(TABLE_TMAC))
684 .setMatch(matchIp)
685 .setInstructions(instructionsIp)
686 .setPriority(1000) // strict priority required lower than
687 // multicastMac
688 .setBufferId(OFBufferId.NO_BUFFER)
689 .setIdleTimeout(0)
690 .setHardTimeout(0)
691 .setXid(getNextTransactionId())
692 .build();
693
694 // match for router-mac and mpls packets
695 OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
696 OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls);
697 OFMatchV3 matchMpls = factory.buildMatchV3()
698 .setOxmList(oxmListMpls).build();
699 OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
700 .setTableId(TableId.of(TABLE_MPLS)).build();
701 List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
702 OFMessage mplsEntry = factory.buildFlowAdd()
703 .setTableId(TableId.of(TABLE_TMAC))
704 .setMatch(matchMpls)
705 .setInstructions(instructionsMpls)
706 .setPriority(1001) // strict priority required lower than
707 // multicastMac
708 .setBufferId(OFBufferId.NO_BUFFER)
709 .setIdleTimeout(0)
710 .setHardTimeout(0)
711 .setXid(getNextTransactionId())
712 .build();
713
714 log.debug("Adding termination-mac-rules in sw {}", getStringId());
715 List<OFMessage> msglist = new ArrayList<OFMessage>(2);
716 msglist.add(ipEntry);
717 msglist.add(mplsEntry);
718 write(msglist);
719 }
720
721 private MacAddress getRouterMacAddr() {
722 if (srConfig != null) {
723 return MacAddress.of(srConfig.getRouterMac());
724 } else {
725 // return a dummy mac address - it will not be used
726 return MacAddress.of("00:00:00:00:00:00");
727 }
728 }
729
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700730 private boolean isEdgeRouter(Dpid ndpid) {
731 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
732 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
733 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
734 return ((SegmentRouterConfig) scs.getSwitchConfig()).isEdgeRouter();
735 } else {
736 // TODO: return false if router not allowed
737 return false;
738 }
739 }
740
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700741 private MacAddress getNeighborRouterMacAddress(Dpid ndpid) {
742 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
743 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
744 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
745 return MacAddress.of(((SegmentRouterConfig) scs.getSwitchConfig())
746 .getRouterMac());
747 } else {
748 // return a dummy mac address - it will not be used
749 return MacAddress.of("00:00:00:00:00:00");
750 }
751 }
752
753 private void setNeighbors(List<LinkConfig> linkConfigList) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700754 for (LinkConfig lg : linkConfigList) {
755 if (!lg.getType().equals(NetworkConfigManager.PKT_LINK)) {
Saurav Das80d17392014-10-01 10:24:56 -0700756 continue;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700757 }
758 PktLinkConfig plg = (PktLinkConfig) lg;
759 if (plg.getDpid1() == getId()) {
760 addNeighborAtPort(new Dpid(plg.getDpid2()),
761 PortNumber.uint32(plg.getPort1()));
762 } else if (plg.getDpid2() == getId()) {
763 addNeighborAtPort(new Dpid(plg.getDpid1()),
764 PortNumber.uint32(plg.getPort2()));
765 }
766 }
767 }
768
769 private void addNeighborAtPort(Dpid neighborDpid, PortNumber portToNeighbor) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700770 /* Update NeighborToPort database */
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700771 if (neighbors.get(neighborDpid) != null) {
772 neighbors.get(neighborDpid).add(portToNeighbor);
773 } else {
774 Set<PortNumber> ports = new HashSet<PortNumber>();
775 ports.add(portToNeighbor);
776 neighbors.put(neighborDpid, ports);
777 }
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700778
779 /* Update portToNeighbors database */
780 if (portToNeighbors.get(portToNeighbor) == null)
781 portToNeighbors.put(portToNeighbor, neighborDpid);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700782 }
783
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700784 private void getAllNodeSegmentIds(List<SwitchConfig> switchList) {
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700785 for (SwitchConfig sc : switchList) {
786 /* TODO: Do we need to check if the SwitchConfig is of
787 * type SegmentRouter?
788 */
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700789 if (sc.getDpid() == getId()) {
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700790 continue;
791 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700792 segmentIds.add(((SegmentRouterConfig) sc).getNodeSid());
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700793 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700794 log.debug("getAllNodeSegmentIds: at sw {} are {}",
795 getStringId(), segmentIds);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700796 }
797
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700798 private boolean isSegmentIdSameAsNodeSegmentId(Dpid dpid, int sId) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700799 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
800 SwitchConfigStatus scs = ncs.checkSwitchConfig(dpid);
801 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
802 return (((SegmentRouterConfig) scs.getSwitchConfig()).
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700803 getNodeSid() == sId);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700804 } else {
805 // TODO: return false if router not allowed
806 return false;
807 }
808 }
809
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700810 private Set<Set<Dpid>> getAllNeighborSets(Set<Dpid> neighbors) {
811 List<Dpid> list = new ArrayList<Dpid>(neighbors);
812 Set<Set<Dpid>> sets = new HashSet<Set<Dpid>>();
813 /* get the number of elements in the neighbors */
814 int elements = list.size();
815 /* the number of members of a power set is 2^n
816 * including the empty set
817 */
818 int powerElements = (1 << elements);
819
820 /* run a binary counter for the number of power elements */
821 for (long i = 1; i < powerElements; i++) {
822 Set<Dpid> dpidSubSet = new HashSet<Dpid>();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700823 for (int j = 0; j < elements; j++) {
824 if ((i >> j) % 2 == 1) {
825 dpidSubSet.add(list.get(j));
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700826 }
827 }
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700828 /* NOTE: Avoid any pairings of edge routers only
829 * at a backbone router */
830 boolean avoidEdgeRouterPairing = true;
831 if ((!isEdgeRouter) && (dpidSubSet.size() > 1)) {
Srikanth Vavilapalli696010f2014-10-08 17:00:17 -0700832 for (Dpid dpid : dpidSubSet) {
833 if (!isEdgeRouter(dpid)) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700834 avoidEdgeRouterPairing = false;
Srikanth Vavilapalli696010f2014-10-08 17:00:17 -0700835 break;
836 }
837 }
838 }
839 else
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700840 avoidEdgeRouterPairing = false;
Srikanth Vavilapalli696010f2014-10-08 17:00:17 -0700841
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700842 if (!avoidEdgeRouterPairing)
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700843 sets.add(dpidSubSet);
844 }
845 return sets;
846 }
847
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700848 private void createGroupForANeighborSet(NeighborSet ns, int groupId) {
849 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
850 for (Dpid d : ns.getDpids()) {
851 for (PortNumber sp : neighbors.get(d)) {
852 BucketInfo b = new BucketInfo(d,
853 MacAddress.of(srConfig.getRouterMac()),
854 getNeighborRouterMacAddress(d), sp,
855 ns.getEdgeLabel());
856 buckets.add(b);
857
858 /* Update Port Neighborset map */
859 ArrayList<NeighborSet> portNeighborSets =
860 portNeighborSetMap.get(sp);
861 if (portNeighborSets == null) {
862 portNeighborSets = new ArrayList<NeighborSet>();
863 portNeighborSets.add(ns);
864 portNeighborSetMap.put(sp, portNeighborSets);
865 }
866 else
867 portNeighborSets.add(ns);
868 }
869 }
870 EcmpInfo ecmpInfo = new EcmpInfo(groupId, buckets);
871 setEcmpGroup(ecmpInfo);
872 ecmpGroups.put(ns, ecmpInfo);
873 log.debug(
874 "createGroupForANeighborSet: Creating ecmp group {} in sw {} "
875 + "for neighbor set {} with: {}",
876 groupId, getStringId(), ns, ecmpInfo);
877 return;
878 }
879
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700880 /**
881 * createGroups creates ECMP groups for all ports on this router connected
882 * to other routers (in the OF network). The information for ports is
883 * gleaned from the configured links. If no links are configured no groups
884 * will be created, and it is up to the caller of the IOF13Switch API to
885 * create groups.
886 * <p>
887 * By default all ports connected to the same neighbor router will be part
888 * of the same ECMP group. In addition, groups will be created for all
889 * possible combinations of neighbor routers.
890 * <p>
891 * For example, consider this router (R0) connected to 3 neighbors (R1, R2,
892 * and R3). The following groups will be created in R0:
893 * <li>1) all ports to R1,
894 * <li>2) all ports to R2,
895 * <li>3) all ports to R3,
896 * <li>4) all ports to R1 and R2
897 * <li>5) all ports to R1 and R3
898 * <li>6) all ports to R2 and R3
899 * <li>7) all ports to R1, R2, and R3
900 */
901 private void createGroups() {
902 Set<Dpid> dpids = neighbors.keySet();
903 if (dpids == null || dpids.isEmpty()) {
904 return;
905 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700906 /* Create all possible Neighbor sets from this router
907 * NOTE: Avoid any pairings of edge routers only
908 */
909 Set<Set<Dpid>> powerSet = getAllNeighborSets(dpids);
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700910 log.debug("createGroups: The size of neighbor powerset for sw {} is {}",
Srikanth Vavilapallica2263c2014-10-09 15:19:11 -0700911 getStringId(), powerSet.size());
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700912 Set<NeighborSet> nsSet = new HashSet<NeighborSet>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700913 for (Set<Dpid> combo : powerSet) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700914 if (combo.isEmpty())
915 continue;
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700916 if (isEdgeRouter && !segmentIds.isEmpty()) {
917 for (Integer sId : segmentIds) {
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700918 NeighborSet ns = new NeighborSet();
919 ns.addDpids(combo);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700920 /* Check if the edge label being set is of the
921 * same node in the Neighbor set
922 */
923 if ((combo.size() != 1) ||
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700924 (!isSegmentIdSameAsNodeSegmentId(
925 combo.iterator().next(), sId))) {
926 ns.setEdgeLabel(sId);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700927 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700928 nsSet.add(ns);
929 }
930 } else {
931 NeighborSet ns = new NeighborSet();
932 ns.addDpids(combo);
933 nsSet.add(ns);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700934 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700935 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700936 log.debug("createGroups: The neighborset with label for sw {} is {}",
Srikanth Vavilapallica2263c2014-10-09 15:19:11 -0700937 getStringId(), nsSet);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700938
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700939 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700940 createGroupForANeighborSet(ns, groupid.incrementAndGet());
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700941 }
942 }
943
944 private class EcmpInfo {
945 int groupId;
946 List<BucketInfo> buckets;
947
948 EcmpInfo(int gid, List<BucketInfo> bucketInfos) {
949 groupId = gid;
950 buckets = bucketInfos;
951 }
952
953 @Override
954 public String toString() {
955 return "groupId: " + groupId + ", buckets: " + buckets;
956 }
957 }
958
959 private class BucketInfo {
960 Dpid neighborDpid;
961 MacAddress srcMac;
962 MacAddress dstMac;
963 PortNumber outport;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700964 int mplsLabel;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700965
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700966 BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac,
967 PortNumber p, int label) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700968 neighborDpid = nDpid;
969 srcMac = smac;
970 dstMac = dmac;
971 outport = p;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700972 mplsLabel = label;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700973 }
974
975 @Override
976 public String toString() {
977 return " {neighborDpid: " + neighborDpid + ", dstMac: " + dstMac +
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700978 ", srcMac: " + srcMac + ", outport: " + outport +
979 "mplsLabel: " + mplsLabel + "}";
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700980 }
981 }
982
983 private void setEcmpGroup(EcmpInfo ecmpInfo) {
984 List<OFMessage> msglist = new ArrayList<OFMessage>();
985 OFGroup group = OFGroup.of(ecmpInfo.groupId);
986
987 List<OFBucket> buckets = new ArrayList<OFBucket>();
988 for (BucketInfo b : ecmpInfo.buckets) {
989 OFOxmEthDst dmac = factory.oxms()
990 .ethDst(b.dstMac);
991 OFAction setDA = factory.actions().buildSetField()
992 .setField(dmac).build();
Saurav Das0a344b02014-09-26 14:18:52 -0700993 OFOxmEthSrc smac = factory.oxms()
994 .ethSrc(b.srcMac);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700995 OFAction setSA = factory.actions().buildSetField()
996 .setField(smac).build();
997 OFAction outp = factory.actions().buildOutput()
998 .setPort(OFPort.of(b.outport.shortValue()))
999 .build();
1000 List<OFAction> actions = new ArrayList<OFAction>();
1001 actions.add(setSA);
1002 actions.add(setDA);
1003 actions.add(outp);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001004 if (b.mplsLabel != -1) {
1005 OFAction pushLabel = factory.actions().buildPushMpls()
1006 .setEthertype(EthType.MPLS_UNICAST).build();
Sangho Shin62ce5c12014-10-08 16:24:40 -07001007 OFOxmMplsLabel lid = factory.oxms()
1008 .mplsLabel(U32.of(b.mplsLabel));
1009 OFAction setLabel = factory.actions().buildSetField()
1010 .setField(lid).build();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001011 OFAction copyTtl = factory.actions().copyTtlOut();
1012 OFAction decrTtl = factory.actions().decMplsTtl();
1013 actions.add(pushLabel);
1014 actions.add(setLabel);
1015 actions.add(copyTtl);
1016 actions.add(decrTtl);
1017 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001018 OFBucket ofb = factory.buildBucket()
1019 .setWeight(1)
1020 .setActions(actions)
1021 .build();
1022 buckets.add(ofb);
1023 }
1024
1025 OFMessage gm = factory.buildGroupAdd()
1026 .setGroup(group)
1027 .setBuckets(buckets)
1028 .setGroupType(OFGroupType.SELECT)
1029 .setXid(getNextTransactionId())
1030 .build();
1031 msglist.add(gm);
1032 try {
1033 write(msglist);
1034 } catch (IOException e) {
1035 // TODO Auto-generated catch block
1036 e.printStackTrace();
1037 }
1038 }
1039
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -07001040 private void modifyEcmpGroup(EcmpInfo ecmpInfo) {
1041 List<OFMessage> msglist = new ArrayList<OFMessage>();
1042 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1043
1044 List<OFBucket> buckets = new ArrayList<OFBucket>();
1045 for (BucketInfo b : ecmpInfo.buckets) {
1046 OFOxmEthDst dmac = factory.oxms()
1047 .ethDst(b.dstMac);
1048 OFAction setDA = factory.actions().buildSetField()
1049 .setField(dmac).build();
1050 OFOxmEthSrc smac = factory.oxms()
1051 .ethSrc(b.srcMac);
1052 OFAction setSA = factory.actions().buildSetField()
1053 .setField(smac).build();
1054 OFAction outp = factory.actions().buildOutput()
1055 .setPort(OFPort.of(b.outport.shortValue()))
1056 .build();
1057 List<OFAction> actions = new ArrayList<OFAction>();
1058 actions.add(setSA);
1059 actions.add(setDA);
1060 actions.add(outp);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001061 if (b.mplsLabel != -1) {
1062 OFAction pushLabel = factory.actions().buildPushMpls()
1063 .setEthertype(EthType.MPLS_UNICAST).build();
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -07001064 OFOxmMplsLabel lid = factory.oxms()
1065 .mplsLabel(U32.of(b.mplsLabel));
1066 OFAction setLabel = factory.actions().buildSetField()
1067 .setField(lid).build();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001068 OFAction copyTtl = factory.actions().copyTtlOut();
1069 OFAction decrTtl = factory.actions().decMplsTtl();
1070 actions.add(pushLabel);
1071 actions.add(setLabel);
1072 actions.add(copyTtl);
1073 actions.add(decrTtl);
1074 }
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -07001075 OFBucket ofb = factory.buildBucket()
1076 .setWeight(1)
1077 .setActions(actions)
1078 .build();
1079 buckets.add(ofb);
1080 }
1081
1082 OFMessage gm = factory.buildGroupModify()
1083 .setGroup(group)
1084 .setBuckets(buckets)
1085 .setGroupType(OFGroupType.SELECT)
1086 .setXid(getNextTransactionId())
1087 .build();
1088 msglist.add(gm);
1089 try {
1090 write(msglist);
1091 } catch (IOException e) {
1092 // TODO Auto-generated catch block
1093 e.printStackTrace();
1094 }
1095 }
1096
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001097 private void verifyGroups() throws IOException {
1098 sendGroupDescRequest();
1099 }
1100
1101 private void sendGroupDescRequest() throws IOException {
1102 OFMessage gdr = factory.buildGroupDescStatsRequest()
1103 .setXid(getNextTransactionId())
1104 .build();
1105 write(gdr, null);
1106 }
1107
1108 private void assignAdjacencyLabels() {
1109 // TODO
1110 try {
1111 nextDriverState();
1112 } catch (IOException e) {
1113 // TODO Auto-generated catch block
1114 e.printStackTrace();
1115 }
1116 }
1117
Saurav Das1cd10152014-09-26 09:38:07 -07001118 private OFAction getOFAction(Action action) {
1119 OFAction ofAction = null;
1120 if (action instanceof OutputAction) {
1121 OutputAction outputAction = (OutputAction) action;
1122 OFPort port = OFPort.of((int) outputAction.getPortNumber().value());
1123 ofAction = factory.actions().output(port, Short.MAX_VALUE);
1124 } else if (action instanceof ModifyDstMacAction) {
1125 long dstMac = ((ModifyDstMacAction) action).getDstMac().toLong();
1126 OFOxmEthDst dmac = factory.oxms()
1127 .ethDst(MacAddress.of(dstMac));
1128 ofAction = factory.actions().buildSetField()
1129 .setField(dmac).build();
1130 } else if (action instanceof ModifySrcMacAction) {
1131 long srcMac = ((ModifySrcMacAction) action).getSrcMac().toLong();
1132 OFOxmEthSrc smac = factory.oxms()
1133 .ethSrc(MacAddress.of(srcMac));
1134 ofAction = factory.actions().buildSetField()
1135 .setField(smac).build();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001136 /*} else if (action instanceof PushMplsAction) {
1137 ofAction = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1138 } else if (action instanceof SetMplsIdAction) {
1139 int labelid = ((SetMplsIdAction) action).getMplsId();
1140 OFOxmMplsLabel lid = factory.oxms()
1141 .mplsLabel(U32.of(labelid));
1142 ofAction = factory.actions().buildSetField()
1143 .setField(lid).build();
1144 */} else if (action instanceof PopMplsAction) {
Saurav Das1cd10152014-09-26 09:38:07 -07001145 EthType ethertype = ((PopMplsAction) action).getEthType();
1146 ofAction = factory.actions().popMpls(ethertype);
1147 } else if (action instanceof GroupAction) {
1148 NeighborSet ns = ((GroupAction) action).getDpids();
1149 EcmpInfo ei = ecmpGroups.get(ns);
1150 if (ei != null) {
1151 int gid = ei.groupId;
1152 ofAction = factory.actions().buildGroup()
1153 .setGroup(OFGroup.of(gid))
1154 .build();
1155 } else {
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -07001156 log.debug("Unable to find ecmp group for neighbors {} at "
1157 + "switch {} and hence creating it", ns, getStringId());
1158 createGroupForANeighborSet(ns, groupid.incrementAndGet());
Saurav Das1cd10152014-09-26 09:38:07 -07001159 }
1160 } else if (action instanceof DecNwTtlAction) {
1161 ofAction = factory.actions().decNwTtl();
1162 } else if (action instanceof DecMplsTtlAction) {
1163 ofAction = factory.actions().decMplsTtl();
1164 } else if (action instanceof CopyTtlInAction) {
1165 ofAction = factory.actions().copyTtlIn();
1166 } else if (action instanceof CopyTtlOutAction) {
1167 ofAction = factory.actions().copyTtlOut();
1168 } else {
1169 log.warn("Unsupported Action type: {}", action.getClass().getName());
1170 return null;
1171 }
1172
1173 // not supported by loxigen
1174 // OFAction setBos =
1175 // factory.actions().buildSetField().setField(bos).build();
1176
1177 return ofAction;
1178 }
1179
Saurav Das0a344b02014-09-26 14:18:52 -07001180 private OFMessage getIpEntry(MatchActionOperationEntry mao) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001181 MatchAction ma = mao.getTarget();
1182 Operator op = mao.getOperator();
1183 Ipv4Match ipm = (Ipv4Match) ma.getMatch();
1184
1185 // set match
1186 IPv4Net ipdst = ipm.getDestination();
1187 OFOxmEthType ethTypeIp = factory.oxms()
1188 .ethType(EthType.IPv4);
1189 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
1190 .ipv4DstMasked(
1191 IPv4Address.of(ipdst.address().value()),
1192 IPv4Address.ofCidrMaskLength(ipdst.prefixLen())
1193 );
1194 OFOxmList oxmList = OFOxmList.of(ethTypeIp, ipPrefix);
1195 OFMatchV3 match = factory.buildMatchV3()
1196 .setOxmList(oxmList).build();
1197
1198 // set actions
1199 List<OFAction> writeActions = new ArrayList<OFAction>();
1200 for (Action action : ma.getActions()) {
Saurav Das1cd10152014-09-26 09:38:07 -07001201 OFAction ofAction = getOFAction(action);
1202 if (ofAction != null) {
1203 writeActions.add(ofAction);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001204 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001205 }
1206
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001207 // set instructions
1208 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1209 .setActions(writeActions).build();
1210 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1211 .setTableId(TableId.of(TABLE_ACL)).build();
1212 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1213 instructions.add(writeInstr);
1214 instructions.add(gotoInstr);
1215
Saurav Das1cd10152014-09-26 09:38:07 -07001216 // set flow priority to emulate longest prefix match
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001217 int priority = ipdst.prefixLen() * PRIORITY_MULTIPLIER;
1218 if (ipdst.prefixLen() == (short) 32) {
1219 priority = MAX_PRIORITY;
1220 }
1221
Saurav Dasbc594a42014-09-25 20:13:50 -07001222 // set flow-mod
Saurav Dase972b3a2014-09-26 15:41:06 -07001223 OFFlowMod.Builder fmBuilder = null;
1224 switch (op) {
1225 case ADD:
1226 fmBuilder = factory.buildFlowAdd();
1227 break;
1228 case REMOVE:
1229 fmBuilder = factory.buildFlowDeleteStrict();
1230 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001231 case MODIFY: // TODO
1232 fmBuilder = factory.buildFlowModifyStrict();
1233 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001234 default:
1235 log.warn("Unsupported MatchAction Operator: {}", op);
1236 return null;
Saurav Dasbc594a42014-09-25 20:13:50 -07001237 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001238 OFMessage ipFlow = fmBuilder
1239 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
1240 .setMatch(match)
1241 .setInstructions(instructions)
1242 .setPriority(priority)
1243 .setBufferId(OFBufferId.NO_BUFFER)
1244 .setIdleTimeout(0)
1245 .setHardTimeout(0)
1246 .setXid(getNextTransactionId())
1247 .build();
Saurav Dasbc594a42014-09-25 20:13:50 -07001248 log.debug("{} ip-rule {}-{} in sw {}",
1249 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1250 match, writeActions,
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001251 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001252 return ipFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001253 }
1254
Saurav Das0a344b02014-09-26 14:18:52 -07001255 private OFMessage getMplsEntry(MatchActionOperationEntry mao) {
Saurav Das1cd10152014-09-26 09:38:07 -07001256 MatchAction ma = mao.getTarget();
1257 Operator op = mao.getOperator();
1258 MplsMatch mplsm = (MplsMatch) ma.getMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001259
Saurav Das1cd10152014-09-26 09:38:07 -07001260 // set match
1261 OFOxmEthType ethTypeMpls = factory.oxms()
1262 .ethType(EthType.MPLS_UNICAST);
1263 OFOxmMplsLabel labelid = factory.oxms()
1264 .mplsLabel(U32.of(mplsm.getMplsLabel()));
Saurav Dascc3e35f2014-10-10 15:33:32 -07001265 // OFOxmMplsBos bos = factory.oxms()
1266 // .mplsBos(OFBooleanValue.of(mplsm.isBos()));
1267 OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid); // XXX add bos
Saurav Das1cd10152014-09-26 09:38:07 -07001268 OFMatchV3 matchlabel = factory.buildMatchV3()
1269 .setOxmList(oxmList).build();
1270
1271 // set actions
1272 List<OFAction> writeActions = new ArrayList<OFAction>();
1273 for (Action action : ma.getActions()) {
1274 OFAction ofAction = getOFAction(action);
1275 if (ofAction != null) {
1276 writeActions.add(ofAction);
1277 }
1278 }
1279
1280 // set instructions
1281 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1282 .setActions(writeActions).build();
1283 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1284 .setTableId(TableId.of(TABLE_ACL)).build();
1285 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1286 instructions.add(writeInstr);
1287 instructions.add(gotoInstr);
1288
Saurav Dase972b3a2014-09-26 15:41:06 -07001289 // set flow-mod
1290 OFFlowMod.Builder fmBuilder = null;
1291 switch (op) {
1292 case ADD:
1293 fmBuilder = factory.buildFlowAdd();
1294 break;
1295 case REMOVE:
1296 fmBuilder = factory.buildFlowDeleteStrict();
1297 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001298 case MODIFY: // TODO
1299 fmBuilder = factory.buildFlowModifyStrict();
1300 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001301 default:
1302 log.warn("Unsupported MatchAction Operator: {}", op);
1303 return null;
Saurav Das1cd10152014-09-26 09:38:07 -07001304 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001305
1306 OFMessage mplsFlow = fmBuilder
1307 .setTableId(TableId.of(TABLE_MPLS))
1308 .setMatch(matchlabel)
1309 .setInstructions(instructions)
1310 .setPriority(MAX_PRIORITY) // exact match and exclusive
1311 .setBufferId(OFBufferId.NO_BUFFER)
1312 .setIdleTimeout(0)
1313 .setHardTimeout(0)
1314 .setXid(getNextTransactionId())
1315 .build();
Saurav Das1cd10152014-09-26 09:38:07 -07001316 log.debug("{} mpls-rule {}-{} in sw {}",
1317 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1318 matchlabel, writeActions,
1319 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001320 return mplsFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001321 }
1322
Saurav Das0a344b02014-09-26 14:18:52 -07001323 private OFMessage getAclEntry(MatchActionOperationEntry mao) {
Saurav Dase972b3a2014-09-26 15:41:06 -07001324 MatchAction ma = mao.getTarget();
1325 Operator op = mao.getOperator();
1326 PacketMatch packetMatch = (PacketMatch) ma.getMatch();
1327 Builder matchBuilder = factory.buildMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001328
Saurav Dase972b3a2014-09-26 15:41:06 -07001329 // set match
1330 int inport = 0;
1331 if (ma.getSwitchPort() != null) {
1332 inport = (int) ma.getSwitchPort().getPortNumber().value();
1333 }
1334 final MACAddress srcMac = packetMatch.getSrcMacAddress();
1335 final MACAddress dstMac = packetMatch.getDstMacAddress();
1336 final Short etherType = packetMatch.getEtherType();
1337 final IPv4Net srcIp = packetMatch.getSrcIpAddress();
1338 final IPv4Net dstIp = packetMatch.getDstIpAddress();
1339 final Byte ipProto = packetMatch.getIpProtocolNumber();
1340 final Short srcTcpPort = packetMatch.getSrcTcpPortNumber();
1341 final Short dstTcpPort = packetMatch.getDstTcpPortNumber();
1342 if (inport > 0) {
1343 matchBuilder.setExact(MatchField.IN_PORT,
1344 OFPort.of(inport));
1345 }
1346 if (srcMac != null) {
1347 matchBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(srcMac.toLong()));
1348 }
1349 if (dstMac != null) {
1350 matchBuilder.setExact(MatchField.ETH_DST, MacAddress.of(dstMac.toLong()));
1351 }
1352 if (etherType != null) {
1353 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(etherType));
1354 }
1355 if (srcIp != null) {
1356 matchBuilder.setMasked(MatchField.IPV4_SRC,
1357 IPv4Address.of(srcIp.address().value())
1358 .withMaskOfLength(srcIp.prefixLen()));
1359 }
1360 if (dstIp != null) {
1361 matchBuilder.setMasked(MatchField.IPV4_DST,
1362 IPv4Address.of(dstIp.address().value())
1363 .withMaskOfLength(dstIp.prefixLen()));
1364 }
1365 if (ipProto != null) {
1366 matchBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(ipProto));
1367 }
1368 if (srcTcpPort != null) {
1369 matchBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(srcTcpPort));
1370 }
1371 if (dstTcpPort != null) {
1372 matchBuilder.setExact(MatchField.TCP_DST, TransportPort.of(dstTcpPort));
1373 }
1374
1375 // set actions
Saurav Dascc3e35f2014-10-10 15:33:32 -07001376 List<OFAction> writeActions = new ArrayList<OFAction>();
Saurav Dase972b3a2014-09-26 15:41:06 -07001377 for (Action action : ma.getActions()) {
1378 OFAction ofAction = getOFAction(action);
1379 if (ofAction != null) {
Saurav Dascc3e35f2014-10-10 15:33:32 -07001380 writeActions.add(ofAction);
Saurav Dase972b3a2014-09-26 15:41:06 -07001381 }
1382 }
1383
1384 // set instructions
1385 OFInstruction clearInstr = factory.instructions().clearActions();
Saurav Dascc3e35f2014-10-10 15:33:32 -07001386 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1387 .setActions(writeActions).build();
Saurav Dase972b3a2014-09-26 15:41:06 -07001388 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1389 instructions.add(clearInstr);
Saurav Dascc3e35f2014-10-10 15:33:32 -07001390 instructions.add(writeInstr);
Saurav Dase972b3a2014-09-26 15:41:06 -07001391
1392 // set flow-mod
1393 OFFlowMod.Builder fmBuilder = null;
1394 switch (op) {
1395 case ADD:
1396 fmBuilder = factory.buildFlowAdd();
1397 break;
1398 case REMOVE:
1399 fmBuilder = factory.buildFlowDeleteStrict();
1400 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001401 case MODIFY: // TODO
1402 fmBuilder = factory.buildFlowModifyStrict();
1403 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001404 default:
1405 log.warn("Unsupported MatchAction Operator: {}", op);
1406 return null;
1407 }
1408
1409 OFMessage aclFlow = fmBuilder
1410 .setTableId(TableId.of(TABLE_ACL))
1411 .setMatch(matchBuilder.build())
1412 .setInstructions(instructions)
1413 .setPriority(MAX_PRIORITY / 2) // TODO: wrong - should be MA
1414 // priority
1415 .setBufferId(OFBufferId.NO_BUFFER)
1416 .setIdleTimeout(0)
1417 .setHardTimeout(0)
1418 .setXid(getNextTransactionId())
1419 .build();
Saurav Das0a344b02014-09-26 14:18:52 -07001420 return aclFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001421 }
1422
1423 // *****************************
1424 // IOF13Switch
1425 // *****************************
1426
1427 @Override
1428 public void pushFlow(MatchActionOperationEntry matchActionOp) throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001429 OFMessage ofm = getFlow(matchActionOp);
1430 if (ofm != null) {
1431 write(Collections.singletonList(ofm));
1432 }
1433 }
1434
1435 private OFMessage getFlow(MatchActionOperationEntry matchActionOp) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001436 final MatchAction matchAction = matchActionOp.getTarget();
1437 final Match match = matchAction.getMatch();
1438 if (match instanceof Ipv4Match) {
Saurav Das0a344b02014-09-26 14:18:52 -07001439 return getIpEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001440 } else if (match instanceof MplsMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001441 return getMplsEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001442 } else if (match instanceof PacketMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001443 return getAclEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001444 } else {
1445 log.error("Unknown match type {} pushed to switch {}", match,
1446 getStringId());
1447 }
Saurav Das0a344b02014-09-26 14:18:52 -07001448 return null;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001449 }
1450
1451 @Override
1452 public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps)
1453 throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001454 List<OFMessage> flowMods = new ArrayList<OFMessage>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001455 for (MatchActionOperationEntry matchActionOp : matchActionOps) {
Saurav Das0a344b02014-09-26 14:18:52 -07001456 OFMessage ofm = getFlow(matchActionOp);
1457 if (ofm != null) {
1458 flowMods.add(ofm);
1459 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001460 }
Saurav Das0a344b02014-09-26 14:18:52 -07001461 write(flowMods);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001462 }
1463
1464 @Override
1465 public int getEcmpGroupId(NeighborSet ns) {
1466 EcmpInfo ei = ecmpGroups.get(ns);
1467 if (ei == null) {
1468 return -1;
1469 } else {
1470 return ei.groupId;
1471 }
1472 }
1473
Saurav Dascc3e35f2014-10-10 15:33:32 -07001474 @Override
1475 public TableId getTableId(String tableType) {
1476 tableType = tableType.toLowerCase();
1477 if (tableType.contentEquals("ip")) {
1478 return TableId.of(OFSwitchImplCPqD13.TABLE_IPv4_UNICAST);
1479 }
1480 else if (tableType.contentEquals("mpls")) {
1481 return TableId.of(OFSwitchImplCPqD13.TABLE_MPLS);
1482 }
1483 else if (tableType.contentEquals("acl")) {
1484 return TableId.of(OFSwitchImplCPqD13.TABLE_ACL);
1485 }
1486 else {
1487 log.warn("Invalid tableType: {}", tableType);
1488 return null;
1489 }
1490 }
1491
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001492 // *****************************
Saurav Das80d17392014-10-01 10:24:56 -07001493 // Unused
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001494 // *****************************
1495
Saurav Das80d17392014-10-01 10:24:56 -07001496 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001497 private void setAsyncConfig() throws IOException {
1498 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
1499 OFMessage setAC = null;
1500
1501 if (role == Role.MASTER) {
1502 setAC = factory.buildAsyncSet()
1503 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
1504 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
1505 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
1506 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1507 .setPacketInMaskSlave(SET_ALL_SLAVE)
1508 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1509 .setXid(getNextTransactionId())
1510 .build();
1511 } else if (role == Role.EQUAL) {
1512 setAC = factory.buildAsyncSet()
1513 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
1514 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
1515 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
1516 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1517 .setPacketInMaskSlave(SET_ALL_SLAVE)
1518 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1519 .setXid(getNextTransactionId())
1520 .build();
1521 }
1522 msglist.add(setAC);
1523
1524 OFMessage br = factory.buildBarrierRequest()
1525 .setXid(getNextTransactionId())
1526 .build();
1527 msglist.add(br);
1528
1529 OFMessage getAC = factory.buildAsyncGetRequest()
1530 .setXid(getNextTransactionId())
1531 .build();
1532 msglist.add(getAC);
1533
1534 write(msglist);
1535 }
1536
Saurav Das80d17392014-10-01 10:24:56 -07001537 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001538 private void decodeAsyncGetReply(OFAsyncGetReply rep) {
1539 long frm = rep.getFlowRemovedMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001540 long frs = rep.getFlowRemovedMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001541 long pim = rep.getPacketInMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001542 long pis = rep.getPacketInMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001543 long psm = rep.getPortStatusMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001544 long pss = rep.getPortStatusMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001545
1546 if (role == Role.MASTER || role == Role.EQUAL) { // should separate
1547 log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
1548 log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
1549 log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
1550 }
1551
1552 }
1553
Saurav Das80d17392014-10-01 10:24:56 -07001554 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001555 private void getTableFeatures() throws IOException {
1556 OFMessage gtf = factory.buildTableFeaturesStatsRequest()
1557 .setXid(getNextTransactionId())
1558 .build();
1559 write(gtf, null);
1560 }
1561
Saurav Das80d17392014-10-01 10:24:56 -07001562 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001563 private void sendGroupFeaturesRequest() throws IOException {
1564 OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
1565 .setXid(getNextTransactionId())
1566 .build();
1567 write(gfr, null);
1568 }
1569
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001570 private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
1571 log.info("Sw: {} Group Features {}", getStringId(), gfsr);
1572 }
1573
Saurav Dascc3e35f2014-10-10 15:33:32 -07001574 @SuppressWarnings("unused")
1575 private void testMultipleLabels() {
1576 if (getId() == 1) {
1577 List<OFMessage> msglist = new ArrayList<OFMessage>();
1578
1579 // first all the indirect groups
1580
1581 // the group to switch 2 with outer label
1582 OFGroup g1 = OFGroup.of(201);
1583 OFOxmEthDst dmac1 = factory.oxms().ethDst(MacAddress.of("00:00:02:02:02:80"));
1584 OFAction push1 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1585 OFOxmMplsLabel lid1 = factory.oxms()
1586 .mplsLabel(U32.of(105)); // outer label
1587 OFAction setMpls1 = factory.actions().buildSetField()
1588 .setField(lid1).build();
1589 OFOxmMplsBos bos1 = factory.oxms()
1590 .mplsBos(OFBooleanValue.FALSE);
1591 OFAction setB1 = factory.actions().buildSetField()
1592 .setField(bos1).build();
1593 OFAction setDA1 = factory.actions().buildSetField()
1594 .setField(dmac1).build();
1595 OFAction outp1 = factory.actions().buildOutput()
1596 .setPort(OFPort.of(2))
1597 .build();
1598 List<OFAction> a1 = new ArrayList<OFAction>();
1599 a1.add(push1);
1600 a1.add(setMpls1);
1601 a1.add(setB1);
1602 a1.add(setDA1);
1603 a1.add(outp1);
1604 OFBucket b1 = factory.buildBucket()
1605 .setActions(a1)
1606 .build();
1607 OFMessage gm1 = factory.buildGroupAdd()
1608 .setGroup(g1)
1609 .setBuckets(Collections.singletonList(b1))
1610 .setGroupType(OFGroupType.INDIRECT)
1611 .setXid(getNextTransactionId())
1612 .build();
1613 msglist.add(gm1);
1614
1615 // the group to switch 3 with outer label
1616 OFGroup g2 = OFGroup.of(301);
1617 OFOxmEthDst dmac2 = factory.oxms().ethDst(MacAddress.of("00:00:03:03:03:80"));
1618 OFAction push2 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1619 OFOxmMplsLabel lid2 = factory.oxms()
1620 .mplsLabel(U32.of(104)); // outer label
1621 OFAction setMpls2 = factory.actions().buildSetField()
1622 .setField(lid2).build();
1623 OFOxmMplsBos bos2 = factory.oxms()
1624 .mplsBos(OFBooleanValue.FALSE);
1625 OFAction setB2 = factory.actions().buildSetField()
1626 .setField(bos2).build();
1627 OFAction setDA2 = factory.actions().buildSetField()
1628 .setField(dmac2).build();
1629 OFAction outp2 = factory.actions().buildOutput()
1630 .setPort(OFPort.of(3))
1631 .build();
1632 List<OFAction> a2 = new ArrayList<OFAction>();
1633 a2.add(push2);
1634 a2.add(setMpls2);
1635 a2.add(setB2);
1636 a2.add(setDA2);
1637 a2.add(outp2);
1638 OFBucket b2 = factory.buildBucket()
1639 .setActions(a2)
1640 .build();
1641 OFMessage gm2 = factory.buildGroupAdd()
1642 .setGroup(g2)
1643 .setBuckets(Collections.singletonList(b2))
1644 .setGroupType(OFGroupType.INDIRECT)
1645 .setXid(getNextTransactionId())
1646 .build();
1647 msglist.add(gm2);
1648
1649 // now add main ECMP group with inner labels
1650 OFGroup group = OFGroup.of(786);
1651 List<OFBucket> buckets = new ArrayList<OFBucket>();
1652 for (int i = 0; i < 2; i++) { // 2 buckets
1653
1654 List<OFAction> actions = new ArrayList<OFAction>();
1655 OFOxmEthSrc smac = factory.oxms()
1656 .ethSrc(MacAddress.of("00:00:01:01:01:80"));
1657 OFAction setSA = factory.actions().buildSetField()
1658 .setField(smac).build();
1659 actions.add(setSA);
1660
1661 if (i == 0) {
1662 // send to switch 2
1663 OFAction pushX = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1664 OFOxmMplsLabel lidX = factory.oxms()
1665 .mplsLabel(U32.of(106)); // inner label
1666 OFAction setX = factory.actions().buildSetField()
1667 .setField(lidX).build();
1668 OFOxmMplsBos bosX = factory.oxms()
1669 .mplsBos(OFBooleanValue.TRUE);
1670 OFAction setBX = factory.actions().buildSetField()
1671 .setField(bosX).build();
1672 OFAction ogX = factory.actions().buildGroup()
1673 .setGroup(g1).build();
1674 actions.add(pushX);
1675 actions.add(setX);
1676 actions.add(setBX);
1677 actions.add(ogX);
1678
1679 } else {
1680 // send to switch 3
1681 OFAction pushY = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1682 OFOxmMplsLabel lidY = factory.oxms()
1683 .mplsLabel(U32.of(106)); // inner label
1684 OFAction setY = factory.actions().buildSetField()
1685 .setField(lidY).build();
1686 OFOxmMplsBos bosY = factory.oxms()
1687 .mplsBos(OFBooleanValue.TRUE);
1688 OFAction setBY = factory.actions().buildSetField()
1689 .setField(bosY).build();
1690 OFAction ogY = factory.actions().buildGroup()
1691 .setGroup(g2).build();
1692 actions.add(pushY);
1693 actions.add(setY);
1694 actions.add(setBY);
1695 actions.add(ogY);
1696 }
1697
1698 OFBucket ofb = factory.buildBucket()
1699 .setWeight(1)
1700 .setActions(actions)
1701 .build();
1702 buckets.add(ofb);
1703 }
1704
1705 OFMessage gm = factory.buildGroupAdd()
1706 .setGroup(group)
1707 .setBuckets(buckets)
1708 .setGroupType(OFGroupType.SELECT)
1709 .setXid(getNextTransactionId())
1710 .build();
1711 msglist.add(gm);
1712
1713 // create an ACL entry to use this ecmp group
1714 Builder matchBuilder = factory.buildMatch();
1715 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(0x800));
1716 matchBuilder.setMasked(MatchField.IPV4_DST,
1717 IPv4Address.of("7.7.7.0")
1718 .withMaskOfLength(24));
1719
1720 OFAction grp = factory.actions().buildGroup()
1721 .setGroup(OFGroup.of(786))
1722 .build();
1723 List<OFAction> writeActions = Collections.singletonList(grp);
1724
1725 OFInstruction clearInstr = factory.instructions().clearActions();
1726 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1727 .setActions(writeActions).build();
1728 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1729 instructions.add(clearInstr);
1730 instructions.add(writeInstr);
1731
1732 OFFlowMod.Builder fmBuilder = factory.buildFlowAdd();
1733
1734 OFMessage aclFlow = fmBuilder
1735 .setTableId(TableId.of(TABLE_ACL))
1736 .setMatch(matchBuilder.build())
1737 .setInstructions(instructions)
1738 .setPriority(10) // TODO: wrong - should be MA
1739 // priority
1740 .setBufferId(OFBufferId.NO_BUFFER)
1741 .setIdleTimeout(0)
1742 .setHardTimeout(0)
1743 .setXid(getNextTransactionId())
1744 .build();
1745 msglist.add(aclFlow);
1746
1747 try {
1748 write(msglist);
1749 } catch (IOException e) {
1750 // TODO Auto-generated catch block
1751 e.printStackTrace();
1752 }
Fahad Naeem Khand563af62014-10-08 17:37:25 -07001753 }
1754 }
1755
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001756}