blob: e63a404c6fab93c38005a572ab024eb46592cb12 [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;
Saurav Das2857f382015-11-03 14:39:27 -0800125 protected static final int DEFAULT_PRIORITY = 0x8000;
Saurav Das822c4e22015-10-23 10:51:11 -0700126 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 Das2857f382015-11-03 14:39:27 -0800461 // XXX ofdpa will require an additional vlan match on the assigned vlan
462 // and it may not require the push. This is not in compliance with OF
463 // standard. Waiting on what the exact flows are going to look like.
Saurav Das822c4e22015-10-23 10:51:11 -0700464 }
465 treatment.transition(TMAC_TABLE);
466
467 // ofdpa cannot match on ALL portnumber, so we need to use separate
468 // rules for each port.
469 List<PortNumber> portnums = new ArrayList<PortNumber>();
470 if (portCriterion.port() == PortNumber.ALL) {
471 for (Port port : deviceService.getPorts(deviceId)) {
472 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
473 portnums.add(port.number());
474 }
475 }
476 } else {
477 portnums.add(portCriterion.port());
478 }
479 for (PortNumber pnum : portnums) {
480 selector.matchInPort(pnum);
481 FlowRule rule = DefaultFlowRule.builder()
482 .forDevice(deviceId)
483 .withSelector(selector.build())
484 .withTreatment(treatment.build())
485 .withPriority(DEFAULT_PRIORITY)
486 .fromApp(applicationId)
487 .makePermanent()
488 .forTable(VLAN_TABLE).build();
489 rules.add(rule);
490 }
491 return rules;
492 }
493
494 /**
495 * Allows routed packets with correct destination MAC to be directed
496 * to unicast-IP routing table or MPLS forwarding table.
497 * XXX need to add rule for multicast routing.
498 *
499 * @param portCriterion port on device for which this filter is programmed
500 * @param ethCriterion dstMac of device for which is filter is programmed
501 * @param vidCriterion vlan assigned to port, or NONE for untagged
Saurav Das0e99e2b2015-10-28 12:39:42 -0700502 * @param assignedVlan assigned vlan-id for untagged packets
Saurav Das822c4e22015-10-23 10:51:11 -0700503 * @param applicationId for application programming this filter
504 * @return list of FlowRule for port-vlan filters
505
506 */
507 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
508 EthCriterion ethCriterion,
509 VlanIdCriterion vidCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700510 VlanId assignedVlan,
Saurav Das822c4e22015-10-23 10:51:11 -0700511 ApplicationId applicationId) {
512 //handling untagged packets via assigned VLAN
513 if (vidCriterion.vlanId() == VlanId.NONE) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700514 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
Saurav Das822c4e22015-10-23 10:51:11 -0700515 }
516 // ofdpa cannot match on ALL portnumber, so we need to use separate
517 // rules for each port.
518 List<PortNumber> portnums = new ArrayList<PortNumber>();
519 if (portCriterion.port() == PortNumber.ALL) {
520 for (Port port : deviceService.getPorts(deviceId)) {
521 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
522 portnums.add(port.number());
523 }
524 }
525 } else {
526 portnums.add(portCriterion.port());
527 }
528
529 List<FlowRule> rules = new ArrayList<FlowRule>();
530 for (PortNumber pnum : portnums) {
531 // for unicast IP packets
532 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
533 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
534 selector.matchInPort(pnum);
535 selector.matchVlanId(vidCriterion.vlanId());
536 selector.matchEthType(Ethernet.TYPE_IPV4);
537 selector.matchEthDst(ethCriterion.mac());
538 treatment.transition(UNICAST_ROUTING_TABLE);
539 FlowRule rule = DefaultFlowRule.builder()
540 .forDevice(deviceId)
541 .withSelector(selector.build())
542 .withTreatment(treatment.build())
543 .withPriority(DEFAULT_PRIORITY)
544 .fromApp(applicationId)
545 .makePermanent()
546 .forTable(TMAC_TABLE).build();
547 rules.add(rule);
548 //for MPLS packets
549 selector = DefaultTrafficSelector.builder();
550 treatment = DefaultTrafficTreatment.builder();
551 selector.matchInPort(pnum);
552 selector.matchVlanId(vidCriterion.vlanId());
553 selector.matchEthType(Ethernet.MPLS_UNICAST);
554 selector.matchEthDst(ethCriterion.mac());
555 treatment.transition(MPLS_TABLE_0);
556 rule = DefaultFlowRule.builder()
557 .forDevice(deviceId)
558 .withSelector(selector.build())
559 .withTreatment(treatment.build())
560 .withPriority(DEFAULT_PRIORITY)
561 .fromApp(applicationId)
562 .makePermanent()
563 .forTable(TMAC_TABLE).build();
564 rules.add(rule);
565 }
566 return rules;
567 }
568
569 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
570 switch (fwd.flag()) {
571 case SPECIFIC:
572 return processSpecific(fwd);
573 case VERSATILE:
574 return processVersatile(fwd);
575 default:
576 fail(fwd, ObjectiveError.UNKNOWN);
577 log.warn("Unknown forwarding flag {}", fwd.flag());
578 }
579 return Collections.emptySet();
580 }
581
582 /**
583 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
584 * ACL table.
585 * @param fwd the forwarding objective of type 'versatile'
586 * @return a collection of flow rules to be sent to the switch. An empty
587 * collection may be returned if there is a problem in processing
588 * the flow rule
589 */
590 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
591 log.info("Processing versatile forwarding objective");
592 TrafficSelector selector = fwd.selector();
593
594 EthTypeCriterion ethType =
595 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
596 if (ethType == null) {
597 log.error("Versatile forwarding objective must include ethType");
598 fail(fwd, ObjectiveError.BADPARAMS);
599 return Collections.emptySet();
600 }
601 if (fwd.nextId() == null && fwd.treatment() == null) {
602 log.error("Forwarding objective {} from {} must contain "
603 + "nextId or Treatment", fwd.selector(), fwd.appId());
604 return Collections.emptySet();
605 }
606 // XXX driver does not currently do type checking as per Tables 65-67 in
607 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
608 if (fwd.treatment() != null &&
609 fwd.treatment().allInstructions().size() == 1 &&
610 fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
611 OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
612 if (o.port() == PortNumber.CONTROLLER) {
613 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
614 .fromApp(fwd.appId())
615 .withPriority(fwd.priority())
616 .forDevice(deviceId)
617 .withSelector(fwd.selector())
618 .withTreatment(fwd.treatment())
619 .makePermanent()
620 .forTable(ACL_TABLE);
621 return Collections.singletonList(ruleBuilder.build());
622 } else {
623 log.warn("Only allowed treatments in versatile forwarding "
624 + "objectives are punts to the controller");
625 return Collections.emptySet();
626 }
627 }
628
629 if (fwd.nextId() != null) {
630 // XXX overide case
631 log.warn("versatile objective --> next Id not yet implemeted");
632 }
633 return Collections.emptySet();
634 }
635
636 /**
637 * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table
638 * (unicast or multicast) or the L2 table (mac + vlan).
639 *
640 * @param fwd the forwarding objective of type 'specific'
641 * @return a collection of flow rules. Typically there will be only one
642 * for this type of forwarding objective. An empty set may be
643 * returned if there is an issue in processing the objective.
644 */
645 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
646 log.debug("Processing specific forwarding objective");
647 TrafficSelector selector = fwd.selector();
648 EthTypeCriterion ethType =
649 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
650 // XXX currently supporting only the L3 unicast table
651 if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) {
652 fail(fwd, ObjectiveError.UNSUPPORTED);
653 return Collections.emptySet();
654 }
655
656 TrafficSelector filteredSelector =
657 DefaultTrafficSelector.builder()
658 .matchEthType(Ethernet.TYPE_IPV4)
659 .matchIPDst(
660 ((IPCriterion)
661 selector.getCriterion(Criterion.Type.IPV4_DST)).ip())
662 .build();
663
664 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
665
666 if (fwd.nextId() != null) {
667 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
668 List<GroupKey> gkeys = appKryo.deserialize(next.data());
669 Group group = groupService.getGroup(deviceId, gkeys.get(0));
670 if (group == null) {
671 log.warn("The group left!");
672 fail(fwd, ObjectiveError.GROUPMISSING);
673 return Collections.emptySet();
674 }
675 tb.deferred().group(group.id());
676 }
677 tb.transition(ACL_TABLE);
678 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
679 .fromApp(fwd.appId())
680 .withPriority(fwd.priority())
681 .forDevice(deviceId)
682 .withSelector(filteredSelector)
683 .withTreatment(tb.build());
684
685 if (fwd.permanent()) {
686 ruleBuilder.makePermanent();
687 } else {
688 ruleBuilder.makeTemporary(fwd.timeout());
689 }
690
691 ruleBuilder.forTable(UNICAST_ROUTING_TABLE);
692 return Collections.singletonList(ruleBuilder.build());
693 }
694
695 private void pass(Objective obj) {
696 if (obj.context().isPresent()) {
697 obj.context().get().onSuccess(obj);
698 }
699 }
700
701 private void fail(Objective obj, ObjectiveError error) {
702 if (obj.context().isPresent()) {
703 obj.context().get().onError(obj, error);
704 }
705 }
706
707 //////////////////////////////////////
708 // Group handling
709 //////////////////////////////////////
710
711 /**
712 * As per the OFDPA 2.0 TTP, packets are sent out of ports by using
713 * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface
714 * Group which in turns points to an output port. The Next Objective passed
715 * in by the application has to be broken up into a group chain
716 * to satisfy this TTP.
717 *
718 * @param nextObj the nextObjective of type SIMPLE
719 */
720 private void processSimpleNextObjective(NextObjective nextObj) {
721 // break up simple next objective to GroupChain objects
722 TrafficTreatment treatment = nextObj.next().iterator().next();
723 // for the l2interface group, get vlan and port info
724 // for the l3unicast group, get the src/dst mac and vlan info
725 TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder();
726 TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder();
727 VlanId vlanid = null;
728 long portNum = 0;
729 for (Instruction ins : treatment.allInstructions()) {
730 if (ins.type() == Instruction.Type.L2MODIFICATION) {
731 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
732 switch (l2ins.subtype()) {
733 case ETH_DST:
734 l3utt.setEthDst(((ModEtherInstruction) l2ins).mac());
735 break;
736 case ETH_SRC:
737 l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac());
738 break;
739 case VLAN_ID:
740 vlanid = ((ModVlanIdInstruction) l2ins).vlanId();
741 l3utt.setVlanId(vlanid);
742 break;
743 case DEC_MPLS_TTL:
744 case MPLS_LABEL:
745 case MPLS_POP:
746 case MPLS_PUSH:
747 case VLAN_PCP:
748 case VLAN_POP:
749 case VLAN_PUSH:
750 default:
751 break;
752 }
753 } else if (ins.type() == Instruction.Type.OUTPUT) {
754 portNum = ((OutputInstruction) ins).port().toLong();
755 l2itt.add(ins);
756 } else {
757 log.warn("Driver does not handle this type of TrafficTreatment"
758 + " instruction in nextObjectives: {}", ins.type());
759 }
760 }
761
762 // assemble information for ofdpa l2interface group
763 int l2gk = nextObj.id() | GROUP1MASK;
764 final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk));
765 Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum;
766
767 // assemble information for ofdpa l3unicast group
768 int l3gk = nextObj.id() | GROUP0MASK;
769 final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk));
770 Integer l3groupId = L3UNICASTMASK | (int) portNum;
771 l3utt.group(new DefaultGroupId(l2groupId));
772 GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId,
773 l3utt.build(), nextObj.appId());
774
775 // create object for local and distributed storage
776 List<GroupKey> gkeys = new ArrayList<GroupKey>();
777 gkeys.add(l3groupkey); // group0 in chain
778 gkeys.add(l2groupkey); // group1 in chain
779 OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj);
780
781 // store l2groupkey with the groupChainElem for the l3group that depends on it
782 pendingGroups.put(l2groupkey, gce);
783
784 // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it
785 pendingNextObjectives.put(l3groupkey, ofdpaGrp);
786
787 // create group description for the ofdpa l2interfacegroup and send to groupservice
788 GroupBucket bucket =
789 DefaultGroupBucket.createIndirectGroupBucket(l2itt.build());
790 GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
791 GroupDescription.Type.INDIRECT,
792 new GroupBuckets(Collections.singletonList(bucket)),
793 l2groupkey,
794 l2groupId,
795 nextObj.appId());
796 groupService.addGroup(groupDescription);
797 }
798
799 /**
800 * Processes next element of a group chain. Assumption is that if this
801 * group points to another group, the latter has already been created
802 * and this driver has received notification for it. A second assumption is
803 * that if there is another group waiting for this group then the appropriate
804 * stores already have the information to act upon the notification for the
805 * creating of this group.
806 *
807 * @param gce the group chain element to be processed next
808 */
809 private void processGroupChain(GroupChainElem gce) {
810 GroupBucket bucket = DefaultGroupBucket
811 .createIndirectGroupBucket(gce.getBucketActions());
812 GroupDescription groupDesc = new DefaultGroupDescription(deviceId,
813 GroupDescription.Type.INDIRECT,
814 new GroupBuckets(Collections.singletonList(bucket)),
815 gce.getGkey(),
816 gce.getGivenGroupId(),
817 gce.getAppId());
818 groupService.addGroup(groupDesc);
819 }
820
821
822 private class GroupChecker implements Runnable {
823 @Override
824 public void run() {
825 Set<GroupKey> keys = pendingGroups.keySet().stream()
826 .filter(key -> groupService.getGroup(deviceId, key) != null)
827 .collect(Collectors.toSet());
828 Set<GroupKey> otherkeys = pendingNextObjectives.asMap().keySet().stream()
829 .filter(otherkey -> groupService.getGroup(deviceId, otherkey) != null)
830 .collect(Collectors.toSet());
831 keys.addAll(otherkeys);
832
833 keys.stream().forEach(key -> {
834 //first check for group chain
835 GroupChainElem gce = pendingGroups.remove(key);
836 if (gce != null) {
837 log.info("Group service processed group key {}. Processing next "
838 + "group in group chain with group key {}",
839 appKryo.deserialize(key.key()),
840 appKryo.deserialize(gce.getGkey().key()));
841 processGroupChain(gce);
842 } else {
843 OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key);
844 log.info("Group service processed group key {}. Done implementing "
845 + "next objective: {}", appKryo.deserialize(key.key()),
846 obj.nextObjective().id());
847 if (obj != null) {
848 pass(obj.nextObjective());
849 pendingNextObjectives.invalidate(key);
850 flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj);
851 }
852 }
853 });
854 }
855 }
856
857 private class InnerGroupListener implements GroupListener {
858 @Override
859 public void event(GroupEvent event) {
860 log.debug("received group event of type {}", event.type());
861 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
862 GroupKey key = event.subject().appCookie();
863 // first check for group chain
864 GroupChainElem gce = pendingGroups.remove(key);
865 if (gce != null) {
866 log.info("group ADDED with group key {} .. "
867 + "Processing next group in group chain with group key {}",
868 appKryo.deserialize(key.key()),
869 appKryo.deserialize(gce.getGkey().key()));
870 processGroupChain(gce);
871 } else {
872 OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key);
873 if (obj != null) {
874 log.info("group ADDED with key {}.. Done implementing next "
875 + "objective: {}",
876 appKryo.deserialize(key.key()), obj.nextObjective().id());
877 pass(obj.nextObjective());
878 pendingNextObjectives.invalidate(key);
879 flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj);
880 }
881 }
882 }
883 }
884 }
885
886 /**
887 * Represents a group-chain that implements a Next-Objective from
888 * the application. Includes information about the next objective Id, and the
889 * group keys for the groups in the group chain. The chain is expected to
890 * look like group0 --> group 1 --> outPort. Information about the groups
891 * themselves can be fetched from the Group Service using the group keys from
892 * objects instantiating this class.
893 */
894 private class OfdpaGroupChain implements NextGroup {
895 private final NextObjective nextObj;
896 private final List<GroupKey> gkeys;
897
898 /** expected group chain: group0 --> group1 --> port. */
899 public OfdpaGroupChain(List<GroupKey> gkeys, NextObjective nextObj) {
900 this.gkeys = gkeys;
901 this.nextObj = nextObj;
902 }
903
904 @SuppressWarnings("unused")
905 public List<GroupKey> groupKeys() {
906 return gkeys;
907 }
908
909 public NextObjective nextObjective() {
910 return nextObj;
911 }
912
913 @Override
914 public byte[] data() {
915 return appKryo.serialize(gkeys);
916 }
917
918 }
919
920 /**
921 * Represents a group element that is part of a chain of groups.
922 * Stores enough information to create a Group Description to add the group
923 * to the switch by requesting the Group Service. Objects instantiating this
924 * class are meant to be temporary and live as long as it is needed to wait for
925 * preceding groups in the group chain to be created.
926 */
927 private class GroupChainElem {
928 private TrafficTreatment bucketActions;
929 private Integer givenGroupId;
930 private GroupKey gkey;
931 private ApplicationId appId;
932
933 public GroupChainElem(GroupKey gkey, Integer givenGroupId,
934 TrafficTreatment tr, ApplicationId appId) {
935 this.bucketActions = tr;
936 this.givenGroupId = givenGroupId;
937 this.gkey = gkey;
938 this.appId = appId;
939 }
940
941 public TrafficTreatment getBucketActions() {
942 return bucketActions;
943 }
944
945 public Integer getGivenGroupId() {
946 return givenGroupId;
947 }
948
949 public GroupKey getGkey() {
950 return gkey;
951 }
952
953 public ApplicationId getAppId() {
954 return appId;
955 }
956
957 }
958
959 //////////////////////////////////////
960 // Test code to be used for future
961 // static-flow-pusher app
962 //////////////////////////////////////
963
964 public void processStaticFlows() {
965 //processPortTable();
966 processGroupTable();
967 processVlanTable();
968 processTmacTable();
969 processIpTable();
970 //processMcastTable();
971 //processBridgingTable();
972 processAclTable();
973 sendPackets();
974 processMplsTable();
975 }
976
977 protected void processGroupTable() {
978 TrafficTreatment.Builder act = DefaultTrafficTreatment.builder();
979
980 act.popVlan(); // to send out untagged packets
981 act.setOutput(PortNumber.portNumber(24));
982 GroupBucket bucket =
983 DefaultGroupBucket.createIndirectGroupBucket(act.build());
984 final GroupKey groupkey = new DefaultGroupKey(appKryo.serialize(500));
985 Integer groupId = 0x00c80018; //l2 interface, vlan 200, port 24
986 GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
987 GroupDescription.Type.INDIRECT,
988 new GroupBuckets(Collections.singletonList(bucket)),
989 groupkey,
990 groupId,
991 driverId);
992 groupService.addGroup(groupDescription);
993
994 TrafficTreatment.Builder act2 = DefaultTrafficTreatment.builder();
995 act2.setOutput(PortNumber.portNumber(40));
996 GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(act2.build());
997 final GroupKey groupkey2 = new DefaultGroupKey(appKryo.serialize(502));
998 Integer groupId2 = 0x00c50028; //l2 interface, vlan 197, port 40
999 GroupDescription groupDescription2 = new DefaultGroupDescription(deviceId,
1000 GroupDescription.Type.INDIRECT,
1001 new GroupBuckets(Collections.singletonList(bucket2)),
1002 groupkey2,
1003 groupId2,
1004 driverId);
1005 groupService.addGroup(groupDescription2);
1006
1007 while (groupService.getGroup(deviceId, groupkey2) == null) {
1008 try {
1009 Thread.sleep(500);
1010 } catch (InterruptedException e) {
1011 // TODO Auto-generated catch block
1012 e.printStackTrace();
1013 }
1014 }
1015
1016 //Now for L3 Unicast group
1017 TrafficTreatment.Builder act3 = DefaultTrafficTreatment.builder();
1018 act3.setEthDst(MacAddress.valueOf(0x2020));
1019 act3.setEthSrc(MacAddress.valueOf(0x1010));
1020 act3.setVlanId(VlanId.vlanId((short) 200));
1021 act3.group(new DefaultGroupId(0x00c80018)); // point to L2 interface
1022 // MPLS interface group - does not work for popping single label
1023 //Integer secGroupId = MPLSINTERFACEMASK | 38; // 0x90000026
1024 Integer groupId3 = L3UNICASTMASK | 1; // 0x20000001
1025 GroupBucket bucket3 =
1026 DefaultGroupBucket.createIndirectGroupBucket(act3.build());
1027 final GroupKey groupkey3 = new DefaultGroupKey(appKryo.serialize(503));
1028 GroupDescription groupDescription3 = new DefaultGroupDescription(deviceId,
1029 GroupDescription.Type.INDIRECT,
1030 new GroupBuckets(Collections.singletonList(bucket3)),
1031 groupkey3,
1032 groupId3,
1033 driverId);
1034 groupService.addGroup(groupDescription3);
1035
1036 //Another L3 Unicast group
1037 TrafficTreatment.Builder act4 = DefaultTrafficTreatment.builder();
1038 act4.setEthDst(MacAddress.valueOf(0x3030));
1039 act4.setEthSrc(MacAddress.valueOf(0x1010));
1040 act4.setVlanId(VlanId.vlanId((short) 197));
1041 act4.group(new DefaultGroupId(0x00c50028)); // point to L2 interface
1042 Integer groupId4 = L3UNICASTMASK | 2; // 0x20000002
1043 GroupBucket bucket4 =
1044 DefaultGroupBucket.createIndirectGroupBucket(act4.build());
1045 final GroupKey groupkey4 = new DefaultGroupKey(appKryo.serialize(504));
1046 GroupDescription groupDescription4 = new DefaultGroupDescription(deviceId,
1047 GroupDescription.Type.INDIRECT,
1048 new GroupBuckets(Collections.singletonList(bucket4)),
1049 groupkey4,
1050 groupId4,
1051 driverId);
1052 groupService.addGroup(groupDescription4);
1053
1054 while (groupService.getGroup(deviceId, groupkey4) == null) {
1055 try {
1056 Thread.sleep(500);
1057 } catch (InterruptedException e) {
1058 // TODO Auto-generated catch block
1059 e.printStackTrace();
1060 }
1061 }
1062
1063 // L3 ecmp group
1064 TrafficTreatment.Builder act5 = DefaultTrafficTreatment.builder();
1065 act5.group(new DefaultGroupId(0x20000001));
1066 TrafficTreatment.Builder act6 = DefaultTrafficTreatment.builder();
1067 act6.group(new DefaultGroupId(0x20000002));
1068 GroupBucket buckete1 =
1069 DefaultGroupBucket.createSelectGroupBucket(act5.build());
1070 GroupBucket buckete2 =
1071 DefaultGroupBucket.createSelectGroupBucket(act6.build());
1072 List<GroupBucket> bktlist = new ArrayList<GroupBucket>();
1073 bktlist.add(buckete1);
1074 bktlist.add(buckete2);
1075 final GroupKey groupkey5 = new DefaultGroupKey(appKryo.serialize(505));
1076 Integer groupId5 = L3ECMPMASK | 5; // 0x70000005
1077 GroupDescription groupDescription5 = new DefaultGroupDescription(deviceId,
1078 GroupDescription.Type.SELECT,
1079 new GroupBuckets(bktlist),
1080 groupkey5,
1081 groupId5,
1082 driverId);
1083 groupService.addGroup(groupDescription5);
1084
1085
1086 }
1087
1088 @SuppressWarnings("deprecation")
1089 protected void processMplsTable() {
1090 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1091 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1092 selector.matchEthType(Ethernet.MPLS_UNICAST);
1093 selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); //255
1094 selector.matchMplsBos(true);
1095 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1096 treatment.decMplsTtl(); // nw_ttl does not work
1097 treatment.copyTtlIn();
1098 treatment.popMpls(Ethernet.TYPE_IPV4);
1099 treatment.deferred().group(new DefaultGroupId(0x20000001)); // point to L3 Unicast
1100 //treatment.deferred().group(new DefaultGroupId(0x70000005)); // point to L3 ECMP
1101 treatment.transition(ACL_TABLE);
1102 FlowRule test = DefaultFlowRule.builder().forDevice(deviceId)
1103 .withSelector(selector.build()).withTreatment(treatment.build())
1104 .withPriority(DEFAULT_PRIORITY).fromApp(driverId).makePermanent()
1105 .forTable(24).build();
1106 ops = ops.add(test);
1107
1108 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1109 @Override
1110 public void onSuccess(FlowRuleOperations ops) {
1111 log.info("Initialized mpls table");
1112 }
1113
1114 @Override
1115 public void onError(FlowRuleOperations ops) {
1116 log.info("Failed to initialize mpls table");
1117 }
1118 }));
1119
1120 }
1121
1122 protected void processPortTable() {
1123 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1124 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1125 selector.matchInPort(PortNumber.portNumber(0)); // should be maskable?
1126 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1127 treatment.transition(VLAN_TABLE);
1128 FlowRule tmisse = DefaultFlowRule.builder()
1129 .forDevice(deviceId)
1130 .withSelector(selector.build())
1131 .withTreatment(treatment.build())
1132 .withPriority(LOWEST_PRIORITY)
1133 .fromApp(driverId)
1134 .makePermanent()
1135 .forTable(PORT_TABLE).build();
1136 ops = ops.add(tmisse);
1137
1138 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1139 @Override
1140 public void onSuccess(FlowRuleOperations ops) {
1141 log.info("Initialized port table");
1142 }
1143
1144 @Override
1145 public void onError(FlowRuleOperations ops) {
1146 log.info("Failed to initialize port table");
1147 }
1148 }));
1149
1150 }
1151
1152 private void processVlanTable() {
1153 // Table miss entry is not required as ofdpa default is to drop
1154 // In OF terms, the absence of a t.m.e. also implies drop
1155 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1156 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1157 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1158 selector.matchInPort(PortNumber.portNumber(12));
1159 selector.matchVlanId(VlanId.vlanId((short) 100));
1160 treatment.transition(TMAC_TABLE);
1161 FlowRule rule = DefaultFlowRule.builder()
1162 .forDevice(deviceId)
1163 .withSelector(selector.build())
1164 .withTreatment(treatment.build())
1165 .withPriority(DEFAULT_PRIORITY)
1166 .fromApp(driverId)
1167 .makePermanent()
1168 .forTable(VLAN_TABLE).build();
1169 ops = ops.add(rule);
1170 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1171 @Override
1172 public void onSuccess(FlowRuleOperations ops) {
1173 log.info("Initialized vlan table");
1174 }
1175
1176 @Override
1177 public void onError(FlowRuleOperations ops) {
1178 log.info("Failed to initialize vlan table");
1179 }
1180 }));
1181 }
1182
1183 protected void processTmacTable() {
1184 //table miss entry
1185 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1186 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1187 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1188 selector.matchInPort(PortNumber.portNumber(12));
1189 selector.matchVlanId(VlanId.vlanId((short) 100));
1190 selector.matchEthType(Ethernet.TYPE_IPV4);
1191 selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
1192 treatment.transition(UNICAST_ROUTING_TABLE);
1193 FlowRule rule = DefaultFlowRule.builder()
1194 .forDevice(deviceId)
1195 .withSelector(selector.build())
1196 .withTreatment(treatment.build())
1197 .withPriority(DEFAULT_PRIORITY)
1198 .fromApp(driverId)
1199 .makePermanent()
1200 .forTable(TMAC_TABLE).build();
1201 ops = ops.add(rule);
1202
1203 selector.matchEthType(Ethernet.MPLS_UNICAST);
1204 treatment.transition(MPLS_TABLE_0);
1205 FlowRule rulempls = DefaultFlowRule.builder()
1206 .forDevice(deviceId)
1207 .withSelector(selector.build())
1208 .withTreatment(treatment.build())
1209 .withPriority(DEFAULT_PRIORITY)
1210 .fromApp(driverId)
1211 .makePermanent()
1212 .forTable(TMAC_TABLE).build();
1213 ops = ops.add(rulempls);
1214
1215 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1216 @Override
1217 public void onSuccess(FlowRuleOperations ops) {
1218 log.info("Initialized tmac table");
1219 }
1220
1221 @Override
1222 public void onError(FlowRuleOperations ops) {
1223 log.info("Failed to initialize tmac table");
1224 }
1225 }));
1226 }
1227
1228 protected void processIpTable() {
1229 //table miss entry
1230 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1231 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1232 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1233 selector.matchEthType(Ethernet.TYPE_IPV4);
1234 selector.matchIPDst(IpPrefix.valueOf("2.0.0.0/16"));
1235 treatment.deferred().group(new DefaultGroupId(0x20000001));
1236 treatment.transition(ACL_TABLE);
1237 FlowRule rule = DefaultFlowRule.builder()
1238 .forDevice(deviceId)
1239 .withSelector(selector.build())
1240 .withTreatment(treatment.build())
1241 .withPriority(30000)
1242 .fromApp(driverId)
1243 .makePermanent()
1244 .forTable(UNICAST_ROUTING_TABLE).build();
1245 ops = ops.add(rule);
1246 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1247 @Override
1248 public void onSuccess(FlowRuleOperations ops) {
1249 log.info("Initialized IP table");
1250 }
1251
1252 @Override
1253 public void onError(FlowRuleOperations ops) {
1254 log.info("Failed to initialize unicast IP table");
1255 }
1256 }));
1257 }
1258
1259 protected void processAclTable() {
1260 //table miss entry
1261 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1262 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1263 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1264 selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
1265 treatment.deferred().group(new DefaultGroupId(0x20000001));
1266 FlowRule rule = DefaultFlowRule.builder()
1267 .forDevice(deviceId)
1268 .withSelector(selector.build())
1269 .withTreatment(treatment.build())
1270 .withPriority(60000)
1271 .fromApp(driverId)
1272 .makePermanent()
1273 .forTable(ACL_TABLE).build();
1274 ops = ops.add(rule);
1275 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1276 @Override
1277 public void onSuccess(FlowRuleOperations ops) {
1278 log.info("Initialized Acl table");
1279 }
1280
1281 @Override
1282 public void onError(FlowRuleOperations ops) {
1283 log.info("Failed to initialize Acl table");
1284 }
1285 }));
1286 }
1287
1288 private void sendPackets() {
1289 Ethernet eth = new Ethernet();
1290 eth.setDestinationMACAddress("00:00:00:00:00:02");
1291 eth.setSourceMACAddress("00:00:00:11:22:33");
1292 eth.setVlanID((short) 100);
1293 eth.setEtherType(Ethernet.MPLS_UNICAST);
1294 MPLS mplsPkt = new MPLS();
1295 mplsPkt.setLabel(255);
1296 mplsPkt.setTtl((byte) 5);
1297
1298 IPv4 ipv4 = new IPv4();
1299
1300 ipv4.setDestinationAddress("4.0.5.6");
1301 ipv4.setSourceAddress("1.0.2.3");
1302 ipv4.setTtl((byte) 64);
1303 ipv4.setChecksum((short) 0);
1304
1305 UDP udp = new UDP();
1306 udp.setDestinationPort(666);
1307 udp.setSourcePort(333);
1308 udp.setPayload(new Data(new byte[]{(byte) 1, (byte) 2}));
1309 udp.setChecksum((short) 0);
1310
1311 ipv4.setPayload(udp);
1312 mplsPkt.setPayload(ipv4);
1313 eth.setPayload(mplsPkt);
1314
1315 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1316 .setOutput(PortNumber.portNumber(24))
1317 .build();
1318 OutboundPacket packet = new DefaultOutboundPacket(deviceId,
1319 treatment,
1320 ByteBuffer.wrap(eth.serialize()));
1321
1322
1323 Ethernet eth2 = new Ethernet();
1324 eth2.setDestinationMACAddress("00:00:00:00:00:02");
1325 eth2.setSourceMACAddress("00:00:00:11:22:33");
1326 eth2.setVlanID((short) 100);
1327 eth2.setEtherType(Ethernet.TYPE_IPV4);
1328
1329 IPv4 ipv42 = new IPv4();
1330 ipv42.setDestinationAddress("2.0.0.2");
1331 ipv42.setSourceAddress("1.0.9.9");
1332 ipv42.setTtl((byte) 64);
1333 ipv42.setChecksum((short) 0);
1334
1335 UDP udp2 = new UDP();
1336 udp2.setDestinationPort(999);
1337 udp2.setSourcePort(333);
1338 udp2.setPayload(new Data(new byte[]{(byte) 1, (byte) 2}));
1339 udp2.setChecksum((short) 0);
1340
1341 ipv42.setPayload(udp2);
1342 eth2.setPayload(ipv42);
1343
1344 TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
1345 .setOutput(PortNumber.portNumber(26))
1346 .build();
1347 OutboundPacket packet2 = new DefaultOutboundPacket(deviceId,
1348 treatment2,
1349 ByteBuffer.wrap(eth2.serialize()));
1350
1351
1352 log.info("Emitting packets now");
1353 packetService.emit(packet);
1354 packetService.emit(packet);
1355 packetService.emit(packet2);
1356 packetService.emit(packet);
1357 packetService.emit(packet);
1358 log.info("Done emitting packets");
1359 }
1360
1361 private class InternalPacketProcessor implements PacketProcessor {
1362
1363 @Override
1364 public void process(PacketContext context) {
1365
1366
1367 }
1368 }
1369
1370}