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