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