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