blob: 2e80c3b3305d39402520188587e9dce27cbad760 [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;
5import java.util.Collections;
6import java.util.List;
7import java.util.concurrent.ConcurrentHashMap;
8import java.util.concurrent.atomic.AtomicBoolean;
9
10import net.floodlightcontroller.core.IFloodlightProviderService.Role;
11import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
12import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
13import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
14import net.floodlightcontroller.core.internal.OFSwitchImplBase;
15
16import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
17import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
18import org.projectfloodlight.openflow.protocol.OFBucket;
19import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
20import org.projectfloodlight.openflow.protocol.OFErrorMsg;
21import org.projectfloodlight.openflow.protocol.OFFactory;
22import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
23import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
24import org.projectfloodlight.openflow.protocol.OFGroupType;
25import org.projectfloodlight.openflow.protocol.OFMatchV3;
26import org.projectfloodlight.openflow.protocol.OFMessage;
27import org.projectfloodlight.openflow.protocol.OFOxmList;
28import org.projectfloodlight.openflow.protocol.OFPortDesc;
29import org.projectfloodlight.openflow.protocol.OFStatsReply;
30import org.projectfloodlight.openflow.protocol.action.OFAction;
31import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
32import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
33import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
34import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
35import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
36import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070037import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
38import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
39import org.projectfloodlight.openflow.types.EthType;
40import org.projectfloodlight.openflow.types.IPv4Address;
41import org.projectfloodlight.openflow.types.MacAddress;
42import org.projectfloodlight.openflow.types.OFBufferId;
43import org.projectfloodlight.openflow.types.OFGroup;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070044import org.projectfloodlight.openflow.types.OFPort;
45import org.projectfloodlight.openflow.types.OFVlanVidMatch;
46import org.projectfloodlight.openflow.types.TableId;
47import org.projectfloodlight.openflow.types.U32;
48import org.projectfloodlight.openflow.types.U64;
49import org.projectfloodlight.openflow.util.HexString;
50
51/**
52 * OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
53 * Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
54 * Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
55 * None
56 */
57public class OFSwitchImplCPqD13 extends OFSwitchImplBase {
58 private static final int VLAN_ID_OFFSET = 16;
59 private AtomicBoolean driverHandshakeComplete;
60 private OFFactory factory;
61 private static final int OFPCML_NO_BUFFER = 0xffff;
62 // Configuration of asynch messages to controller. We need different
63 // asynch messages depending on role-equal or role-master.
64 // We don't want to get anything if we are slave.
65 private static final long SET_FLOW_REMOVED_MASK_MASTER = 0xf;
66 private static final long SET_PACKET_IN_MASK_MASTER = 0x7;
67 private static final long SET_PORT_STATUS_MASK_MASTER = 0x7;
68 private static final long SET_FLOW_REMOVED_MASK_EQUAL = 0x0;
69 private static final long SET_PACKET_IN_MASK_EQUAL = 0x0;
70 private static final long SET_PORT_STATUS_MASK_EQUAL = 0x7;
71 private static final long SET_ALL_SLAVE = 0x0;
72
73 private static final long TEST_FLOW_REMOVED_MASK = 0xf;
74 private static final long TEST_PACKET_IN_MASK = 0x7;
75 private static final long TEST_PORT_STATUS_MASK = 0x7;
76 private long barrierXidToWaitFor = -1;
77
78 private static final int TABLE_VLAN = 0;
79 private static final int TABLE_TMAC = 1;
Sangho Shin01bca862014-09-12 11:18:59 -070080 private static final int TABLE_IPv4_UNICAST = 2;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070081 private static final int TABLE_MPLS = 3;
82 private static final int TABLE_META = 4;
83 private static final int TABLE_ACL = 5;
84
85 private static final short MAX_PRIORITY = (short) 0xffff;
86 private static final short SLASH_24_PRIORITY = (short) 0xfff0;
87 private static final short SLASH_16_PRIORITY = (short) 0xff00;
88 private static final short SLASH_8_PRIORITY = (short) 0xf000;
89 private static final short MIN_PRIORITY = 0x0;
90 private static final U64 METADATA_MASK = U64.of(Long.MAX_VALUE << 1 | 0x1);
91
92 ConcurrentHashMap<Integer, OFGroup> l2groups;
93
Jonathan Hartcb34f382014-08-12 21:11:03 -070094 private final boolean usePipeline13;
95
96 public OFSwitchImplCPqD13(OFDescStatsReply desc, boolean usePipeline13) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070097 super();
98 driverHandshakeComplete = new AtomicBoolean(false);
99 l2groups = new ConcurrentHashMap<Integer, OFGroup>();
100 setSwitchDescription(desc);
101
Jonathan Hartcb34f382014-08-12 21:11:03 -0700102 this.usePipeline13 = usePipeline13;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700103 }
104
105 /* (non-Javadoc)
106 * @see java.lang.Object#toString()
107 */
108 @Override
109 public String toString() {
110 return "OFSwitchImplCPqD13 [" + ((channel != null)
111 ? channel.getRemoteAddress() : "?")
112 + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
113 }
114
115 @Override
116 public void startDriverHandshake() throws IOException {
117 log.debug("Starting driver handshake for sw {}", getStringId());
118 if (startDriverHandshakeCalled) {
119 throw new SwitchDriverSubHandshakeAlreadyStarted();
120 }
121 startDriverHandshakeCalled = true;
Jonathan Harta213bce2014-08-11 15:44:07 -0700122 factory = getFactory();
Jonathan Hartcb34f382014-08-12 21:11:03 -0700123 if (!usePipeline13) {
124 // Send packet-in to controller if a packet misses the first table
125 populateTableMissEntry(0, true, false, false, 0);
Sangho Shin01bca862014-09-12 11:18:59 -0700126 } else {
127 configureSwitch();
128 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700129 sendBarrier(true);
130 }
131
Sangho Shin01bca862014-09-12 11:18:59 -0700132
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700133 @Override
134 public boolean isDriverHandshakeComplete() {
Sangho Shin01bca862014-09-12 11:18:59 -0700135 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700136 throw new SwitchDriverSubHandshakeNotStarted();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700137 return driverHandshakeComplete.get();
138 }
139
140 @Override
141 public void processDriverHandshakeMessage(OFMessage m) {
Sangho Shin01bca862014-09-12 11:18:59 -0700142 if (!startDriverHandshakeCalled)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700143 throw new SwitchDriverSubHandshakeNotStarted();
Sangho Shin01bca862014-09-12 11:18:59 -0700144 if (driverHandshakeComplete.get())
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700145 throw new SwitchDriverSubHandshakeCompleted(m);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700146
147 switch (m.getType()) {
148 case BARRIER_REPLY:
Sangho Shin01bca862014-09-12 11:18:59 -0700149 if (m.getXid() == barrierXidToWaitFor)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700150 driverHandshakeComplete.set(true);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700151 break;
152
153 case ERROR:
154 log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
155 break;
156
157 case FEATURES_REPLY:
158 break;
159 case FLOW_REMOVED:
160 break;
161 case GET_ASYNC_REPLY:
162 OFAsyncGetReply asrep = (OFAsyncGetReply) m;
163 decodeAsyncGetReply(asrep);
164 break;
165
166 case PACKET_IN:
167 break;
168 case PORT_STATUS:
169 break;
170 case QUEUE_GET_CONFIG_REPLY:
171 break;
172 case ROLE_REPLY:
173 break;
174
175 case STATS_REPLY:
176 processStatsReply((OFStatsReply) m);
177 break;
178
179 default:
180 log.debug("Received message {} during switch-driver subhandshake "
181 + "from switch {} ... Ignoring message", m, getStringId());
182
183 }
184 }
185
186 private void configureSwitch() throws IOException {
187 // setAsyncConfig();
188 // getTableFeatures();
189 sendGroupFeaturesRequest();
190 setL2Groups();
191 sendBarrier(false);
192 setL3Groups();
193 setL25Groups();
Saurav Dasdf783ae2014-09-22 09:36:32 -0700194 setEcmpGroup();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700195 sendGroupDescRequest();
196 populateTableVlan();
197 populateTableTMac();
198 populateIpTable();
199 populateMplsTable();
200 populateTableMissEntry(TABLE_ACL, false, false, false, -1);
201 sendBarrier(true);
202 }
203
204 private void setAsyncConfig() throws IOException {
205 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
206 OFMessage setAC = null;
207
208 if (role == Role.MASTER) {
209 setAC = factory.buildAsyncSet()
210 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
211 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
212 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
213 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
214 .setPacketInMaskSlave(SET_ALL_SLAVE)
215 .setPortStatusMaskSlave(SET_ALL_SLAVE)
216 .setXid(getNextTransactionId())
217 .build();
218 } else if (role == Role.EQUAL) {
219 setAC = factory.buildAsyncSet()
220 .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
221 .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
222 .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
223 .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
224 .setPacketInMaskSlave(SET_ALL_SLAVE)
225 .setPortStatusMaskSlave(SET_ALL_SLAVE)
226 .setXid(getNextTransactionId())
227 .build();
228 }
229 msglist.add(setAC);
230
231 OFMessage br = factory.buildBarrierRequest()
232 .setXid(getNextTransactionId())
233 .build();
234 msglist.add(br);
235
236 OFMessage getAC = factory.buildAsyncGetRequest()
237 .setXid(getNextTransactionId())
238 .build();
239 msglist.add(getAC);
240
241 write(msglist);
242 }
243
244 private void decodeAsyncGetReply(OFAsyncGetReply rep) {
245 long frm = rep.getFlowRemovedMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -0700246 long frs = rep.getFlowRemovedMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700247 long pim = rep.getPacketInMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -0700248 long pis = rep.getPacketInMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700249 long psm = rep.getPortStatusMaskEqualMaster();
Sangho Shin01bca862014-09-12 11:18:59 -0700250 long pss = rep.getPortStatusMaskSlave();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700251
252 if (role == Role.MASTER || role == Role.EQUAL) { // should separate
253 log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
254 log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
255 log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
256 }
257
258 }
259
260 private void getTableFeatures() throws IOException {
261 OFMessage gtf = factory.buildTableFeaturesStatsRequest()
262 .setXid(getNextTransactionId())
263 .build();
264 write(gtf, null);
265 }
266
267 private void sendGroupFeaturesRequest() throws IOException {
268 OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
269 .setXid(getNextTransactionId())
270 .build();
271 write(gfr, null);
272 }
273
274 private void sendGroupDescRequest() throws IOException {
275 OFMessage gdr = factory.buildGroupDescStatsRequest()
276 .setXid(getNextTransactionId())
277 .build();
278 write(gdr, null);
279 }
280
281 /*Create L2 interface groups for all physical ports
282 Naming convention followed is the same as OF-DPA spec
283 eg. port 1 with allowed vlan 10, is enveloped in group with id,
284 0x0 00a 0001, where the uppermost 4 bits identify an L2 interface,
285 the next 12 bits identify the vlan-id, and the lowermost 16 bits
286 identify the port number.*/
287 private void setL2Groups() throws IOException {
288 List<OFMessage> msglist = new ArrayList<OFMessage>();
289 for (OFPortDesc p : getPorts()) {
290 int pnum = p.getPortNo().getPortNumber();
291 int portVlan = getVlanConfig(pnum);
292 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
293 OFGroup gl2 = OFGroup.of(pnum | (portVlan << VLAN_ID_OFFSET));
294 OFAction out = factory.actions().buildOutput()
295 .setPort(p.getPortNo()).build();
296 OFAction popVlan = factory.actions().popVlan();
297 List<OFAction> actions = new ArrayList<OFAction>();
Sangho Shin01bca862014-09-12 11:18:59 -0700298 // actions.add(popVlan);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700299 actions.add(out);
300 OFBucket bucket = factory.buildBucket()
301 .setActions(actions).build();
302 List<OFBucket> buckets = Collections.singletonList(bucket);
303 OFMessage gmAdd = factory.buildGroupAdd()
304 .setGroup(gl2)
305 .setBuckets(buckets)
306 .setGroupType(OFGroupType.INDIRECT)
307 .setXid(getNextTransactionId())
308 .build();
309 msglist.add(gmAdd);
310 l2groups.put(pnum, gl2);
311 }
312 }
313 log.debug("Creating {} L2 groups in sw {}", msglist.size(), getStringId());
314 write(msglist);
315 }
316
317 private int getVlanConfig(int portnum) {
318 int portVlan = 10 * portnum;
319 if ((getId() == 0x1 && portnum == 6) ||
320 (getId() == 0x2) ||
321 (getId() == 0x3 && portnum == 2)) {
322 portVlan = 192; // 0xc0
323 }
324 return portVlan;
325 }
326
327 private MacAddress getRouterMacAddr() {
Sangho Shin01bca862014-09-12 11:18:59 -0700328 if (getId() == 0x3)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700329 return MacAddress.of("00:00:07:07:07:80"); // router mac
Sangho Shin01bca862014-09-12 11:18:59 -0700330 if (getId() == 0x1)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700331 return MacAddress.of("00:00:01:01:01:80");
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700332 // switch 0x2
333 return MacAddress.of("00:00:02:02:02:80");
334 }
335
336 // only for ports connected to other routers
337 private OFAction getDestAction(int portnum) {
338 OFAction setDA = null;
339 MacAddress dAddr = null;
340 if (getId() == 0x1 && portnum == 6) { // connected to switch 2
341 dAddr = MacAddress.of("00:00:02:02:02:80");
342 }
Saurav Dasdf783ae2014-09-22 09:36:32 -0700343 if (getId() == 0x1 && portnum == 7) { // connected to switch 2
344 dAddr = MacAddress.of("00:00:02:02:02:80");
345 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700346 if (getId() == 0x2) {
347 if (portnum == 1) { // connected to sw 1
348 dAddr = MacAddress.of("00:00:01:01:01:80");
349 } else if (portnum == 2) { // connected to sw 3
350 dAddr = MacAddress.of("00:00:07:07:07:80");
351 }
352 }
353 if (getId() == 0x3) {
354 if (portnum == 2) { // connected to switch 2
355 dAddr = MacAddress.of("00:00:02:02:02:80");
356 }
357 }
358
359 if (dAddr != null) {
360 OFOxmEthDst dstAddr = factory.oxms().ethDst(dAddr);
361 setDA = factory.actions().buildSetField()
362 .setField(dstAddr).build();
363 }
364 return setDA;
365 }
366
367 /*
368 * L3 groups are created for all router ports and they all point to corresponding
369 * L2 groups. Only the ports that connect to other routers will have the
370 * DA set.
371 */
372 private void setL3Groups() throws IOException {
373 List<OFMessage> msglist = new ArrayList<OFMessage>();
374 for (OFGroup gl2 : l2groups.values()) {
375 int gnum = gl2.getGroupNumber();
376 int portnum = gnum & 0x0000ffff;
377 int vlanid = ((gnum & 0x0fff0000) >> VLAN_ID_OFFSET);
378 MacAddress sAddr = getRouterMacAddr();
379
380 OFGroup gl3 = OFGroup.of(0x20000000 | portnum);
381 OFAction group = factory.actions().buildGroup()
382 .setGroup(gl2).build();
383 OFOxmEthSrc srcAddr = factory.oxms().ethSrc(sAddr);
384 OFAction setSA = factory.actions().buildSetField()
385 .setField(srcAddr).build();
386 OFOxmVlanVid vid = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanid));
387 OFAction setVlan = factory.actions().buildSetField()
388 .setField(vid).build();
389 OFAction decTtl = factory.actions().decNwTtl();
390
391 List<OFAction> actions = new ArrayList<OFAction>();
392 actions.add(decTtl); // decrement the IP TTL/do-checksum/check TTL
393 // and MTU
Sangho Shin01bca862014-09-12 11:18:59 -0700394 // actions.add(setVlan); // set the vlan-id of the exit-port (and
395 // l2group)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700396 actions.add(setSA); // set this routers mac address
397 // make L3Unicast group setDA for known (configured) ports
398 // that connect to other routers
399 OFAction setDA = getDestAction(portnum);
Sangho Shin01bca862014-09-12 11:18:59 -0700400 if (setDA != null)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700401 actions.add(setDA);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700402 actions.add(group);
403
404 OFBucket bucket = factory.buildBucket()
405 .setActions(actions).build();
406 List<OFBucket> buckets = Collections.singletonList(bucket);
407 OFMessage gmAdd = factory.buildGroupAdd()
408 .setGroup(gl3)
409 .setBuckets(buckets)
410 .setGroupType(OFGroupType.INDIRECT)
411 .setXid(getNextTransactionId())
412 .build();
413 msglist.add(gmAdd);
414 }
415 write(msglist);
416 log.debug("Creating {} L3 groups in sw {}", msglist.size(), getStringId());
417 }
418
419 /*
420 * L2.5 or mpls-unicast groups are only created for those router ports
421 * connected to other router ports. They differ from the corresponding
422 * L3-unicast group only by the fact that they decrement the MPLS TTL
423 * instead of the IP ttl
424 */
425 private void setL25Groups() throws IOException {
426 List<OFMessage> msglist = new ArrayList<OFMessage>();
427 for (OFGroup gl2 : l2groups.values()) {
428 int gnum = gl2.getGroupNumber();
429 int portnum = gnum & 0x0000ffff;
430 int vlanid = ((gnum & 0x0fff0000) >> VLAN_ID_OFFSET);
431 MacAddress sAddr = getRouterMacAddr();
432 OFAction setDA = getDestAction(portnum);
433 // setDA will only be non-null for ports connected to routers
434 if (setDA != null) {
435 OFGroup gl3 = OFGroup.of(0xa0000000 | portnum); // different id
436 // for mpls
437 // group
438 OFAction group = factory.actions().buildGroup()
439 .setGroup(gl2).build();
440 OFOxmEthSrc srcAddr = factory.oxms().ethSrc(sAddr);
441 OFAction setSA = factory.actions().buildSetField()
442 .setField(srcAddr).build();
443 OFOxmVlanVid vid = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanid));
444 OFAction setVlan = factory.actions().buildSetField()
445 .setField(vid).build();
446 OFAction decMplsTtl = factory.actions().decMplsTtl();
447 List<OFAction> actions = new ArrayList<OFAction>();
448 actions.add(decMplsTtl); // decrement the MPLS
449 // TTL/do-checksum/check TTL and MTU
Sangho Shin01bca862014-09-12 11:18:59 -0700450 // actions.add(setVlan); // set the vlan-id of the exit-port
451 // (and
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700452 // l2group)
453 actions.add(setSA); // set this routers mac address
454 actions.add(setDA);
455 actions.add(group);
456 OFBucket bucket = factory.buildBucket()
457 .setActions(actions).build();
458 List<OFBucket> buckets = Collections.singletonList(bucket);
459 OFMessage gmAdd = factory.buildGroupAdd()
460 .setGroup(gl3)
461 .setBuckets(buckets)
462 .setGroupType(OFGroupType.INDIRECT)
463 .setXid(getNextTransactionId())
464 .build();
465 msglist.add(gmAdd);
466 }
467 }
468 write(msglist);
469 log.debug("Creating {} MPLS groups in sw {}", msglist.size(), getStringId());
470 }
471
Saurav Dasdf783ae2014-09-22 09:36:32 -0700472 private void setEcmpGroup() throws IOException {
473 if (getId() != 0x1)
474 return;
475 List<OFMessage> msglist = new ArrayList<OFMessage>();
476 OFGroup group47 = OFGroup.of(47);
477
478 OFAction outg1 = factory.actions().buildGroup()
479 .setGroup(OFGroup.of(0xa0000000 | // mpls group id
480 6))
Sangho Shin01bca862014-09-12 11:18:59 -0700481 .build();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700482 OFBucket buc47_1 = factory.buildBucket()
Sangho Shin01bca862014-09-12 11:18:59 -0700483 .setWeight(1)
Saurav Dasdf783ae2014-09-22 09:36:32 -0700484 .setActions(Collections.singletonList(outg1))
Sangho Shin01bca862014-09-12 11:18:59 -0700485 .build();
Saurav Dasdf783ae2014-09-22 09:36:32 -0700486
487 OFAction outg2 = factory.actions().buildGroup()
488 .setGroup(OFGroup.of(0xa0000000 | // mpls group id
489 7))
Sangho Shin01bca862014-09-12 11:18:59 -0700490 .build();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700491 OFBucket buc47_2 = factory.buildBucket()
Sangho Shin01bca862014-09-12 11:18:59 -0700492 .setWeight(1)
Saurav Dasdf783ae2014-09-22 09:36:32 -0700493 .setActions(Collections.singletonList(outg2))
Sangho Shin01bca862014-09-12 11:18:59 -0700494 .build();
Saurav Dasdf783ae2014-09-22 09:36:32 -0700495
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700496 List<OFBucket> buckets47 = new ArrayList<OFBucket>();
497 buckets47.add(buc47_1);
498 buckets47.add(buc47_2);
499 OFMessage gmS12 = factory.buildGroupAdd()
Sangho Shin01bca862014-09-12 11:18:59 -0700500 .setGroup(group47)
501 .setBuckets(buckets47)
502 .setGroupType(OFGroupType.SELECT)
503 .setXid(getNextTransactionId())
504 .build();
Saurav Dasdf783ae2014-09-22 09:36:32 -0700505 msglist.add(gmS12);
506 write(msglist);
507 log.debug("Creating {} ECMP groups in sw {}", msglist.size(), getStringId());
508 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700509
510 private void processStatsReply(OFStatsReply sr) {
511 switch (sr.getStatsType()) {
512 case AGGREGATE:
513 break;
514 case DESC:
515 break;
516 case EXPERIMENTER:
517 break;
518 case FLOW:
519 break;
520 case GROUP_DESC:
521 processGroupDesc((OFGroupDescStatsReply) sr);
522 break;
523 case GROUP_FEATURES:
524 processGroupFeatures((OFGroupFeaturesStatsReply) sr);
525 break;
526 case METER_CONFIG:
527 break;
528 case METER_FEATURES:
529 break;
530 case PORT_DESC:
531 break;
532 case TABLE_FEATURES:
533 break;
534 default:
535 break;
536
537 }
538 }
539
540 private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
541 log.info("Sw: {} Group Features {}", getStringId(), gfsr);
542 }
543
544 private void processGroupDesc(OFGroupDescStatsReply gdsr) {
545 log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
546 }
547
548 private void populateTableVlan() throws IOException {
549 // for all incoming ports assign configured port-vlans
550 // currently assign portnum*10 -> vlanid to access ports
551 // and vlan 192 to router to router ports
552 List<OFMessage> msglist = new ArrayList<OFMessage>();
553 for (OFPortDesc p : getPorts()) {
554 int pnum = p.getPortNo().getPortNumber();
555 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
556 int vlanid = getVlanConfig(pnum);
557 OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
558 OFOxmVlanVid oxv = factory.oxms()
559 .vlanVid(OFVlanVidMatch.UNTAGGED);
560 OFOxmList oxmList = OFOxmList.of(oxp, oxv);
561 OFMatchV3 match = factory.buildMatchV3()
562 .setOxmList(oxmList).build();
563 OFOxmVlanVid vidToSet = factory.oxms()
564 .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
565 OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
566 OFAction setVlan = factory.actions().setField(vidToSet);
567 List<OFAction> actionlist = new ArrayList<OFAction>();
568 actionlist.add(pushVlan);
569 actionlist.add(setVlan);
570 OFInstruction appAction = factory.instructions().buildApplyActions()
571 .setActions(actionlist).build();
572 OFInstruction gotoTbl = factory.instructions().buildGotoTable()
573 .setTableId(TableId.of(TABLE_TMAC)).build();
574 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
Sangho Shin01bca862014-09-12 11:18:59 -0700575 // instructions.add(appAction);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700576 instructions.add(gotoTbl);
577 OFMessage flowEntry = factory.buildFlowAdd()
578 .setTableId(TableId.of(TABLE_VLAN))
579 .setMatch(match)
580 .setInstructions(instructions)
581 .setPriority(1000) // does not matter - all rules
582 // exclusive
583 .setBufferId(OFBufferId.NO_BUFFER)
584 .setIdleTimeout(0)
585 .setHardTimeout(0)
586 .setXid(getNextTransactionId())
587 .build();
588 msglist.add(flowEntry);
589 }
590 }
591 // table-vlan has no table-miss entry, and so packets that miss are
592 // essentially dropped
593 write(msglist);
594 log.debug("Adding {} vlan-rules in sw {}", msglist.size(), getStringId());
595 }
596
597 private void populateTableTMac() throws IOException {
598 // match for ip packets
599 OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
600 OFOxmList oxmListIp = OFOxmList.of(oxe);
601 OFMatchV3 matchIp = factory.buildMatchV3()
602 .setOxmList(oxmListIp).build();
603 OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
Sangho Shin01bca862014-09-12 11:18:59 -0700604 .setTableId(TableId.of(TABLE_IPv4_UNICAST)).build();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700605 List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
606 OFMessage ipEntry = factory.buildFlowAdd()
607 .setTableId(TableId.of(TABLE_TMAC))
608 .setMatch(matchIp)
609 .setInstructions(instructionsIp)
610 .setPriority(1000) // strict priority required lower than
611 // multicastMac
612 .setBufferId(OFBufferId.NO_BUFFER)
613 .setIdleTimeout(0)
614 .setHardTimeout(0)
615 .setXid(getNextTransactionId())
616 .build();
617
618 // match for mpls packets
619 OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
620 OFOxmList oxmListMpls = OFOxmList.of(oxmpls);
621 OFMatchV3 matchMpls = factory.buildMatchV3()
622 .setOxmList(oxmListMpls).build();
623 OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
624 .setTableId(TableId.of(TABLE_MPLS)).build();
625 List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
626 OFMessage mplsEntry = factory.buildFlowAdd()
627 .setTableId(TableId.of(TABLE_TMAC))
628 .setMatch(matchMpls)
629 .setInstructions(instructionsMpls)
630 .setPriority(1001) // strict priority required lower than
631 // multicastMac
632 .setBufferId(OFBufferId.NO_BUFFER)
633 .setIdleTimeout(0)
634 .setHardTimeout(0)
635 .setXid(getNextTransactionId())
636 .build();
637
638 // match for everything else to send to controller. Essentially
639 // the table miss flow entry
640 populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
641 log.debug("Adding termination-mac-rules in sw {}", getStringId());
642 List<OFMessage> msglist = new ArrayList<OFMessage>(2);
643 msglist.add(ipEntry);
644 msglist.add(mplsEntry);
645 write(msglist);
646 }
647
648 private List<String> getMyIps() { // send to controller
649 List<String> myIps = new ArrayList<String>();
650 if (getId() == 0x1) {
651 myIps.add("10.0.2.128");
652 myIps.add("10.0.3.128");
653 myIps.add("10.0.1.128");
654 myIps.add("192.168.0.1");
655 }
656 if (getId() == 0x2) {
657 myIps.add("192.168.0.2");
658 }
659 if (getId() == 0x3) {
660 myIps.add("192.168.0.3");
661 myIps.add("7.7.7.128");
662 }
663 return myIps;
664 }
665
666 private List<String> getMySubnetIps() { // send to controller
667 List<String> subnetIps = new ArrayList<String>();
668 if (getId() == 0x1) {
669 subnetIps.add("10.0.2.0");
670 subnetIps.add("10.0.3.0");
671 subnetIps.add("10.0.1.0");
672 }
Sangho Shin01bca862014-09-12 11:18:59 -0700673 if (getId() == 0x2) {
674 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700675 if (getId() == 0x3) {
676 subnetIps.add("7.7.7.0");
677 }
678 return subnetIps;
679 }
680
Sangho Shin01bca862014-09-12 11:18:59 -0700681 private class RouteEntry {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700682 String prefix;
683 String mask;
684 int nextHopPort;
685 String dstMac;
686 int label;
687
688 public RouteEntry(String prefix, String mask, int nextHopPort, int label) {
689 this.prefix = prefix;
690 this.mask = mask;
691 this.nextHopPort = nextHopPort;
692 this.label = label;
693 }
694
695 public RouteEntry(String prefix, int nextHopPort, String dstMac) {
696 this.prefix = prefix;
697 this.nextHopPort = nextHopPort;
698 this.dstMac = dstMac;
699 }
700 }
701
702 // send out of mpls-group where the next-hop mac-da is already set
703 private List<RouteEntry> getRouterNextHopIps() {
704 List<RouteEntry> routerNextHopIps = new ArrayList<RouteEntry>();
705 if (getId() == 0x1) {
706 routerNextHopIps
707 .add(new RouteEntry("192.168.0.2", "255.255.255.255", 6, 102));
708 routerNextHopIps
709 .add(new RouteEntry("192.168.0.3", "255.255.255.255", 6, 103));
710 routerNextHopIps.add(new RouteEntry("7.7.7.0", "255.255.255.0", 6, 103));
711 }
Sangho Shin01bca862014-09-12 11:18:59 -0700712 if (getId() == 0x2) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700713 /* These are required for normal IP routing without labels.
714 routerNextHopIps.add(new RouteEntry("192.168.0.1","255.255.255.255",1));
715 routerNextHopIps.add(new RouteEntry("192.168.0.3","255.255.255.255",2));
716 routerNextHopIps.add(new RouteEntry("10.0.1.0","255.255.255.0",1));
717 routerNextHopIps.add(new RouteEntry("10.0.2.0","255.255.255.0",1));
718 routerNextHopIps.add(new RouteEntry("10.0.3.0","255.255.255.0",1));
719 routerNextHopIps.add(new RouteEntry("7.7.7.0","255.255.255.0",2));*/
Sangho Shin01bca862014-09-12 11:18:59 -0700720 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700721 if (getId() == 0x3) {
722 routerNextHopIps
723 .add(new RouteEntry("192.168.0.2", "255.255.255.255", 2, 102));
724 routerNextHopIps
725 .add(new RouteEntry("192.168.0.1", "255.255.255.255", 2, 101));
726 routerNextHopIps.add(new RouteEntry("10.0.1.0", "255.255.255.0", 2, 101));
727 routerNextHopIps.add(new RouteEntry("10.0.2.0", "255.255.255.0", 2, 101));
728 routerNextHopIps.add(new RouteEntry("10.0.3.0", "255.255.255.0", 2, 101));
729 }
730 return routerNextHopIps;
731 }
732
733 // known host mac-addr, setDA/send out of l3group
734 private List<RouteEntry> getHostNextHopIps() {
735 List<RouteEntry> hostNextHopIps = new ArrayList<RouteEntry>();
736 if (getId() == 0x1) {
Sangho Shin01bca862014-09-12 11:18:59 -0700737 //hostNextHopIps.add(new RouteEntry("10.0.1.1", 1, "00:00:00:00:01:01")); // Just for Test - SSH
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700738 hostNextHopIps.add(new RouteEntry("10.0.2.1", 4, "00:00:00:00:02:01"));
739 hostNextHopIps.add(new RouteEntry("10.0.3.1", 5, "00:00:00:00:03:01"));
740 }
Sangho Shin01bca862014-09-12 11:18:59 -0700741 if (getId() == 0x2) {
742 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700743 if (getId() == 0x3) {
744 hostNextHopIps.add(new RouteEntry("7.7.7.7", 1, "00:00:07:07:07:07"));
745 }
746 return hostNextHopIps;
747 }
748
749 private void populateIpTable() throws IOException {
Sangho Shin01bca862014-09-12 11:18:59 -0700750 // populateMyIps();
751 // populateMySubnets();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700752 populateRoutes();
753 populateHostRoutes();
754
755 // match for everything else to send to ACL table. Essentially
756 // the table miss flow entry
Sangho Shin01bca862014-09-12 11:18:59 -0700757 populateTableMissEntry(TABLE_IPv4_UNICAST, false, true,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700758 true, TABLE_ACL);
759 }
760
761 private void populateMyIps() throws IOException {
762 List<OFMessage> msglist = new ArrayList<OFMessage>();
763 // first all my ip's as exact-matches
764 // write-action instruction to send to controller
765 List<String> myIps = getMyIps();
766 for (int i = 0; i < myIps.size(); i++) {
767 OFOxmEthType ethTypeIp = factory.oxms()
768 .ethType(EthType.IPv4);
769 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
770 .ipv4DstMasked(IPv4Address.of(myIps.get(i)), IPv4Address.NO_MASK);
771 OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
772 OFMatchV3 match = factory.buildMatchV3()
773 .setOxmList(oxmListSlash32).build();
774 OFAction outc = factory.actions().buildOutput()
775 .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
776 .build();
777 OFInstruction writeInstr = factory.instructions().buildWriteActions()
778 .setActions(Collections.singletonList(outc)).build();
779 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
780 .setTableId(TableId.of(TABLE_ACL)).build();
781 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
782 instructions.add(writeInstr);
783 instructions.add(gotoInstr);
784 OFMessage myIpEntry = factory.buildFlowAdd()
Sangho Shin01bca862014-09-12 11:18:59 -0700785 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700786 .setMatch(match)
787 .setInstructions(instructions)
788 .setPriority(MAX_PRIORITY) // highest priority for exact
789 // match
790 .setBufferId(OFBufferId.NO_BUFFER)
791 .setIdleTimeout(0)
792 .setHardTimeout(0)
793 .setXid(getNextTransactionId())
794 .build();
795 msglist.add(myIpEntry);
796 }
797 write(msglist);
798 log.debug("Adding {} my-ip-rules in sw {}", msglist.size(), getStringId());
799 }
800
801 private void populateMySubnets() throws IOException {
802 List<OFMessage> msglist = new ArrayList<OFMessage>();
803 // next prefix-based subnet-IP's configured on my interfaces
804 // need to ARP for exact-IP, so write-action instruction to send to
805 // controller
806 // this has different mask and priority than earlier case
807 List<String> subnetIps = getMySubnetIps();
808 for (int i = 0; i < subnetIps.size(); i++) {
809 OFOxmEthType ethTypeIp = factory.oxms()
810 .ethType(EthType.IPv4);
811 OFOxmIpv4DstMasked ipPrefix = factory.oxms().ipv4DstMasked(
812 IPv4Address.of(subnetIps.get(i)),
813 IPv4Address.of(0xffffff00)); // '/24' mask
814 OFOxmList oxmListSlash24 = OFOxmList.of(ethTypeIp, ipPrefix);
815 OFMatchV3 match = factory.buildMatchV3()
816 .setOxmList(oxmListSlash24).build();
817 OFAction outc = factory.actions().buildOutput()
818 .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
819 .build();
820 OFInstruction writeInstr = factory.instructions().buildWriteActions()
821 .setActions(Collections.singletonList(outc)).build();
822 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
823 .setTableId(TableId.of(TABLE_ACL)).build();
824 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
825 instructions.add(writeInstr);
826 instructions.add(gotoInstr);
827 OFMessage myIpEntry = factory.buildFlowAdd()
Sangho Shin01bca862014-09-12 11:18:59 -0700828 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700829 .setMatch(match)
830 .setInstructions(instructions)
831 .setPriority(SLASH_24_PRIORITY)
832 .setBufferId(OFBufferId.NO_BUFFER)
833 .setIdleTimeout(0)
834 .setHardTimeout(0)
835 .setXid(getNextTransactionId())
836 .build();
837 msglist.add(myIpEntry);
838 }
839 write(msglist);
840 log.debug("Adding {} subnet-ip-rules in sw {}", msglist.size(), getStringId());
841 msglist.clear();
842 }
843
844 private void populateRoutes() throws IOException {
845 List<OFMessage> msglist = new ArrayList<OFMessage>();
846 // addresses where I know the next-hop's mac-address because it is a
847 // router port - so I have an L3 interface to it (and an MPLS interface)
848 List<RouteEntry> routerNextHopIps = getRouterNextHopIps();
849 for (int i = 0; i < routerNextHopIps.size(); i++) {
850 OFOxmEthType ethTypeIp = factory.oxms()
851 .ethType(EthType.IPv4);
852 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
853 .ipv4DstMasked(
854 IPv4Address.of(routerNextHopIps.get(i).prefix),
855 IPv4Address.of(routerNextHopIps.get(i).mask)
856 );
857 OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
858 OFMatchV3 match = factory.buildMatchV3()
859 .setOxmList(oxmListSlash32).build();
860 OFAction outg = factory.actions().buildGroup()
861 .setGroup(OFGroup.of(0xa0000000 | // mpls group id
862 routerNextHopIps.get(i).nextHopPort))
863 .build();
864 // lots of actions before forwarding to mpls group, and
865 // unfortunately
866 // they need to be apply-actions
867
868 OFAction pushlabel = factory.actions().pushMpls(EthType.MPLS_UNICAST);
869 OFOxmMplsLabel l = factory.oxms()
870 .mplsLabel(U32.of(routerNextHopIps.get(i).label));
871 OFAction setlabelid = factory.actions().buildSetField()
872 .setField(l).build();
873 OFAction copyTtlOut = factory.actions().copyTtlOut();
874 // OFAction setBos =
875 // factory.actions().buildSetField().setField(bos).build();
876
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700877 List<OFAction> writeActions = new ArrayList<OFAction>();
Sangho Shin01bca862014-09-12 11:18:59 -0700878 writeActions.add(pushlabel);
879 writeActions.add(copyTtlOut);
880 writeActions.add(setlabelid);
881 // writeActions.add(setBos); no support in loxigen
882
883 // List<OFAction> applyActions = new ArrayList<OFAction>();
884 // applyActions.add(pushlabel);
885 // applyActions.add(copyTtlOut);
886 // OFInstruction applyInstr =
887 // factory.instructions().buildApplyActions()
888 // .setActions(applyActions).build();
Saurav Dasdf783ae2014-09-22 09:36:32 -0700889
890 if (getId() == 0x1) {
891 OFAction group47 = factory.actions().buildGroup()
892 .setGroup(OFGroup.of(47)).build();
893 writeActions.add(group47);
894 } else {
895 writeActions.add(outg); // group will decr mpls-ttl, set
896 // mac-sa/da,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700897 // vlan
Saurav Dasdf783ae2014-09-22 09:36:32 -0700898 }
899
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700900 OFInstruction writeInstr = factory.instructions().buildWriteActions()
901 .setActions(writeActions).build();
Sangho Shin01bca862014-09-12 11:18:59 -0700902 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
903 .setTableId(TableId.of(TABLE_ACL)).build();
904 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
905 instructions.add(writeInstr);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700906
907 // necessary to match in pseudo-table to overcome cpqd 1.3 flaw
Sangho Shin01bca862014-09-12 11:18:59 -0700908 /*OFInstruction writeMeta = factory.instructions().buildWriteMetadata()
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700909 .setMetadata(U64.of(routerNextHopIps.get(i).label))
910 .setMetadataMask(METADATA_MASK).build();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700911 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
Sangho Shin01bca862014-09-12 11:18:59 -0700912 .setTableId(TableId.of(TABLE_META)).build();*/
913 /*instructions.add(applyInstr);
914 instructions.add(writeMeta);*/
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700915
Sangho Shin01bca862014-09-12 11:18:59 -0700916 instructions.add(gotoInstr);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700917 int priority = -1;
Sangho Shin01bca862014-09-12 11:18:59 -0700918 if (routerNextHopIps.get(i).mask.equals("255.255.255.255"))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700919 priority = MAX_PRIORITY;
Sangho Shin01bca862014-09-12 11:18:59 -0700920 else
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700921 priority = SLASH_24_PRIORITY;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700922 OFMessage myIpEntry = factory.buildFlowAdd()
Sangho Shin01bca862014-09-12 11:18:59 -0700923 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700924 .setMatch(match)
925 .setInstructions(instructions)
926 .setPriority(priority)
927 .setBufferId(OFBufferId.NO_BUFFER)
928 .setIdleTimeout(0)
929 .setHardTimeout(0)
930 .setXid(getNextTransactionId())
931 .build();
932 msglist.add(myIpEntry);
933
934 // need to also handle psuedo-table entries to match-metadata and
935 // set mpls
936 // label-id
Sangho Shin01bca862014-09-12 11:18:59 -0700937 /*OFOxmEthType ethTypeMpls = factory.oxms()
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700938 .ethType(EthType.MPLS_UNICAST);
939 OFOxmMetadataMasked meta = factory.oxms()
940 .metadataMasked(
941 OFMetadata.ofRaw(routerNextHopIps.get(i).label),
942 OFMetadata.NO_MASK);
943 OFOxmList oxmListMeta = OFOxmList.of(ethTypeMpls, meta);
944 OFMatchV3 matchMeta = factory.buildMatchV3()
945 .setOxmList(oxmListMeta).build();
946 List<OFAction> writeActions2 = new ArrayList<OFAction>();
947 writeActions2.add(setlabelid);
948 OFAction outg2 = factory.actions().buildGroup()
949 .setGroup(OFGroup.of(routerNextHopIps.get(i).nextHopPort |
Sangho Shin01bca862014-09-12 11:18:59 -0700950 (192 << VLAN_ID_OFFSET)))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700951 .build();
952 writeActions2.add(outg2);
953 OFInstruction writeInstr2 = factory.instructions().buildWriteActions()
954 .setActions(writeActions2).build();
955 OFInstruction gotoInstr2 = factory.instructions().buildGotoTable()
956 .setTableId(TableId.of(TABLE_ACL)).build();
957 List<OFInstruction> instructions2 = new ArrayList<OFInstruction>();
958 // unfortunately have to apply this action too
959 OFInstruction applyInstr2 = factory.instructions().buildApplyActions()
960 .setActions(writeActions2).build();
Sangho Shin01bca862014-09-12 11:18:59 -0700961 instructions2.add(applyInstr2); */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700962 // instructions2.add(writeInstr2);
963 // instructions2.add(gotoInstr2);
964
965 /*OFMatchV3 match3 = factory.buildMatchV3()
Sangho Shin01bca862014-09-12 11:18:59 -0700966 .setOxmList(OFOxmList.of(meta)).build();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700967 OFInstruction clearInstruction = factory.instructions().clearActions();
968 List<OFInstruction> instructions3 = new ArrayList<OFInstruction>();
969 OFAction outc = factory.actions().buildOutput()
Sangho Shin01bca862014-09-12 11:18:59 -0700970 .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
971 .build();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700972 OFInstruction writec = factory.instructions()
Sangho Shin01bca862014-09-12 11:18:59 -0700973 .writeActions(Collections.singletonList(outc));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700974 instructions3.add(clearInstruction);
975 instructions3.add(writec);
976 instructions3.add(gotoInstr2); */
Sangho Shin01bca862014-09-12 11:18:59 -0700977 /*OFMessage myMetaEntry = factory.buildFlowAdd()
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700978 .setTableId(TableId.of(TABLE_META))
979 .setMatch(matchMeta)
980 .setInstructions(instructions2)
981 .setPriority(MAX_PRIORITY)
982 .setBufferId(OFBufferId.NO_BUFFER)
983 .setIdleTimeout(0)
984 .setHardTimeout(0)
985 .setXid(getNextTransactionId())
986 .build();
Sangho Shin01bca862014-09-12 11:18:59 -0700987 msglist.add(myMetaEntry); */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700988
989 }
990 write(msglist);
991 log.debug("Adding {} next-hop-router-rules in sw {}", msglist.size(),
992 getStringId());
993
994 // add a table-miss entry to table 4 for debugging - leave it out
995 // unclear packet state - causes switch to crash
996 // populateTableMissEntry(TABLE_META, false, true,
997 // true, TABLE_ACL);
998 }
999
1000 private void populateHostRoutes() throws IOException {
1001 List<OFMessage> msglist = new ArrayList<OFMessage>();
1002 // addresses where I know the next hop's mac-address and I can set the
1003 // destination mac in the match-instruction.write-action
1004 // either I sent out arp-request or I got an arp-request from this host
1005 List<RouteEntry> hostNextHopIps = getHostNextHopIps();
1006 for (int i = 0; i < hostNextHopIps.size(); i++) {
1007 OFOxmEthType ethTypeIp = factory.oxms()
1008 .ethType(EthType.IPv4);
1009 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
1010 .ipv4DstMasked(
1011 IPv4Address.of(hostNextHopIps.get(i).prefix),
1012 IPv4Address.NO_MASK); // host addr should be /32
1013 OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
1014 OFMatchV3 match = factory.buildMatchV3()
1015 .setOxmList(oxmListSlash32).build();
1016 OFAction setDmac = null, outg = null;
1017 OFOxmEthDst dmac = factory.oxms()
1018 .ethDst(MacAddress.of(hostNextHopIps.get(i).dstMac));
1019 setDmac = factory.actions().buildSetField()
1020 .setField(dmac).build();
1021 outg = factory.actions().buildGroup()
1022 .setGroup(OFGroup.of(0x20000000 | hostNextHopIps.get(i).nextHopPort)) // l3group
1023 // id
1024 .build();
1025 List<OFAction> writeActions = new ArrayList<OFAction>();
1026 writeActions.add(setDmac);
1027 writeActions.add(outg);
1028 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1029 .setActions(writeActions).build();
1030 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1031 .setTableId(TableId.of(TABLE_ACL)).build();
1032 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1033 instructions.add(writeInstr);
1034 instructions.add(gotoInstr);
1035 OFMessage myIpEntry = factory.buildFlowAdd()
Sangho Shin01bca862014-09-12 11:18:59 -07001036 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001037 .setMatch(match)
1038 .setInstructions(instructions)
1039 .setPriority(MAX_PRIORITY) // highest priority for exact
1040 // match
1041 .setBufferId(OFBufferId.NO_BUFFER)
1042 .setIdleTimeout(0)
1043 .setHardTimeout(0)
1044 .setXid(getNextTransactionId())
1045 .build();
1046 msglist.add(myIpEntry);
1047 }
1048 write(msglist);
1049 log.debug("Adding {} next-hop-host-rules in sw {}", msglist.size(), getStringId());
1050 }
1051
Sangho Shin01bca862014-09-12 11:18:59 -07001052 private class MplsEntry {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001053 int labelid;
1054 int portnum;
1055
1056 public MplsEntry(int labelid, int portnum) {
1057 this.labelid = labelid;
1058 this.portnum = portnum;
1059 }
1060 }
1061
1062 private List<MplsEntry> getMplsEntries() {
1063 List<MplsEntry> myLabels = new ArrayList<MplsEntry>();
1064 if (getId() == 0x1) {
1065 myLabels.add(new MplsEntry(101, OFPort.CONTROLLER.getPortNumber()));
1066 myLabels.add(new MplsEntry(103, 6));
1067 }
1068 if (getId() == 0x2) {
1069 myLabels.add(new MplsEntry(103, 2));
1070 myLabels.add(new MplsEntry(102, OFPort.CONTROLLER.getPortNumber()));
1071 myLabels.add(new MplsEntry(101, 1));
1072 }
1073 if (getId() == 0x3) {
1074 myLabels.add(new MplsEntry(103, OFPort.CONTROLLER.getPortNumber()));
1075 myLabels.add(new MplsEntry(101, 2));
1076 }
1077 return myLabels;
1078 }
1079
1080 private void populateMplsTable() throws IOException {
1081 List<OFMessage> msglist = new ArrayList<OFMessage>();
1082 List<MplsEntry> lfibEntries = getMplsEntries();
1083 for (int i = 0; i < lfibEntries.size(); i++) {
1084 OFOxmEthType ethTypeMpls = factory.oxms()
1085 .ethType(EthType.MPLS_UNICAST);
1086 OFOxmMplsLabel labelid = factory.oxms()
1087 .mplsLabel(U32.of(lfibEntries.get(i).labelid));
1088 OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid);
1089 OFMatchV3 matchlabel = factory.buildMatchV3()
1090 .setOxmList(oxmList).build();
1091 OFAction poplabel = factory.actions().popMpls(EthType.IPv4);
Sangho Shin01bca862014-09-12 11:18:59 -07001092 OFAction copyttlin = factory.actions().copyTtlIn();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001093 OFAction sendTo = null;
1094 if (lfibEntries.get(i).portnum == OFPort.CONTROLLER.getPortNumber()) {
1095 sendTo = factory.actions().output(OFPort.CONTROLLER,
1096 OFPCML_NO_BUFFER);
1097 } else {
Sangho Shin01bca862014-09-12 11:18:59 -07001098 // after popping send to L3 intf, not MPLS intf
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001099 sendTo = factory.actions().group(OFGroup.of(
Sangho Shin01bca862014-09-12 11:18:59 -07001100 0x20000000 | lfibEntries.get(i).portnum));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001101 }
1102 List<OFAction> writeActions = new ArrayList<OFAction>();
Sangho Shin01bca862014-09-12 11:18:59 -07001103 writeActions.add(copyttlin);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001104 writeActions.add(poplabel);
1105 writeActions.add(sendTo);
1106 OFInstruction writeInstr = factory.instructions().buildWriteActions()
1107 .setActions(writeActions).build();
1108 OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1109 .setTableId(TableId.of(TABLE_ACL)).build();
1110 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1111 instructions.add(writeInstr);
1112 instructions.add(gotoInstr);
1113 OFMessage myMplsEntry = factory.buildFlowAdd()
1114 .setTableId(TableId.of(TABLE_MPLS))
1115 .setMatch(matchlabel)
1116 .setInstructions(instructions)
1117 .setPriority(MAX_PRIORITY) // exact match and exclusive
1118 .setBufferId(OFBufferId.NO_BUFFER)
1119 .setIdleTimeout(0)
1120 .setHardTimeout(0)
1121 .setXid(getNextTransactionId())
1122 .build();
1123 msglist.add(myMplsEntry);
1124 }
1125 write(msglist);
1126 log.debug("Adding {} mpls-forwarding-rules in sw {}", msglist.size(),
1127 getStringId());
1128
1129 // match for everything else to send to ACL table. Essentially
1130 // the table miss flow entry
1131 populateTableMissEntry(TABLE_MPLS, false, true,
1132 true, TABLE_ACL);
1133
1134 }
1135
1136 /**
1137 * By default if none of the booleans in the call are set, then the
1138 * table-miss entry is added with no instructions, which means that pipeline
1139 * execution will stop, and the action set associated with the packet will
1140 * be executed.
1141 *
1142 * @param tableToAdd
1143 * @param toControllerNow as an APPLY_ACTION instruction
1144 * @param toControllerWrite as a WRITE_ACITION instruction
1145 * @param toTable as a GOTO_TABLE instruction
1146 * @param tableToSend
1147 * @throws IOException
1148 */
1149 @SuppressWarnings("unchecked")
1150 private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
1151 boolean toControllerWrite,
1152 boolean toTable, int tableToSend) throws IOException {
1153 OFOxmList oxmList = OFOxmList.EMPTY;
1154 OFMatchV3 match = factory.buildMatchV3()
1155 .setOxmList(oxmList)
1156 .build();
1157 OFAction outc = factory.actions()
1158 .buildOutput()
1159 .setPort(OFPort.CONTROLLER)
1160 .setMaxLen(OFPCML_NO_BUFFER)
1161 .build();
1162 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1163 if (toControllerNow) {
1164 // table-miss instruction to send to controller immediately
1165 OFInstruction instr = factory.instructions()
1166 .buildApplyActions()
1167 .setActions(Collections.singletonList(outc))
1168 .build();
1169 instructions.add(instr);
1170 }
1171
1172 if (toControllerWrite) {
1173 // table-miss instruction to write-action to send to controller
1174 // this will be executed whenever the action-set gets executed
1175 OFInstruction instr = factory.instructions()
1176 .buildWriteActions()
1177 .setActions(Collections.singletonList(outc))
1178 .build();
1179 instructions.add(instr);
1180 }
1181
1182 if (toTable) {
1183 // table-miss instruction to goto-table x
1184 OFInstruction instr = factory.instructions()
1185 .gotoTable(TableId.of(tableToSend));
1186 instructions.add(instr);
1187 }
1188
1189 if (!toControllerNow && !toControllerWrite && !toTable) {
1190 // table-miss has no instruction - at which point action-set will be
1191 // executed - if there is an action to output/group in the action
1192 // set
1193 // the packet will be sent there, otherwise it will be dropped.
1194 instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
1195 }
1196
1197 OFMessage tableMissEntry = factory.buildFlowAdd()
1198 .setTableId(TableId.of(tableToAdd))
1199 .setMatch(match) // match everything
1200 .setInstructions(instructions)
1201 .setPriority(MIN_PRIORITY)
1202 .setBufferId(OFBufferId.NO_BUFFER)
1203 .setIdleTimeout(0)
1204 .setHardTimeout(0)
1205 .setXid(getNextTransactionId())
1206 .build();
1207 write(tableMissEntry, null);
1208 }
1209
1210 private void sendBarrier(boolean finalBarrier) throws IOException {
1211 int xid = getNextTransactionId();
1212 if (finalBarrier) {
1213 barrierXidToWaitFor = xid;
1214 }
1215 OFBarrierRequest br = factory
1216 .buildBarrierRequest()
1217 .setXid(xid)
1218 .build();
1219 write(br, null);
1220 }
1221
1222}