blob: fd22969faf122bddda132334c5fd2fbb87c42460 [file] [log] [blame]
Saurav Das822c4e22015-10-23 10:51:11 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * 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
7 *
8 * 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.
15 */
16package org.onosproject.driver.pipeline;
17
18import static org.onlab.util.Tools.groupedThreads;
19import static org.slf4j.LoggerFactory.getLogger;
20
21import java.nio.ByteBuffer;
22import java.util.ArrayList;
23import java.util.Collection;
24import java.util.Collections;
25import java.util.List;
26import java.util.Set;
27import java.util.concurrent.ConcurrentHashMap;
28import java.util.concurrent.Executors;
29import java.util.concurrent.ScheduledExecutorService;
30import java.util.concurrent.TimeUnit;
31import java.util.stream.Collectors;
32
33import org.onlab.osgi.ServiceDirectory;
34import org.onlab.packet.Data;
35import org.onlab.packet.Ethernet;
36import org.onlab.packet.IPv4;
37import org.onlab.packet.IpPrefix;
38import org.onlab.packet.MPLS;
39import org.onlab.packet.MacAddress;
40import org.onlab.packet.MplsLabel;
41import org.onlab.packet.UDP;
42import org.onlab.packet.VlanId;
43import org.onlab.util.KryoNamespace;
44import org.onosproject.core.ApplicationId;
45import org.onosproject.core.CoreService;
46import org.onosproject.core.DefaultGroupId;
47import org.onosproject.net.DeviceId;
48import org.onosproject.net.Port;
49import org.onosproject.net.PortNumber;
50import org.onosproject.net.behaviour.NextGroup;
51import org.onosproject.net.behaviour.Pipeliner;
52import org.onosproject.net.behaviour.PipelinerContext;
53import org.onosproject.net.device.DeviceService;
54import org.onosproject.net.driver.AbstractHandlerBehaviour;
55import org.onosproject.net.flow.DefaultFlowRule;
56import org.onosproject.net.flow.DefaultTrafficSelector;
57import org.onosproject.net.flow.DefaultTrafficTreatment;
58import org.onosproject.net.flow.FlowRule;
59import org.onosproject.net.flow.FlowRuleOperations;
60import org.onosproject.net.flow.FlowRuleOperationsContext;
61import org.onosproject.net.flow.FlowRuleService;
62import org.onosproject.net.flow.TrafficSelector;
63import org.onosproject.net.flow.TrafficTreatment;
64import org.onosproject.net.flow.criteria.Criteria;
65import org.onosproject.net.flow.criteria.Criterion;
66import org.onosproject.net.flow.criteria.EthCriterion;
67import org.onosproject.net.flow.criteria.EthTypeCriterion;
68import org.onosproject.net.flow.criteria.IPCriterion;
69import org.onosproject.net.flow.criteria.PortCriterion;
70import org.onosproject.net.flow.criteria.VlanIdCriterion;
71import org.onosproject.net.flow.instructions.Instruction;
72import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
73import org.onosproject.net.flow.instructions.L2ModificationInstruction;
74import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
75import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
76import org.onosproject.net.flowobjective.FilteringObjective;
77import org.onosproject.net.flowobjective.FlowObjectiveStore;
78import org.onosproject.net.flowobjective.ForwardingObjective;
79import org.onosproject.net.flowobjective.NextObjective;
80import org.onosproject.net.flowobjective.Objective;
81import org.onosproject.net.flowobjective.ObjectiveError;
82import org.onosproject.net.group.DefaultGroupBucket;
83import org.onosproject.net.group.DefaultGroupDescription;
84import org.onosproject.net.group.DefaultGroupKey;
85import org.onosproject.net.group.Group;
86import org.onosproject.net.group.GroupBucket;
87import org.onosproject.net.group.GroupBuckets;
88import org.onosproject.net.group.GroupDescription;
89import org.onosproject.net.group.GroupEvent;
90import org.onosproject.net.group.GroupKey;
91import org.onosproject.net.group.GroupListener;
92import org.onosproject.net.group.GroupService;
93import org.onosproject.net.packet.DefaultOutboundPacket;
94import org.onosproject.net.packet.OutboundPacket;
95import org.onosproject.net.packet.PacketContext;
96import org.onosproject.net.packet.PacketProcessor;
97import org.onosproject.net.packet.PacketService;
98import org.onosproject.store.serializers.KryoNamespaces;
99import org.slf4j.Logger;
100
101import com.google.common.cache.Cache;
102import com.google.common.cache.CacheBuilder;
103import com.google.common.cache.RemovalCause;
104import com.google.common.cache.RemovalNotification;
105
106/**
107 * Driver for Broadcom's OF-DPA v2.0 TTP.
108 *
109 */
110public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeliner {
111
112 protected static final int PORT_TABLE = 0;
113 protected static final int VLAN_TABLE = 10;
114 protected static final int TMAC_TABLE = 20;
115 protected static final int UNICAST_ROUTING_TABLE = 30;
116 protected static final int MULTICAST_ROUTING_TABLE = 40;
117 protected static final int MPLS_TABLE_0 = 23;
118 protected static final int MPLS_TABLE_1 = 24;
119 protected static final int BRIDGING_TABLE = 50;
120 protected static final int ACL_TABLE = 60;
121 protected static final int MAC_LEARNING_TABLE = 254;
122 protected static final long OFPP_MAX = 0xffffff00L;
123
124 private static final int HIGHEST_PRIORITY = 0xffff;
125 private static final int DEFAULT_PRIORITY = 0x8000;
126 protected static final int LOWEST_PRIORITY = 0x0;
127
128 /*
129 * Group keys are normally generated by using the next Objective id. In the
130 * case of a next objective resulting in a group chain, each group derives a
131 * group key from the next objective id in the following way:
132 * The upper 4 bits of the group-key are used to denote the position of the
133 * group in the group chain. For example, in the chain
134 * group0 --> group1 --> group2 --> port
135 * group0's group key would have the upper 4 bits as 0, group1's upper four
136 * bits would be 1, and so on
137 */
138 private static final int GROUP0MASK = 0x0;
139 private static final int GROUP1MASK = 0x10000000;
140
141 /*
142 * OFDPA requires group-id's to have a certain form.
143 * L2 Interface Groups have <4bits-0><12bits-vlanid><16bits-portid>
144 * L3 Unicast Groups have <4bits-2><28bits-index>
145 */
146 private static final int L2INTERFACEMASK = 0x0;
147 private static final int L3UNICASTMASK = 0x20000000;
148 //private static final int MPLSINTERFACEMASK = 0x90000000;
149 private static final int L3ECMPMASK = 0x70000000;
150
151 /*
152 * This driver assigns all incoming untagged packets the same VLAN ID
153 */
154 private static final short UNTAGGED_ASSIGNED_VLAN = 0xffa; // 4090
155
156
157 private final Logger log = getLogger(getClass());
158 private ServiceDirectory serviceDirectory;
159 protected FlowRuleService flowRuleService;
160 private CoreService coreService;
161 private GroupService groupService;
162 private FlowObjectiveStore flowObjectiveStore;
163 protected DeviceId deviceId;
164 protected ApplicationId driverId;
165 protected PacketService packetService;
166 protected DeviceService deviceService;
167 private InternalPacketProcessor processor = new InternalPacketProcessor();
168 private KryoNamespace appKryo = new KryoNamespace.Builder()
169 .register(KryoNamespaces.API)
170 .register(GroupKey.class)
171 .register(DefaultGroupKey.class)
172 .register(OfdpaGroupChain.class)
173 .register(byte[].class)
174 .build();
175
176 private Cache<GroupKey, OfdpaGroupChain> pendingNextObjectives;
177 private ConcurrentHashMap<GroupKey, GroupChainElem> pendingGroups;
178
179 private ScheduledExecutorService groupChecker =
180 Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
181 "ofdpa2-%d"));
182 private Set<IPCriterion> sentIpFilters = Collections.newSetFromMap(
183 new ConcurrentHashMap<IPCriterion, Boolean>());
184
185 @Override
186 public void init(DeviceId deviceId, PipelinerContext context) {
187 this.serviceDirectory = context.directory();
188 this.deviceId = deviceId;
189
190 pendingNextObjectives = CacheBuilder.newBuilder()
191 .expireAfterWrite(20, TimeUnit.SECONDS)
192 .removalListener((RemovalNotification<GroupKey, OfdpaGroupChain> notification) -> {
193 if (notification.getCause() == RemovalCause.EXPIRED) {
194 fail(notification.getValue().nextObjective(),
195 ObjectiveError.GROUPINSTALLATIONFAILED);
196 }
197 }).build();
198
199 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
200 pendingGroups = new ConcurrentHashMap<GroupKey, GroupChainElem>();
201
202 coreService = serviceDirectory.get(CoreService.class);
203 flowRuleService = serviceDirectory.get(FlowRuleService.class);
204 groupService = serviceDirectory.get(GroupService.class);
205 flowObjectiveStore = context.store();
206 packetService = serviceDirectory.get(PacketService.class);
207 deviceService = serviceDirectory.get(DeviceService.class);
208 packetService.addProcessor(processor, PacketProcessor.director(2));
209 groupService.addListener(new InnerGroupListener());
210
211 driverId = coreService.registerApplication(
212 "org.onosproject.driver.OFDPA2Pipeline");
213
214 // OF-DPA does not require initializing the pipeline as it puts default
215 // rules automatically in the hardware. However emulation of OFDPA in
216 // software switches does require table-miss-entries.
217 initializePipeline();
218
219 }
220
221 protected void initializePipeline() {
222
223 }
224
225 //////////////////////////////////////
226 // Flow Objectives
227 //////////////////////////////////////
228
229 @Override
230 public void filter(FilteringObjective filteringObjective) {
231 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
232 processFilter(filteringObjective,
233 filteringObjective.op() == Objective.Operation.ADD,
234 filteringObjective.appId());
235 } else {
236 // Note that packets that don't match the PERMIT filter are
237 // automatically denied. The DENY filter is used to deny packets
238 // that are otherwise permitted by the PERMIT filter.
239 // Use ACL table flow rules here for DENY filtering objectives
240 log.debug("filter objective other than PERMIT currently not supported");
241 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
242 }
243 }
244
245 @Override
246 public void forward(ForwardingObjective fwd) {
247 Collection<FlowRule> rules;
248 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
249
250 rules = processForward(fwd);
251 switch (fwd.op()) {
252 case ADD:
253 rules.stream()
254 .filter(rule -> rule != null)
255 .forEach(flowOpsBuilder::add);
256 break;
257 case REMOVE:
258 rules.stream()
259 .filter(rule -> rule != null)
260 .forEach(flowOpsBuilder::remove);
261 break;
262 default:
263 fail(fwd, ObjectiveError.UNKNOWN);
264 log.warn("Unknown forwarding type {}", fwd.op());
265 }
266
267
268 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
269 @Override
270 public void onSuccess(FlowRuleOperations ops) {
271 pass(fwd);
272 }
273
274 @Override
275 public void onError(FlowRuleOperations ops) {
276 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
277 }
278 }));
279
280 }
281
282 @Override
283 public void next(NextObjective nextObjective) {
284 switch (nextObjective.type()) {
285 case SIMPLE:
286 Collection<TrafficTreatment> treatments = nextObjective.next();
287 if (treatments.size() != 1) {
288 log.error("Next Objectives of type Simple should only have a "
289 + "single Traffic Treatment. Next Objective Id:{}", nextObjective.id());
290 fail(nextObjective, ObjectiveError.BADPARAMS);
291 return;
292 }
293 processSimpleNextObjective(nextObjective);
294 break;
295 case HASHED:
296 case BROADCAST:
297 case FAILOVER:
298 fail(nextObjective, ObjectiveError.UNSUPPORTED);
299 log.warn("Unsupported next objective type {}", nextObjective.type());
300 break;
301 default:
302 fail(nextObjective, ObjectiveError.UNKNOWN);
303 log.warn("Unknown next objective type {}", nextObjective.type());
304 }
305 }
306
307 //////////////////////////////////////
308 // Flow handling
309 //////////////////////////////////////
310
311 /**
312 * As per OFDPA 2.0 TTP, filtering of VLAN ids, MAC addresses (for routing)
313 * and IP addresses configured on switch ports happen in different tables.
314 * Note that IP filtering rules need to be added to the ACL table, as there
315 * is no mechanism to send to controller via IP table.
316 *
317 * @param filt the filtering objective
318 * @param install indicates whether to add or remove the objective
319 * @param applicationId the application that sent this objective
320 */
321 private void processFilter(FilteringObjective filt,
322 boolean install, ApplicationId applicationId) {
323 // This driver only processes filtering criteria defined with switch
324 // ports as the key
325 PortCriterion portCriterion = null;
326 EthCriterion ethCriterion = null;
327 VlanIdCriterion vidCriterion = null;
328 Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
329 if (!filt.key().equals(Criteria.dummy()) &&
330 filt.key().type() == Criterion.Type.IN_PORT) {
331 portCriterion = (PortCriterion) filt.key();
332 } else {
333 log.warn("No key defined in filtering objective from app: {}. Not"
334 + "processing filtering objective", applicationId);
335 fail(filt, ObjectiveError.UNKNOWN);
336 return;
337 }
338 // convert filtering conditions for switch-intfs into flowrules
339 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
340 for (Criterion criterion : filt.conditions()) {
341 if (criterion.type() == Criterion.Type.ETH_DST) {
342 ethCriterion = (EthCriterion) criterion;
343 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
344 vidCriterion = (VlanIdCriterion) criterion;
345 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
346 ips.add((IPCriterion) criterion);
347 } else {
348 log.error("Unsupported filter {}", criterion);
349 fail(filt, ObjectiveError.UNSUPPORTED);
350 return;
351 }
352 }
353
354 if (ethCriterion == null) {
355 log.debug("filtering objective missing dstMac, cannot program TMAC table");
356 } else {
357 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
358 vidCriterion, applicationId)) {
359 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
360 tmacRule, deviceId);
361 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
362 }
363 }
364
365 if (ethCriterion == null || vidCriterion == null) {
366 log.debug("filtering objective missing dstMac or vlan, cannot program"
367 + "Vlan Table");
368 } else {
369 for (FlowRule vlanRule : processVlanIdFilter(portCriterion, vidCriterion,
370 applicationId)) {
371 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
372 vlanRule, deviceId);
373 ops = install ? ops.add(vlanRule) : ops.remove(vlanRule);
374 }
375 }
376
377 for (IPCriterion ipaddr : ips) {
378 // since we ignore port information for IP rules, and the same (gateway) IP
379 // can be configured on multiple ports, we make sure that we send
380 // only a single rule to the switch.
381 if (!sentIpFilters.contains(ipaddr)) {
382 sentIpFilters.add(ipaddr);
383 log.debug("adding IP filtering rules in ACL table {} for dev: {}",
384 ipaddr, deviceId);
385 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
386 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
387 selector.matchEthType(Ethernet.TYPE_IPV4);
388 selector.matchIPDst(ipaddr.ip());
389 treatment.setOutput(PortNumber.CONTROLLER);
390 FlowRule rule = DefaultFlowRule.builder()
391 .forDevice(deviceId)
392 .withSelector(selector.build())
393 .withTreatment(treatment.build())
394 .withPriority(HIGHEST_PRIORITY)
395 .fromApp(applicationId)
396 .makePermanent()
397 .forTable(ACL_TABLE).build();
398 ops = install ? ops.add(rule) : ops.remove(rule);
399 }
400 }
401
402 // apply filtering flow rules
403 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
404 @Override
405 public void onSuccess(FlowRuleOperations ops) {
406 log.info("Applied {} filtering rules in device {}",
407 ops.stages().get(0).size(), deviceId);
408 pass(filt);
409 }
410
411 @Override
412 public void onError(FlowRuleOperations ops) {
413 log.info("Failed to apply all filtering rules in dev {}", deviceId);
414 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
415 }
416 }));
417
418 }
419
420 /**
421 * Allows untagged packets into pipeline by assigning a vlan id.
422 * Allows tagged packets into pipeline as per configured port-vlan info.
423 * @param portCriterion port on device for which this filter is programmed
424 * @param vidCriterion vlan assigned to port, or NONE for untagged
425 * @param applicationId for application programming this filter
426 * @return list of FlowRule for port-vlan filters
427 */
428 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
429 VlanIdCriterion vidCriterion,
430 ApplicationId applicationId) {
431 List<FlowRule> rules = new ArrayList<FlowRule>();
432 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
433 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
434 selector.matchVlanId(vidCriterion.vlanId());
435 if (vidCriterion.vlanId() == VlanId.NONE) {
436 // untagged packets are assigned vlans
437 treatment.pushVlan().setVlanId(VlanId.vlanId(UNTAGGED_ASSIGNED_VLAN));
438 // XXX ofdpa may require an additional vlan match on the assigned vlan
439 // and it may not require the push.
440 }
441 treatment.transition(TMAC_TABLE);
442
443 // ofdpa cannot match on ALL portnumber, so we need to use separate
444 // rules for each port.
445 List<PortNumber> portnums = new ArrayList<PortNumber>();
446 if (portCriterion.port() == PortNumber.ALL) {
447 for (Port port : deviceService.getPorts(deviceId)) {
448 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
449 portnums.add(port.number());
450 }
451 }
452 } else {
453 portnums.add(portCriterion.port());
454 }
455 for (PortNumber pnum : portnums) {
456 selector.matchInPort(pnum);
457 FlowRule rule = DefaultFlowRule.builder()
458 .forDevice(deviceId)
459 .withSelector(selector.build())
460 .withTreatment(treatment.build())
461 .withPriority(DEFAULT_PRIORITY)
462 .fromApp(applicationId)
463 .makePermanent()
464 .forTable(VLAN_TABLE).build();
465 rules.add(rule);
466 }
467 return rules;
468 }
469
470 /**
471 * Allows routed packets with correct destination MAC to be directed
472 * to unicast-IP routing table or MPLS forwarding table.
473 * XXX need to add rule for multicast routing.
474 *
475 * @param portCriterion port on device for which this filter is programmed
476 * @param ethCriterion dstMac of device for which is filter is programmed
477 * @param vidCriterion vlan assigned to port, or NONE for untagged
478 * @param applicationId for application programming this filter
479 * @return list of FlowRule for port-vlan filters
480
481 */
482 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
483 EthCriterion ethCriterion,
484 VlanIdCriterion vidCriterion,
485 ApplicationId applicationId) {
486 //handling untagged packets via assigned VLAN
487 if (vidCriterion.vlanId() == VlanId.NONE) {
488 vidCriterion = (VlanIdCriterion) Criteria
489 .matchVlanId(VlanId.vlanId(UNTAGGED_ASSIGNED_VLAN));
490 }
491 // ofdpa cannot match on ALL portnumber, so we need to use separate
492 // rules for each port.
493 List<PortNumber> portnums = new ArrayList<PortNumber>();
494 if (portCriterion.port() == PortNumber.ALL) {
495 for (Port port : deviceService.getPorts(deviceId)) {
496 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
497 portnums.add(port.number());
498 }
499 }
500 } else {
501 portnums.add(portCriterion.port());
502 }
503
504 List<FlowRule> rules = new ArrayList<FlowRule>();
505 for (PortNumber pnum : portnums) {
506 // for unicast IP packets
507 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
508 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
509 selector.matchInPort(pnum);
510 selector.matchVlanId(vidCriterion.vlanId());
511 selector.matchEthType(Ethernet.TYPE_IPV4);
512 selector.matchEthDst(ethCriterion.mac());
513 treatment.transition(UNICAST_ROUTING_TABLE);
514 FlowRule rule = DefaultFlowRule.builder()
515 .forDevice(deviceId)
516 .withSelector(selector.build())
517 .withTreatment(treatment.build())
518 .withPriority(DEFAULT_PRIORITY)
519 .fromApp(applicationId)
520 .makePermanent()
521 .forTable(TMAC_TABLE).build();
522 rules.add(rule);
523 //for MPLS packets
524 selector = DefaultTrafficSelector.builder();
525 treatment = DefaultTrafficTreatment.builder();
526 selector.matchInPort(pnum);
527 selector.matchVlanId(vidCriterion.vlanId());
528 selector.matchEthType(Ethernet.MPLS_UNICAST);
529 selector.matchEthDst(ethCriterion.mac());
530 treatment.transition(MPLS_TABLE_0);
531 rule = DefaultFlowRule.builder()
532 .forDevice(deviceId)
533 .withSelector(selector.build())
534 .withTreatment(treatment.build())
535 .withPriority(DEFAULT_PRIORITY)
536 .fromApp(applicationId)
537 .makePermanent()
538 .forTable(TMAC_TABLE).build();
539 rules.add(rule);
540 }
541 return rules;
542 }
543
544 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
545 switch (fwd.flag()) {
546 case SPECIFIC:
547 return processSpecific(fwd);
548 case VERSATILE:
549 return processVersatile(fwd);
550 default:
551 fail(fwd, ObjectiveError.UNKNOWN);
552 log.warn("Unknown forwarding flag {}", fwd.flag());
553 }
554 return Collections.emptySet();
555 }
556
557 /**
558 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
559 * ACL table.
560 * @param fwd the forwarding objective of type 'versatile'
561 * @return a collection of flow rules to be sent to the switch. An empty
562 * collection may be returned if there is a problem in processing
563 * the flow rule
564 */
565 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
566 log.info("Processing versatile forwarding objective");
567 TrafficSelector selector = fwd.selector();
568
569 EthTypeCriterion ethType =
570 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
571 if (ethType == null) {
572 log.error("Versatile forwarding objective must include ethType");
573 fail(fwd, ObjectiveError.BADPARAMS);
574 return Collections.emptySet();
575 }
576 if (fwd.nextId() == null && fwd.treatment() == null) {
577 log.error("Forwarding objective {} from {} must contain "
578 + "nextId or Treatment", fwd.selector(), fwd.appId());
579 return Collections.emptySet();
580 }
581 // XXX driver does not currently do type checking as per Tables 65-67 in
582 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
583 if (fwd.treatment() != null &&
584 fwd.treatment().allInstructions().size() == 1 &&
585 fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
586 OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
587 if (o.port() == PortNumber.CONTROLLER) {
588 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
589 .fromApp(fwd.appId())
590 .withPriority(fwd.priority())
591 .forDevice(deviceId)
592 .withSelector(fwd.selector())
593 .withTreatment(fwd.treatment())
594 .makePermanent()
595 .forTable(ACL_TABLE);
596 return Collections.singletonList(ruleBuilder.build());
597 } else {
598 log.warn("Only allowed treatments in versatile forwarding "
599 + "objectives are punts to the controller");
600 return Collections.emptySet();
601 }
602 }
603
604 if (fwd.nextId() != null) {
605 // XXX overide case
606 log.warn("versatile objective --> next Id not yet implemeted");
607 }
608 return Collections.emptySet();
609 }
610
611 /**
612 * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table
613 * (unicast or multicast) or the L2 table (mac + vlan).
614 *
615 * @param fwd the forwarding objective of type 'specific'
616 * @return a collection of flow rules. Typically there will be only one
617 * for this type of forwarding objective. An empty set may be
618 * returned if there is an issue in processing the objective.
619 */
620 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
621 log.debug("Processing specific forwarding objective");
622 TrafficSelector selector = fwd.selector();
623 EthTypeCriterion ethType =
624 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
625 // XXX currently supporting only the L3 unicast table
626 if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) {
627 fail(fwd, ObjectiveError.UNSUPPORTED);
628 return Collections.emptySet();
629 }
630
631 TrafficSelector filteredSelector =
632 DefaultTrafficSelector.builder()
633 .matchEthType(Ethernet.TYPE_IPV4)
634 .matchIPDst(
635 ((IPCriterion)
636 selector.getCriterion(Criterion.Type.IPV4_DST)).ip())
637 .build();
638
639 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
640
641 if (fwd.nextId() != null) {
642 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
643 List<GroupKey> gkeys = appKryo.deserialize(next.data());
644 Group group = groupService.getGroup(deviceId, gkeys.get(0));
645 if (group == null) {
646 log.warn("The group left!");
647 fail(fwd, ObjectiveError.GROUPMISSING);
648 return Collections.emptySet();
649 }
650 tb.deferred().group(group.id());
651 }
652 tb.transition(ACL_TABLE);
653 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
654 .fromApp(fwd.appId())
655 .withPriority(fwd.priority())
656 .forDevice(deviceId)
657 .withSelector(filteredSelector)
658 .withTreatment(tb.build());
659
660 if (fwd.permanent()) {
661 ruleBuilder.makePermanent();
662 } else {
663 ruleBuilder.makeTemporary(fwd.timeout());
664 }
665
666 ruleBuilder.forTable(UNICAST_ROUTING_TABLE);
667 return Collections.singletonList(ruleBuilder.build());
668 }
669
670 private void pass(Objective obj) {
671 if (obj.context().isPresent()) {
672 obj.context().get().onSuccess(obj);
673 }
674 }
675
676 private void fail(Objective obj, ObjectiveError error) {
677 if (obj.context().isPresent()) {
678 obj.context().get().onError(obj, error);
679 }
680 }
681
682 //////////////////////////////////////
683 // Group handling
684 //////////////////////////////////////
685
686 /**
687 * As per the OFDPA 2.0 TTP, packets are sent out of ports by using
688 * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface
689 * Group which in turns points to an output port. The Next Objective passed
690 * in by the application has to be broken up into a group chain
691 * to satisfy this TTP.
692 *
693 * @param nextObj the nextObjective of type SIMPLE
694 */
695 private void processSimpleNextObjective(NextObjective nextObj) {
696 // break up simple next objective to GroupChain objects
697 TrafficTreatment treatment = nextObj.next().iterator().next();
698 // for the l2interface group, get vlan and port info
699 // for the l3unicast group, get the src/dst mac and vlan info
700 TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder();
701 TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder();
702 VlanId vlanid = null;
703 long portNum = 0;
704 for (Instruction ins : treatment.allInstructions()) {
705 if (ins.type() == Instruction.Type.L2MODIFICATION) {
706 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
707 switch (l2ins.subtype()) {
708 case ETH_DST:
709 l3utt.setEthDst(((ModEtherInstruction) l2ins).mac());
710 break;
711 case ETH_SRC:
712 l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac());
713 break;
714 case VLAN_ID:
715 vlanid = ((ModVlanIdInstruction) l2ins).vlanId();
716 l3utt.setVlanId(vlanid);
717 break;
718 case DEC_MPLS_TTL:
719 case MPLS_LABEL:
720 case MPLS_POP:
721 case MPLS_PUSH:
722 case VLAN_PCP:
723 case VLAN_POP:
724 case VLAN_PUSH:
725 default:
726 break;
727 }
728 } else if (ins.type() == Instruction.Type.OUTPUT) {
729 portNum = ((OutputInstruction) ins).port().toLong();
730 l2itt.add(ins);
731 } else {
732 log.warn("Driver does not handle this type of TrafficTreatment"
733 + " instruction in nextObjectives: {}", ins.type());
734 }
735 }
736
737 // assemble information for ofdpa l2interface group
738 int l2gk = nextObj.id() | GROUP1MASK;
739 final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk));
740 Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum;
741
742 // assemble information for ofdpa l3unicast group
743 int l3gk = nextObj.id() | GROUP0MASK;
744 final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk));
745 Integer l3groupId = L3UNICASTMASK | (int) portNum;
746 l3utt.group(new DefaultGroupId(l2groupId));
747 GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId,
748 l3utt.build(), nextObj.appId());
749
750 // create object for local and distributed storage
751 List<GroupKey> gkeys = new ArrayList<GroupKey>();
752 gkeys.add(l3groupkey); // group0 in chain
753 gkeys.add(l2groupkey); // group1 in chain
754 OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj);
755
756 // store l2groupkey with the groupChainElem for the l3group that depends on it
757 pendingGroups.put(l2groupkey, gce);
758
759 // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it
760 pendingNextObjectives.put(l3groupkey, ofdpaGrp);
761
762 // create group description for the ofdpa l2interfacegroup and send to groupservice
763 GroupBucket bucket =
764 DefaultGroupBucket.createIndirectGroupBucket(l2itt.build());
765 GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
766 GroupDescription.Type.INDIRECT,
767 new GroupBuckets(Collections.singletonList(bucket)),
768 l2groupkey,
769 l2groupId,
770 nextObj.appId());
771 groupService.addGroup(groupDescription);
772 }
773
774 /**
775 * Processes next element of a group chain. Assumption is that if this
776 * group points to another group, the latter has already been created
777 * and this driver has received notification for it. A second assumption is
778 * that if there is another group waiting for this group then the appropriate
779 * stores already have the information to act upon the notification for the
780 * creating of this group.
781 *
782 * @param gce the group chain element to be processed next
783 */
784 private void processGroupChain(GroupChainElem gce) {
785 GroupBucket bucket = DefaultGroupBucket
786 .createIndirectGroupBucket(gce.getBucketActions());
787 GroupDescription groupDesc = new DefaultGroupDescription(deviceId,
788 GroupDescription.Type.INDIRECT,
789 new GroupBuckets(Collections.singletonList(bucket)),
790 gce.getGkey(),
791 gce.getGivenGroupId(),
792 gce.getAppId());
793 groupService.addGroup(groupDesc);
794 }
795
796
797 private class GroupChecker implements Runnable {
798 @Override
799 public void run() {
800 Set<GroupKey> keys = pendingGroups.keySet().stream()
801 .filter(key -> groupService.getGroup(deviceId, key) != null)
802 .collect(Collectors.toSet());
803 Set<GroupKey> otherkeys = pendingNextObjectives.asMap().keySet().stream()
804 .filter(otherkey -> groupService.getGroup(deviceId, otherkey) != null)
805 .collect(Collectors.toSet());
806 keys.addAll(otherkeys);
807
808 keys.stream().forEach(key -> {
809 //first check for group chain
810 GroupChainElem gce = pendingGroups.remove(key);
811 if (gce != null) {
812 log.info("Group service processed group key {}. Processing next "
813 + "group in group chain with group key {}",
814 appKryo.deserialize(key.key()),
815 appKryo.deserialize(gce.getGkey().key()));
816 processGroupChain(gce);
817 } else {
818 OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key);
819 log.info("Group service processed group key {}. Done implementing "
820 + "next objective: {}", appKryo.deserialize(key.key()),
821 obj.nextObjective().id());
822 if (obj != null) {
823 pass(obj.nextObjective());
824 pendingNextObjectives.invalidate(key);
825 flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj);
826 }
827 }
828 });
829 }
830 }
831
832 private class InnerGroupListener implements GroupListener {
833 @Override
834 public void event(GroupEvent event) {
835 log.debug("received group event of type {}", event.type());
836 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
837 GroupKey key = event.subject().appCookie();
838 // first check for group chain
839 GroupChainElem gce = pendingGroups.remove(key);
840 if (gce != null) {
841 log.info("group ADDED with group key {} .. "
842 + "Processing next group in group chain with group key {}",
843 appKryo.deserialize(key.key()),
844 appKryo.deserialize(gce.getGkey().key()));
845 processGroupChain(gce);
846 } else {
847 OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key);
848 if (obj != null) {
849 log.info("group ADDED with key {}.. Done implementing next "
850 + "objective: {}",
851 appKryo.deserialize(key.key()), obj.nextObjective().id());
852 pass(obj.nextObjective());
853 pendingNextObjectives.invalidate(key);
854 flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj);
855 }
856 }
857 }
858 }
859 }
860
861 /**
862 * Represents a group-chain that implements a Next-Objective from
863 * the application. Includes information about the next objective Id, and the
864 * group keys for the groups in the group chain. The chain is expected to
865 * look like group0 --> group 1 --> outPort. Information about the groups
866 * themselves can be fetched from the Group Service using the group keys from
867 * objects instantiating this class.
868 */
869 private class OfdpaGroupChain implements NextGroup {
870 private final NextObjective nextObj;
871 private final List<GroupKey> gkeys;
872
873 /** expected group chain: group0 --> group1 --> port. */
874 public OfdpaGroupChain(List<GroupKey> gkeys, NextObjective nextObj) {
875 this.gkeys = gkeys;
876 this.nextObj = nextObj;
877 }
878
879 @SuppressWarnings("unused")
880 public List<GroupKey> groupKeys() {
881 return gkeys;
882 }
883
884 public NextObjective nextObjective() {
885 return nextObj;
886 }
887
888 @Override
889 public byte[] data() {
890 return appKryo.serialize(gkeys);
891 }
892
893 }
894
895 /**
896 * Represents a group element that is part of a chain of groups.
897 * Stores enough information to create a Group Description to add the group
898 * to the switch by requesting the Group Service. Objects instantiating this
899 * class are meant to be temporary and live as long as it is needed to wait for
900 * preceding groups in the group chain to be created.
901 */
902 private class GroupChainElem {
903 private TrafficTreatment bucketActions;
904 private Integer givenGroupId;
905 private GroupKey gkey;
906 private ApplicationId appId;
907
908 public GroupChainElem(GroupKey gkey, Integer givenGroupId,
909 TrafficTreatment tr, ApplicationId appId) {
910 this.bucketActions = tr;
911 this.givenGroupId = givenGroupId;
912 this.gkey = gkey;
913 this.appId = appId;
914 }
915
916 public TrafficTreatment getBucketActions() {
917 return bucketActions;
918 }
919
920 public Integer getGivenGroupId() {
921 return givenGroupId;
922 }
923
924 public GroupKey getGkey() {
925 return gkey;
926 }
927
928 public ApplicationId getAppId() {
929 return appId;
930 }
931
932 }
933
934 //////////////////////////////////////
935 // Test code to be used for future
936 // static-flow-pusher app
937 //////////////////////////////////////
938
939 public void processStaticFlows() {
940 //processPortTable();
941 processGroupTable();
942 processVlanTable();
943 processTmacTable();
944 processIpTable();
945 //processMcastTable();
946 //processBridgingTable();
947 processAclTable();
948 sendPackets();
949 processMplsTable();
950 }
951
952 protected void processGroupTable() {
953 TrafficTreatment.Builder act = DefaultTrafficTreatment.builder();
954
955 act.popVlan(); // to send out untagged packets
956 act.setOutput(PortNumber.portNumber(24));
957 GroupBucket bucket =
958 DefaultGroupBucket.createIndirectGroupBucket(act.build());
959 final GroupKey groupkey = new DefaultGroupKey(appKryo.serialize(500));
960 Integer groupId = 0x00c80018; //l2 interface, vlan 200, port 24
961 GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
962 GroupDescription.Type.INDIRECT,
963 new GroupBuckets(Collections.singletonList(bucket)),
964 groupkey,
965 groupId,
966 driverId);
967 groupService.addGroup(groupDescription);
968
969 TrafficTreatment.Builder act2 = DefaultTrafficTreatment.builder();
970 act2.setOutput(PortNumber.portNumber(40));
971 GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(act2.build());
972 final GroupKey groupkey2 = new DefaultGroupKey(appKryo.serialize(502));
973 Integer groupId2 = 0x00c50028; //l2 interface, vlan 197, port 40
974 GroupDescription groupDescription2 = new DefaultGroupDescription(deviceId,
975 GroupDescription.Type.INDIRECT,
976 new GroupBuckets(Collections.singletonList(bucket2)),
977 groupkey2,
978 groupId2,
979 driverId);
980 groupService.addGroup(groupDescription2);
981
982 while (groupService.getGroup(deviceId, groupkey2) == null) {
983 try {
984 Thread.sleep(500);
985 } catch (InterruptedException e) {
986 // TODO Auto-generated catch block
987 e.printStackTrace();
988 }
989 }
990
991 //Now for L3 Unicast group
992 TrafficTreatment.Builder act3 = DefaultTrafficTreatment.builder();
993 act3.setEthDst(MacAddress.valueOf(0x2020));
994 act3.setEthSrc(MacAddress.valueOf(0x1010));
995 act3.setVlanId(VlanId.vlanId((short) 200));
996 act3.group(new DefaultGroupId(0x00c80018)); // point to L2 interface
997 // MPLS interface group - does not work for popping single label
998 //Integer secGroupId = MPLSINTERFACEMASK | 38; // 0x90000026
999 Integer groupId3 = L3UNICASTMASK | 1; // 0x20000001
1000 GroupBucket bucket3 =
1001 DefaultGroupBucket.createIndirectGroupBucket(act3.build());
1002 final GroupKey groupkey3 = new DefaultGroupKey(appKryo.serialize(503));
1003 GroupDescription groupDescription3 = new DefaultGroupDescription(deviceId,
1004 GroupDescription.Type.INDIRECT,
1005 new GroupBuckets(Collections.singletonList(bucket3)),
1006 groupkey3,
1007 groupId3,
1008 driverId);
1009 groupService.addGroup(groupDescription3);
1010
1011 //Another L3 Unicast group
1012 TrafficTreatment.Builder act4 = DefaultTrafficTreatment.builder();
1013 act4.setEthDst(MacAddress.valueOf(0x3030));
1014 act4.setEthSrc(MacAddress.valueOf(0x1010));
1015 act4.setVlanId(VlanId.vlanId((short) 197));
1016 act4.group(new DefaultGroupId(0x00c50028)); // point to L2 interface
1017 Integer groupId4 = L3UNICASTMASK | 2; // 0x20000002
1018 GroupBucket bucket4 =
1019 DefaultGroupBucket.createIndirectGroupBucket(act4.build());
1020 final GroupKey groupkey4 = new DefaultGroupKey(appKryo.serialize(504));
1021 GroupDescription groupDescription4 = new DefaultGroupDescription(deviceId,
1022 GroupDescription.Type.INDIRECT,
1023 new GroupBuckets(Collections.singletonList(bucket4)),
1024 groupkey4,
1025 groupId4,
1026 driverId);
1027 groupService.addGroup(groupDescription4);
1028
1029 while (groupService.getGroup(deviceId, groupkey4) == null) {
1030 try {
1031 Thread.sleep(500);
1032 } catch (InterruptedException e) {
1033 // TODO Auto-generated catch block
1034 e.printStackTrace();
1035 }
1036 }
1037
1038 // L3 ecmp group
1039 TrafficTreatment.Builder act5 = DefaultTrafficTreatment.builder();
1040 act5.group(new DefaultGroupId(0x20000001));
1041 TrafficTreatment.Builder act6 = DefaultTrafficTreatment.builder();
1042 act6.group(new DefaultGroupId(0x20000002));
1043 GroupBucket buckete1 =
1044 DefaultGroupBucket.createSelectGroupBucket(act5.build());
1045 GroupBucket buckete2 =
1046 DefaultGroupBucket.createSelectGroupBucket(act6.build());
1047 List<GroupBucket> bktlist = new ArrayList<GroupBucket>();
1048 bktlist.add(buckete1);
1049 bktlist.add(buckete2);
1050 final GroupKey groupkey5 = new DefaultGroupKey(appKryo.serialize(505));
1051 Integer groupId5 = L3ECMPMASK | 5; // 0x70000005
1052 GroupDescription groupDescription5 = new DefaultGroupDescription(deviceId,
1053 GroupDescription.Type.SELECT,
1054 new GroupBuckets(bktlist),
1055 groupkey5,
1056 groupId5,
1057 driverId);
1058 groupService.addGroup(groupDescription5);
1059
1060
1061 }
1062
1063 @SuppressWarnings("deprecation")
1064 protected void processMplsTable() {
1065 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1066 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1067 selector.matchEthType(Ethernet.MPLS_UNICAST);
1068 selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); //255
1069 selector.matchMplsBos(true);
1070 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1071 treatment.decMplsTtl(); // nw_ttl does not work
1072 treatment.copyTtlIn();
1073 treatment.popMpls(Ethernet.TYPE_IPV4);
1074 treatment.deferred().group(new DefaultGroupId(0x20000001)); // point to L3 Unicast
1075 //treatment.deferred().group(new DefaultGroupId(0x70000005)); // point to L3 ECMP
1076 treatment.transition(ACL_TABLE);
1077 FlowRule test = DefaultFlowRule.builder().forDevice(deviceId)
1078 .withSelector(selector.build()).withTreatment(treatment.build())
1079 .withPriority(DEFAULT_PRIORITY).fromApp(driverId).makePermanent()
1080 .forTable(24).build();
1081 ops = ops.add(test);
1082
1083 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1084 @Override
1085 public void onSuccess(FlowRuleOperations ops) {
1086 log.info("Initialized mpls table");
1087 }
1088
1089 @Override
1090 public void onError(FlowRuleOperations ops) {
1091 log.info("Failed to initialize mpls table");
1092 }
1093 }));
1094
1095 }
1096
1097 protected void processPortTable() {
1098 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1099 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1100 selector.matchInPort(PortNumber.portNumber(0)); // should be maskable?
1101 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1102 treatment.transition(VLAN_TABLE);
1103 FlowRule tmisse = DefaultFlowRule.builder()
1104 .forDevice(deviceId)
1105 .withSelector(selector.build())
1106 .withTreatment(treatment.build())
1107 .withPriority(LOWEST_PRIORITY)
1108 .fromApp(driverId)
1109 .makePermanent()
1110 .forTable(PORT_TABLE).build();
1111 ops = ops.add(tmisse);
1112
1113 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1114 @Override
1115 public void onSuccess(FlowRuleOperations ops) {
1116 log.info("Initialized port table");
1117 }
1118
1119 @Override
1120 public void onError(FlowRuleOperations ops) {
1121 log.info("Failed to initialize port table");
1122 }
1123 }));
1124
1125 }
1126
1127 private void processVlanTable() {
1128 // Table miss entry is not required as ofdpa default is to drop
1129 // In OF terms, the absence of a t.m.e. also implies drop
1130 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1131 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1132 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1133 selector.matchInPort(PortNumber.portNumber(12));
1134 selector.matchVlanId(VlanId.vlanId((short) 100));
1135 treatment.transition(TMAC_TABLE);
1136 FlowRule rule = DefaultFlowRule.builder()
1137 .forDevice(deviceId)
1138 .withSelector(selector.build())
1139 .withTreatment(treatment.build())
1140 .withPriority(DEFAULT_PRIORITY)
1141 .fromApp(driverId)
1142 .makePermanent()
1143 .forTable(VLAN_TABLE).build();
1144 ops = ops.add(rule);
1145 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1146 @Override
1147 public void onSuccess(FlowRuleOperations ops) {
1148 log.info("Initialized vlan table");
1149 }
1150
1151 @Override
1152 public void onError(FlowRuleOperations ops) {
1153 log.info("Failed to initialize vlan table");
1154 }
1155 }));
1156 }
1157
1158 protected void processTmacTable() {
1159 //table miss entry
1160 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1161 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1162 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1163 selector.matchInPort(PortNumber.portNumber(12));
1164 selector.matchVlanId(VlanId.vlanId((short) 100));
1165 selector.matchEthType(Ethernet.TYPE_IPV4);
1166 selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
1167 treatment.transition(UNICAST_ROUTING_TABLE);
1168 FlowRule rule = DefaultFlowRule.builder()
1169 .forDevice(deviceId)
1170 .withSelector(selector.build())
1171 .withTreatment(treatment.build())
1172 .withPriority(DEFAULT_PRIORITY)
1173 .fromApp(driverId)
1174 .makePermanent()
1175 .forTable(TMAC_TABLE).build();
1176 ops = ops.add(rule);
1177
1178 selector.matchEthType(Ethernet.MPLS_UNICAST);
1179 treatment.transition(MPLS_TABLE_0);
1180 FlowRule rulempls = DefaultFlowRule.builder()
1181 .forDevice(deviceId)
1182 .withSelector(selector.build())
1183 .withTreatment(treatment.build())
1184 .withPriority(DEFAULT_PRIORITY)
1185 .fromApp(driverId)
1186 .makePermanent()
1187 .forTable(TMAC_TABLE).build();
1188 ops = ops.add(rulempls);
1189
1190 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1191 @Override
1192 public void onSuccess(FlowRuleOperations ops) {
1193 log.info("Initialized tmac table");
1194 }
1195
1196 @Override
1197 public void onError(FlowRuleOperations ops) {
1198 log.info("Failed to initialize tmac table");
1199 }
1200 }));
1201 }
1202
1203 protected void processIpTable() {
1204 //table miss entry
1205 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1206 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1207 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1208 selector.matchEthType(Ethernet.TYPE_IPV4);
1209 selector.matchIPDst(IpPrefix.valueOf("2.0.0.0/16"));
1210 treatment.deferred().group(new DefaultGroupId(0x20000001));
1211 treatment.transition(ACL_TABLE);
1212 FlowRule rule = DefaultFlowRule.builder()
1213 .forDevice(deviceId)
1214 .withSelector(selector.build())
1215 .withTreatment(treatment.build())
1216 .withPriority(30000)
1217 .fromApp(driverId)
1218 .makePermanent()
1219 .forTable(UNICAST_ROUTING_TABLE).build();
1220 ops = ops.add(rule);
1221 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1222 @Override
1223 public void onSuccess(FlowRuleOperations ops) {
1224 log.info("Initialized IP table");
1225 }
1226
1227 @Override
1228 public void onError(FlowRuleOperations ops) {
1229 log.info("Failed to initialize unicast IP table");
1230 }
1231 }));
1232 }
1233
1234 protected void processAclTable() {
1235 //table miss entry
1236 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1237 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1238 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1239 selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
1240 treatment.deferred().group(new DefaultGroupId(0x20000001));
1241 FlowRule rule = DefaultFlowRule.builder()
1242 .forDevice(deviceId)
1243 .withSelector(selector.build())
1244 .withTreatment(treatment.build())
1245 .withPriority(60000)
1246 .fromApp(driverId)
1247 .makePermanent()
1248 .forTable(ACL_TABLE).build();
1249 ops = ops.add(rule);
1250 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1251 @Override
1252 public void onSuccess(FlowRuleOperations ops) {
1253 log.info("Initialized Acl table");
1254 }
1255
1256 @Override
1257 public void onError(FlowRuleOperations ops) {
1258 log.info("Failed to initialize Acl table");
1259 }
1260 }));
1261 }
1262
1263 private void sendPackets() {
1264 Ethernet eth = new Ethernet();
1265 eth.setDestinationMACAddress("00:00:00:00:00:02");
1266 eth.setSourceMACAddress("00:00:00:11:22:33");
1267 eth.setVlanID((short) 100);
1268 eth.setEtherType(Ethernet.MPLS_UNICAST);
1269 MPLS mplsPkt = new MPLS();
1270 mplsPkt.setLabel(255);
1271 mplsPkt.setTtl((byte) 5);
1272
1273 IPv4 ipv4 = new IPv4();
1274
1275 ipv4.setDestinationAddress("4.0.5.6");
1276 ipv4.setSourceAddress("1.0.2.3");
1277 ipv4.setTtl((byte) 64);
1278 ipv4.setChecksum((short) 0);
1279
1280 UDP udp = new UDP();
1281 udp.setDestinationPort(666);
1282 udp.setSourcePort(333);
1283 udp.setPayload(new Data(new byte[]{(byte) 1, (byte) 2}));
1284 udp.setChecksum((short) 0);
1285
1286 ipv4.setPayload(udp);
1287 mplsPkt.setPayload(ipv4);
1288 eth.setPayload(mplsPkt);
1289
1290 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1291 .setOutput(PortNumber.portNumber(24))
1292 .build();
1293 OutboundPacket packet = new DefaultOutboundPacket(deviceId,
1294 treatment,
1295 ByteBuffer.wrap(eth.serialize()));
1296
1297
1298 Ethernet eth2 = new Ethernet();
1299 eth2.setDestinationMACAddress("00:00:00:00:00:02");
1300 eth2.setSourceMACAddress("00:00:00:11:22:33");
1301 eth2.setVlanID((short) 100);
1302 eth2.setEtherType(Ethernet.TYPE_IPV4);
1303
1304 IPv4 ipv42 = new IPv4();
1305 ipv42.setDestinationAddress("2.0.0.2");
1306 ipv42.setSourceAddress("1.0.9.9");
1307 ipv42.setTtl((byte) 64);
1308 ipv42.setChecksum((short) 0);
1309
1310 UDP udp2 = new UDP();
1311 udp2.setDestinationPort(999);
1312 udp2.setSourcePort(333);
1313 udp2.setPayload(new Data(new byte[]{(byte) 1, (byte) 2}));
1314 udp2.setChecksum((short) 0);
1315
1316 ipv42.setPayload(udp2);
1317 eth2.setPayload(ipv42);
1318
1319 TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
1320 .setOutput(PortNumber.portNumber(26))
1321 .build();
1322 OutboundPacket packet2 = new DefaultOutboundPacket(deviceId,
1323 treatment2,
1324 ByteBuffer.wrap(eth2.serialize()));
1325
1326
1327 log.info("Emitting packets now");
1328 packetService.emit(packet);
1329 packetService.emit(packet);
1330 packetService.emit(packet2);
1331 packetService.emit(packet);
1332 packetService.emit(packet);
1333 log.info("Done emitting packets");
1334 }
1335
1336 private class InternalPacketProcessor implements PacketProcessor {
1337
1338 @Override
1339 public void process(PacketContext context) {
1340
1341
1342 }
1343 }
1344
1345}