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