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