blob: bd55d83ebfe48fb9825c295d8775d6ac6cec2011 [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;
Sangho Shin4b46bcd2014-10-20 15:48:47 -0700150 private ConcurrentMap<String, List<Integer>> tunnelGroupIdTable;
Srikanth Vavilapallib95e6e02014-10-02 13:56:39 -0700151 private ConcurrentMap<PortNumber, ArrayList<NeighborSet>> portNeighborSetMap;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700152 private AtomicInteger groupid;
Saurav Das2d41a432014-10-21 20:40:10 -0700153 private Map<String, String> publishAttributes;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700154
Jonathan Hartcb34f382014-08-12 21:11:03 -0700155 public OFSwitchImplCPqD13(OFDescStatsReply desc, boolean usePipeline13) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700156 super();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700157 haltStateMachine = new AtomicBoolean(false);
158 driverState = DriverState.INIT;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700159 driverHandshakeComplete = new AtomicBoolean(false);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700160 setSwitchDescription(desc);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700161 neighbors = new ConcurrentHashMap<Dpid, Set<PortNumber>>();
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700162 portToNeighbors = new ConcurrentHashMap<PortNumber, Dpid>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700163 ecmpGroups = new ConcurrentHashMap<NeighborSet, EcmpInfo>();
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -0700164 userDefinedGroups = new ConcurrentHashMap<Integer, EcmpInfo>();
Srikanth Vavilapallib95e6e02014-10-02 13:56:39 -0700165 portNeighborSetMap =
166 new ConcurrentHashMap<PortNumber, ArrayList<NeighborSet>>();
Sangho Shin4b46bcd2014-10-20 15:48:47 -0700167 tunnelGroupIdTable = new ConcurrentHashMap<String, List<Integer>>();
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700168 segmentIds = new ArrayList<Integer>();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700169 isEdgeRouter = false;
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700170 groupid = new AtomicInteger(0);
Jonathan Hartcb34f382014-08-12 21:11:03 -0700171 this.usePipeline13 = usePipeline13;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700172 }
173
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700174 // *****************************
175 // OFSwitchImplBase
176 // *****************************
177
178
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700179 /* (non-Javadoc)
180 * @see java.lang.Object#toString()
181 */
182 @Override
183 public String toString() {
184 return "OFSwitchImplCPqD13 [" + ((channel != null)
185 ? channel.getRemoteAddress() : "?")
186 + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
187 }
188
189 @Override
190 public void startDriverHandshake() throws IOException {
191 log.debug("Starting driver handshake for sw {}", getStringId());
192 if (startDriverHandshakeCalled) {
193 throw new SwitchDriverSubHandshakeAlreadyStarted();
194 }
195 startDriverHandshakeCalled = true;
Jonathan Harta213bce2014-08-11 15:44:07 -0700196 factory = getFactory();
Jonathan Hartcb34f382014-08-12 21:11:03 -0700197 if (!usePipeline13) {
198 // Send packet-in to controller if a packet misses the first table
199 populateTableMissEntry(0, true, false, false, 0);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700200 driverHandshakeComplete.set(true);
Sangho Shin01bca862014-09-12 11:18:59 -0700201 } else {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700202 nextDriverState();
Sangho Shin01bca862014-09-12 11:18:59 -0700203 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700204 }
205
206 @Override
207 public boolean isDriverHandshakeComplete() {
Sangho Shin01bca862014-09-12 11:18:59 -0700208 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700209 throw new SwitchDriverSubHandshakeNotStarted();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700210 return driverHandshakeComplete.get();
211 }
212
213 @Override
214 public void processDriverHandshakeMessage(OFMessage m) {
Sangho Shin01bca862014-09-12 11:18:59 -0700215 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700216 throw new SwitchDriverSubHandshakeNotStarted();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700217 if (isDriverHandshakeComplete())
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700218 throw new SwitchDriverSubHandshakeCompleted(m);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700219 try {
220 processOFMessage(this, m);
221 } catch (IOException e) {
222 log.error("Error generated when processing OFMessage", e.getCause());
223 }
224 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700225
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700226 @Override
227 public String getSwitchDriverState() {
228 return driverState.toString();
229 }
230
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700231 public void removePortFromGroups(PortNumber port) {
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700232 log.debug("removePortFromGroups: Remove port {} from Switch {}",
233 port, getStringId());
234 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
235 if (portNSSet == null)
236 {
237 /* No Groups are created with this port yet */
238 log.warn("removePortFromGroups: No groups exist with Switch {} port {}",
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700239 getStringId(), port);
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700240 return;
241 }
242 log.debug("removePortFromGroups: Neighborsets that the port {} is part"
243 + "of on Switch {} are {}",
244 port, getStringId(), portNSSet);
245
246 for (NeighborSet ns : portNSSet) {
247 /* Delete the first matched bucket */
248 EcmpInfo portEcmpInfo = ecmpGroups.get(ns);
249 Iterator<BucketInfo> it = portEcmpInfo.buckets.iterator();
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700250 log.debug("removePortFromGroups: Group {} on Switch {} has {} buckets",
251 portEcmpInfo.groupId, getStringId(),
252 portEcmpInfo.buckets.size());
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700253 while (it.hasNext()) {
254 BucketInfo bucket = it.next();
255 if (bucket.outport.equals(port)) {
256 it.remove();
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700257 }
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700258 }
259 log.debug("removePortFromGroups: Modifying Group on Switch {} "
260 + "and Neighborset {} with {}",
261 getStringId(), ns, portEcmpInfo);
262 modifyEcmpGroup(portEcmpInfo);
263 }
264 /* Don't delete the entry from portNeighborSetMap because
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700265 * when the port is up again this info is needed
266 */
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -0700267 return;
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700268 }
269
270 public void addPortToGroups(PortNumber port) {
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700271 log.debug("addPortToGroups: Add port {} to Switch {}",
272 port, getStringId());
273 ArrayList<NeighborSet> portNSSet = portNeighborSetMap.get(port);
274 if (portNSSet == null) {
275 /* Unknown Port */
276 log.warn("addPortToGroups: Switch {} port {} is unknown",
Srikanth Vavilapallicf1840b2014-10-09 15:29:51 -0700277 getStringId(), port);
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700278 return;
279 }
280 log.debug("addPortToGroups: Neighborsets that the port {} is part"
281 + "of on Switch {} are {}",
282 port, getStringId(), portNSSet);
283
284 Dpid neighborDpid = portToNeighbors.get(port);
285 for (NeighborSet ns : portNSSet) {
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700286 EcmpInfo portEcmpInfo = ecmpGroups.get(ns);
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700287 /* Find if this port is already part of any bucket
288 * in this group
289 * NOTE: This is needed because in some cases
290 * (such as for configured network nodes), both driver and
291 * application detect the network elements and creates the
292 * buckets in the same group. This check is to avoid
293 * duplicate bucket creation in such scenarios
294 */
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700295 List<BucketInfo> buckets = portEcmpInfo.buckets;
296 if (buckets == null) {
297 buckets = new ArrayList<BucketInfo>();
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700298 portEcmpInfo.buckets = buckets;
299 } else {
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700300 Iterator<BucketInfo> it = buckets.iterator();
301 boolean matchingBucketExist = false;
302 while (it.hasNext()) {
303 BucketInfo bucket = it.next();
304 if (bucket.outport.equals(port)) {
305 matchingBucketExist = true;
306 break;
307 }
308 }
309 if (matchingBucketExist) {
310 log.warn("addPortToGroups: On Switch {} duplicate "
311 + "portAdd is called for port {} with buckets {}",
312 getStringId(), port, buckets);
313 continue;
314 }
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700315 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700316 BucketInfo b = new BucketInfo(neighborDpid,
317 MacAddress.of(srConfig.getRouterMac()),
318 getNeighborRouterMacAddress(neighborDpid),
319 port,
320 ns.getEdgeLabel());
321 buckets.add(b);
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700322 log.debug("addPortToGroups: Modifying Group on Switch {} "
323 + "and Neighborset {} with {}",
324 getStringId(), ns, portEcmpInfo);
325 modifyEcmpGroup(portEcmpInfo);
326 }
327 return;
Srikanth Vavilapallibd9b3e22014-10-02 08:57:46 -0700328 }
329
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700330 @Override
331 public OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps) {
332 OrderedCollection<PortChangeEvent> events = super.processOFPortStatus(ps);
333 for (PortChangeEvent e : events) {
334 switch (e.type) {
335 case DELETE:
336 case DOWN:
337 log.debug("processOFPortStatus: sw {} Port {} DOWN",
338 getStringId(), e.port.getPortNo().getPortNumber());
339 removePortFromGroups(PortNumber.uint32(
340 e.port.getPortNo().getPortNumber()));
341 break;
342 case UP:
343 log.debug("processOFPortStatus: sw {} Port {} UP",
344 getStringId(), e.port.getPortNo().getPortNumber());
345 addPortToGroups(PortNumber.uint32(
346 e.port.getPortNo().getPortNumber()));
347 }
348 }
349 return events;
350 }
351
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700352 // *****************************
353 // Driver handshake state-machine
354 // *****************************
355
356 enum DriverState {
357 INIT,
358 SET_TABLE_MISS_ENTRIES,
359 SET_TABLE_VLAN_TMAC,
360 SET_GROUPS,
361 VERIFY_GROUPS,
362 SET_ADJACENCY_LABELS,
363 EXIT
364 }
365
366 protected void nextDriverState() throws IOException {
367 DriverState currentState = driverState;
Saurav Das80d17392014-10-01 10:24:56 -0700368 if (haltStateMachine.get()) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700369 return;
Saurav Das80d17392014-10-01 10:24:56 -0700370 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700371 switch (currentState) {
372 case INIT:
373 driverState = DriverState.SET_TABLE_MISS_ENTRIES;
374 setTableMissEntries();
Saurav Dasd84178f2014-09-29 17:48:54 -0700375 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700376 break;
377 case SET_TABLE_MISS_ENTRIES:
378 driverState = DriverState.SET_TABLE_VLAN_TMAC;
379 getNetworkConfig();
380 populateTableVlan();
381 populateTableTMac();
Saurav Dasd84178f2014-09-29 17:48:54 -0700382 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700383 break;
384 case SET_TABLE_VLAN_TMAC:
385 driverState = DriverState.SET_GROUPS;
386 createGroups();
Saurav Dasd84178f2014-09-29 17:48:54 -0700387 sendHandshakeBarrier();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700388 break;
389 case SET_GROUPS:
390 driverState = DriverState.VERIFY_GROUPS;
391 verifyGroups();
392 break;
393 case VERIFY_GROUPS:
394 driverState = DriverState.SET_ADJACENCY_LABELS;
395 assignAdjacencyLabels();
396 break;
397 case SET_ADJACENCY_LABELS:
398 driverState = DriverState.EXIT;
399 driverHandshakeComplete.set(true);
400 break;
401 case EXIT:
402 default:
403 driverState = DriverState.EXIT;
404 log.error("Driver handshake has exited for sw: {}", getStringId());
405 }
406 }
407
408 void processOFMessage(IOFSwitch sw, OFMessage m) throws IOException {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700409 switch (m.getType()) {
410 case BARRIER_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700411 processBarrierReply(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700412 break;
413
414 case ERROR:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700415 processErrorMessage(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700416 break;
417
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700418 case GET_ASYNC_REPLY:
419 OFAsyncGetReply asrep = (OFAsyncGetReply) m;
420 decodeAsyncGetReply(asrep);
421 break;
422
423 case PACKET_IN:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700424 // not ready to handle packet-ins
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700425 break;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700426
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700427 case QUEUE_GET_CONFIG_REPLY:
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700428 // not doing queue config yet
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700429 break;
430
431 case STATS_REPLY:
432 processStatsReply((OFStatsReply) m);
433 break;
434
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700435 case ROLE_REPLY: // channelHandler should handle this
436 case PORT_STATUS: // channelHandler should handle this
437 case FEATURES_REPLY: // don't care
438 case FLOW_REMOVED: // don't care
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700439 default:
440 log.debug("Received message {} during switch-driver subhandshake "
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700441 + "from switch {} ... Ignoring message", m, sw.getStringId());
442 }
443 }
444
445 private void processStatsReply(OFStatsReply sr) {
446 switch (sr.getStatsType()) {
447 case AGGREGATE:
448 break;
449 case DESC:
450 break;
451 case EXPERIMENTER:
452 break;
453 case FLOW:
454 break;
455 case GROUP_DESC:
456 processGroupDesc((OFGroupDescStatsReply) sr);
457 break;
458 case GROUP_FEATURES:
459 processGroupFeatures((OFGroupFeaturesStatsReply) sr);
460 break;
461 case METER_CONFIG:
462 break;
463 case METER_FEATURES:
464 break;
465 case PORT_DESC:
466 break;
467 case TABLE_FEATURES:
468 break;
469 default:
470 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700471
472 }
473 }
474
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700475 private void processErrorMessage(OFMessage m) {
476 log.error("Switch {} Error {} in DriverState", getStringId(),
477 (OFErrorMsg) m, driverState);
478 }
479
480 private void processBarrierReply(OFMessage m) throws IOException {
481 if (m.getXid() == barrierXidToWaitFor) {
482 // Driver state-machine progresses to the next state.
483 // If Barrier messages is not received, then eventually
484 // the ChannelHandler state machine will timeout, and the switch
485 // will be disconnected.
486 nextDriverState();
487 } else {
488 log.error("Received incorrect barrier-message xid {} (expected: {}) in "
489 + "switch-driver state {} for switch {}", m, barrierXidToWaitFor,
490 driverState, getStringId());
491 }
492 }
493
494 private void processGroupDesc(OFGroupDescStatsReply gdsr) {
495 log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
Saurav Das2d41a432014-10-21 20:40:10 -0700496 // TODO -- actually do verification
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700497 try {
498 nextDriverState();
499 } catch (IOException e) {
500 // TODO Auto-generated catch block
501 e.printStackTrace();
502 }
503 }
504
505 // *****************************
506 // Utility methods
507 // *****************************
508
509 void setTableMissEntries() throws IOException {
510 // set all table-miss-entries
511 populateTableMissEntry(TABLE_VLAN, true, false, false, -1);
512 populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
513 populateTableMissEntry(TABLE_IPv4_UNICAST, false, true, true,
514 TABLE_ACL);
515 populateTableMissEntry(TABLE_MPLS, false, true, true,
516 TABLE_ACL);
517 populateTableMissEntry(TABLE_ACL, false, false, false, -1);
518 }
519
Saurav Dasd84178f2014-09-29 17:48:54 -0700520 private void sendHandshakeBarrier() throws IOException {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700521 long xid = getNextTransactionId();
522 barrierXidToWaitFor = xid;
523 OFBarrierRequest br = getFactory()
524 .buildBarrierRequest()
525 .setXid(xid)
526 .build();
527 write(br, null);
528 }
529
530 /**
531 * Adds a table-miss-entry to a pipeline table.
532 * <p>
533 * The table-miss-entry can be added with 'write-actions' or
534 * 'apply-actions'. It can also add a 'goto-table' instruction. By default
535 * if none of the booleans in the call are set, then the table-miss entry is
536 * added with no instructions, which means that if a packet hits the
537 * table-miss-entry, pipeline execution will stop, and the action set
538 * associated with the packet will be executed.
539 *
540 * @param tableToAdd the table to where the table-miss-entry will be added
541 * @param toControllerNow as an APPLY_ACTION instruction
542 * @param toControllerWrite as a WRITE_ACTION instruction
543 * @param toTable as a GOTO_TABLE instruction
544 * @param tableToSend the table to send as per the GOTO_TABLE instruction it
545 * needs to be set if 'toTable' is true. Ignored of 'toTable' is
546 * false.
547 * @throws IOException
548 */
549 @SuppressWarnings("unchecked")
550 private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
551 boolean toControllerWrite,
552 boolean toTable, int tableToSend) throws IOException {
553 OFOxmList oxmList = OFOxmList.EMPTY;
554 OFMatchV3 match = factory.buildMatchV3()
555 .setOxmList(oxmList)
556 .build();
557 OFAction outc = factory.actions()
558 .buildOutput()
559 .setPort(OFPort.CONTROLLER)
560 .setMaxLen(OFPCML_NO_BUFFER)
561 .build();
562 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
563 if (toControllerNow) {
564 // table-miss instruction to send to controller immediately
565 OFInstruction instr = factory.instructions()
566 .buildApplyActions()
567 .setActions(Collections.singletonList(outc))
568 .build();
569 instructions.add(instr);
570 }
571
572 if (toControllerWrite) {
573 // table-miss instruction to write-action to send to controller
574 // this will be executed whenever the action-set gets executed
575 OFInstruction instr = factory.instructions()
576 .buildWriteActions()
577 .setActions(Collections.singletonList(outc))
578 .build();
579 instructions.add(instr);
580 }
581
582 if (toTable) {
583 // table-miss instruction to goto-table x
584 OFInstruction instr = factory.instructions()
585 .gotoTable(TableId.of(tableToSend));
586 instructions.add(instr);
587 }
588
589 if (!toControllerNow && !toControllerWrite && !toTable) {
590 // table-miss has no instruction - at which point action-set will be
591 // executed - if there is an action to output/group in the action
592 // set
593 // the packet will be sent there, otherwise it will be dropped.
594 instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
595 }
596
597 OFMessage tableMissEntry = factory.buildFlowAdd()
598 .setTableId(TableId.of(tableToAdd))
599 .setMatch(match) // match everything
600 .setInstructions(instructions)
601 .setPriority(MIN_PRIORITY)
602 .setBufferId(OFBufferId.NO_BUFFER)
603 .setIdleTimeout(0)
604 .setHardTimeout(0)
605 .setXid(getNextTransactionId())
606 .build();
607 write(tableMissEntry, null);
608 }
609
610 private void getNetworkConfig() {
611 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
612 SwitchConfigStatus scs = ncs.checkSwitchConfig(new Dpid(getId()));
613 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
614 srConfig = (SegmentRouterConfig) scs.getSwitchConfig();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700615 isEdgeRouter = srConfig.isEdgeRouter();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700616 } else {
617 log.error("Switch not configured as Segment-Router");
618 }
619
620 List<LinkConfig> linkConfigList = ncs.getConfiguredAllowedLinks();
621 setNeighbors(linkConfigList);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700622
623 if (isEdgeRouter) {
624 List<SwitchConfig> switchList = ncs.getConfiguredAllowedSwitches();
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700625 getAllNodeSegmentIds(switchList);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700626 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700627 }
628
629 private void populateTableVlan() throws IOException {
630 List<OFMessage> msglist = new ArrayList<OFMessage>();
631 for (OFPortDesc p : getPorts()) {
632 int pnum = p.getPortNo().getPortNumber();
633 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
634 OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
635 OFOxmVlanVid oxv = factory.oxms()
636 .vlanVid(OFVlanVidMatch.UNTAGGED);
637 OFOxmList oxmList = OFOxmList.of(oxp, oxv);
638 OFMatchV3 match = factory.buildMatchV3()
639 .setOxmList(oxmList).build();
640
641 // TODO: match on vlan-tagged packets for vlans configured on
642 // subnet ports and strip-vlan
643
644 // Do not need to add vlans
645 /*int vlanid = getVlanConfig(pnum);
646 OFOxmVlanVid vidToSet = factory.oxms()
647 .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
648 OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
649 OFAction setVlan = factory.actions().setField(vidToSet);
650 List<OFAction> actionlist = new ArrayList<OFAction>();
651 actionlist.add(pushVlan);
652 actionlist.add(setVlan);
653 OFInstruction appAction = factory.instructions().buildApplyActions()
654 .setActions(actionlist).build();*/
655
656 OFInstruction gotoTbl = factory.instructions().buildGotoTable()
657 .setTableId(TableId.of(TABLE_TMAC)).build();
658 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
659 // instructions.add(appAction);
660 instructions.add(gotoTbl);
661 OFMessage flowEntry = factory.buildFlowAdd()
662 .setTableId(TableId.of(TABLE_VLAN))
663 .setMatch(match)
664 .setInstructions(instructions)
665 .setPriority(1000) // does not matter - all rules
666 // exclusive
667 .setBufferId(OFBufferId.NO_BUFFER)
668 .setIdleTimeout(0)
669 .setHardTimeout(0)
670 .setXid(getNextTransactionId())
671 .build();
672 msglist.add(flowEntry);
673 }
674 }
675 write(msglist);
676 log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId());
677 }
678
679 private void populateTableTMac() throws IOException {
680 // match for router-mac and ip-packets
681 OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
682 OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr());
683 OFOxmList oxmListIp = OFOxmList.of(dmac, oxe);
684 OFMatchV3 matchIp = factory.buildMatchV3()
685 .setOxmList(oxmListIp).build();
686 OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
687 .setTableId(TableId.of(TABLE_IPv4_UNICAST)).build();
688 List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
689 OFMessage ipEntry = factory.buildFlowAdd()
690 .setTableId(TableId.of(TABLE_TMAC))
691 .setMatch(matchIp)
692 .setInstructions(instructionsIp)
693 .setPriority(1000) // strict priority required lower than
694 // multicastMac
695 .setBufferId(OFBufferId.NO_BUFFER)
696 .setIdleTimeout(0)
697 .setHardTimeout(0)
698 .setXid(getNextTransactionId())
699 .build();
700
701 // match for router-mac and mpls packets
702 OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
703 OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls);
704 OFMatchV3 matchMpls = factory.buildMatchV3()
705 .setOxmList(oxmListMpls).build();
706 OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
707 .setTableId(TableId.of(TABLE_MPLS)).build();
708 List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
709 OFMessage mplsEntry = factory.buildFlowAdd()
710 .setTableId(TableId.of(TABLE_TMAC))
711 .setMatch(matchMpls)
712 .setInstructions(instructionsMpls)
713 .setPriority(1001) // strict priority required lower than
714 // multicastMac
715 .setBufferId(OFBufferId.NO_BUFFER)
716 .setIdleTimeout(0)
717 .setHardTimeout(0)
718 .setXid(getNextTransactionId())
719 .build();
720
721 log.debug("Adding termination-mac-rules in sw {}", getStringId());
722 List<OFMessage> msglist = new ArrayList<OFMessage>(2);
723 msglist.add(ipEntry);
724 msglist.add(mplsEntry);
725 write(msglist);
726 }
727
728 private MacAddress getRouterMacAddr() {
729 if (srConfig != null) {
730 return MacAddress.of(srConfig.getRouterMac());
731 } else {
732 // return a dummy mac address - it will not be used
733 return MacAddress.of("00:00:00:00:00:00");
734 }
735 }
736
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700737 private boolean isEdgeRouter(Dpid ndpid) {
738 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
739 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
740 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
741 return ((SegmentRouterConfig) scs.getSwitchConfig()).isEdgeRouter();
742 } else {
743 // TODO: return false if router not allowed
744 return false;
745 }
746 }
747
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700748 private MacAddress getNeighborRouterMacAddress(Dpid ndpid) {
749 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
750 SwitchConfigStatus scs = ncs.checkSwitchConfig(ndpid);
751 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
752 return MacAddress.of(((SegmentRouterConfig) scs.getSwitchConfig())
753 .getRouterMac());
754 } else {
755 // return a dummy mac address - it will not be used
756 return MacAddress.of("00:00:00:00:00:00");
757 }
758 }
759
760 private void setNeighbors(List<LinkConfig> linkConfigList) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700761 for (LinkConfig lg : linkConfigList) {
762 if (!lg.getType().equals(NetworkConfigManager.PKT_LINK)) {
Saurav Das80d17392014-10-01 10:24:56 -0700763 continue;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700764 }
765 PktLinkConfig plg = (PktLinkConfig) lg;
766 if (plg.getDpid1() == getId()) {
767 addNeighborAtPort(new Dpid(plg.getDpid2()),
768 PortNumber.uint32(plg.getPort1()));
769 } else if (plg.getDpid2() == getId()) {
770 addNeighborAtPort(new Dpid(plg.getDpid1()),
771 PortNumber.uint32(plg.getPort2()));
772 }
773 }
774 }
775
776 private void addNeighborAtPort(Dpid neighborDpid, PortNumber portToNeighbor) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700777 /* Update NeighborToPort database */
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700778 if (neighbors.get(neighborDpid) != null) {
779 neighbors.get(neighborDpid).add(portToNeighbor);
780 } else {
781 Set<PortNumber> ports = new HashSet<PortNumber>();
782 ports.add(portToNeighbor);
783 neighbors.put(neighborDpid, ports);
784 }
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700785
786 /* Update portToNeighbors database */
787 if (portToNeighbors.get(portToNeighbor) == null)
788 portToNeighbors.put(portToNeighbor, neighborDpid);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700789 }
790
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700791 private void getAllNodeSegmentIds(List<SwitchConfig> switchList) {
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700792 for (SwitchConfig sc : switchList) {
793 /* TODO: Do we need to check if the SwitchConfig is of
794 * type SegmentRouter?
795 */
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700796 if (sc.getDpid() == getId()) {
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700797 continue;
798 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700799 segmentIds.add(((SegmentRouterConfig) sc).getNodeSid());
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700800 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700801 log.debug("getAllNodeSegmentIds: at sw {} are {}",
802 getStringId(), segmentIds);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700803 }
804
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700805 private boolean isSegmentIdSameAsNodeSegmentId(Dpid dpid, int sId) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700806 INetworkConfigService ncs = floodlightProvider.getNetworkConfigService();
807 SwitchConfigStatus scs = ncs.checkSwitchConfig(dpid);
808 if (scs.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
809 return (((SegmentRouterConfig) scs.getSwitchConfig()).
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700810 getNodeSid() == sId);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700811 } else {
812 // TODO: return false if router not allowed
813 return false;
814 }
815 }
816
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700817 private Set<Set<Dpid>> getAllNeighborSets(Set<Dpid> neighbors) {
818 List<Dpid> list = new ArrayList<Dpid>(neighbors);
819 Set<Set<Dpid>> sets = new HashSet<Set<Dpid>>();
820 /* get the number of elements in the neighbors */
821 int elements = list.size();
822 /* the number of members of a power set is 2^n
823 * including the empty set
824 */
825 int powerElements = (1 << elements);
826
827 /* run a binary counter for the number of power elements */
828 for (long i = 1; i < powerElements; i++) {
829 Set<Dpid> dpidSubSet = new HashSet<Dpid>();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700830 for (int j = 0; j < elements; j++) {
831 if ((i >> j) % 2 == 1) {
832 dpidSubSet.add(list.get(j));
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700833 }
834 }
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700835 /* NOTE: Avoid any pairings of edge routers only
836 * at a backbone router */
837 boolean avoidEdgeRouterPairing = true;
838 if ((!isEdgeRouter) && (dpidSubSet.size() > 1)) {
Srikanth Vavilapalli696010f2014-10-08 17:00:17 -0700839 for (Dpid dpid : dpidSubSet) {
840 if (!isEdgeRouter(dpid)) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700841 avoidEdgeRouterPairing = false;
Srikanth Vavilapalli696010f2014-10-08 17:00:17 -0700842 break;
843 }
844 }
845 }
846 else
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700847 avoidEdgeRouterPairing = false;
Srikanth Vavilapalli696010f2014-10-08 17:00:17 -0700848
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700849 if (!avoidEdgeRouterPairing)
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700850 sets.add(dpidSubSet);
851 }
852 return sets;
853 }
854
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700855 private void createGroupForANeighborSet(NeighborSet ns, int groupId) {
856 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
857 for (Dpid d : ns.getDpids()) {
858 for (PortNumber sp : neighbors.get(d)) {
859 BucketInfo b = new BucketInfo(d,
860 MacAddress.of(srConfig.getRouterMac()),
861 getNeighborRouterMacAddress(d), sp,
862 ns.getEdgeLabel());
863 buckets.add(b);
864
865 /* Update Port Neighborset map */
866 ArrayList<NeighborSet> portNeighborSets =
867 portNeighborSetMap.get(sp);
868 if (portNeighborSets == null) {
869 portNeighborSets = new ArrayList<NeighborSet>();
870 portNeighborSets.add(ns);
871 portNeighborSetMap.put(sp, portNeighborSets);
872 }
873 else
874 portNeighborSets.add(ns);
875 }
876 }
877 EcmpInfo ecmpInfo = new EcmpInfo(groupId, buckets);
878 setEcmpGroup(ecmpInfo);
879 ecmpGroups.put(ns, ecmpInfo);
880 log.debug(
881 "createGroupForANeighborSet: Creating ecmp group {} in sw {} "
882 + "for neighbor set {} with: {}",
883 groupId, getStringId(), ns, ecmpInfo);
884 return;
885 }
886
Sangho Shin15273b62014-10-16 22:22:05 -0700887 private void createGroupForMplsLabel(int groupId, String nodeId,
888 int nextGroupId, boolean bos) {
889 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
890 BucketInfo bucket = new BucketInfo(nextGroupId,
891 Integer.parseInt(nodeId), bos);
892 buckets.add(bucket);
893 EcmpInfo ecmpInfo = new EcmpInfo(groupId, buckets);
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -0700894 setEcmpGroup(ecmpInfo);
Sangho Shin15273b62014-10-16 22:22:05 -0700895// ecmpGroups.put(ns, ecmpInfo);
896 log.debug(
897 "createGroupForANeighborSet: Creating ecmp group {} in sw {} "
898 + "for pushing label {} and group to {}",
899 groupId, getStringId(), nodeId, nextGroupId);
900 return;
901 }
902
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700903 /**
904 * createGroups creates ECMP groups for all ports on this router connected
905 * to other routers (in the OF network). The information for ports is
906 * gleaned from the configured links. If no links are configured no groups
907 * will be created, and it is up to the caller of the IOF13Switch API to
908 * create groups.
909 * <p>
910 * By default all ports connected to the same neighbor router will be part
911 * of the same ECMP group. In addition, groups will be created for all
912 * possible combinations of neighbor routers.
913 * <p>
914 * For example, consider this router (R0) connected to 3 neighbors (R1, R2,
915 * and R3). The following groups will be created in R0:
916 * <li>1) all ports to R1,
917 * <li>2) all ports to R2,
918 * <li>3) all ports to R3,
919 * <li>4) all ports to R1 and R2
920 * <li>5) all ports to R1 and R3
921 * <li>6) all ports to R2 and R3
922 * <li>7) all ports to R1, R2, and R3
923 */
924 private void createGroups() {
Sangho Shin15273b62014-10-16 22:22:05 -0700925
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700926 Set<Dpid> dpids = neighbors.keySet();
927 if (dpids == null || dpids.isEmpty()) {
928 return;
929 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700930 /* Create all possible Neighbor sets from this router
931 * NOTE: Avoid any pairings of edge routers only
932 */
933 Set<Set<Dpid>> powerSet = getAllNeighborSets(dpids);
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700934 log.debug("createGroups: The size of neighbor powerset for sw {} is {}",
Srikanth Vavilapallica2263c2014-10-09 15:19:11 -0700935 getStringId(), powerSet.size());
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700936 Set<NeighborSet> nsSet = new HashSet<NeighborSet>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700937 for (Set<Dpid> combo : powerSet) {
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700938 if (combo.isEmpty())
939 continue;
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700940 if (isEdgeRouter && !segmentIds.isEmpty()) {
941 for (Integer sId : segmentIds) {
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700942 NeighborSet ns = new NeighborSet();
943 ns.addDpids(combo);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700944 /* Check if the edge label being set is of the
945 * same node in the Neighbor set
946 */
947 if ((combo.size() != 1) ||
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700948 (!isSegmentIdSameAsNodeSegmentId(
949 combo.iterator().next(), sId))) {
950 ns.setEdgeLabel(sId);
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -0700951 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700952 nsSet.add(ns);
953 }
954 } else {
955 NeighborSet ns = new NeighborSet();
956 ns.addDpids(combo);
957 nsSet.add(ns);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700958 }
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700959 }
Srikanth Vavilapalli2cd0ff12014-10-10 13:07:46 -0700960 log.debug("createGroups: The neighborset with label for sw {} is {}",
Srikanth Vavilapallica2263c2014-10-09 15:19:11 -0700961 getStringId(), nsSet);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700962
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700963 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli25fbe392014-10-10 15:04:51 -0700964 createGroupForANeighborSet(ns, groupid.incrementAndGet());
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700965 }
966 }
967
968 private class EcmpInfo {
969 int groupId;
970 List<BucketInfo> buckets;
971
972 EcmpInfo(int gid, List<BucketInfo> bucketInfos) {
973 groupId = gid;
974 buckets = bucketInfos;
975 }
976
977 @Override
978 public String toString() {
979 return "groupId: " + groupId + ", buckets: " + buckets;
980 }
981 }
982
983 private class BucketInfo {
984 Dpid neighborDpid;
985 MacAddress srcMac;
986 MacAddress dstMac;
987 PortNumber outport;
Sangho Shin15273b62014-10-16 22:22:05 -0700988 int groupNo;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700989 int mplsLabel;
Sangho Shin15273b62014-10-16 22:22:05 -0700990 boolean bos;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700991
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700992 BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac,
993 PortNumber p, int label) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700994 neighborDpid = nDpid;
995 srcMac = smac;
996 dstMac = dmac;
997 outport = p;
Srikanth Vavilapalli68144302014-10-08 15:55:24 -0700998 mplsLabel = label;
Sangho Shin15273b62014-10-16 22:22:05 -0700999 groupNo = -1;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001000 }
1001
Sangho Shin15273b62014-10-16 22:22:05 -07001002 BucketInfo(int no, int label, boolean b) {
1003 neighborDpid = null;
1004 srcMac = null;
1005 dstMac = null;
1006 outport = null;
1007 groupNo = no;
1008 mplsLabel = label;
1009 bos = b;
1010 }
1011
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001012 BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac,
1013 PortNumber p, int label, boolean bos, int gotoGroupNo) {
1014 neighborDpid = nDpid;
1015 srcMac = smac;
1016 dstMac = dmac;
1017 outport = p;
1018 mplsLabel = label;
1019 this.bos = bos;
1020 groupNo = gotoGroupNo;
1021 }
1022
Sangho Shin15273b62014-10-16 22:22:05 -07001023
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001024 @Override
1025 public String toString() {
1026 return " {neighborDpid: " + neighborDpid + ", dstMac: " + dstMac +
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001027 ", srcMac: " + srcMac + ", outport: " + outport +
Sangho Shin15273b62014-10-16 22:22:05 -07001028 ", groupNo: " + groupNo +
1029 ", mplsLabel: " + mplsLabel + "}";
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001030 }
1031 }
1032
1033 private void setEcmpGroup(EcmpInfo ecmpInfo) {
1034 List<OFMessage> msglist = new ArrayList<OFMessage>();
1035 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1036
1037 List<OFBucket> buckets = new ArrayList<OFBucket>();
1038 for (BucketInfo b : ecmpInfo.buckets) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001039 List<OFAction> actions = new ArrayList<OFAction>();
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001040 if (b.dstMac != null) {
Sangho Shin15273b62014-10-16 22:22:05 -07001041 OFOxmEthDst dmac = factory.oxms()
1042 .ethDst(b.dstMac);
1043 OFAction setDA = factory.actions().buildSetField()
1044 .setField(dmac).build();
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001045 actions.add(setDA);
1046 }
1047 if (b.srcMac != null) {
Sangho Shin15273b62014-10-16 22:22:05 -07001048 OFOxmEthSrc smac = factory.oxms()
1049 .ethSrc(b.srcMac);
1050 OFAction setSA = factory.actions().buildSetField()
1051 .setField(smac).build();
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001052 actions.add(setSA);
1053 }
1054 if (b.outport != null) {
Sangho Shin15273b62014-10-16 22:22:05 -07001055 OFAction outp = factory.actions().buildOutput()
1056 .setPort(OFPort.of(b.outport.shortValue()))
1057 .build();
Sangho Shin15273b62014-10-16 22:22:05 -07001058 actions.add(outp);
1059 }
Sangho Shin15273b62014-10-16 22:22:05 -07001060 if (b.mplsLabel != -1) {
1061 OFAction pushLabel = factory.actions().buildPushMpls()
1062 .setEthertype(EthType.MPLS_UNICAST).build();
Sangho Shin15273b62014-10-16 22:22:05 -07001063 OFBooleanValue bosValue = null;
1064 if (b.bos)
1065 bosValue = OFBooleanValue.TRUE;
1066 else
1067 bosValue = OFBooleanValue.FALSE;
1068 OFOxmMplsBos bosX = factory.oxms()
1069 .mplsBos(bosValue);
1070 OFAction setBX = factory.actions().buildSetField()
1071 .setField(bosX).build();
1072 OFOxmMplsLabel lid = factory.oxms()
1073 .mplsLabel(U32.of(b.mplsLabel));
1074 OFAction setLabel = factory.actions().buildSetField()
1075 .setField(lid).build();
1076 OFAction copyTtl = factory.actions().copyTtlOut();
1077 OFAction decrTtl = factory.actions().decMplsTtl();
1078 actions.add(pushLabel);
1079 actions.add(setLabel);
1080 actions.add(setBX);
1081 actions.add(copyTtl);
1082 // decrement TTL only when the first MPLS label is pushed
1083 if (b.bos)
1084 actions.add(decrTtl);
1085 }
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001086 if (b.groupNo > 0) {
1087 OFAction groupTo = factory.actions().buildGroup()
1088 .setGroup(OFGroup.of(b.groupNo))
1089 .build();
1090 actions.add(groupTo);
1091 }
Sangho Shin15273b62014-10-16 22:22:05 -07001092 OFBucket ofb = factory.buildBucket()
1093 .setWeight(1)
1094 .setActions(actions)
1095 .build();
1096 buckets.add(ofb);
1097 }
1098
1099 OFMessage gm = factory.buildGroupAdd()
1100 .setGroup(group)
1101 .setBuckets(buckets)
1102 .setGroupType(OFGroupType.SELECT)
1103 .setXid(getNextTransactionId())
1104 .build();
1105 msglist.add(gm);
1106 try {
1107 write(msglist);
1108 } catch (IOException e) {
1109 // TODO Auto-generated catch block
1110 e.printStackTrace();
1111 }
1112 }
1113
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001114 /*
1115 private void setPolicyEcmpGroup(EcmpInfo ecmpInfo) {
1116 List<OFMessage> msglist = new ArrayList<OFMessage>();
1117 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1118
1119 List<OFBucket> buckets = new ArrayList<OFBucket>();
1120 List<OFAction> actions = new ArrayList<OFAction>();
1121 for (BucketInfo b : ecmpInfo.buckets) {
1122 if (b.dstMac != null && b.srcMac != null && b.outport != null) {
1123 OFOxmEthDst dmac = factory.oxms()
1124 .ethDst(b.dstMac);
1125 OFAction setDA = factory.actions().buildSetField()
1126 .setField(dmac).build();
1127 OFOxmEthSrc smac = factory.oxms()
1128 .ethSrc(b.srcMac);
1129 OFAction setSA = factory.actions().buildSetField()
1130 .setField(smac).build();
1131 OFAction outp = factory.actions().buildOutput()
1132 .setPort(OFPort.of(b.outport.shortValue()))
1133 .build();
1134 actions.add(setSA);
1135 actions.add(setDA);
1136 actions.add(outp);
1137 }
1138 if (b.groupNo > 0) {
1139 OFAction groupTo = factory.actions().buildGroup()
1140 .setGroup(OFGroup.of(b.groupNo))
1141 .build();
1142 actions.add(groupTo);
1143 }
1144 if (b.mplsLabel != -1) {
1145 OFAction pushLabel = factory.actions().buildPushMpls()
1146 .setEthertype(EthType.MPLS_UNICAST).build();
1147
1148 OFBooleanValue bosValue = null;
1149 if (b.bos)
1150 bosValue = OFBooleanValue.TRUE;
1151 else
1152 bosValue = OFBooleanValue.FALSE;
1153 OFOxmMplsBos bosX = factory.oxms()
1154 .mplsBos(bosValue);
1155 OFAction setBX = factory.actions().buildSetField()
1156 .setField(bosX).build();
1157 OFOxmMplsLabel lid = factory.oxms()
1158 .mplsLabel(U32.of(b.mplsLabel));
1159 OFAction setLabel = factory.actions().buildSetField()
1160 .setField(lid).build();
1161 OFAction copyTtl = factory.actions().copyTtlOut();
1162 OFAction decrTtl = factory.actions().decMplsTtl();
1163 actions.add(pushLabel);
1164 actions.add(setLabel);
1165 actions.add(setBX);
1166 actions.add(copyTtl);
1167 // decrement TTL only when the first MPLS label is pushed
1168 if (b.bos)
1169 actions.add(decrTtl);
1170 }
1171 OFBucket ofb = factory.buildBucket()
1172 .setWeight(1)
1173 .setActions(actions)
1174 .build();
1175 buckets.add(ofb);
1176 }
1177
1178 OFMessage gm = factory.buildGroupAdd()
1179 .setGroup(group)
1180 .setBuckets(buckets)
1181 .setGroupType(OFGroupType.SELECT)
1182 .setXid(getNextTransactionId())
1183 .build();
1184 msglist.add(gm);
1185 try {
1186 write(msglist);
1187 } catch (IOException e) {
1188 // TODO Auto-generated catch block
1189 e.printStackTrace();
1190 }
1191 }
1192 */
Sangho Shin55d00e12014-10-20 12:13:07 -07001193 private void deleteGroup(int groupId) {
1194
1195 List<OFMessage> msglist = new ArrayList<OFMessage>();
1196 OFGroup group = OFGroup.of(groupId);
1197
1198 OFMessage gm = factory.buildGroupDelete()
1199 .setGroup(group)
1200 .setGroupType(OFGroupType.SELECT)
1201 .setXid(getNextTransactionId())
1202 .build();
1203 msglist.add(gm);
1204 try {
1205 write(msglist);
1206 } catch (IOException e) {
1207 // TODO Auto-generated catch block
1208 e.printStackTrace();
1209 }
1210 }
1211
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -07001212 private void modifyEcmpGroup(EcmpInfo ecmpInfo) {
1213 List<OFMessage> msglist = new ArrayList<OFMessage>();
1214 OFGroup group = OFGroup.of(ecmpInfo.groupId);
1215
1216 List<OFBucket> buckets = new ArrayList<OFBucket>();
1217 for (BucketInfo b : ecmpInfo.buckets) {
1218 OFOxmEthDst dmac = factory.oxms()
1219 .ethDst(b.dstMac);
1220 OFAction setDA = factory.actions().buildSetField()
1221 .setField(dmac).build();
1222 OFOxmEthSrc smac = factory.oxms()
1223 .ethSrc(b.srcMac);
1224 OFAction setSA = factory.actions().buildSetField()
1225 .setField(smac).build();
1226 OFAction outp = factory.actions().buildOutput()
1227 .setPort(OFPort.of(b.outport.shortValue()))
1228 .build();
1229 List<OFAction> actions = new ArrayList<OFAction>();
1230 actions.add(setSA);
1231 actions.add(setDA);
1232 actions.add(outp);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001233 if (b.mplsLabel != -1) {
1234 OFAction pushLabel = factory.actions().buildPushMpls()
1235 .setEthertype(EthType.MPLS_UNICAST).build();
Srikanth Vavilapalli11dc6072014-10-13 13:32:11 -07001236 OFOxmMplsBos bosX = factory.oxms()
1237 .mplsBos(OFBooleanValue.TRUE);
1238 OFAction setBX = factory.actions().buildSetField()
1239 .setField(bosX).build();
Srikanth Vavilapalli4ae146e2014-10-09 14:35:26 -07001240 OFOxmMplsLabel lid = factory.oxms()
1241 .mplsLabel(U32.of(b.mplsLabel));
1242 OFAction setLabel = factory.actions().buildSetField()
1243 .setField(lid).build();
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001244 OFAction copyTtl = factory.actions().copyTtlOut();
1245 OFAction decrTtl = factory.actions().decMplsTtl();
1246 actions.add(pushLabel);
1247 actions.add(setLabel);
Srikanth Vavilapalli11dc6072014-10-13 13:32:11 -07001248 actions.add(setBX);
Srikanth Vavilapalli68144302014-10-08 15:55:24 -07001249 actions.add(copyTtl);
1250 actions.add(decrTtl);
1251 }
Srikanth Vavilapalli7d873fd2014-10-04 07:50:57 -07001252 OFBucket ofb = factory.buildBucket()
1253 .setWeight(1)
1254 .setActions(actions)
1255 .build();
1256 buckets.add(ofb);
1257 }
1258
1259 OFMessage gm = factory.buildGroupModify()
1260 .setGroup(group)
1261 .setBuckets(buckets)
1262 .setGroupType(OFGroupType.SELECT)
1263 .setXid(getNextTransactionId())
1264 .build();
1265 msglist.add(gm);
1266 try {
1267 write(msglist);
1268 } catch (IOException e) {
1269 // TODO Auto-generated catch block
1270 e.printStackTrace();
1271 }
1272 }
1273
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001274 private void verifyGroups() throws IOException {
1275 sendGroupDescRequest();
1276 }
1277
1278 private void sendGroupDescRequest() throws IOException {
1279 OFMessage gdr = factory.buildGroupDescStatsRequest()
1280 .setXid(getNextTransactionId())
1281 .build();
1282 write(gdr, null);
1283 }
1284
1285 private void assignAdjacencyLabels() {
Saurav Das2d41a432014-10-21 20:40:10 -07001286 List<AdjacencySid> autogenAdjSids = new ArrayList<AdjacencySid>();
1287 publishAttributes = new HashMap<String, String>();
1288 for (OFPortDesc p : getPorts()) {
1289 int pnum = p.getPortNo().getPortNumber();
1290
1291 if (U32.ofRaw(pnum).compareTo(U32.ofRaw(OFPort.MAX.getPortNumber())) >= 1) {
1292 continue;
1293 }
1294 // create unique adj-sid assuming that operator only
1295 // enters adjSids for multiple-ports and only in the range
1296 // 1-10k XXX make sure that happens
1297 int adjSid = srConfig.getNodeSid() * 1000 + pnum;
1298 AdjacencySid as = new AdjacencySid(adjSid,
1299 Collections.singletonList(pnum));
1300 autogenAdjSids.add(as);
1301 }
1302 ObjectMapper mapper = new ObjectMapper();
1303 try {
1304 publishAttributes.put("autogenAdjSids",
1305 mapper.writeValueAsString(autogenAdjSids));
1306 } catch (IOException e1) {
1307 log.error("Error while writing adjacency labels: {}", e1.getCause());
1308 }
1309
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001310 try {
1311 nextDriverState();
1312 } catch (IOException e) {
1313 // TODO Auto-generated catch block
1314 e.printStackTrace();
1315 }
1316 }
1317
Saurav Das1cd10152014-09-26 09:38:07 -07001318 private OFAction getOFAction(Action action) {
1319 OFAction ofAction = null;
1320 if (action instanceof OutputAction) {
1321 OutputAction outputAction = (OutputAction) action;
1322 OFPort port = OFPort.of((int) outputAction.getPortNumber().value());
1323 ofAction = factory.actions().output(port, Short.MAX_VALUE);
1324 } else if (action instanceof ModifyDstMacAction) {
1325 long dstMac = ((ModifyDstMacAction) action).getDstMac().toLong();
1326 OFOxmEthDst dmac = factory.oxms()
1327 .ethDst(MacAddress.of(dstMac));
1328 ofAction = factory.actions().buildSetField()
1329 .setField(dmac).build();
1330 } else if (action instanceof ModifySrcMacAction) {
1331 long srcMac = ((ModifySrcMacAction) action).getSrcMac().toLong();
1332 OFOxmEthSrc smac = factory.oxms()
1333 .ethSrc(MacAddress.of(srcMac));
1334 ofAction = factory.actions().buildSetField()
1335 .setField(smac).build();
Saurav Dasa962a692014-10-17 14:52:38 -07001336 } else if (action instanceof PushMplsAction) {
1337 ofAction = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1338 } else if (action instanceof SetMplsIdAction) {
1339 int labelid = ((SetMplsIdAction) action).getMplsId();
1340 OFOxmMplsLabel lid = factory.oxms()
1341 .mplsLabel(U32.of(labelid));
1342 ofAction = factory.actions().buildSetField()
1343 .setField(lid).build();
1344 } else if (action instanceof SetMplsBosAction) {
1345 OFBooleanValue val = OFBooleanValue.of(
1346 ((SetMplsBosAction) action).isSet());
1347 OFOxmMplsBos bos = factory.oxms().mplsBos(val);
1348 OFAction setBos = factory.actions().buildSetField()
1349 .setField(bos).build();
1350 } else if (action instanceof PopMplsAction) {
Saurav Das1cd10152014-09-26 09:38:07 -07001351 EthType ethertype = ((PopMplsAction) action).getEthType();
1352 ofAction = factory.actions().popMpls(ethertype);
1353 } else if (action instanceof GroupAction) {
Sangho Shin15273b62014-10-16 22:22:05 -07001354 int gid = -1;
1355 GroupAction ga = (GroupAction)action;
Sangho Shin81655442014-10-20 14:22:46 -07001356 if (ga.getTunnelId() != null) {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001357 List<Integer> groupIds = tunnelGroupIdTable.get(ga.getTunnelId());
Sangho Shin81655442014-10-20 14:22:46 -07001358 gid = groupIds.get(groupIds.size()-1);
Saurav Das1cd10152014-09-26 09:38:07 -07001359 }
Sangho Shin15273b62014-10-16 22:22:05 -07001360 else {
1361 NeighborSet ns = ((GroupAction) action).getDpids();
1362 EcmpInfo ei = ecmpGroups.get(ns);
1363 if (ei == null) {
1364 log.debug("Unable to find ecmp group for neighbors {} at "
1365 + "switch {} and hence creating it", ns, getStringId());
1366 createGroupForANeighborSet(ns, groupid.incrementAndGet());
1367 ei = ecmpGroups.get(ns);
1368 }
1369 gid = ei.groupId;
1370 }
Srikanth Vavilapalli846df292014-10-10 15:47:16 -07001371 ofAction = factory.actions().buildGroup()
1372 .setGroup(OFGroup.of(gid))
1373 .build();
Saurav Das1cd10152014-09-26 09:38:07 -07001374 } else if (action instanceof DecNwTtlAction) {
1375 ofAction = factory.actions().decNwTtl();
1376 } else if (action instanceof DecMplsTtlAction) {
1377 ofAction = factory.actions().decMplsTtl();
1378 } else if (action instanceof CopyTtlInAction) {
1379 ofAction = factory.actions().copyTtlIn();
1380 } else if (action instanceof CopyTtlOutAction) {
1381 ofAction = factory.actions().copyTtlOut();
1382 } else {
1383 log.warn("Unsupported Action type: {}", action.getClass().getName());
1384 return null;
1385 }
1386
Saurav Das1cd10152014-09-26 09:38:07 -07001387 return ofAction;
1388 }
1389
Saurav Das0a344b02014-09-26 14:18:52 -07001390 private OFMessage getIpEntry(MatchActionOperationEntry mao) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001391 MatchAction ma = mao.getTarget();
1392 Operator op = mao.getOperator();
1393 Ipv4Match ipm = (Ipv4Match) ma.getMatch();
1394
1395 // set match
1396 IPv4Net ipdst = ipm.getDestination();
1397 OFOxmEthType ethTypeIp = factory.oxms()
1398 .ethType(EthType.IPv4);
1399 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
1400 .ipv4DstMasked(
1401 IPv4Address.of(ipdst.address().value()),
1402 IPv4Address.ofCidrMaskLength(ipdst.prefixLen())
1403 );
1404 OFOxmList oxmList = OFOxmList.of(ethTypeIp, ipPrefix);
1405 OFMatchV3 match = factory.buildMatchV3()
1406 .setOxmList(oxmList).build();
1407
1408 // set actions
1409 List<OFAction> writeActions = new ArrayList<OFAction>();
1410 for (Action action : ma.getActions()) {
Saurav Das1cd10152014-09-26 09:38:07 -07001411 OFAction ofAction = getOFAction(action);
1412 if (ofAction != null) {
1413 writeActions.add(ofAction);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001414 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001415 }
1416
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001417 // set instructions
1418 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1419 .setActions(writeActions).build();
1420 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1421 .setTableId(TableId.of(TABLE_ACL)).build();
1422 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1423 instructions.add(writeInstr);
1424 instructions.add(gotoInstr);
1425
Saurav Das1cd10152014-09-26 09:38:07 -07001426 // set flow priority to emulate longest prefix match
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001427 int priority = ipdst.prefixLen() * PRIORITY_MULTIPLIER;
1428 if (ipdst.prefixLen() == (short) 32) {
1429 priority = MAX_PRIORITY;
1430 }
1431
Saurav Dasbc594a42014-09-25 20:13:50 -07001432 // set flow-mod
Saurav Dase972b3a2014-09-26 15:41:06 -07001433 OFFlowMod.Builder fmBuilder = null;
1434 switch (op) {
1435 case ADD:
1436 fmBuilder = factory.buildFlowAdd();
1437 break;
1438 case REMOVE:
1439 fmBuilder = factory.buildFlowDeleteStrict();
1440 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001441 case MODIFY: // TODO
1442 fmBuilder = factory.buildFlowModifyStrict();
1443 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001444 default:
1445 log.warn("Unsupported MatchAction Operator: {}", op);
1446 return null;
Saurav Dasbc594a42014-09-25 20:13:50 -07001447 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001448 OFMessage ipFlow = fmBuilder
1449 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
1450 .setMatch(match)
1451 .setInstructions(instructions)
1452 .setPriority(priority)
1453 .setBufferId(OFBufferId.NO_BUFFER)
1454 .setIdleTimeout(0)
1455 .setHardTimeout(0)
1456 .setXid(getNextTransactionId())
1457 .build();
Saurav Dasbc594a42014-09-25 20:13:50 -07001458 log.debug("{} ip-rule {}-{} in sw {}",
1459 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1460 match, writeActions,
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001461 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001462 return ipFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001463 }
1464
Saurav Das0a344b02014-09-26 14:18:52 -07001465 private OFMessage getMplsEntry(MatchActionOperationEntry mao) {
Saurav Das1cd10152014-09-26 09:38:07 -07001466 MatchAction ma = mao.getTarget();
1467 Operator op = mao.getOperator();
1468 MplsMatch mplsm = (MplsMatch) ma.getMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001469
Saurav Das1cd10152014-09-26 09:38:07 -07001470 // set match
1471 OFOxmEthType ethTypeMpls = factory.oxms()
1472 .ethType(EthType.MPLS_UNICAST);
1473 OFOxmMplsLabel labelid = factory.oxms()
1474 .mplsLabel(U32.of(mplsm.getMplsLabel()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001475 OFOxmMplsBos bos = factory.oxms()
1476 .mplsBos(OFBooleanValue.of(mplsm.isBos()));
1477 OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid, bos);
Saurav Das1cd10152014-09-26 09:38:07 -07001478 OFMatchV3 matchlabel = factory.buildMatchV3()
1479 .setOxmList(oxmList).build();
1480
1481 // set actions
1482 List<OFAction> writeActions = new ArrayList<OFAction>();
1483 for (Action action : ma.getActions()) {
1484 OFAction ofAction = getOFAction(action);
1485 if (ofAction != null) {
1486 writeActions.add(ofAction);
1487 }
1488 }
1489
1490 // set instructions
1491 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1492 .setActions(writeActions).build();
1493 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1494 .setTableId(TableId.of(TABLE_ACL)).build();
1495 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1496 instructions.add(writeInstr);
1497 instructions.add(gotoInstr);
1498
Saurav Dase972b3a2014-09-26 15:41:06 -07001499 // set flow-mod
1500 OFFlowMod.Builder fmBuilder = null;
1501 switch (op) {
1502 case ADD:
1503 fmBuilder = factory.buildFlowAdd();
1504 break;
1505 case REMOVE:
1506 fmBuilder = factory.buildFlowDeleteStrict();
1507 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001508 case MODIFY: // TODO
1509 fmBuilder = factory.buildFlowModifyStrict();
1510 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001511 default:
1512 log.warn("Unsupported MatchAction Operator: {}", op);
1513 return null;
Saurav Das1cd10152014-09-26 09:38:07 -07001514 }
Saurav Dase972b3a2014-09-26 15:41:06 -07001515
1516 OFMessage mplsFlow = fmBuilder
1517 .setTableId(TableId.of(TABLE_MPLS))
1518 .setMatch(matchlabel)
1519 .setInstructions(instructions)
1520 .setPriority(MAX_PRIORITY) // exact match and exclusive
1521 .setBufferId(OFBufferId.NO_BUFFER)
1522 .setIdleTimeout(0)
1523 .setHardTimeout(0)
1524 .setXid(getNextTransactionId())
1525 .build();
Saurav Das1cd10152014-09-26 09:38:07 -07001526 log.debug("{} mpls-rule {}-{} in sw {}",
1527 (op == MatchActionOperations.Operator.ADD) ? "Adding" : "Deleting",
1528 matchlabel, writeActions,
1529 getStringId());
Saurav Das0a344b02014-09-26 14:18:52 -07001530 return mplsFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001531 }
1532
Saurav Das0a344b02014-09-26 14:18:52 -07001533 private OFMessage getAclEntry(MatchActionOperationEntry mao) {
Saurav Dase972b3a2014-09-26 15:41:06 -07001534 MatchAction ma = mao.getTarget();
1535 Operator op = mao.getOperator();
1536 PacketMatch packetMatch = (PacketMatch) ma.getMatch();
1537 Builder matchBuilder = factory.buildMatch();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001538
Saurav Dase972b3a2014-09-26 15:41:06 -07001539 // set match
1540 int inport = 0;
1541 if (ma.getSwitchPort() != null) {
1542 inport = (int) ma.getSwitchPort().getPortNumber().value();
1543 }
1544 final MACAddress srcMac = packetMatch.getSrcMacAddress();
1545 final MACAddress dstMac = packetMatch.getDstMacAddress();
1546 final Short etherType = packetMatch.getEtherType();
1547 final IPv4Net srcIp = packetMatch.getSrcIpAddress();
1548 final IPv4Net dstIp = packetMatch.getDstIpAddress();
1549 final Byte ipProto = packetMatch.getIpProtocolNumber();
1550 final Short srcTcpPort = packetMatch.getSrcTcpPortNumber();
1551 final Short dstTcpPort = packetMatch.getDstTcpPortNumber();
1552 if (inport > 0) {
1553 matchBuilder.setExact(MatchField.IN_PORT,
1554 OFPort.of(inport));
1555 }
1556 if (srcMac != null) {
1557 matchBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(srcMac.toLong()));
1558 }
1559 if (dstMac != null) {
1560 matchBuilder.setExact(MatchField.ETH_DST, MacAddress.of(dstMac.toLong()));
1561 }
1562 if (etherType != null) {
1563 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(etherType));
1564 }
1565 if (srcIp != null) {
1566 matchBuilder.setMasked(MatchField.IPV4_SRC,
1567 IPv4Address.of(srcIp.address().value())
1568 .withMaskOfLength(srcIp.prefixLen()));
1569 }
1570 if (dstIp != null) {
1571 matchBuilder.setMasked(MatchField.IPV4_DST,
1572 IPv4Address.of(dstIp.address().value())
1573 .withMaskOfLength(dstIp.prefixLen()));
1574 }
1575 if (ipProto != null) {
1576 matchBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(ipProto));
1577 }
1578 if (srcTcpPort != null) {
1579 matchBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(srcTcpPort));
1580 }
1581 if (dstTcpPort != null) {
1582 matchBuilder.setExact(MatchField.TCP_DST, TransportPort.of(dstTcpPort));
1583 }
1584
1585 // set actions
Saurav Dascc3e35f2014-10-10 15:33:32 -07001586 List<OFAction> writeActions = new ArrayList<OFAction>();
Saurav Dase972b3a2014-09-26 15:41:06 -07001587 for (Action action : ma.getActions()) {
1588 OFAction ofAction = getOFAction(action);
1589 if (ofAction != null) {
Saurav Dascc3e35f2014-10-10 15:33:32 -07001590 writeActions.add(ofAction);
Saurav Dase972b3a2014-09-26 15:41:06 -07001591 }
1592 }
1593
1594 // set instructions
1595 OFInstruction clearInstr = factory.instructions().clearActions();
Saurav Dascc3e35f2014-10-10 15:33:32 -07001596 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1597 .setActions(writeActions).build();
Saurav Dase972b3a2014-09-26 15:41:06 -07001598 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1599 instructions.add(clearInstr);
Saurav Dascc3e35f2014-10-10 15:33:32 -07001600 instructions.add(writeInstr);
Saurav Dase972b3a2014-09-26 15:41:06 -07001601
1602 // set flow-mod
1603 OFFlowMod.Builder fmBuilder = null;
1604 switch (op) {
1605 case ADD:
1606 fmBuilder = factory.buildFlowAdd();
1607 break;
1608 case REMOVE:
1609 fmBuilder = factory.buildFlowDeleteStrict();
1610 break;
Sangho Shin5be3e532014-10-03 17:20:58 -07001611 case MODIFY: // TODO
1612 fmBuilder = factory.buildFlowModifyStrict();
1613 break;
Saurav Dase972b3a2014-09-26 15:41:06 -07001614 default:
1615 log.warn("Unsupported MatchAction Operator: {}", op);
1616 return null;
1617 }
1618
1619 OFMessage aclFlow = fmBuilder
1620 .setTableId(TableId.of(TABLE_ACL))
1621 .setMatch(matchBuilder.build())
1622 .setInstructions(instructions)
Sangho Shin6f47dd32014-10-17 23:10:39 -07001623 .setPriority(ma.getPriority()) // exact match and exclusive
Saurav Dase972b3a2014-09-26 15:41:06 -07001624 .setBufferId(OFBufferId.NO_BUFFER)
1625 .setIdleTimeout(0)
1626 .setHardTimeout(0)
1627 .setXid(getNextTransactionId())
1628 .build();
Sangho Shin15273b62014-10-16 22:22:05 -07001629
Saurav Das0a344b02014-09-26 14:18:52 -07001630 return aclFlow;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001631 }
1632
1633 // *****************************
1634 // IOF13Switch
1635 // *****************************
1636
1637 @Override
1638 public void pushFlow(MatchActionOperationEntry matchActionOp) throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001639 OFMessage ofm = getFlow(matchActionOp);
1640 if (ofm != null) {
1641 write(Collections.singletonList(ofm));
1642 }
1643 }
1644
1645 private OFMessage getFlow(MatchActionOperationEntry matchActionOp) {
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001646 final MatchAction matchAction = matchActionOp.getTarget();
1647 final Match match = matchAction.getMatch();
1648 if (match instanceof Ipv4Match) {
Saurav Das0a344b02014-09-26 14:18:52 -07001649 return getIpEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001650 } else if (match instanceof MplsMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001651 return getMplsEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001652 } else if (match instanceof PacketMatch) {
Saurav Das0a344b02014-09-26 14:18:52 -07001653 return getAclEntry(matchActionOp);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001654 } else {
1655 log.error("Unknown match type {} pushed to switch {}", match,
1656 getStringId());
1657 }
Saurav Das0a344b02014-09-26 14:18:52 -07001658 return null;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001659 }
1660
1661 @Override
1662 public void pushFlows(Collection<MatchActionOperationEntry> matchActionOps)
1663 throws IOException {
Saurav Das0a344b02014-09-26 14:18:52 -07001664 List<OFMessage> flowMods = new ArrayList<OFMessage>();
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001665 for (MatchActionOperationEntry matchActionOp : matchActionOps) {
Saurav Das0a344b02014-09-26 14:18:52 -07001666 OFMessage ofm = getFlow(matchActionOp);
1667 if (ofm != null) {
1668 flowMods.add(ofm);
1669 }
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001670 }
Saurav Das0a344b02014-09-26 14:18:52 -07001671 write(flowMods);
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001672 }
1673
1674 @Override
1675 public int getEcmpGroupId(NeighborSet ns) {
1676 EcmpInfo ei = ecmpGroups.get(ns);
1677 if (ei == null) {
1678 return -1;
1679 } else {
1680 return ei.groupId;
1681 }
1682 }
1683
Saurav Dascc3e35f2014-10-10 15:33:32 -07001684 @Override
1685 public TableId getTableId(String tableType) {
1686 tableType = tableType.toLowerCase();
1687 if (tableType.contentEquals("ip")) {
1688 return TableId.of(OFSwitchImplCPqD13.TABLE_IPv4_UNICAST);
1689 }
1690 else if (tableType.contentEquals("mpls")) {
1691 return TableId.of(OFSwitchImplCPqD13.TABLE_MPLS);
1692 }
1693 else if (tableType.contentEquals("acl")) {
1694 return TableId.of(OFSwitchImplCPqD13.TABLE_ACL);
1695 }
1696 else {
1697 log.warn("Invalid tableType: {}", tableType);
1698 return null;
1699 }
1700 }
1701
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001702 @Override
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001703 @Deprecated
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001704 public void createTunnel(String tunnelId, List<String> route, NeighborSet ns) {
1705
1706 List<Integer> groups = new ArrayList<Integer>();
Sangho Shin15273b62014-10-16 22:22:05 -07001707
1708 // create a last group of the group chaining
1709 int finalGroupId = groupid.incrementAndGet();
1710 createGroupForANeighborSet(ns, finalGroupId);
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001711 groups.add(Integer.valueOf(finalGroupId));
Sangho Shin15273b62014-10-16 22:22:05 -07001712
1713 int groupId = 0;
1714 int nextGroupId = finalGroupId;
1715 boolean bos = false;
1716
Sangho Shine020cc32014-10-20 13:28:02 -07001717 // process the node ID in order
Sangho Shin15273b62014-10-16 22:22:05 -07001718 for (int i = 0; i < route.size(); i++) {
1719 String nodeId = route.get(i);
1720 groupId = groupid.incrementAndGet();
Sangho Shine020cc32014-10-20 13:28:02 -07001721 groups.add(Integer.valueOf(groupId));
Sangho Shin15273b62014-10-16 22:22:05 -07001722 if (i == route.size()-1)
1723 bos = true;
1724 createGroupForMplsLabel(groupId, nodeId, nextGroupId, bos);
1725 nextGroupId = groupId;
1726 }
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001727 tunnelGroupIdTable.putIfAbsent(tunnelId, groups);
Sangho Shin15273b62014-10-16 22:22:05 -07001728 }
1729
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001730 @Override
1731 public void removeTunnel(String tunnelId) {
1732 List<Integer> groups = tunnelGroupIdTable.get(tunnelId);
Sangho Shin1ad7be02014-10-20 16:56:49 -07001733 if (groups == null)
1734 return;
1735
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001736 // we need to delete groups in reverse order
1737 for (int i = groups.size() - 1; i >= 0; i--) {
1738 int groupId = groups.get(i);
1739 deleteGroup(groupId);
1740 }
1741 tunnelGroupIdTable.remove(tunnelId);
1742 }
Sangho Shin15273b62014-10-16 22:22:05 -07001743
Sangho Shin1ad7be02014-10-20 16:56:49 -07001744 @Override
1745 public int getTunnelGroupId(String tunnelId) {
1746 List<Integer> groups = tunnelGroupIdTable.get(tunnelId);
1747 if (groups == null)
1748 return -1;
1749
1750 return groups.get(0);
1751 }
1752
Srikanth Vavilapalli2edeada2014-10-22 19:19:01 -07001753 private void createIndirectGroup(int groupId, MacAddress srcMac,
1754 MacAddress dstMac, PortNumber outPort, int gotoGroupNo,
1755 int mplsLabel, boolean bos) {
1756 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
1757 BucketInfo b = new BucketInfo(null, srcMac, dstMac, outPort,
1758 mplsLabel, bos, gotoGroupNo);
1759 buckets.add(b);
1760
1761 EcmpInfo ecmpInfo = new EcmpInfo(groupId, buckets);
1762 setEcmpGroup(ecmpInfo);
1763 log.debug(
1764 "createIndirectGroup: Creating indirect group {} in sw {} "
1765 + "with: {}", groupId, getStringId(), ecmpInfo);
1766 return;
1767 }
1768
1769 private EcmpInfo createInnermostLabelGroup(int innermostGroupId,
1770 List<PortNumber> ports, int mplsLabel, boolean bos,
1771 HashMap<PortNumber, Integer> lastSetOfGroupIds) {
1772 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
1773 for (PortNumber sp : ports) {
1774 Dpid neighborDpid = portToNeighbors.get(sp);
1775 BucketInfo b = new BucketInfo(neighborDpid,
1776 MacAddress.of(srConfig.getRouterMac()),
1777 getNeighborRouterMacAddress(neighborDpid), null,
1778 mplsLabel, bos,
1779 lastSetOfGroupIds.get(sp));
1780 buckets.add(b);
1781 }
1782 EcmpInfo ecmpInfo = new EcmpInfo(innermostGroupId, buckets);
1783 setEcmpGroup(ecmpInfo);
1784 log.debug(
1785 "createInnermostLabelGroup: Creating indirect group {} in sw {} "
1786 + "with: {}", innermostGroupId, getStringId(), ecmpInfo);
1787 return ecmpInfo;
1788 }
1789 @Override
1790 /**
1791 * Create a group chain with the same label stack for a given set of ports
1792 * in the neighborset. This can be used for a basic scenario of tunnel based
1793 * policy routing.
1794 *
1795 * @param labelStack list of router segment Ids to be pushed
1796 * @param ns neighborSet to get to the first router in the labelStack
1797 * NOTE:
1798 * The edgeLabel inside the neighborSet is ignored and user should
1799 * explicitly push that label on to the labelStack that is passed as
1800 * first argument
1801 * @return group identifier
1802 */
1803 public int createGroup(List<Integer> labelStack, List<PortNumber> ports) {
1804
1805 if ((ports == null) ||
1806 ((labelStack != null) && (labelStack.size() > 3))) {
1807 log.warn("createGroup with wrong input parameters");
1808 }
1809 log.debug("createGroup with labelStack {} and ports {}",
1810 labelStack, ports);
1811
1812 /* Create for each port, through which neighbors in ns are reachable,
1813 * an indirect group with the outermost label
1814 */
1815 HashMap<PortNumber, Integer> lastSetOfGroupIds =
1816 new HashMap<PortNumber, Integer>();
1817 int innermostGroupId = -1;
1818 if (labelStack.size() < 2) {
1819 int curLabel = -1;
1820 boolean bos = false;
1821 if (labelStack.size()==1) {
1822 curLabel = labelStack.get(0).intValue();
1823 bos = true;
1824 }
1825
1826 List<BucketInfo> buckets = new ArrayList<BucketInfo>();
1827 for (PortNumber sp : ports) {
1828 Dpid neighborDpid = portToNeighbors.get(sp);
1829 BucketInfo b = new BucketInfo(neighborDpid,
1830 MacAddress.of(srConfig.getRouterMac()),
1831 getNeighborRouterMacAddress(neighborDpid),
1832 sp, curLabel, bos, -1);
1833 buckets.add(b);
1834 }
1835 innermostGroupId = groupid.incrementAndGet();
1836 EcmpInfo ecmpInfo = new EcmpInfo(innermostGroupId, buckets);
1837 setEcmpGroup(ecmpInfo);
1838 userDefinedGroups.put(innermostGroupId, ecmpInfo);
1839 return innermostGroupId;
1840 }
1841
1842 for (int i = 0; i < labelStack.size(); i++) {
1843 for (PortNumber sp : ports) {
1844 if (i == 0) {
1845 /* Outermost label processing */
1846 int currGroupId = groupid.incrementAndGet();
1847 createIndirectGroup(currGroupId,
1848 null, null, sp, -1,
1849 labelStack.get(i).intValue(), false);
1850 lastSetOfGroupIds.put(sp, currGroupId);
1851 }
1852 else if (i == (labelStack.size() - 1)) {
1853 /* Innermost label processing */
1854 innermostGroupId = groupid.incrementAndGet();
1855 EcmpInfo topLevelGroup = createInnermostLabelGroup(
1856 innermostGroupId,
1857 ports,
1858 labelStack.get(i).intValue(), true,
1859 lastSetOfGroupIds);
1860 userDefinedGroups.put(
1861 innermostGroupId, topLevelGroup);
1862 break;
1863 }
1864 else {
1865 /* Middle label processing */
1866 int currGroupId = groupid.incrementAndGet();
1867 createIndirectGroup(currGroupId,
1868 null, null, null,
1869 lastSetOfGroupIds.get(sp),
1870 labelStack.get(i).intValue(), false);
1871 /* Overwrite with this iteration's group IDs */
1872 lastSetOfGroupIds.put(sp, currGroupId);
1873 }
1874 }
1875 }
1876 return innermostGroupId;
1877 }
1878
1879 /**
1880 * Remove the specified group
1881 *
1882 * @param groupId group identifier
1883 * @return success/fail
1884 */
1885 public boolean removeGroup(int groupId) {
1886 return false;
1887 }
Saurav Das2d41a432014-10-21 20:40:10 -07001888 @Override
1889 public Map<String, String> getPublishAttributes() {
1890 return publishAttributes;
1891 }
Sangho Shin1ad7be02014-10-20 16:56:49 -07001892
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001893 // *****************************
Saurav Das80d17392014-10-01 10:24:56 -07001894 // Unused
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001895 // *****************************
1896
Saurav Das80d17392014-10-01 10:24:56 -07001897 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001898 private void setAsyncConfig() throws IOException {
1899 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
1900 OFMessage setAC = null;
1901
1902 if (role == Role.MASTER) {
1903 setAC = factory.buildAsyncSet()
1904 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
1905 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
1906 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
1907 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1908 .setPacketInMaskSlave(SET_ALL_SLAVE)
1909 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1910 .setXid(getNextTransactionId())
1911 .build();
1912 } else if (role == Role.EQUAL) {
1913 setAC = factory.buildAsyncSet()
1914 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
1915 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
1916 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
1917 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
1918 .setPacketInMaskSlave(SET_ALL_SLAVE)
1919 .setPortStatusMaskSlave(SET_ALL_SLAVE)
1920 .setXid(getNextTransactionId())
1921 .build();
1922 }
1923 msglist.add(setAC);
1924
1925 OFMessage br = factory.buildBarrierRequest()
1926 .setXid(getNextTransactionId())
1927 .build();
1928 msglist.add(br);
1929
1930 OFMessage getAC = factory.buildAsyncGetRequest()
1931 .setXid(getNextTransactionId())
1932 .build();
1933 msglist.add(getAC);
1934
1935 write(msglist);
1936 }
1937
Saurav Das80d17392014-10-01 10:24:56 -07001938 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001939 private void decodeAsyncGetReply(OFAsyncGetReply rep) {
1940 long frm = rep.getFlowRemovedMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001941 long frs = rep.getFlowRemovedMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001942 long pim = rep.getPacketInMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001943 long pis = rep.getPacketInMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001944 long psm = rep.getPortStatusMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -07001945 long pss = rep.getPortStatusMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001946
1947 if (role == Role.MASTER || role == Role.EQUAL) { // should separate
1948 log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
1949 log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
1950 log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
1951 }
1952
1953 }
1954
Saurav Das80d17392014-10-01 10:24:56 -07001955 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001956 private void getTableFeatures() throws IOException {
1957 OFMessage gtf = factory.buildTableFeaturesStatsRequest()
1958 .setXid(getNextTransactionId())
1959 .build();
1960 write(gtf, null);
1961 }
1962
Saurav Das80d17392014-10-01 10:24:56 -07001963 @SuppressWarnings("unused")
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001964 private void sendGroupFeaturesRequest() throws IOException {
1965 OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
1966 .setXid(getNextTransactionId())
1967 .build();
1968 write(gfr, null);
1969 }
1970
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001971 private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
1972 log.info("Sw: {} Group Features {}", getStringId(), gfsr);
1973 }
1974
Saurav Dascc3e35f2014-10-10 15:33:32 -07001975 @SuppressWarnings("unused")
1976 private void testMultipleLabels() {
1977 if (getId() == 1) {
1978 List<OFMessage> msglist = new ArrayList<OFMessage>();
1979
1980 // first all the indirect groups
1981
1982 // the group to switch 2 with outer label
1983 OFGroup g1 = OFGroup.of(201);
1984 OFOxmEthDst dmac1 = factory.oxms().ethDst(MacAddress.of("00:00:02:02:02:80"));
1985 OFAction push1 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
1986 OFOxmMplsLabel lid1 = factory.oxms()
1987 .mplsLabel(U32.of(105)); // outer label
1988 OFAction setMpls1 = factory.actions().buildSetField()
1989 .setField(lid1).build();
1990 OFOxmMplsBos bos1 = factory.oxms()
1991 .mplsBos(OFBooleanValue.FALSE);
1992 OFAction setB1 = factory.actions().buildSetField()
1993 .setField(bos1).build();
1994 OFAction setDA1 = factory.actions().buildSetField()
1995 .setField(dmac1).build();
1996 OFAction outp1 = factory.actions().buildOutput()
1997 .setPort(OFPort.of(2))
1998 .build();
1999 List<OFAction> a1 = new ArrayList<OFAction>();
2000 a1.add(push1);
2001 a1.add(setMpls1);
2002 a1.add(setB1);
2003 a1.add(setDA1);
2004 a1.add(outp1);
2005 OFBucket b1 = factory.buildBucket()
2006 .setActions(a1)
2007 .build();
2008 OFMessage gm1 = factory.buildGroupAdd()
2009 .setGroup(g1)
2010 .setBuckets(Collections.singletonList(b1))
2011 .setGroupType(OFGroupType.INDIRECT)
2012 .setXid(getNextTransactionId())
2013 .build();
2014 msglist.add(gm1);
2015
2016 // the group to switch 3 with outer label
2017 OFGroup g2 = OFGroup.of(301);
2018 OFOxmEthDst dmac2 = factory.oxms().ethDst(MacAddress.of("00:00:03:03:03:80"));
2019 OFAction push2 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
2020 OFOxmMplsLabel lid2 = factory.oxms()
2021 .mplsLabel(U32.of(104)); // outer label
2022 OFAction setMpls2 = factory.actions().buildSetField()
2023 .setField(lid2).build();
2024 OFOxmMplsBos bos2 = factory.oxms()
2025 .mplsBos(OFBooleanValue.FALSE);
2026 OFAction setB2 = factory.actions().buildSetField()
2027 .setField(bos2).build();
2028 OFAction setDA2 = factory.actions().buildSetField()
2029 .setField(dmac2).build();
2030 OFAction outp2 = factory.actions().buildOutput()
2031 .setPort(OFPort.of(3))
2032 .build();
2033 List<OFAction> a2 = new ArrayList<OFAction>();
2034 a2.add(push2);
2035 a2.add(setMpls2);
2036 a2.add(setB2);
2037 a2.add(setDA2);
2038 a2.add(outp2);
2039 OFBucket b2 = factory.buildBucket()
2040 .setActions(a2)
2041 .build();
2042 OFMessage gm2 = factory.buildGroupAdd()
2043 .setGroup(g2)
2044 .setBuckets(Collections.singletonList(b2))
2045 .setGroupType(OFGroupType.INDIRECT)
2046 .setXid(getNextTransactionId())
2047 .build();
2048 msglist.add(gm2);
2049
2050 // now add main ECMP group with inner labels
2051 OFGroup group = OFGroup.of(786);
2052 List<OFBucket> buckets = new ArrayList<OFBucket>();
2053 for (int i = 0; i < 2; i++) { // 2 buckets
2054
2055 List<OFAction> actions = new ArrayList<OFAction>();
2056 OFOxmEthSrc smac = factory.oxms()
2057 .ethSrc(MacAddress.of("00:00:01:01:01:80"));
2058 OFAction setSA = factory.actions().buildSetField()
2059 .setField(smac).build();
2060 actions.add(setSA);
2061
2062 if (i == 0) {
2063 // send to switch 2
2064 OFAction pushX = factory.actions().pushMpls(EthType.MPLS_UNICAST);
2065 OFOxmMplsLabel lidX = factory.oxms()
2066 .mplsLabel(U32.of(106)); // inner label
2067 OFAction setX = factory.actions().buildSetField()
2068 .setField(lidX).build();
2069 OFOxmMplsBos bosX = factory.oxms()
2070 .mplsBos(OFBooleanValue.TRUE);
2071 OFAction setBX = factory.actions().buildSetField()
2072 .setField(bosX).build();
2073 OFAction ogX = factory.actions().buildGroup()
2074 .setGroup(g1).build();
2075 actions.add(pushX);
2076 actions.add(setX);
2077 actions.add(setBX);
2078 actions.add(ogX);
2079
2080 } else {
2081 // send to switch 3
2082 OFAction pushY = factory.actions().pushMpls(EthType.MPLS_UNICAST);
2083 OFOxmMplsLabel lidY = factory.oxms()
2084 .mplsLabel(U32.of(106)); // inner label
2085 OFAction setY = factory.actions().buildSetField()
2086 .setField(lidY).build();
2087 OFOxmMplsBos bosY = factory.oxms()
2088 .mplsBos(OFBooleanValue.TRUE);
2089 OFAction setBY = factory.actions().buildSetField()
2090 .setField(bosY).build();
2091 OFAction ogY = factory.actions().buildGroup()
2092 .setGroup(g2).build();
2093 actions.add(pushY);
2094 actions.add(setY);
2095 actions.add(setBY);
2096 actions.add(ogY);
2097 }
2098
2099 OFBucket ofb = factory.buildBucket()
2100 .setWeight(1)
2101 .setActions(actions)
2102 .build();
2103 buckets.add(ofb);
2104 }
2105
2106 OFMessage gm = factory.buildGroupAdd()
2107 .setGroup(group)
2108 .setBuckets(buckets)
2109 .setGroupType(OFGroupType.SELECT)
2110 .setXid(getNextTransactionId())
2111 .build();
2112 msglist.add(gm);
2113
2114 // create an ACL entry to use this ecmp group
2115 Builder matchBuilder = factory.buildMatch();
2116 matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(0x800));
2117 matchBuilder.setMasked(MatchField.IPV4_DST,
2118 IPv4Address.of("7.7.7.0")
2119 .withMaskOfLength(24));
2120
2121 OFAction grp = factory.actions().buildGroup()
2122 .setGroup(OFGroup.of(786))
2123 .build();
2124 List<OFAction> writeActions = Collections.singletonList(grp);
2125
2126 OFInstruction clearInstr = factory.instructions().clearActions();
2127 OFInstruction writeInstr = factory.instructions().buildWriteActions()
2128 .setActions(writeActions).build();
2129 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
2130 instructions.add(clearInstr);
2131 instructions.add(writeInstr);
2132
2133 OFFlowMod.Builder fmBuilder = factory.buildFlowAdd();
2134
2135 OFMessage aclFlow = fmBuilder
2136 .setTableId(TableId.of(TABLE_ACL))
2137 .setMatch(matchBuilder.build())
2138 .setInstructions(instructions)
2139 .setPriority(10) // TODO: wrong - should be MA
2140 // priority
2141 .setBufferId(OFBufferId.NO_BUFFER)
2142 .setIdleTimeout(0)
2143 .setHardTimeout(0)
2144 .setXid(getNextTransactionId())
2145 .build();
2146 msglist.add(aclFlow);
2147
2148 try {
2149 write(msglist);
2150 } catch (IOException e) {
2151 // TODO Auto-generated catch block
2152 e.printStackTrace();
2153 }
Fahad Naeem Khand563af62014-10-08 17:37:25 -07002154 }
2155 }
2156
Saurav Das2d41a432014-10-21 20:40:10 -07002157
2158
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07002159}