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