blob: f4264287e26fe725dd854c75f040ec40d6ba9593 [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 Das2d41a432014-10-21 20:40:10 -07007import java.util.HashMap;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07008import java.util.HashSet;
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -07009import java.util.Iterator;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070010import java.util.List;
Saurav Das2d41a432014-10-21 20:40:10 -070011import java.util.Map;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070012import java.util.Set;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070013import java.util.concurrent.ConcurrentHashMap;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070014import java.util.concurrent.ConcurrentMap;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070015import java.util.concurrent.atomic.AtomicBoolean;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -070016import java.util.concurrent.atomic.AtomicInteger;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070017
18import net.floodlightcontroller.core.IFloodlightProviderService.Role;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070019import net.floodlightcontroller.core.IOF13Switch;
20import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070021import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
22import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
23import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
24import net.floodlightcontroller.core.internal.OFSwitchImplBase;
Saurav Dase972b3a2014-09-26 15:41:06 -070025import net.floodlightcontroller.util.MACAddress;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -070026import net.floodlightcontroller.util.OrderedCollection;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070027import net.onrc.onos.core.configmanager.INetworkConfigService;
28import net.onrc.onos.core.configmanager.INetworkConfigService.NetworkConfigState;
29import net.onrc.onos.core.configmanager.INetworkConfigService.SwitchConfigStatus;
30import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -070031import net.onrc.onos.core.configmanager.NetworkConfig.SwitchConfig;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070032import net.onrc.onos.core.configmanager.NetworkConfigManager;
33import net.onrc.onos.core.configmanager.PktLinkConfig;
34import net.onrc.onos.core.configmanager.SegmentRouterConfig;
Saurav Das2d41a432014-10-21 20:40:10 -070035import net.onrc.onos.core.configmanager.SegmentRouterConfig.AdjacencySid;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070036import net.onrc.onos.core.matchaction.MatchAction;
37import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Saurav Dasbc594a42014-09-25 20:13:50 -070038import net.onrc.onos.core.matchaction.MatchActionOperations;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070039import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
40import net.onrc.onos.core.matchaction.action.Action;
41import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
42import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
43import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
44import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
45import net.onrc.onos.core.matchaction.action.GroupAction;
46import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
47import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
48import net.onrc.onos.core.matchaction.action.OutputAction;
49import net.onrc.onos.core.matchaction.action.PopMplsAction;
Saurav Dasa962a692014-10-17 14:52:38 -070050import net.onrc.onos.core.matchaction.action.PushMplsAction;
51import net.onrc.onos.core.matchaction.action.SetMplsBosAction;
52import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070053import net.onrc.onos.core.matchaction.match.Ipv4Match;
54import net.onrc.onos.core.matchaction.match.Match;
55import net.onrc.onos.core.matchaction.match.MplsMatch;
56import net.onrc.onos.core.matchaction.match.PacketMatch;
57import net.onrc.onos.core.util.Dpid;
58import net.onrc.onos.core.util.IPv4Net;
59import net.onrc.onos.core.util.PortNumber;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070060
Saurav Das2d41a432014-10-21 20:40:10 -070061import org.codehaus.jackson.map.ObjectMapper;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070062import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
63import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
64import org.projectfloodlight.openflow.protocol.OFBucket;
65import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
66import org.projectfloodlight.openflow.protocol.OFErrorMsg;
67import org.projectfloodlight.openflow.protocol.OFFactory;
Saurav Dase972b3a2014-09-26 15:41:06 -070068import org.projectfloodlight.openflow.protocol.OFFlowMod;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070069import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
70import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
71import org.projectfloodlight.openflow.protocol.OFGroupType;
72import org.projectfloodlight.openflow.protocol.OFMatchV3;
73import org.projectfloodlight.openflow.protocol.OFMessage;
74import org.projectfloodlight.openflow.protocol.OFOxmList;
75import org.projectfloodlight.openflow.protocol.OFPortDesc;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -070076import org.projectfloodlight.openflow.protocol.OFPortStatus;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070077import org.projectfloodlight.openflow.protocol.OFStatsReply;
78import org.projectfloodlight.openflow.protocol.action.OFAction;
79import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
Saurav Dase972b3a2014-09-26 15:41:06 -070080import org.projectfloodlight.openflow.protocol.match.Match.Builder;
81import org.projectfloodlight.openflow.protocol.match.MatchField;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070082import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
83import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
84import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
85import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
86import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
Saurav Dascc3e35f2014-10-10 15:33:32 -070087import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsBos;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070088import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
89import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
90import org.projectfloodlight.openflow.types.EthType;
91import org.projectfloodlight.openflow.types.IPv4Address;
Saurav Dase972b3a2014-09-26 15:41:06 -070092import org.projectfloodlight.openflow.types.IpProtocol;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070093import org.projectfloodlight.openflow.types.MacAddress;
Saurav Dascc3e35f2014-10-10 15:33:32 -070094import org.projectfloodlight.openflow.types.OFBooleanValue;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070095import org.projectfloodlight.openflow.types.OFBufferId;
96import org.projectfloodlight.openflow.types.OFGroup;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070097import org.projectfloodlight.openflow.types.OFPort;
98import org.projectfloodlight.openflow.types.OFVlanVidMatch;
99import org.projectfloodlight.openflow.types.TableId;
Saurav Dase972b3a2014-09-26 15:41:06 -0700100import org.projectfloodlight.openflow.types.TransportPort;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700101import org.projectfloodlight.openflow.types.U32;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700102import org.projectfloodlight.openflow.util.HexString;
103
104/**
105 * OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
106 * Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
107 * Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
108 * None
109 */
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700110public class OFSwitchImplCPqD13 extends OFSwitchImplBase implements IOF13Switch {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700111 private AtomicBoolean driverHandshakeComplete;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700112 private AtomicBoolean haltStateMachine;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700113 private OFFactory factory;
114 private static final int OFPCML_NO_BUFFER = 0xffff;
115 // Configuration of asynch messages to controller. We need different
116 // asynch messages depending on role-equal or role-master.
117 // We don't want to get anything if we are slave.
118 private static final long SET_FLOW_REMOVED_MASK_MASTER = 0xf;
119 private static final long SET_PACKET_IN_MASK_MASTER = 0x7;
120 private static final long SET_PORT_STATUS_MASK_MASTER = 0x7;
121 private static final long SET_FLOW_REMOVED_MASK_EQUAL = 0x0;
122 private static final long SET_PACKET_IN_MASK_EQUAL = 0x0;
123 private static final long SET_PORT_STATUS_MASK_EQUAL = 0x7;
124 private static final long SET_ALL_SLAVE = 0x0;
125
126 private static final long TEST_FLOW_REMOVED_MASK = 0xf;
127 private static final long TEST_PACKET_IN_MASK = 0x7;
128 private static final long TEST_PORT_STATUS_MASK = 0x7;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700129
130 private static final int TABLE_VLAN = 0;
131 private static final int TABLE_TMAC = 1;
Sangho Shin01bca862014-09-12 11:18:59 -0700132 private static final int TABLE_IPv4_UNICAST = 2;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700133 private static final int TABLE_MPLS = 3;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700134 private static final int TABLE_ACL = 5;
135
136 private static final short MAX_PRIORITY = (short) 0xffff;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700137 private static final short PRIORITY_MULTIPLIER = (short) 2046;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700138 private static final short MIN_PRIORITY = 0x0;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700139
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700140 private long barrierXidToWaitFor = -1;
141 private DriverState driverState;
Jonathan Hartcb34f382014-08-12 21:11:03 -0700142 private final boolean usePipeline13;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700143 private SegmentRouterConfig srConfig;
144 private ConcurrentMap<Dpid, Set<PortNumber>> neighbors;
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700145 private ConcurrentMap<PortNumber, Dpid> portToNeighbors;
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700146 private List<Integer> segmentIds;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700147 private boolean isEdgeRouter;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700148 private ConcurrentMap<NeighborSet, EcmpInfo> ecmpGroups;
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -0700149 private ConcurrentMap<Integer, EcmpInfo> userDefinedGroups;
Srikanth Vavilapallib95e6e02014-10-02 13:56:39 -0700150 private ConcurrentMap<PortNumber, ArrayList<NeighborSet>> portNeighborSetMap;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700151 private AtomicInteger groupid;
Saurav Das2d41a432014-10-21 20:40:10 -0700152 private Map<String, String> publishAttributes;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700153
Jonathan Hartcb34f382014-08-12 21:11:03 -0700154 public OFSwitchImplCPqD13(OFDescStatsReply desc, boolean usePipeline13) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700155 super();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700156 haltStateMachine = new AtomicBoolean(false);
157 driverState = DriverState.INIT;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700158 driverHandshakeComplete = new AtomicBoolean(false);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700159 setSwitchDescription(desc);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700160 neighbors = new ConcurrentHashMap<Dpid, Set<PortNumber>>();
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700161 portToNeighbors = new ConcurrentHashMap<PortNumber, Dpid>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700162 ecmpGroups = new ConcurrentHashMap<NeighborSet, EcmpInfo>();
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -0700163 userDefinedGroups = new ConcurrentHashMap<Integer, EcmpInfo>();
Srikanth Vavilapallib95e6e02014-10-02 13:56:39 -0700164 portNeighborSetMap =
165 new ConcurrentHashMap<PortNumber, ArrayList<NeighborSet>>();
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700166 segmentIds = new ArrayList<Integer>();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700167 isEdgeRouter = false;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700168 groupid = new AtomicInteger(0);
Jonathan Hartcb34f382014-08-12 21:11:03 -0700169 this.usePipeline13 = usePipeline13;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700170 }
171
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700172 // *****************************
173 // OFSwitchImplBase
174 // *****************************
175
176
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700177 /* (non-Javadoc)
178 * @see java.lang.Object#toString()
179 */
180 @Override
181 public String toString() {
182 return "OFSwitchImplCPqD13 [" + ((channel != null)
183 ? channel.getRemoteAddress() : "?")
184 + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
185 }
186
187 @Override
188 public void startDriverHandshake() throws IOException {
189 log.debug("Starting driver handshake for sw {}", getStringId());
190 if (startDriverHandshakeCalled) {
191 throw new SwitchDriverSubHandshakeAlreadyStarted();
192 }
193 startDriverHandshakeCalled = true;
Jonathan Harta213bce2014-08-11 15:44:07 -0700194 factory = getFactory();
Jonathan Hartcb34f382014-08-12 21:11:03 -0700195 if (!usePipeline13) {
196 // Send packet-in to controller if a packet misses the first table
197 populateTableMissEntry(0, true, false, false, 0);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700198 driverHandshakeComplete.set(true);
Sangho Shin01bca862014-09-12 11:18:59 -0700199 } else {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700200 nextDriverState();
Sangho Shin01bca862014-09-12 11:18:59 -0700201 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700202 }
203
204 @Override
205 public boolean isDriverHandshakeComplete() {
Sangho Shin01bca862014-09-12 11:18:59 -0700206 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700207 throw new SwitchDriverSubHandshakeNotStarted();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700208 return driverHandshakeComplete.get();
209 }
210
211 @Override
212 public void processDriverHandshakeMessage(OFMessage m) {
Sangho Shin01bca862014-09-12 11:18:59 -0700213 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700214 throw new SwitchDriverSubHandshakeNotStarted();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700215 if (isDriverHandshakeComplete())
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700216 throw new SwitchDriverSubHandshakeCompleted(m);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700217 try {
218 processOFMessage(this, m);
219 } catch (IOException e) {
220 log.error("Error generated when processing OFMessage", e.getCause());
221 }
222 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700223
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700224 @Override
225 public String getSwitchDriverState() {
226 return driverState.toString();
227 }
228
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700229 public void removePortFromGroups(PortNumber port) {
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,
Srikanth Vavilapalli16a04722014-10-23 11:09:24 -0700318 ns.getEdgeLabel(), true, -1);
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700319 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);
Saurav Das2d41a432014-10-21 20:40:10 -0700494 // TODO -- actually do verification
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700495 try {
496 nextDriverState();
497 } catch (IOException e) {
498 // TODO Auto-generated catch block
499 e.printStackTrace();
500 }
501 }
502
503 // *****************************
504 // Utility methods
505 // *****************************
506
507 void setTableMissEntries() throws IOException {
508 // set all table-miss-entries
509 populateTableMissEntry(TABLE_VLAN, true, false, false, -1);
510 populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
511 populateTableMissEntry(TABLE_IPv4_UNICAST, false, true, true,
512 TABLE_ACL);
513 populateTableMissEntry(TABLE_MPLS, false, true, true,
514 TABLE_ACL);
515 populateTableMissEntry(TABLE_ACL, false, false, false, -1);
516 }
517
Saurav Dasd84178f2014-09-29 17:48:54 -0700518 private void sendHandshakeBarrier() throws IOException {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700519 long xid = getNextTransactionId();
520 barrierXidToWaitFor = xid;
521 OFBarrierRequest br = getFactory()
522 .buildBarrierRequest()
523 .setXid(xid)
524 .build();
525 write(br, null);
526 }
527
528 /**
529 * Adds a table-miss-entry to a pipeline table.
530 * <p>
531 * The table-miss-entry can be added with 'write-actions' or
532 * 'apply-actions'. It can also add a 'goto-table' instruction. By default
533 * if none of the booleans in the call are set, then the table-miss entry is
534 * added with no instructions, which means that if a packet hits the
535 * table-miss-entry, pipeline execution will stop, and the action set
536 * associated with the packet will be executed.
537 *
538 * @param tableToAdd the table to where the table-miss-entry will be added
539 * @param toControllerNow as an APPLY_ACTION instruction
540 * @param toControllerWrite as a WRITE_ACTION instruction
541 * @param toTable as a GOTO_TABLE instruction
542 * @param tableToSend the table to send as per the GOTO_TABLE instruction it
543 * needs to be set if 'toTable' is true. Ignored of 'toTable' is
544 * false.
545 * @throws IOException
546 */
547 @SuppressWarnings("unchecked")
548 private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
549 boolean toControllerWrite,
550 boolean toTable, int tableToSend) throws IOException {
551 OFOxmList oxmList = OFOxmList.EMPTY;
552 OFMatchV3 match = factory.buildMatchV3()
553 .setOxmList(oxmList)
554 .build();
555 OFAction outc = factory.actions()
556 .buildOutput()
557 .setPort(OFPort.CONTROLLER)
558 .setMaxLen(OFPCML_NO_BUFFER)
559 .build();
560 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
561 if (toControllerNow) {
562 // table-miss instruction to send to controller immediately
563 OFInstruction instr = factory.instructions()
564 .buildApplyActions()
565 .setActions(Collections.singletonList(outc))
566 .build();
567 instructions.add(instr);
568 }
569
570 if (toControllerWrite) {
571 // table-miss instruction to write-action to send to controller
572 // this will be executed whenever the action-set gets executed
573 OFInstruction instr = factory.instructions()
574 .buildWriteActions()
575 .setActions(Collections.singletonList(outc))
576 .build();
577 instructions.add(instr);
578 }
579
580 if (toTable) {
581 // table-miss instruction to goto-table x
582 OFInstruction instr = factory.instructions()
583 .gotoTable(TableId.of(tableToSend));
584 instructions.add(instr);
585 }
586
587 if (!toControllerNow && !toControllerWrite && !toTable) {
588 // table-miss has no instruction - at which point action-set will be
589 // executed - if there is an action to output/group in the action
590 // set
591 // the packet will be sent there, otherwise it will be dropped.
592 instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
593 }
594
595 OFMessage tableMissEntry = factory.buildFlowAdd()
596 .setTableId(TableId.of(tableToAdd))
597 .setMatch(match) // match everything
598 .setInstructions(instructions)
599 .setPriority(MIN_PRIORITY)
600 .setBufferId(OFBufferId.NO_BUFFER)
601 .setIdleTimeout(0)
602 .setHardTimeout(0)
603 .setXid(getNextTransactionId())
604 .build();
605 write(tableMissEntry, null);
606 }
607
608 private void getNetworkConfig() {
609 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
610 SwitchConfigStatus scs = ncs.checkSwitchConfig(new Dpid(getId()));
611 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
612 srConfig = (SegmentRouterConfig) scs.getSwitchConfig();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700613 isEdgeRouter = srConfig.isEdgeRouter();
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,
Srikanth Vavilapalli16a04722014-10-23 11:09:24 -0700860 ns.getEdgeLabel(), true, -1);
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700861 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
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700885 /**
886 * createGroups creates ECMP groups for all ports on this router connected
887 * to other routers (in the OF network). The information for ports is
888 * gleaned from the configured links. If no links are configured no groups
889 * will be created, and it is up to the caller of the IOF13Switch API to
890 * create groups.
891 * <p>
892 * By default all ports connected to the same neighbor router will be part
893 * of the same ECMP group. In addition, groups will be created for all
894 * possible combinations of neighbor routers.
895 * <p>
896 * For example, consider this router (R0) connected to 3 neighbors (R1, R2,
897 * and R3). The following groups will be created in R0:
898 * <li>1) all ports to R1,
899 * <li>2) all ports to R2,
900 * <li>3) all ports to R3,
901 * <li>4) all ports to R1 and R2
902 * <li>5) all ports to R1 and R3
903 * <li>6) all ports to R2 and R3
904 * <li>7) all ports to R1, R2, and R3
905 */
906 private void createGroups() {
Sangho Shin15273b62014-10-16 22:22:05 -0700907
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700908 Set<Dpid> dpids = neighbors.keySet();
909 if (dpids == null || dpids.isEmpty()) {
910 return;
911 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700912 /* Create all possible Neighbor sets from this router
913 * NOTE: Avoid any pairings of edge routers only
914 */
915 Set<Set<Dpid>> powerSet = getAllNeighborSets(dpids);
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700916 log.debug("createGroups: The size of neighbor powerset for sw {} is {}",
Srikanth Vavilapallica2263c2014-10-09 15:19:11 -0700917 getStringId(), powerSet.size());
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700918 Set<NeighborSet> nsSet = new HashSet<NeighborSet>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700919 for (Set<Dpid> combo : powerSet) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700920 if (combo.isEmpty())
921 continue;
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700922 if (isEdgeRouter && !segmentIds.isEmpty()) {
923 for (Integer sId : segmentIds) {
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700924 NeighborSet ns = new NeighborSet();
925 ns.addDpids(combo);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700926 /* Check if the edge label being set is of the
927 * same node in the Neighbor set
928 */
929 if ((combo.size() != 1) ||
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700930 (!isSegmentIdSameAsNodeSegmentId(
931 combo.iterator().next(), sId))) {
932 ns.setEdgeLabel(sId);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700933 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700934 nsSet.add(ns);
935 }
936 } else {
937 NeighborSet ns = new NeighborSet();
938 ns.addDpids(combo);
939 nsSet.add(ns);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700940 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700941 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700942 log.debug("createGroups: The neighborset with label for sw {} is {}",
Srikanth Vavilapallica2263c2014-10-09 15:19:11 -0700943 getStringId(), nsSet);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700944
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700945 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700946 createGroupForANeighborSet(ns, groupid.incrementAndGet());
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700947 }
948 }
949
950 private class EcmpInfo {
951 int groupId;
952 List<BucketInfo> buckets;
953
954 EcmpInfo(int gid, List<BucketInfo> bucketInfos) {
955 groupId = gid;
956 buckets = bucketInfos;
957 }
958
959 @Override
960 public String toString() {
961 return "groupId: " + groupId + ", buckets: " + buckets;
962 }
963 }
964
965 private class BucketInfo {
966 Dpid neighborDpid;
967 MacAddress srcMac;
968 MacAddress dstMac;
969 PortNumber outport;
Sangho Shin15273b62014-10-16 22:22:05 -0700970 int groupNo;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700971 int mplsLabel;
Sangho Shin15273b62014-10-16 22:22:05 -0700972 boolean bos;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700973
Srikanth Vavilapalli16a04722014-10-23 11:09:24 -0700974 /*
975 BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac,
976 PortNumber p, int label) {
977 neighborDpid = nDpid;
978 srcMac = smac;
979 dstMac = dmac;
980 outport = p;
981 mplsLabel = label;
982 groupNo = -1;
983 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700984
Srikanth Vavilapalli16a04722014-10-23 11:09:24 -0700985 BucketInfo(int no, int label, boolean b) {
986 neighborDpid = null;
987 srcMac = null;
988 dstMac = null;
989 outport = null;
990 groupNo = no;
991 mplsLabel = label;
992 bos = b;
993 }
994 */
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -0700995 BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac,
996 PortNumber p, int label, boolean bos, int gotoGroupNo) {
997 neighborDpid = nDpid;
998 srcMac = smac;
999 dstMac = dmac;
1000 outport = p;
1001 mplsLabel = label;
1002 this.bos = bos;
1003 groupNo = gotoGroupNo;
1004 }
1005
Sangho Shin15273b62014-10-16 22:22:05 -07001006
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001007 @Override
1008 public String toString() {
1009 return " {neighborDpid: " + neighborDpid + ", dstMac: " + dstMac +
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001010 ", srcMac: " + srcMac + ", outport: " + outport +
Sangho Shin15273b62014-10-16 22:22:05 -07001011 ", groupNo: " + groupNo +
1012 ", mplsLabel: " + mplsLabel + "}";
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001013 }
1014 }
1015
1016 private void setEcmpGroup(EcmpInfo ecmpInfo) {
1017 List<OFMessage> msglist = new ArrayList<OFMessage>();
1018 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1019
1020 List<OFBucket> buckets = new ArrayList<OFBucket>();
1021 for (BucketInfo b : ecmpInfo.buckets) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001022 List<OFAction> actions = new ArrayList<OFAction>();
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001023 if (b.dstMac != null) {
Sangho Shin15273b62014-10-16 22:22:05 -07001024 OFOxmEthDst dmac = factory.oxms()
1025 .ethDst(b.dstMac);
1026 OFAction setDA = factory.actions().buildSetField()
1027 .setField(dmac).build();
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001028 actions.add(setDA);
1029 }
1030 if (b.srcMac != null) {
Sangho Shin15273b62014-10-16 22:22:05 -07001031 OFOxmEthSrc smac = factory.oxms()
1032 .ethSrc(b.srcMac);
1033 OFAction setSA = factory.actions().buildSetField()
1034 .setField(smac).build();
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001035 actions.add(setSA);
1036 }
1037 if (b.outport != null) {
Sangho Shin15273b62014-10-16 22:22:05 -07001038 OFAction outp = factory.actions().buildOutput()
1039 .setPort(OFPort.of(b.outport.shortValue()))
1040 .build();
Sangho Shin15273b62014-10-16 22:22:05 -07001041 actions.add(outp);
1042 }
Sangho Shin15273b62014-10-16 22:22:05 -07001043 if (b.mplsLabel != -1) {
1044 OFAction pushLabel = factory.actions().buildPushMpls()
1045 .setEthertype(EthType.MPLS_UNICAST).build();
Sangho Shin15273b62014-10-16 22:22:05 -07001046 OFBooleanValue bosValue = null;
1047 if (b.bos)
1048 bosValue = OFBooleanValue.TRUE;
1049 else
1050 bosValue = OFBooleanValue.FALSE;
1051 OFOxmMplsBos bosX = factory.oxms()
1052 .mplsBos(bosValue);
1053 OFAction setBX = factory.actions().buildSetField()
1054 .setField(bosX).build();
1055 OFOxmMplsLabel lid = factory.oxms()
1056 .mplsLabel(U32.of(b.mplsLabel));
1057 OFAction setLabel = factory.actions().buildSetField()
1058 .setField(lid).build();
1059 OFAction copyTtl = factory.actions().copyTtlOut();
1060 OFAction decrTtl = factory.actions().decMplsTtl();
1061 actions.add(pushLabel);
1062 actions.add(setLabel);
1063 actions.add(setBX);
1064 actions.add(copyTtl);
1065 // decrement TTL only when the first MPLS label is pushed
1066 if (b.bos)
1067 actions.add(decrTtl);
1068 }
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001069 if (b.groupNo > 0) {
1070 OFAction groupTo = factory.actions().buildGroup()
1071 .setGroup(OFGroup.of(b.groupNo))
1072 .build();
1073 actions.add(groupTo);
1074 }
Sangho Shin15273b62014-10-16 22:22:05 -07001075 OFBucket ofb = factory.buildBucket()
1076 .setWeight(1)
1077 .setActions(actions)
1078 .build();
1079 buckets.add(ofb);
1080 }
1081
1082 OFMessage gm = factory.buildGroupAdd()
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
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001097 /*
1098 private void setPolicyEcmpGroup(EcmpInfo ecmpInfo) {
1099 List<OFMessage> msglist = new ArrayList<OFMessage>();
1100 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1101
1102 List<OFBucket> buckets = new ArrayList<OFBucket>();
1103 List<OFAction> actions = new ArrayList<OFAction>();
1104 for (BucketInfo b : ecmpInfo.buckets) {
1105 if (b.dstMac != null && b.srcMac != null && b.outport != null) {
1106 OFOxmEthDst dmac = factory.oxms()
1107 .ethDst(b.dstMac);
1108 OFAction setDA = factory.actions().buildSetField()
1109 .setField(dmac).build();
1110 OFOxmEthSrc smac = factory.oxms()
1111 .ethSrc(b.srcMac);
1112 OFAction setSA = factory.actions().buildSetField()
1113 .setField(smac).build();
1114 OFAction outp = factory.actions().buildOutput()
1115 .setPort(OFPort.of(b.outport.shortValue()))
1116 .build();
1117 actions.add(setSA);
1118 actions.add(setDA);
1119 actions.add(outp);
1120 }
1121 if (b.groupNo > 0) {
1122 OFAction groupTo = factory.actions().buildGroup()
1123 .setGroup(OFGroup.of(b.groupNo))
1124 .build();
1125 actions.add(groupTo);
1126 }
1127 if (b.mplsLabel != -1) {
1128 OFAction pushLabel = factory.actions().buildPushMpls()
1129 .setEthertype(EthType.MPLS_UNICAST).build();
1130
1131 OFBooleanValue bosValue = null;
1132 if (b.bos)
1133 bosValue = OFBooleanValue.TRUE;
1134 else
1135 bosValue = OFBooleanValue.FALSE;
1136 OFOxmMplsBos bosX = factory.oxms()
1137 .mplsBos(bosValue);
1138 OFAction setBX = factory.actions().buildSetField()
1139 .setField(bosX).build();
1140 OFOxmMplsLabel lid = factory.oxms()
1141 .mplsLabel(U32.of(b.mplsLabel));
1142 OFAction setLabel = factory.actions().buildSetField()
1143 .setField(lid).build();
1144 OFAction copyTtl = factory.actions().copyTtlOut();
1145 OFAction decrTtl = factory.actions().decMplsTtl();
1146 actions.add(pushLabel);
1147 actions.add(setLabel);
1148 actions.add(setBX);
1149 actions.add(copyTtl);
1150 // decrement TTL only when the first MPLS label is pushed
1151 if (b.bos)
1152 actions.add(decrTtl);
1153 }
1154 OFBucket ofb = factory.buildBucket()
1155 .setWeight(1)
1156 .setActions(actions)
1157 .build();
1158 buckets.add(ofb);
1159 }
1160
1161 OFMessage gm = factory.buildGroupAdd()
1162 .setGroup(group)
1163 .setBuckets(buckets)
1164 .setGroupType(OFGroupType.SELECT)
1165 .setXid(getNextTransactionId())
1166 .build();
1167 msglist.add(gm);
1168 try {
1169 write(msglist);
1170 } catch (IOException e) {
1171 // TODO Auto-generated catch block
1172 e.printStackTrace();
1173 }
1174 }
1175 */
Sangho Shin55d00e12014-10-20 12:13:07 -07001176 private void deleteGroup(int groupId) {
1177
1178 List<OFMessage> msglist = new ArrayList<OFMessage>();
1179 OFGroup group = OFGroup.of(groupId);
1180
1181 OFMessage gm = factory.buildGroupDelete()
1182 .setGroup(group)
1183 .setGroupType(OFGroupType.SELECT)
1184 .setXid(getNextTransactionId())
1185 .build();
1186 msglist.add(gm);
1187 try {
1188 write(msglist);
1189 } catch (IOException e) {
1190 // TODO Auto-generated catch block
1191 e.printStackTrace();
1192 }
1193 }
1194
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -07001195 private void modifyEcmpGroup(EcmpInfo ecmpInfo) {
1196 List<OFMessage> msglist = new ArrayList<OFMessage>();
1197 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1198
1199 List<OFBucket> buckets = new ArrayList<OFBucket>();
1200 for (BucketInfo b : ecmpInfo.buckets) {
1201 OFOxmEthDst dmac = factory.oxms()
1202 .ethDst(b.dstMac);
1203 OFAction setDA = factory.actions().buildSetField()
1204 .setField(dmac).build();
1205 OFOxmEthSrc smac = factory.oxms()
1206 .ethSrc(b.srcMac);
1207 OFAction setSA = factory.actions().buildSetField()
1208 .setField(smac).build();
1209 OFAction outp = factory.actions().buildOutput()
1210 .setPort(OFPort.of(b.outport.shortValue()))
1211 .build();
1212 List<OFAction> actions = new ArrayList<OFAction>();
1213 actions.add(setSA);
1214 actions.add(setDA);
1215 actions.add(outp);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001216 if (b.mplsLabel != -1) {
1217 OFAction pushLabel = factory.actions().buildPushMpls()
1218 .setEthertype(EthType.MPLS_UNICAST).build();
Srikanth Vavilapalli11dc6072014-10-13 13:32:11 -07001219 OFOxmMplsBos bosX = factory.oxms()
1220 .mplsBos(OFBooleanValue.TRUE);
1221 OFAction setBX = factory.actions().buildSetField()
1222 .setField(bosX).build();
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -07001223 OFOxmMplsLabel lid = factory.oxms()
1224 .mplsLabel(U32.of(b.mplsLabel));
1225 OFAction setLabel = factory.actions().buildSetField()
1226 .setField(lid).build();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001227 OFAction copyTtl = factory.actions().copyTtlOut();
1228 OFAction decrTtl = factory.actions().decMplsTtl();
1229 actions.add(pushLabel);
1230 actions.add(setLabel);
Srikanth Vavilapalli11dc6072014-10-13 13:32:11 -07001231 actions.add(setBX);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001232 actions.add(copyTtl);
1233 actions.add(decrTtl);
1234 }
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -07001235 OFBucket ofb = factory.buildBucket()
1236 .setWeight(1)
1237 .setActions(actions)
1238 .build();
1239 buckets.add(ofb);
1240 }
1241
1242 OFMessage gm = factory.buildGroupModify()
1243 .setGroup(group)
1244 .setBuckets(buckets)
1245 .setGroupType(OFGroupType.SELECT)
1246 .setXid(getNextTransactionId())
1247 .build();
1248 msglist.add(gm);
1249 try {
1250 write(msglist);
1251 } catch (IOException e) {
1252 // TODO Auto-generated catch block
1253 e.printStackTrace();
1254 }
1255 }
1256
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001257 private void verifyGroups() throws IOException {
1258 sendGroupDescRequest();
1259 }
1260
1261 private void sendGroupDescRequest() throws IOException {
1262 OFMessage gdr = factory.buildGroupDescStatsRequest()
1263 .setXid(getNextTransactionId())
1264 .build();
1265 write(gdr, null);
1266 }
1267
1268 private void assignAdjacencyLabels() {
Saurav Das2d41a432014-10-21 20:40:10 -07001269 List<AdjacencySid> autogenAdjSids = new ArrayList<AdjacencySid>();
1270 publishAttributes = new HashMap<String, String>();
1271 for (OFPortDesc p : getPorts()) {
1272 int pnum = p.getPortNo().getPortNumber();
1273
1274 if (U32.ofRaw(pnum).compareTo(U32.ofRaw(OFPort.MAX.getPortNumber())) >= 1) {
1275 continue;
1276 }
1277 // create unique adj-sid assuming that operator only
1278 // enters adjSids for multiple-ports and only in the range
1279 // 1-10k XXX make sure that happens
1280 int adjSid = srConfig.getNodeSid() * 1000 + pnum;
1281 AdjacencySid as = new AdjacencySid(adjSid,
1282 Collections.singletonList(pnum));
1283 autogenAdjSids.add(as);
1284 }
1285 ObjectMapper mapper = new ObjectMapper();
1286 try {
1287 publishAttributes.put("autogenAdjSids",
1288 mapper.writeValueAsString(autogenAdjSids));
1289 } catch (IOException e1) {
1290 log.error("Error while writing adjacency labels: {}", e1.getCause());
1291 }
1292
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001293 try {
1294 nextDriverState();
1295 } catch (IOException e) {
1296 // TODO Auto-generated catch block
1297 e.printStackTrace();
1298 }
1299 }
1300
Saurav Das1cd10152014-09-26 09:38:07 -07001301 private OFAction getOFAction(Action action) {
1302 OFAction ofAction = null;
1303 if (action instanceof OutputAction) {
1304 OutputAction outputAction = (OutputAction) action;
1305 OFPort port = OFPort.of((int) outputAction.getPortNumber().value());
1306 ofAction = factory.actions().output(port, Short.MAX_VALUE);
1307 } else if (action instanceof ModifyDstMacAction) {
1308 long dstMac = ((ModifyDstMacAction) action).getDstMac().toLong();
1309 OFOxmEthDst dmac = factory.oxms()
1310 .ethDst(MacAddress.of(dstMac));
1311 ofAction = factory.actions().buildSetField()
1312 .setField(dmac).build();
1313 } else if (action instanceof ModifySrcMacAction) {
1314 long srcMac = ((ModifySrcMacAction) action).getSrcMac().toLong();
1315 OFOxmEthSrc smac = factory.oxms()
1316 .ethSrc(MacAddress.of(srcMac));
1317 ofAction = factory.actions().buildSetField()
1318 .setField(smac).build();
Saurav Dasa962a692014-10-17 14:52:38 -07001319 } else if (action instanceof PushMplsAction) {
1320 ofAction = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1321 } else if (action instanceof SetMplsIdAction) {
1322 int labelid = ((SetMplsIdAction) action).getMplsId();
1323 OFOxmMplsLabel lid = factory.oxms()
1324 .mplsLabel(U32.of(labelid));
1325 ofAction = factory.actions().buildSetField()
1326 .setField(lid).build();
1327 } else if (action instanceof SetMplsBosAction) {
1328 OFBooleanValue val = OFBooleanValue.of(
1329 ((SetMplsBosAction) action).isSet());
1330 OFOxmMplsBos bos = factory.oxms().mplsBos(val);
1331 OFAction setBos = factory.actions().buildSetField()
1332 .setField(bos).build();
1333 } else if (action instanceof PopMplsAction) {
Saurav Das1cd10152014-09-26 09:38:07 -07001334 EthType ethertype = ((PopMplsAction) action).getEthType();
1335 ofAction = factory.actions().popMpls(ethertype);
1336 } else if (action instanceof GroupAction) {
Sangho Shin15273b62014-10-16 22:22:05 -07001337 int gid = -1;
1338 GroupAction ga = (GroupAction)action;
Srikanth Vavilapalli16a04722014-10-23 11:09:24 -07001339 if (ga.getGroupId() > 0) {
1340 gid = ga.getGroupId();
Saurav Das1cd10152014-09-26 09:38:07 -07001341 }
Sangho Shin15273b62014-10-16 22:22:05 -07001342 else {
1343 NeighborSet ns = ((GroupAction) action).getDpids();
1344 EcmpInfo ei = ecmpGroups.get(ns);
1345 if (ei == null) {
1346 log.debug("Unable to find ecmp group for neighbors {} at "
1347 + "switch {} and hence creating it", ns, getStringId());
1348 createGroupForANeighborSet(ns, groupid.incrementAndGet());
1349 ei = ecmpGroups.get(ns);
1350 }
1351 gid = ei.groupId;
1352 }
Srikanth Vavilapalli846df292014-10-10 15:47:16 -07001353 ofAction = factory.actions().buildGroup()
1354 .setGroup(OFGroup.of(gid))
1355 .build();
Saurav Das1cd10152014-09-26 09:38:07 -07001356 } else if (action instanceof DecNwTtlAction) {
1357 ofAction = factory.actions().decNwTtl();
1358 } else if (action instanceof DecMplsTtlAction) {
1359 ofAction = factory.actions().decMplsTtl();
1360 } else if (action instanceof CopyTtlInAction) {
1361 ofAction = factory.actions().copyTtlIn();
1362 } else if (action instanceof CopyTtlOutAction) {
1363 ofAction = factory.actions().copyTtlOut();
1364 } else {
1365 log.warn("Unsupported Action type: {}", action.getClass().getName());
1366 return null;
1367 }
1368
Saurav Das1cd10152014-09-26 09:38:07 -07001369 return ofAction;
1370 }
1371
Saurav Das0a344b02014-09-26 14:18:52 -07001372 private OFMessage getIpEntry(MatchActionOperationEntry mao) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001373 MatchAction ma = mao.getTarget();
1374 Operator op = mao.getOperator();
1375 Ipv4Match ipm = (Ipv4Match) ma.getMatch();
1376
1377 // set match
1378 IPv4Net ipdst = ipm.getDestination();
1379 OFOxmEthType ethTypeIp = factory.oxms()
1380 .ethType(EthType.IPv4);
1381 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
1382 .ipv4DstMasked(
1383 IPv4Address.of(ipdst.address().value()),
1384 IPv4Address.ofCidrMaskLength(ipdst.prefixLen())
1385 );
1386 OFOxmList oxmList = OFOxmList.of(ethTypeIp, ipPrefix);
1387 OFMatchV3 match = factory.buildMatchV3()
1388 .setOxmList(oxmList).build();
1389
1390 // set actions
1391 List<OFAction> writeActions = new ArrayList<OFAction>();
1392 for (Action action : ma.getActions()) {
Saurav Das1cd10152014-09-26 09:38:07 -07001393 OFAction ofAction = getOFAction(action);
1394 if (ofAction != null) {
1395 writeActions.add(ofAction);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001396 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001397 }
1398
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001399 // set instructions
1400 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1401 .setActions(writeActions).build();
1402 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1403 .setTableId(TableId.of(TABLE_ACL)).build();
1404 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1405 instructions.add(writeInstr);
1406 instructions.add(gotoInstr);
1407
Saurav Das1cd10152014-09-26 09:38:07 -07001408 // set flow priority to emulate longest prefix match
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001409 int priority = ipdst.prefixLen() * PRIORITY_MULTIPLIER;
1410 if (ipdst.prefixLen() == (short) 32) {
1411 priority = MAX_PRIORITY;
1412 }
1413
Saurav Dasbc594a42014-09-25 20:13:50 -07001414 // set flow-mod
Saurav Dase972b3a2014-09-26 15:41:06 -07001415 OFFlowMod.Builder fmBuilder = null;
1416 switch (op) {
1417 case ADD:
1418 fmBuilder = factory.buildFlowAdd();
1419 break;
1420 case REMOVE:
1421 fmBuilder = factory.buildFlowDeleteStrict();
1422 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001423 case MODIFY: // TODO
1424 fmBuilder = factory.buildFlowModifyStrict();
1425 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001426 default:
1427 log.warn("Unsupported MatchAction Operator: {}", op);
1428 return null;
Saurav Dasbc594a42014-09-25 20:13:50 -07001429 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001430 OFMessage ipFlow = fmBuilder
1431 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
1432 .setMatch(match)
1433 .setInstructions(instructions)
1434 .setPriority(priority)
1435 .setBufferId(OFBufferId.NO_BUFFER)
1436 .setIdleTimeout(0)
1437 .setHardTimeout(0)
1438 .setXid(getNextTransactionId())
1439 .build();
Saurav Dasbc594a42014-09-25 20:13:50 -07001440 log.debug("{} ip-rule {}-{} in sw {}",
1441 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1442 match, writeActions,
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001443 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001444 return ipFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001445 }
1446
Saurav Das0a344b02014-09-26 14:18:52 -07001447 private OFMessage getMplsEntry(MatchActionOperationEntry mao) {
Saurav Das1cd10152014-09-26 09:38:07 -07001448 MatchAction ma = mao.getTarget();
1449 Operator op = mao.getOperator();
1450 MplsMatch mplsm = (MplsMatch) ma.getMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001451
Saurav Das1cd10152014-09-26 09:38:07 -07001452 // set match
1453 OFOxmEthType ethTypeMpls = factory.oxms()
1454 .ethType(EthType.MPLS_UNICAST);
1455 OFOxmMplsLabel labelid = factory.oxms()
1456 .mplsLabel(U32.of(mplsm.getMplsLabel()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001457 OFOxmMplsBos bos = factory.oxms()
1458 .mplsBos(OFBooleanValue.of(mplsm.isBos()));
1459 OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid, bos);
Saurav Das1cd10152014-09-26 09:38:07 -07001460 OFMatchV3 matchlabel = factory.buildMatchV3()
1461 .setOxmList(oxmList).build();
1462
1463 // set actions
1464 List<OFAction> writeActions = new ArrayList<OFAction>();
1465 for (Action action : ma.getActions()) {
1466 OFAction ofAction = getOFAction(action);
1467 if (ofAction != null) {
1468 writeActions.add(ofAction);
1469 }
1470 }
1471
1472 // set instructions
1473 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1474 .setActions(writeActions).build();
1475 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1476 .setTableId(TableId.of(TABLE_ACL)).build();
1477 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1478 instructions.add(writeInstr);
1479 instructions.add(gotoInstr);
1480
Saurav Dase972b3a2014-09-26 15:41:06 -07001481 // set flow-mod
1482 OFFlowMod.Builder fmBuilder = null;
1483 switch (op) {
1484 case ADD:
1485 fmBuilder = factory.buildFlowAdd();
1486 break;
1487 case REMOVE:
1488 fmBuilder = factory.buildFlowDeleteStrict();
1489 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001490 case MODIFY: // TODO
1491 fmBuilder = factory.buildFlowModifyStrict();
1492 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001493 default:
1494 log.warn("Unsupported MatchAction Operator: {}", op);
1495 return null;
Saurav Das1cd10152014-09-26 09:38:07 -07001496 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001497
1498 OFMessage mplsFlow = fmBuilder
1499 .setTableId(TableId.of(TABLE_MPLS))
1500 .setMatch(matchlabel)
1501 .setInstructions(instructions)
1502 .setPriority(MAX_PRIORITY) // exact match and exclusive
1503 .setBufferId(OFBufferId.NO_BUFFER)
1504 .setIdleTimeout(0)
1505 .setHardTimeout(0)
1506 .setXid(getNextTransactionId())
1507 .build();
Saurav Das1cd10152014-09-26 09:38:07 -07001508 log.debug("{} mpls-rule {}-{} in sw {}",
1509 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1510 matchlabel, writeActions,
1511 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001512 return mplsFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001513 }
1514
Saurav Das0a344b02014-09-26 14:18:52 -07001515 private OFMessage getAclEntry(MatchActionOperationEntry mao) {
Saurav Dase972b3a2014-09-26 15:41:06 -07001516 MatchAction ma = mao.getTarget();
1517 Operator op = mao.getOperator();
1518 PacketMatch packetMatch = (PacketMatch) ma.getMatch();
1519 Builder matchBuilder = factory.buildMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001520
Saurav Dase972b3a2014-09-26 15:41:06 -07001521 // set match
1522 int inport = 0;
1523 if (ma.getSwitchPort() != null) {
1524 inport = (int) ma.getSwitchPort().getPortNumber().value();
1525 }
1526 final MACAddress srcMac = packetMatch.getSrcMacAddress();
1527 final MACAddress dstMac = packetMatch.getDstMacAddress();
1528 final Short etherType = packetMatch.getEtherType();
1529 final IPv4Net srcIp = packetMatch.getSrcIpAddress();
1530 final IPv4Net dstIp = packetMatch.getDstIpAddress();
1531 final Byte ipProto = packetMatch.getIpProtocolNumber();
1532 final Short srcTcpPort = packetMatch.getSrcTcpPortNumber();
1533 final Short dstTcpPort = packetMatch.getDstTcpPortNumber();
1534 if (inport > 0) {
1535 matchBuilder.setExact(MatchField.IN_PORT,
1536 OFPort.of(inport));
1537 }
1538 if (srcMac != null) {
1539 matchBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(srcMac.toLong()));
1540 }
1541 if (dstMac != null) {
1542 matchBuilder.setExact(MatchField.ETH_DST, MacAddress.of(dstMac.toLong()));
1543 }
1544 if (etherType != null) {
1545 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(etherType));
1546 }
1547 if (srcIp != null) {
1548 matchBuilder.setMasked(MatchField.IPV4_SRC,
1549 IPv4Address.of(srcIp.address().value())
1550 .withMaskOfLength(srcIp.prefixLen()));
1551 }
1552 if (dstIp != null) {
1553 matchBuilder.setMasked(MatchField.IPV4_DST,
1554 IPv4Address.of(dstIp.address().value())
1555 .withMaskOfLength(dstIp.prefixLen()));
1556 }
1557 if (ipProto != null) {
1558 matchBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(ipProto));
1559 }
1560 if (srcTcpPort != null) {
1561 matchBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(srcTcpPort));
1562 }
1563 if (dstTcpPort != null) {
1564 matchBuilder.setExact(MatchField.TCP_DST, TransportPort.of(dstTcpPort));
1565 }
1566
1567 // set actions
Saurav Dascc3e35f2014-10-10 15:33:32 -07001568 List<OFAction> writeActions = new ArrayList<OFAction>();
Saurav Dase972b3a2014-09-26 15:41:06 -07001569 for (Action action : ma.getActions()) {
1570 OFAction ofAction = getOFAction(action);
1571 if (ofAction != null) {
Saurav Dascc3e35f2014-10-10 15:33:32 -07001572 writeActions.add(ofAction);
Saurav Dase972b3a2014-09-26 15:41:06 -07001573 }
1574 }
1575
1576 // set instructions
1577 OFInstruction clearInstr = factory.instructions().clearActions();
Saurav Dascc3e35f2014-10-10 15:33:32 -07001578 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1579 .setActions(writeActions).build();
Saurav Dase972b3a2014-09-26 15:41:06 -07001580 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1581 instructions.add(clearInstr);
Saurav Dascc3e35f2014-10-10 15:33:32 -07001582 instructions.add(writeInstr);
Saurav Dase972b3a2014-09-26 15:41:06 -07001583
1584 // set flow-mod
1585 OFFlowMod.Builder fmBuilder = null;
1586 switch (op) {
1587 case ADD:
1588 fmBuilder = factory.buildFlowAdd();
1589 break;
1590 case REMOVE:
1591 fmBuilder = factory.buildFlowDeleteStrict();
1592 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001593 case MODIFY: // TODO
1594 fmBuilder = factory.buildFlowModifyStrict();
1595 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001596 default:
1597 log.warn("Unsupported MatchAction Operator: {}", op);
1598 return null;
1599 }
1600
1601 OFMessage aclFlow = fmBuilder
1602 .setTableId(TableId.of(TABLE_ACL))
1603 .setMatch(matchBuilder.build())
1604 .setInstructions(instructions)
Sangho Shin6f47dd32014-10-17 23:10:39 -07001605 .setPriority(ma.getPriority()) // exact match and exclusive
Saurav Dase972b3a2014-09-26 15:41:06 -07001606 .setBufferId(OFBufferId.NO_BUFFER)
1607 .setIdleTimeout(0)
1608 .setHardTimeout(0)
1609 .setXid(getNextTransactionId())
1610 .build();
Sangho Shin15273b62014-10-16 22:22:05 -07001611
Saurav Das0a344b02014-09-26 14:18:52 -07001612 return aclFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001613 }
1614
1615 // *****************************
1616 // IOF13Switch
1617 // *****************************
1618
1619 @Override
1620 public void pushFlow(MatchActionOperationEntry matchActionOp) throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001621 OFMessage ofm = getFlow(matchActionOp);
1622 if (ofm != null) {
1623 write(Collections.singletonList(ofm));
1624 }
1625 }
1626
1627 private OFMessage getFlow(MatchActionOperationEntry matchActionOp) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001628 final MatchAction matchAction = matchActionOp.getTarget();
1629 final Match match = matchAction.getMatch();
1630 if (match instanceof Ipv4Match) {
Saurav Das0a344b02014-09-26 14:18:52 -07001631 return getIpEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001632 } else if (match instanceof MplsMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001633 return getMplsEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001634 } else if (match instanceof PacketMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001635 return getAclEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001636 } else {
1637 log.error("Unknown match type {} pushed to switch {}", match,
1638 getStringId());
1639 }
Saurav Das0a344b02014-09-26 14:18:52 -07001640 return null;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001641 }
1642
1643 @Override
1644 public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps)
1645 throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001646 List<OFMessage> flowMods = new ArrayList<OFMessage>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001647 for (MatchActionOperationEntry matchActionOp : matchActionOps) {
Saurav Das0a344b02014-09-26 14:18:52 -07001648 OFMessage ofm = getFlow(matchActionOp);
1649 if (ofm != null) {
1650 flowMods.add(ofm);
1651 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001652 }
Saurav Das0a344b02014-09-26 14:18:52 -07001653 write(flowMods);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001654 }
1655
1656 @Override
1657 public int getEcmpGroupId(NeighborSet ns) {
1658 EcmpInfo ei = ecmpGroups.get(ns);
1659 if (ei == null) {
1660 return -1;
1661 } else {
1662 return ei.groupId;
1663 }
1664 }
1665
Saurav Dascc3e35f2014-10-10 15:33:32 -07001666 @Override
1667 public TableId getTableId(String tableType) {
1668 tableType = tableType.toLowerCase();
1669 if (tableType.contentEquals("ip")) {
1670 return TableId.of(OFSwitchImplCPqD13.TABLE_IPv4_UNICAST);
1671 }
1672 else if (tableType.contentEquals("mpls")) {
1673 return TableId.of(OFSwitchImplCPqD13.TABLE_MPLS);
1674 }
1675 else if (tableType.contentEquals("acl")) {
1676 return TableId.of(OFSwitchImplCPqD13.TABLE_ACL);
1677 }
1678 else {
1679 log.warn("Invalid tableType: {}", tableType);
1680 return null;
1681 }
1682 }
1683
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001684 private EcmpInfo createIndirectGroup(int groupId, MacAddress srcMac,
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001685 MacAddress dstMac, PortNumber outPort, int gotoGroupNo,
1686 int mplsLabel, boolean bos) {
1687 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
1688 BucketInfo b = new BucketInfo(null, srcMac, dstMac, outPort,
1689 mplsLabel, bos, gotoGroupNo);
1690 buckets.add(b);
1691
1692 EcmpInfo ecmpInfo = new EcmpInfo(groupId, buckets);
1693 setEcmpGroup(ecmpInfo);
1694 log.debug(
1695 "createIndirectGroup: Creating indirect group {} in sw {} "
1696 + "with: {}", groupId, getStringId(), ecmpInfo);
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001697 return ecmpInfo;
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001698 }
1699
1700 private EcmpInfo createInnermostLabelGroup(int innermostGroupId,
1701 List<PortNumber> ports, int mplsLabel, boolean bos,
1702 HashMap<PortNumber, Integer> lastSetOfGroupIds) {
1703 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
1704 for (PortNumber sp : ports) {
1705 Dpid neighborDpid = portToNeighbors.get(sp);
1706 BucketInfo b = new BucketInfo(neighborDpid,
1707 MacAddress.of(srConfig.getRouterMac()),
1708 getNeighborRouterMacAddress(neighborDpid), null,
1709 mplsLabel, bos,
1710 lastSetOfGroupIds.get(sp));
1711 buckets.add(b);
1712 }
1713 EcmpInfo ecmpInfo = new EcmpInfo(innermostGroupId, buckets);
1714 setEcmpGroup(ecmpInfo);
1715 log.debug(
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001716 "createInnermostLabelGroup: Creating select group {} in sw {} "
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001717 + "with: {}", innermostGroupId, getStringId(), ecmpInfo);
1718 return ecmpInfo;
1719 }
1720 @Override
1721 /**
Srikanth Vavilapalli1167d0c2014-10-23 09:43:42 -07001722 * Create a group chain with the specified label stack for a given set of
1723 * ports. This API can be used by user to create groups for a tunnel based
1724 * policy routing scenario. NOTE: This API can not be used if a group to be
1725 * created with different label stacks for each port in the given set of
1726 * ports. Use XXX API for this purpose
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001727 *
Srikanth Vavilapalli1167d0c2014-10-23 09:43:42 -07001728 * @param labelStack list of router segment Ids to be pushed. Can be empty.
1729 * labelStack is processed from left to right with leftmost
1730 * representing the outermost label and rightmost representing
1731 * innermost label to be pushed
1732 * @param ports List of ports on this switch to get to the first router in
1733 * the labelStack
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001734 * @return group identifier
1735 */
1736 public int createGroup(List<Integer> labelStack, List<PortNumber> ports) {
1737
1738 if ((ports == null) ||
1739 ((labelStack != null) && (labelStack.size() > 3))) {
1740 log.warn("createGroup with wrong input parameters");
1741 }
1742 log.debug("createGroup with labelStack {} and ports {}",
1743 labelStack, ports);
1744
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001745 HashMap<PortNumber, Integer> lastSetOfGroupIds =
1746 new HashMap<PortNumber, Integer>();
1747 int innermostGroupId = -1;
Srikanth Vavilapalli1167d0c2014-10-23 09:43:42 -07001748 /* If it is empty label stack or label stack with only one label,
1749 * Create a single select group with buckets for each port in the list
1750 * of specified ports and specified label if any and return the
1751 * created group id
1752 */
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001753 if (labelStack.size() < 2) {
1754 int curLabel = -1;
1755 boolean bos = false;
1756 if (labelStack.size()==1) {
1757 curLabel = labelStack.get(0).intValue();
1758 bos = true;
1759 }
1760
1761 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
1762 for (PortNumber sp : ports) {
1763 Dpid neighborDpid = portToNeighbors.get(sp);
1764 BucketInfo b = new BucketInfo(neighborDpid,
1765 MacAddress.of(srConfig.getRouterMac()),
1766 getNeighborRouterMacAddress(neighborDpid),
1767 sp, curLabel, bos, -1);
1768 buckets.add(b);
1769 }
1770 innermostGroupId = groupid.incrementAndGet();
1771 EcmpInfo ecmpInfo = new EcmpInfo(innermostGroupId, buckets);
1772 setEcmpGroup(ecmpInfo);
1773 userDefinedGroups.put(innermostGroupId, ecmpInfo);
1774 return innermostGroupId;
1775 }
1776
Srikanth Vavilapalli1167d0c2014-10-23 09:43:42 -07001777 /* If the label stack has two or more labels, then a chain of groups
1778 * to be created.
1779 * Step1: Create for each port in the list of specified ports,
1780 * an indirect group with the outermost label. These groups are the
1781 * end of the chain and hence don't reference to any other groups
1782 * Step2: Create for each port in the list of specified ports, an
1783 * indirect group with middle labels (if any). These groups will
1784 * have references to group ids that are created in the previous
1785 * iteration for the same ports
1786 * Step3: Create a select group with all ports and innermost label.
1787 * This group will have references to indirect group ids that are
1788 * created in the previous iteration for the same ports
1789 */
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001790 for (int i = 0; i < labelStack.size(); i++) {
1791 for (PortNumber sp : ports) {
1792 if (i == 0) {
1793 /* Outermost label processing */
1794 int currGroupId = groupid.incrementAndGet();
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001795 EcmpInfo indirectGroup = createIndirectGroup(currGroupId,
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001796 null, null, sp, -1,
1797 labelStack.get(i).intValue(), false);
1798 lastSetOfGroupIds.put(sp, currGroupId);
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001799 userDefinedGroups.put(currGroupId, indirectGroup);
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001800 }
1801 else if (i == (labelStack.size() - 1)) {
1802 /* Innermost label processing */
1803 innermostGroupId = groupid.incrementAndGet();
1804 EcmpInfo topLevelGroup = createInnermostLabelGroup(
1805 innermostGroupId,
1806 ports,
1807 labelStack.get(i).intValue(), true,
1808 lastSetOfGroupIds);
1809 userDefinedGroups.put(
1810 innermostGroupId, topLevelGroup);
1811 break;
1812 }
1813 else {
1814 /* Middle label processing */
1815 int currGroupId = groupid.incrementAndGet();
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001816 EcmpInfo indirectGroup = createIndirectGroup(currGroupId,
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001817 null, null, null,
1818 lastSetOfGroupIds.get(sp),
1819 labelStack.get(i).intValue(), false);
1820 /* Overwrite with this iteration's group IDs */
1821 lastSetOfGroupIds.put(sp, currGroupId);
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001822 userDefinedGroups.put(currGroupId, indirectGroup);
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001823 }
1824 }
1825 }
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001826 log.debug("createGroup: group created with innermost group id {}",
1827 innermostGroupId);
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001828 return innermostGroupId;
1829 }
1830
Srikanth Vavilapalli16a04722014-10-23 11:09:24 -07001831 /*
1832 @Override
1833 public void removeTunnel(String tunnelId) {
1834 List<Integer> groups = tunnelGroupIdTable.get(tunnelId);
1835 if (groups == null)
1836 return;
1837
1838 // we need to delete groups in reverse order
1839 for (int i = groups.size() - 1; i >= 0; i--) {
1840 int groupId = groups.get(i);
1841 deleteGroup(groupId);
1842 }
1843 tunnelGroupIdTable.remove(tunnelId);
1844 }
1845 */
1846
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001847 /**
1848 * Remove the specified group
1849 *
1850 * @param groupId group identifier
1851 * @return success/fail
1852 */
1853 public boolean removeGroup(int groupId) {
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001854 EcmpInfo group = userDefinedGroups.get(groupId);
1855 if (group == null) {
1856 log.warn("removeGroup: with invalid group id");
1857 return false;
1858 }
1859 for (BucketInfo bucket : group.buckets) {
1860 int currGroupIdToBeDeleted = bucket.groupNo;
1861 while (currGroupIdToBeDeleted != -1) {
1862 /* Assuming indirect groups with single buckets */
1863 int nextGroupIdToBeDeleted =
1864 userDefinedGroups.get(currGroupIdToBeDeleted).
1865 buckets.get(0).groupNo;
Sangho Shin93f623c2014-10-24 12:59:53 -07001866 deleteGroup(currGroupIdToBeDeleted);
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001867 userDefinedGroups.remove(currGroupIdToBeDeleted);
1868 currGroupIdToBeDeleted = nextGroupIdToBeDeleted;
1869 }
1870 }
1871
Sangho Shin93f623c2014-10-24 12:59:53 -07001872 deleteGroup(groupId);
1873 userDefinedGroups.remove(groupId);
Srikanth Vavilapallifd93b1f2014-10-23 14:15:21 -07001874 log.debug("removeGroup: removed group with group id {}", groupId);
1875 return true;
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001876 }
Srikanth Vavilapalli16a04722014-10-23 11:09:24 -07001877
Saurav Das2d41a432014-10-21 20:40:10 -07001878 @Override
1879 public Map<String, String> getPublishAttributes() {
1880 return publishAttributes;
1881 }
Sangho Shin1ad7be02014-10-20 16:56:49 -07001882
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001883 // *****************************
Saurav Das80d17392014-10-01 10:24:56 -07001884 // Unused
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001885 // *****************************
1886
Saurav Das80d17392014-10-01 10:24:56 -07001887 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001888 private void setAsyncConfig() throws IOException {
1889 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
1890 OFMessage setAC = null;
1891
1892 if (role == Role.MASTER) {
1893 setAC = factory.buildAsyncSet()
1894 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
1895 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
1896 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
1897 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1898 .setPacketInMaskSlave(SET_ALL_SLAVE)
1899 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1900 .setXid(getNextTransactionId())
1901 .build();
1902 } else if (role == Role.EQUAL) {
1903 setAC = factory.buildAsyncSet()
1904 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
1905 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
1906 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
1907 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1908 .setPacketInMaskSlave(SET_ALL_SLAVE)
1909 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1910 .setXid(getNextTransactionId())
1911 .build();
1912 }
1913 msglist.add(setAC);
1914
1915 OFMessage br = factory.buildBarrierRequest()
1916 .setXid(getNextTransactionId())
1917 .build();
1918 msglist.add(br);
1919
1920 OFMessage getAC = factory.buildAsyncGetRequest()
1921 .setXid(getNextTransactionId())
1922 .build();
1923 msglist.add(getAC);
1924
1925 write(msglist);
1926 }
1927
Saurav Das80d17392014-10-01 10:24:56 -07001928 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001929 private void decodeAsyncGetReply(OFAsyncGetReply rep) {
1930 long frm = rep.getFlowRemovedMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001931 long frs = rep.getFlowRemovedMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001932 long pim = rep.getPacketInMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001933 long pis = rep.getPacketInMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001934 long psm = rep.getPortStatusMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001935 long pss = rep.getPortStatusMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001936
1937 if (role == Role.MASTER || role == Role.EQUAL) { // should separate
1938 log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
1939 log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
1940 log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
1941 }
1942
1943 }
1944
Saurav Das80d17392014-10-01 10:24:56 -07001945 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001946 private void getTableFeatures() throws IOException {
1947 OFMessage gtf = factory.buildTableFeaturesStatsRequest()
1948 .setXid(getNextTransactionId())
1949 .build();
1950 write(gtf, null);
1951 }
1952
Saurav Das80d17392014-10-01 10:24:56 -07001953 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001954 private void sendGroupFeaturesRequest() throws IOException {
1955 OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
1956 .setXid(getNextTransactionId())
1957 .build();
1958 write(gfr, null);
1959 }
1960
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001961 private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
1962 log.info("Sw: {} Group Features {}", getStringId(), gfsr);
1963 }
1964
Saurav Dascc3e35f2014-10-10 15:33:32 -07001965 @SuppressWarnings("unused")
1966 private void testMultipleLabels() {
1967 if (getId() == 1) {
1968 List<OFMessage> msglist = new ArrayList<OFMessage>();
1969
1970 // first all the indirect groups
1971
1972 // the group to switch 2 with outer label
1973 OFGroup g1 = OFGroup.of(201);
1974 OFOxmEthDst dmac1 = factory.oxms().ethDst(MacAddress.of("00:00:02:02:02:80"));
1975 OFAction push1 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1976 OFOxmMplsLabel lid1 = factory.oxms()
1977 .mplsLabel(U32.of(105)); // outer label
1978 OFAction setMpls1 = factory.actions().buildSetField()
1979 .setField(lid1).build();
1980 OFOxmMplsBos bos1 = factory.oxms()
1981 .mplsBos(OFBooleanValue.FALSE);
1982 OFAction setB1 = factory.actions().buildSetField()
1983 .setField(bos1).build();
1984 OFAction setDA1 = factory.actions().buildSetField()
1985 .setField(dmac1).build();
1986 OFAction outp1 = factory.actions().buildOutput()
1987 .setPort(OFPort.of(2))
1988 .build();
1989 List<OFAction> a1 = new ArrayList<OFAction>();
1990 a1.add(push1);
1991 a1.add(setMpls1);
1992 a1.add(setB1);
1993 a1.add(setDA1);
1994 a1.add(outp1);
1995 OFBucket b1 = factory.buildBucket()
1996 .setActions(a1)
1997 .build();
1998 OFMessage gm1 = factory.buildGroupAdd()
1999 .setGroup(g1)
2000 .setBuckets(Collections.singletonList(b1))
2001 .setGroupType(OFGroupType.INDIRECT)
2002 .setXid(getNextTransactionId())
2003 .build();
2004 msglist.add(gm1);
2005
2006 // the group to switch 3 with outer label
2007 OFGroup g2 = OFGroup.of(301);
2008 OFOxmEthDst dmac2 = factory.oxms().ethDst(MacAddress.of("00:00:03:03:03:80"));
2009 OFAction push2 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
2010 OFOxmMplsLabel lid2 = factory.oxms()
2011 .mplsLabel(U32.of(104)); // outer label
2012 OFAction setMpls2 = factory.actions().buildSetField()
2013 .setField(lid2).build();
2014 OFOxmMplsBos bos2 = factory.oxms()
2015 .mplsBos(OFBooleanValue.FALSE);
2016 OFAction setB2 = factory.actions().buildSetField()
2017 .setField(bos2).build();
2018 OFAction setDA2 = factory.actions().buildSetField()
2019 .setField(dmac2).build();
2020 OFAction outp2 = factory.actions().buildOutput()
2021 .setPort(OFPort.of(3))
2022 .build();
2023 List<OFAction> a2 = new ArrayList<OFAction>();
2024 a2.add(push2);
2025 a2.add(setMpls2);
2026 a2.add(setB2);
2027 a2.add(setDA2);
2028 a2.add(outp2);
2029 OFBucket b2 = factory.buildBucket()
2030 .setActions(a2)
2031 .build();
2032 OFMessage gm2 = factory.buildGroupAdd()
2033 .setGroup(g2)
2034 .setBuckets(Collections.singletonList(b2))
2035 .setGroupType(OFGroupType.INDIRECT)
2036 .setXid(getNextTransactionId())
2037 .build();
2038 msglist.add(gm2);
2039
2040 // now add main ECMP group with inner labels
2041 OFGroup group = OFGroup.of(786);
2042 List<OFBucket> buckets = new ArrayList<OFBucket>();
2043 for (int i = 0; i < 2; i++) { // 2 buckets
2044
2045 List<OFAction> actions = new ArrayList<OFAction>();
2046 OFOxmEthSrc smac = factory.oxms()
2047 .ethSrc(MacAddress.of("00:00:01:01:01:80"));
2048 OFAction setSA = factory.actions().buildSetField()
2049 .setField(smac).build();
2050 actions.add(setSA);
2051
2052 if (i == 0) {
2053 // send to switch 2
2054 OFAction pushX = factory.actions().pushMpls(EthType.MPLS_UNICAST);
2055 OFOxmMplsLabel lidX = factory.oxms()
2056 .mplsLabel(U32.of(106)); // inner label
2057 OFAction setX = factory.actions().buildSetField()
2058 .setField(lidX).build();
2059 OFOxmMplsBos bosX = factory.oxms()
2060 .mplsBos(OFBooleanValue.TRUE);
2061 OFAction setBX = factory.actions().buildSetField()
2062 .setField(bosX).build();
2063 OFAction ogX = factory.actions().buildGroup()
2064 .setGroup(g1).build();
2065 actions.add(pushX);
2066 actions.add(setX);
2067 actions.add(setBX);
2068 actions.add(ogX);
2069
2070 } else {
2071 // send to switch 3
2072 OFAction pushY = factory.actions().pushMpls(EthType.MPLS_UNICAST);
2073 OFOxmMplsLabel lidY = factory.oxms()
2074 .mplsLabel(U32.of(106)); // inner label
2075 OFAction setY = factory.actions().buildSetField()
2076 .setField(lidY).build();
2077 OFOxmMplsBos bosY = factory.oxms()
2078 .mplsBos(OFBooleanValue.TRUE);
2079 OFAction setBY = factory.actions().buildSetField()
2080 .setField(bosY).build();
2081 OFAction ogY = factory.actions().buildGroup()
2082 .setGroup(g2).build();
2083 actions.add(pushY);
2084 actions.add(setY);
2085 actions.add(setBY);
2086 actions.add(ogY);
2087 }
2088
2089 OFBucket ofb = factory.buildBucket()
2090 .setWeight(1)
2091 .setActions(actions)
2092 .build();
2093 buckets.add(ofb);
2094 }
2095
2096 OFMessage gm = factory.buildGroupAdd()
2097 .setGroup(group)
2098 .setBuckets(buckets)
2099 .setGroupType(OFGroupType.SELECT)
2100 .setXid(getNextTransactionId())
2101 .build();
2102 msglist.add(gm);
2103
2104 // create an ACL entry to use this ecmp group
2105 Builder matchBuilder = factory.buildMatch();
2106 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(0x800));
2107 matchBuilder.setMasked(MatchField.IPV4_DST,
2108 IPv4Address.of("7.7.7.0")
2109 .withMaskOfLength(24));
2110
2111 OFAction grp = factory.actions().buildGroup()
2112 .setGroup(OFGroup.of(786))
2113 .build();
2114 List<OFAction> writeActions = Collections.singletonList(grp);
2115
2116 OFInstruction clearInstr = factory.instructions().clearActions();
2117 OFInstruction writeInstr = factory.instructions().buildWriteActions()
2118 .setActions(writeActions).build();
2119 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
2120 instructions.add(clearInstr);
2121 instructions.add(writeInstr);
2122
2123 OFFlowMod.Builder fmBuilder = factory.buildFlowAdd();
2124
2125 OFMessage aclFlow = fmBuilder
2126 .setTableId(TableId.of(TABLE_ACL))
2127 .setMatch(matchBuilder.build())
2128 .setInstructions(instructions)
2129 .setPriority(10) // TODO: wrong - should be MA
2130 // priority
2131 .setBufferId(OFBufferId.NO_BUFFER)
2132 .setIdleTimeout(0)
2133 .setHardTimeout(0)
2134 .setXid(getNextTransactionId())
2135 .build();
2136 msglist.add(aclFlow);
2137
2138 try {
2139 write(msglist);
2140 } catch (IOException e) {
2141 // TODO Auto-generated catch block
2142 e.printStackTrace();
2143 }
Fahad Naeem Khand563af62014-10-08 17:37:25 -07002144 }
2145 }
2146
Saurav Das2d41a432014-10-21 20:40:10 -07002147
2148
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07002149}