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