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