blob: 863caebb0e6f0379f5f498ba97a05c19e3fad47d [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;
Saurav Das8a0732e2015-11-20 15:27:53 -080022import java.util.ArrayDeque;
Saurav Das822c4e22015-10-23 10:51:11 -070023import java.util.ArrayList;
24import java.util.Collection;
25import java.util.Collections;
Saurav Das8a0732e2015-11-20 15:27:53 -080026import java.util.Deque;
Saurav Das822c4e22015-10-23 10:51:11 -070027import java.util.List;
Saurav Das4f980082015-11-05 13:39:15 -080028import java.util.Map;
Saurav Das822c4e22015-10-23 10:51:11 -070029import java.util.Set;
30import java.util.concurrent.ConcurrentHashMap;
31import java.util.concurrent.Executors;
32import java.util.concurrent.ScheduledExecutorService;
33import java.util.concurrent.TimeUnit;
Saurav Das4f980082015-11-05 13:39:15 -080034import java.util.concurrent.atomic.AtomicInteger;
Saurav Das822c4e22015-10-23 10:51:11 -070035import java.util.stream.Collectors;
36
37import org.onlab.osgi.ServiceDirectory;
38import org.onlab.packet.Data;
39import org.onlab.packet.Ethernet;
40import org.onlab.packet.IPv4;
41import org.onlab.packet.IpPrefix;
42import org.onlab.packet.MPLS;
43import org.onlab.packet.MacAddress;
44import org.onlab.packet.MplsLabel;
45import org.onlab.packet.UDP;
46import org.onlab.packet.VlanId;
47import org.onlab.util.KryoNamespace;
48import org.onosproject.core.ApplicationId;
49import org.onosproject.core.CoreService;
50import org.onosproject.core.DefaultGroupId;
51import org.onosproject.net.DeviceId;
52import org.onosproject.net.Port;
53import org.onosproject.net.PortNumber;
54import org.onosproject.net.behaviour.NextGroup;
55import org.onosproject.net.behaviour.Pipeliner;
56import org.onosproject.net.behaviour.PipelinerContext;
57import org.onosproject.net.device.DeviceService;
58import org.onosproject.net.driver.AbstractHandlerBehaviour;
59import org.onosproject.net.flow.DefaultFlowRule;
60import org.onosproject.net.flow.DefaultTrafficSelector;
61import org.onosproject.net.flow.DefaultTrafficTreatment;
62import org.onosproject.net.flow.FlowRule;
63import org.onosproject.net.flow.FlowRuleOperations;
64import org.onosproject.net.flow.FlowRuleOperationsContext;
65import org.onosproject.net.flow.FlowRuleService;
66import org.onosproject.net.flow.TrafficSelector;
67import org.onosproject.net.flow.TrafficTreatment;
68import org.onosproject.net.flow.criteria.Criteria;
69import org.onosproject.net.flow.criteria.Criterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080070import org.onosproject.net.flow.criteria.Criterion.Type;
Saurav Das822c4e22015-10-23 10:51:11 -070071import org.onosproject.net.flow.criteria.EthCriterion;
72import org.onosproject.net.flow.criteria.EthTypeCriterion;
73import org.onosproject.net.flow.criteria.IPCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080074import org.onosproject.net.flow.criteria.MplsBosCriterion;
75import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das822c4e22015-10-23 10:51:11 -070076import org.onosproject.net.flow.criteria.PortCriterion;
77import org.onosproject.net.flow.criteria.VlanIdCriterion;
78import org.onosproject.net.flow.instructions.Instruction;
79import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
80import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Saurav Das8a0732e2015-11-20 15:27:53 -080081import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
Saurav Das822c4e22015-10-23 10:51:11 -070082import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
Saurav Das8a0732e2015-11-20 15:27:53 -080083import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
Saurav Das822c4e22015-10-23 10:51:11 -070084import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
85import org.onosproject.net.flowobjective.FilteringObjective;
86import org.onosproject.net.flowobjective.FlowObjectiveStore;
87import org.onosproject.net.flowobjective.ForwardingObjective;
88import org.onosproject.net.flowobjective.NextObjective;
89import org.onosproject.net.flowobjective.Objective;
90import org.onosproject.net.flowobjective.ObjectiveError;
91import org.onosproject.net.group.DefaultGroupBucket;
92import org.onosproject.net.group.DefaultGroupDescription;
93import org.onosproject.net.group.DefaultGroupKey;
94import org.onosproject.net.group.Group;
95import org.onosproject.net.group.GroupBucket;
96import org.onosproject.net.group.GroupBuckets;
97import org.onosproject.net.group.GroupDescription;
98import org.onosproject.net.group.GroupEvent;
99import org.onosproject.net.group.GroupKey;
100import org.onosproject.net.group.GroupListener;
101import org.onosproject.net.group.GroupService;
102import org.onosproject.net.packet.DefaultOutboundPacket;
103import org.onosproject.net.packet.OutboundPacket;
104import org.onosproject.net.packet.PacketContext;
105import org.onosproject.net.packet.PacketProcessor;
106import org.onosproject.net.packet.PacketService;
107import org.onosproject.store.serializers.KryoNamespaces;
108import org.slf4j.Logger;
109
110import com.google.common.cache.Cache;
111import com.google.common.cache.CacheBuilder;
112import com.google.common.cache.RemovalCause;
113import com.google.common.cache.RemovalNotification;
114
115/**
116 * Driver for Broadcom's OF-DPA v2.0 TTP.
117 *
118 */
119public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeliner {
120
121 protected static final int PORT_TABLE = 0;
122 protected static final int VLAN_TABLE = 10;
123 protected static final int TMAC_TABLE = 20;
124 protected static final int UNICAST_ROUTING_TABLE = 30;
125 protected static final int MULTICAST_ROUTING_TABLE = 40;
126 protected static final int MPLS_TABLE_0 = 23;
127 protected static final int MPLS_TABLE_1 = 24;
128 protected static final int BRIDGING_TABLE = 50;
129 protected static final int ACL_TABLE = 60;
130 protected static final int MAC_LEARNING_TABLE = 254;
131 protected static final long OFPP_MAX = 0xffffff00L;
132
133 private static final int HIGHEST_PRIORITY = 0xffff;
Saurav Das2857f382015-11-03 14:39:27 -0800134 protected static final int DEFAULT_PRIORITY = 0x8000;
Saurav Das822c4e22015-10-23 10:51:11 -0700135 protected static final int LOWEST_PRIORITY = 0x0;
136
137 /*
Saurav Das822c4e22015-10-23 10:51:11 -0700138 * OFDPA requires group-id's to have a certain form.
139 * L2 Interface Groups have <4bits-0><12bits-vlanid><16bits-portid>
140 * L3 Unicast Groups have <4bits-2><28bits-index>
Saurav Das8a0732e2015-11-20 15:27:53 -0800141 * MPLS Interface Groups have <4bits-9><4bits:0><24bits-index>
142 * L3 ECMP Groups have <4bits-7><28bits-index>
143 * L2 Flood Groups have <4bits-4><12bits-vlanid><16bits-index>
144 * L3 VPN Groups have <4bits-9><4bits-2><24bits-index>
Saurav Das822c4e22015-10-23 10:51:11 -0700145 */
146 private static final int L2INTERFACEMASK = 0x0;
147 private static final int L3UNICASTMASK = 0x20000000;
Saurav Das8a0732e2015-11-20 15:27:53 -0800148 private static final int MPLSINTERFACEMASK = 0x90000000;
Saurav Das822c4e22015-10-23 10:51:11 -0700149 private static final int L3ECMPMASK = 0x70000000;
Saurav Das4f980082015-11-05 13:39:15 -0800150 private static final int L2FLOODMASK = 0x40000000;
Saurav Das8a0732e2015-11-20 15:27:53 -0800151 private static final int L3VPNMASK = 0x92000000;
Saurav Das822c4e22015-10-23 10:51:11 -0700152
Saurav Das822c4e22015-10-23 10:51:11 -0700153 private final Logger log = getLogger(getClass());
154 private ServiceDirectory serviceDirectory;
155 protected FlowRuleService flowRuleService;
156 private CoreService coreService;
Saurav Das8a0732e2015-11-20 15:27:53 -0800157 protected GroupService groupService;
158 protected FlowObjectiveStore flowObjectiveStore;
Saurav Das822c4e22015-10-23 10:51:11 -0700159 protected DeviceId deviceId;
160 protected ApplicationId driverId;
161 protected PacketService packetService;
162 protected DeviceService deviceService;
163 private InternalPacketProcessor processor = new InternalPacketProcessor();
Saurav Das8a0732e2015-11-20 15:27:53 -0800164 protected KryoNamespace appKryo = new KryoNamespace.Builder()
Saurav Das822c4e22015-10-23 10:51:11 -0700165 .register(KryoNamespaces.API)
166 .register(GroupKey.class)
167 .register(DefaultGroupKey.class)
Saurav Das8a0732e2015-11-20 15:27:53 -0800168 .register(OfdpaNextGroup.class)
Saurav Das822c4e22015-10-23 10:51:11 -0700169 .register(byte[].class)
Saurav Das8a0732e2015-11-20 15:27:53 -0800170 .register(ArrayDeque.class)
Saurav Das822c4e22015-10-23 10:51:11 -0700171 .build();
172
Saurav Das8a0732e2015-11-20 15:27:53 -0800173 private Cache<GroupKey, OfdpaNextGroup> pendingNextObjectives;
174 private ConcurrentHashMap<GroupKey, Set<GroupChainElem>> pendingGroups;
Saurav Das822c4e22015-10-23 10:51:11 -0700175
176 private ScheduledExecutorService groupChecker =
177 Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
178 "ofdpa2-%d"));
179 private Set<IPCriterion> sentIpFilters = Collections.newSetFromMap(
180 new ConcurrentHashMap<IPCriterion, Boolean>());
181
Saurav Das4f980082015-11-05 13:39:15 -0800182 // local stores for port-vlan mapping
183 Map<PortNumber, VlanId> port2Vlan = new ConcurrentHashMap<PortNumber, VlanId>();
184 Map<VlanId, Set<PortNumber>> vlan2Port = new ConcurrentHashMap<VlanId,
185 Set<PortNumber>>();
186
Saurav Das8a0732e2015-11-20 15:27:53 -0800187 // index number for group creation
188 AtomicInteger l3vpnindex = new AtomicInteger(0);
Saurav Das4f980082015-11-05 13:39:15 -0800189
190
Saurav Das822c4e22015-10-23 10:51:11 -0700191 @Override
192 public void init(DeviceId deviceId, PipelinerContext context) {
193 this.serviceDirectory = context.directory();
194 this.deviceId = deviceId;
195
196 pendingNextObjectives = CacheBuilder.newBuilder()
197 .expireAfterWrite(20, TimeUnit.SECONDS)
Saurav Das8a0732e2015-11-20 15:27:53 -0800198 .removalListener((
199 RemovalNotification<GroupKey, OfdpaNextGroup> notification) -> {
200 if (notification.getCause() == RemovalCause.EXPIRED) {
201 fail(notification.getValue().nextObjective(),
202 ObjectiveError.GROUPINSTALLATIONFAILED);
203 }
Saurav Das822c4e22015-10-23 10:51:11 -0700204 }).build();
205
206 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
Saurav Das8a0732e2015-11-20 15:27:53 -0800207 pendingGroups = new ConcurrentHashMap<GroupKey, Set<GroupChainElem>>();
Saurav Das822c4e22015-10-23 10:51:11 -0700208
209 coreService = serviceDirectory.get(CoreService.class);
210 flowRuleService = serviceDirectory.get(FlowRuleService.class);
211 groupService = serviceDirectory.get(GroupService.class);
212 flowObjectiveStore = context.store();
213 packetService = serviceDirectory.get(PacketService.class);
214 deviceService = serviceDirectory.get(DeviceService.class);
215 packetService.addProcessor(processor, PacketProcessor.director(2));
216 groupService.addListener(new InnerGroupListener());
217
218 driverId = coreService.registerApplication(
219 "org.onosproject.driver.OFDPA2Pipeline");
220
221 // OF-DPA does not require initializing the pipeline as it puts default
222 // rules automatically in the hardware. However emulation of OFDPA in
223 // software switches does require table-miss-entries.
224 initializePipeline();
225
226 }
227
228 protected void initializePipeline() {
229
230 }
231
232 //////////////////////////////////////
233 // Flow Objectives
234 //////////////////////////////////////
235
236 @Override
237 public void filter(FilteringObjective filteringObjective) {
238 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
239 processFilter(filteringObjective,
240 filteringObjective.op() == Objective.Operation.ADD,
241 filteringObjective.appId());
242 } else {
243 // Note that packets that don't match the PERMIT filter are
244 // automatically denied. The DENY filter is used to deny packets
245 // that are otherwise permitted by the PERMIT filter.
246 // Use ACL table flow rules here for DENY filtering objectives
247 log.debug("filter objective other than PERMIT currently not supported");
248 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
249 }
250 }
251
252 @Override
253 public void forward(ForwardingObjective fwd) {
254 Collection<FlowRule> rules;
255 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
256
257 rules = processForward(fwd);
258 switch (fwd.op()) {
259 case ADD:
260 rules.stream()
261 .filter(rule -> rule != null)
262 .forEach(flowOpsBuilder::add);
263 break;
264 case REMOVE:
265 rules.stream()
266 .filter(rule -> rule != null)
267 .forEach(flowOpsBuilder::remove);
268 break;
269 default:
270 fail(fwd, ObjectiveError.UNKNOWN);
271 log.warn("Unknown forwarding type {}", fwd.op());
272 }
273
274
275 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
276 @Override
277 public void onSuccess(FlowRuleOperations ops) {
278 pass(fwd);
279 }
280
281 @Override
282 public void onError(FlowRuleOperations ops) {
283 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
284 }
285 }));
286
287 }
288
289 @Override
290 public void next(NextObjective nextObjective) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800291 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
292 switch (nextObjective.op()) {
293 case ADD:
Saurav Das4f980082015-11-05 13:39:15 -0800294 if (nextGroup != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800295 log.warn("Cannot add next {} that already exists in device {}",
296 nextObjective.id(), deviceId);
297 return;
298 }
299 log.debug("Processing NextObjective id{} in dev{} - add group",
300 nextObjective.id(), deviceId);
301 addGroup(nextObjective);
302 break;
303 case ADD_TO_EXISTING:
304 if (nextGroup != null) {
305 log.debug("Processing NextObjective id{} in dev{} - add bucket",
306 nextObjective.id(), deviceId);
Saurav Das4f980082015-11-05 13:39:15 -0800307 addBucketToGroup(nextObjective);
308 } else {
Saurav Das8a0732e2015-11-20 15:27:53 -0800309 // it is possible that group-chain has not been fully created yet
310 waitToAddBucketToGroup(nextObjective);
Saurav Das4f980082015-11-05 13:39:15 -0800311 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800312 break;
313 case REMOVE:
314 if (nextGroup == null) {
315 log.warn("Cannot remove next {} that does not exist in device {}",
316 nextObjective.id(), deviceId);
317 return;
318 }
319 log.debug("Processing NextObjective id{} in dev{} - remove group",
320 nextObjective.id(), deviceId);
321 removeGroup(nextObjective);
322 break;
323 case REMOVE_FROM_EXISTING:
324 if (nextGroup == null) {
325 log.warn("Cannot remove from next {} that does not exist in device {}",
326 nextObjective.id(), deviceId);
327 return;
328 }
329 log.debug("Processing NextObjective id{} in dev{} - remove bucket",
330 nextObjective.id(), deviceId);
331 removeBucketFromGroup(nextObjective);
332 break;
333 default:
Saurav Das4f980082015-11-05 13:39:15 -0800334 log.warn("Unsupported operation {}", nextObjective.op());
Saurav Das822c4e22015-10-23 10:51:11 -0700335 }
336 }
337
338 //////////////////////////////////////
339 // Flow handling
340 //////////////////////////////////////
341
342 /**
343 * As per OFDPA 2.0 TTP, filtering of VLAN ids, MAC addresses (for routing)
344 * and IP addresses configured on switch ports happen in different tables.
345 * Note that IP filtering rules need to be added to the ACL table, as there
346 * is no mechanism to send to controller via IP table.
347 *
348 * @param filt the filtering objective
349 * @param install indicates whether to add or remove the objective
350 * @param applicationId the application that sent this objective
351 */
352 private void processFilter(FilteringObjective filt,
353 boolean install, ApplicationId applicationId) {
354 // This driver only processes filtering criteria defined with switch
355 // ports as the key
356 PortCriterion portCriterion = null;
357 EthCriterion ethCriterion = null;
358 VlanIdCriterion vidCriterion = null;
359 Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
360 if (!filt.key().equals(Criteria.dummy()) &&
361 filt.key().type() == Criterion.Type.IN_PORT) {
362 portCriterion = (PortCriterion) filt.key();
363 } else {
364 log.warn("No key defined in filtering objective from app: {}. Not"
365 + "processing filtering objective", applicationId);
366 fail(filt, ObjectiveError.UNKNOWN);
367 return;
368 }
369 // convert filtering conditions for switch-intfs into flowrules
370 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
371 for (Criterion criterion : filt.conditions()) {
372 if (criterion.type() == Criterion.Type.ETH_DST) {
373 ethCriterion = (EthCriterion) criterion;
374 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
375 vidCriterion = (VlanIdCriterion) criterion;
376 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
377 ips.add((IPCriterion) criterion);
378 } else {
379 log.error("Unsupported filter {}", criterion);
380 fail(filt, ObjectiveError.UNSUPPORTED);
381 return;
382 }
383 }
384
Saurav Das0e99e2b2015-10-28 12:39:42 -0700385 VlanId assignedVlan = null;
386 if (vidCriterion != null && vidCriterion.vlanId() == VlanId.NONE) {
387 // untagged packets are assigned vlans in OF-DPA
388 if (filt.meta() == null) {
389 log.error("Missing metadata in filtering objective required "
390 + "for vlan assignment in dev {}", deviceId);
391 fail(filt, ObjectiveError.BADPARAMS);
392 return;
393 }
394 for (Instruction i : filt.meta().allInstructions()) {
395 if (i instanceof ModVlanIdInstruction) {
396 assignedVlan = ((ModVlanIdInstruction) i).vlanId();
397 }
398 }
399 if (assignedVlan == null) {
400 log.error("Driver requires an assigned vlan-id to tag incoming "
401 + "untagged packets. Not processing vlan filters on "
402 + "device {}", deviceId);
403 fail(filt, ObjectiveError.BADPARAMS);
404 return;
405 }
406 }
407
Saurav Das822c4e22015-10-23 10:51:11 -0700408 if (ethCriterion == null) {
409 log.debug("filtering objective missing dstMac, cannot program TMAC table");
410 } else {
411 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700412 vidCriterion, assignedVlan,
413 applicationId)) {
Saurav Das822c4e22015-10-23 10:51:11 -0700414 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
415 tmacRule, deviceId);
416 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
417 }
418 }
419
420 if (ethCriterion == null || vidCriterion == null) {
421 log.debug("filtering objective missing dstMac or vlan, cannot program"
422 + "Vlan Table");
423 } else {
424 for (FlowRule vlanRule : processVlanIdFilter(portCriterion, vidCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700425 assignedVlan,
Saurav Das822c4e22015-10-23 10:51:11 -0700426 applicationId)) {
427 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
428 vlanRule, deviceId);
429 ops = install ? ops.add(vlanRule) : ops.remove(vlanRule);
430 }
431 }
432
433 for (IPCriterion ipaddr : ips) {
434 // since we ignore port information for IP rules, and the same (gateway) IP
435 // can be configured on multiple ports, we make sure that we send
436 // only a single rule to the switch.
437 if (!sentIpFilters.contains(ipaddr)) {
438 sentIpFilters.add(ipaddr);
439 log.debug("adding IP filtering rules in ACL table {} for dev: {}",
440 ipaddr, deviceId);
441 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
442 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
443 selector.matchEthType(Ethernet.TYPE_IPV4);
444 selector.matchIPDst(ipaddr.ip());
445 treatment.setOutput(PortNumber.CONTROLLER);
446 FlowRule rule = DefaultFlowRule.builder()
447 .forDevice(deviceId)
448 .withSelector(selector.build())
449 .withTreatment(treatment.build())
450 .withPriority(HIGHEST_PRIORITY)
451 .fromApp(applicationId)
452 .makePermanent()
453 .forTable(ACL_TABLE).build();
454 ops = install ? ops.add(rule) : ops.remove(rule);
455 }
456 }
457
458 // apply filtering flow rules
459 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
460 @Override
461 public void onSuccess(FlowRuleOperations ops) {
462 log.info("Applied {} filtering rules in device {}",
463 ops.stages().get(0).size(), deviceId);
464 pass(filt);
465 }
466
467 @Override
468 public void onError(FlowRuleOperations ops) {
469 log.info("Failed to apply all filtering rules in dev {}", deviceId);
470 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
471 }
472 }));
473
474 }
475
476 /**
477 * Allows untagged packets into pipeline by assigning a vlan id.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700478 * Vlan assignment is done by the application.
Saurav Das822c4e22015-10-23 10:51:11 -0700479 * Allows tagged packets into pipeline as per configured port-vlan info.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700480 *
Saurav Das822c4e22015-10-23 10:51:11 -0700481 * @param portCriterion port on device for which this filter is programmed
482 * @param vidCriterion vlan assigned to port, or NONE for untagged
Saurav Das0e99e2b2015-10-28 12:39:42 -0700483 * @param assignedVlan assigned vlan-id for untagged packets
Saurav Das822c4e22015-10-23 10:51:11 -0700484 * @param applicationId for application programming this filter
485 * @return list of FlowRule for port-vlan filters
486 */
487 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
488 VlanIdCriterion vidCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700489 VlanId assignedVlan,
Saurav Das822c4e22015-10-23 10:51:11 -0700490 ApplicationId applicationId) {
491 List<FlowRule> rules = new ArrayList<FlowRule>();
492 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
493 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
494 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800495 treatment.transition(TMAC_TABLE);
496
497 VlanId storeVlan = null;
Saurav Das822c4e22015-10-23 10:51:11 -0700498 if (vidCriterion.vlanId() == VlanId.NONE) {
499 // untagged packets are assigned vlans
Saurav Das0e99e2b2015-10-28 12:39:42 -0700500 treatment.pushVlan().setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800501 // XXX ofdpa will require an additional vlan match on the assigned vlan
502 // and it may not require the push. This is not in compliance with OF
503 // standard. Waiting on what the exact flows are going to look like.
Saurav Das4f980082015-11-05 13:39:15 -0800504 storeVlan = assignedVlan;
505 } else {
506 storeVlan = vidCriterion.vlanId();
Saurav Das822c4e22015-10-23 10:51:11 -0700507 }
Saurav Das822c4e22015-10-23 10:51:11 -0700508
509 // ofdpa cannot match on ALL portnumber, so we need to use separate
510 // rules for each port.
511 List<PortNumber> portnums = new ArrayList<PortNumber>();
512 if (portCriterion.port() == PortNumber.ALL) {
513 for (Port port : deviceService.getPorts(deviceId)) {
514 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
515 portnums.add(port.number());
516 }
517 }
518 } else {
519 portnums.add(portCriterion.port());
520 }
Saurav Das4f980082015-11-05 13:39:15 -0800521
Saurav Das822c4e22015-10-23 10:51:11 -0700522 for (PortNumber pnum : portnums) {
Saurav Das4f980082015-11-05 13:39:15 -0800523 // update storage
524 port2Vlan.put(pnum, storeVlan);
525 Set<PortNumber> vlanPorts = vlan2Port.get(storeVlan);
526 if (vlanPorts == null) {
527 vlanPorts = Collections.newSetFromMap(
528 new ConcurrentHashMap<PortNumber, Boolean>());
529 vlanPorts.add(pnum);
530 vlan2Port.put(storeVlan, vlanPorts);
531 } else {
532 vlanPorts.add(pnum);
533 }
534 // create rest of flowrule
Saurav Das822c4e22015-10-23 10:51:11 -0700535 selector.matchInPort(pnum);
536 FlowRule rule = DefaultFlowRule.builder()
537 .forDevice(deviceId)
538 .withSelector(selector.build())
539 .withTreatment(treatment.build())
540 .withPriority(DEFAULT_PRIORITY)
541 .fromApp(applicationId)
542 .makePermanent()
543 .forTable(VLAN_TABLE).build();
544 rules.add(rule);
545 }
546 return rules;
547 }
548
549 /**
550 * Allows routed packets with correct destination MAC to be directed
551 * to unicast-IP routing table or MPLS forwarding table.
Saurav Das822c4e22015-10-23 10:51:11 -0700552 *
553 * @param portCriterion port on device for which this filter is programmed
554 * @param ethCriterion dstMac of device for which is filter is programmed
555 * @param vidCriterion vlan assigned to port, or NONE for untagged
Saurav Das0e99e2b2015-10-28 12:39:42 -0700556 * @param assignedVlan assigned vlan-id for untagged packets
Saurav Das822c4e22015-10-23 10:51:11 -0700557 * @param applicationId for application programming this filter
558 * @return list of FlowRule for port-vlan filters
559
560 */
561 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
562 EthCriterion ethCriterion,
563 VlanIdCriterion vidCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700564 VlanId assignedVlan,
Saurav Das822c4e22015-10-23 10:51:11 -0700565 ApplicationId applicationId) {
566 //handling untagged packets via assigned VLAN
567 if (vidCriterion.vlanId() == VlanId.NONE) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700568 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
Saurav Das822c4e22015-10-23 10:51:11 -0700569 }
570 // ofdpa cannot match on ALL portnumber, so we need to use separate
571 // rules for each port.
572 List<PortNumber> portnums = new ArrayList<PortNumber>();
573 if (portCriterion.port() == PortNumber.ALL) {
574 for (Port port : deviceService.getPorts(deviceId)) {
575 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
576 portnums.add(port.number());
577 }
578 }
579 } else {
580 portnums.add(portCriterion.port());
581 }
582
583 List<FlowRule> rules = new ArrayList<FlowRule>();
584 for (PortNumber pnum : portnums) {
585 // for unicast IP packets
586 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
587 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
588 selector.matchInPort(pnum);
589 selector.matchVlanId(vidCriterion.vlanId());
590 selector.matchEthType(Ethernet.TYPE_IPV4);
591 selector.matchEthDst(ethCriterion.mac());
592 treatment.transition(UNICAST_ROUTING_TABLE);
593 FlowRule rule = DefaultFlowRule.builder()
594 .forDevice(deviceId)
595 .withSelector(selector.build())
596 .withTreatment(treatment.build())
597 .withPriority(DEFAULT_PRIORITY)
598 .fromApp(applicationId)
599 .makePermanent()
600 .forTable(TMAC_TABLE).build();
601 rules.add(rule);
602 //for MPLS packets
603 selector = DefaultTrafficSelector.builder();
604 treatment = DefaultTrafficTreatment.builder();
605 selector.matchInPort(pnum);
606 selector.matchVlanId(vidCriterion.vlanId());
607 selector.matchEthType(Ethernet.MPLS_UNICAST);
608 selector.matchEthDst(ethCriterion.mac());
609 treatment.transition(MPLS_TABLE_0);
610 rule = DefaultFlowRule.builder()
611 .forDevice(deviceId)
612 .withSelector(selector.build())
613 .withTreatment(treatment.build())
614 .withPriority(DEFAULT_PRIORITY)
615 .fromApp(applicationId)
616 .makePermanent()
617 .forTable(TMAC_TABLE).build();
618 rules.add(rule);
619 }
620 return rules;
621 }
622
623 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
624 switch (fwd.flag()) {
625 case SPECIFIC:
626 return processSpecific(fwd);
627 case VERSATILE:
628 return processVersatile(fwd);
629 default:
630 fail(fwd, ObjectiveError.UNKNOWN);
631 log.warn("Unknown forwarding flag {}", fwd.flag());
632 }
633 return Collections.emptySet();
634 }
635
636 /**
637 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
638 * ACL table.
639 * @param fwd the forwarding objective of type 'versatile'
640 * @return a collection of flow rules to be sent to the switch. An empty
641 * collection may be returned if there is a problem in processing
642 * the flow rule
643 */
644 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
645 log.info("Processing versatile forwarding objective");
646 TrafficSelector selector = fwd.selector();
647
648 EthTypeCriterion ethType =
649 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
650 if (ethType == null) {
651 log.error("Versatile forwarding objective must include ethType");
652 fail(fwd, ObjectiveError.BADPARAMS);
653 return Collections.emptySet();
654 }
655 if (fwd.nextId() == null && fwd.treatment() == null) {
656 log.error("Forwarding objective {} from {} must contain "
657 + "nextId or Treatment", fwd.selector(), fwd.appId());
658 return Collections.emptySet();
659 }
660 // XXX driver does not currently do type checking as per Tables 65-67 in
661 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
662 if (fwd.treatment() != null &&
663 fwd.treatment().allInstructions().size() == 1 &&
664 fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
665 OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
666 if (o.port() == PortNumber.CONTROLLER) {
667 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
668 .fromApp(fwd.appId())
669 .withPriority(fwd.priority())
670 .forDevice(deviceId)
671 .withSelector(fwd.selector())
672 .withTreatment(fwd.treatment())
673 .makePermanent()
674 .forTable(ACL_TABLE);
675 return Collections.singletonList(ruleBuilder.build());
676 } else {
677 log.warn("Only allowed treatments in versatile forwarding "
678 + "objectives are punts to the controller");
679 return Collections.emptySet();
680 }
681 }
682
683 if (fwd.nextId() != null) {
684 // XXX overide case
685 log.warn("versatile objective --> next Id not yet implemeted");
686 }
687 return Collections.emptySet();
688 }
689
690 /**
691 * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table
Saurav Das8a0732e2015-11-20 15:27:53 -0800692 * (unicast or multicast) or the L2 table (mac + vlan) or the MPLS table.
Saurav Das822c4e22015-10-23 10:51:11 -0700693 *
694 * @param fwd the forwarding objective of type 'specific'
695 * @return a collection of flow rules. Typically there will be only one
696 * for this type of forwarding objective. An empty set may be
697 * returned if there is an issue in processing the objective.
698 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800699 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
Saurav Das822c4e22015-10-23 10:51:11 -0700700 TrafficSelector selector = fwd.selector();
701 EthTypeCriterion ethType =
702 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Saurav Das8a0732e2015-11-20 15:27:53 -0800703 if ((ethType == null) ||
704 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
705 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
706 log.warn("processSpecific: Unsupported "
707 + "forwarding objective criteraia");
Saurav Das822c4e22015-10-23 10:51:11 -0700708 fail(fwd, ObjectiveError.UNSUPPORTED);
709 return Collections.emptySet();
710 }
711
Saurav Das8a0732e2015-11-20 15:27:53 -0800712 int forTableId = -1;
713 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
714 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
715 filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
716 .matchIPDst(((IPCriterion)
717 selector.getCriterion(Criterion.Type.IPV4_DST)).ip());
718 forTableId = UNICAST_ROUTING_TABLE;
719 log.debug("processing IPv4 specific forwarding objective {} in dev:{}",
720 fwd.id(), deviceId);
721 } else {
722 filteredSelector
723 .matchEthType(Ethernet.MPLS_UNICAST)
724 .matchMplsLabel(((MplsCriterion)
725 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
726 MplsBosCriterion bos = (MplsBosCriterion) selector
727 .getCriterion(Criterion.Type.MPLS_BOS);
728 if (bos != null) {
729 filteredSelector.matchMplsBos(bos.mplsBos());
730 }
731 forTableId = MPLS_TABLE_1;
732 log.debug("processing MPLS specific forwarding objective {} in dev {}",
733 fwd.id(), deviceId);
734 }
Saurav Das822c4e22015-10-23 10:51:11 -0700735
736 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
Saurav Das8a0732e2015-11-20 15:27:53 -0800737 boolean popMpls = false;
738 if (fwd.treatment() != null) {
739 for (Instruction i : fwd.treatment().allInstructions()) {
740 tb.add(i);
741 if (i instanceof L2ModificationInstruction &&
742 ((L2ModificationInstruction) i).subtype() == L2SubType.MPLS_POP) {
743 popMpls = true;
744 }
745 }
746 }
Saurav Das822c4e22015-10-23 10:51:11 -0700747
748 if (fwd.nextId() != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800749 if (forTableId == MPLS_TABLE_1 && !popMpls) {
750 log.warn("SR CONTINUE case cannot be handled as MPLS ECMP "
751 + "is not implemented in OF-DPA yet. Aborting this flow "
752 + "in this device {}", deviceId);
753 // XXX We could convert to forwarding to a single-port, via a
754 // MPLS interface, or a MPLS SWAP (with-same) but that would
755 // have to be handled in the next-objective. Also the pop-mpls
756 // logic used here won't work in non-BoS case.
757 return Collections.emptySet();
758 }
759
Saurav Das822c4e22015-10-23 10:51:11 -0700760 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
Saurav Das8a0732e2015-11-20 15:27:53 -0800761 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
762 // we only need the top level group's key to point the flow to it
763 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
Saurav Das822c4e22015-10-23 10:51:11 -0700764 if (group == null) {
765 log.warn("The group left!");
766 fail(fwd, ObjectiveError.GROUPMISSING);
767 return Collections.emptySet();
768 }
769 tb.deferred().group(group.id());
770 }
771 tb.transition(ACL_TABLE);
772 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
773 .fromApp(fwd.appId())
774 .withPriority(fwd.priority())
775 .forDevice(deviceId)
Saurav Das8a0732e2015-11-20 15:27:53 -0800776 .withSelector(filteredSelector.build())
777 .withTreatment(tb.build())
778 .forTable(forTableId);
Saurav Das822c4e22015-10-23 10:51:11 -0700779
780 if (fwd.permanent()) {
781 ruleBuilder.makePermanent();
782 } else {
783 ruleBuilder.makeTemporary(fwd.timeout());
784 }
785
Saurav Das822c4e22015-10-23 10:51:11 -0700786 return Collections.singletonList(ruleBuilder.build());
787 }
788
789 private void pass(Objective obj) {
790 if (obj.context().isPresent()) {
791 obj.context().get().onSuccess(obj);
792 }
793 }
794
Saurav Das8a0732e2015-11-20 15:27:53 -0800795 protected void fail(Objective obj, ObjectiveError error) {
Saurav Das822c4e22015-10-23 10:51:11 -0700796 if (obj.context().isPresent()) {
797 obj.context().get().onError(obj, error);
798 }
799 }
800
801 //////////////////////////////////////
802 // Group handling
803 //////////////////////////////////////
804
Saurav Das4f980082015-11-05 13:39:15 -0800805 private void addGroup(NextObjective nextObjective) {
806 switch (nextObjective.type()) {
807 case SIMPLE:
808 Collection<TrafficTreatment> treatments = nextObjective.next();
809 if (treatments.size() != 1) {
810 log.error("Next Objectives of type Simple should only have a "
811 + "single Traffic Treatment. Next Objective Id:{}",
812 nextObjective.id());
813 fail(nextObjective, ObjectiveError.BADPARAMS);
814 return;
815 }
816 processSimpleNextObjective(nextObjective);
817 break;
818 case BROADCAST:
819 processBroadcastNextObjective(nextObjective);
820 break;
821 case HASHED:
822 processHashedNextObjective(nextObjective);
823 break;
824 case FAILOVER:
825 fail(nextObjective, ObjectiveError.UNSUPPORTED);
826 log.warn("Unsupported next objective type {}", nextObjective.type());
827 break;
828 default:
829 fail(nextObjective, ObjectiveError.UNKNOWN);
830 log.warn("Unknown next objective type {}", nextObjective.type());
831 }
832 }
833
Saurav Das822c4e22015-10-23 10:51:11 -0700834 /**
835 * As per the OFDPA 2.0 TTP, packets are sent out of ports by using
Saurav Das8a0732e2015-11-20 15:27:53 -0800836 * a chain of groups. The simple Next Objective passed
Saurav Das822c4e22015-10-23 10:51:11 -0700837 * in by the application has to be broken up into a group chain
Saurav Das8a0732e2015-11-20 15:27:53 -0800838 * comprising of an L3 Unicast Group that points to an L2 Interface
839 * Group which in-turn points to an output port. In some cases, the simple
840 * next Objective can just be an L2 interface without the need for chaining.
Saurav Das822c4e22015-10-23 10:51:11 -0700841 *
842 * @param nextObj the nextObjective of type SIMPLE
843 */
844 private void processSimpleNextObjective(NextObjective nextObj) {
845 // break up simple next objective to GroupChain objects
846 TrafficTreatment treatment = nextObj.next().iterator().next();
Saurav Das8a0732e2015-11-20 15:27:53 -0800847
848 GroupInfo groupInfo = createL2L3Chain(treatment, nextObj.id(),
849 nextObj.appId(), false,
850 nextObj.meta());
851 if (groupInfo == null) {
852 log.error("Could not process nextObj={} in dev:{}", nextObj.id(), deviceId);
853 return;
854 }
855 // create object for local and distributed storage
856 Deque<GroupKey> gkeyChain = new ArrayDeque<>();
857 gkeyChain.addFirst(groupInfo.innerGrpDesc.appCookie());
858 gkeyChain.addFirst(groupInfo.outerGrpDesc.appCookie());
859 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(
860 Collections.singletonList(gkeyChain),
861 nextObj);
862
863 // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it
864 pendingNextObjectives.put(groupInfo.outerGrpDesc.appCookie(), ofdpaGrp);
865
866 // now we are ready to send the l2 groupDescription (inner), as all the stores
867 // that will get async replies have been updated. By waiting to update
868 // the stores, we prevent nasty race conditions.
869 groupService.addGroup(groupInfo.innerGrpDesc);
870 }
871
872 /**
873 * Creates one of two possible group-chains from the treatment
874 * passed in. Depending on the MPLS boolean, this method either creates
875 * an L3Unicast Group --> L2Interface Group, if mpls is false;
876 * or MPLSInterface Group --> L2Interface Group, if mpls is true;
877 * The returned 'inner' group description is always the L2 Interface group.
878 *
879 * @param treatment that needs to be broken up to create the group chain
880 * @param nextId of the next objective that needs this group chain
881 * @param appId of the application that sent this next objective
882 * @param mpls determines if L3Unicast or MPLSInterface group is created
883 * @param meta metadata passed in by the application as part of the nextObjective
884 * @return GroupInfo containing the GroupDescription of the
885 * L2Interface group(inner) and the GroupDescription of the (outer)
886 * L3Unicast/MPLSInterface group. May return null if there is an
887 * error in processing the chain
888 */
889 private GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId,
890 ApplicationId appId, boolean mpls,
891 TrafficSelector meta) {
Saurav Das822c4e22015-10-23 10:51:11 -0700892 // for the l2interface group, get vlan and port info
Saurav Das8a0732e2015-11-20 15:27:53 -0800893 // for the outer group, get the src/dst mac, and vlan info
894 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
895 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
Saurav Das822c4e22015-10-23 10:51:11 -0700896 VlanId vlanid = null;
897 long portNum = 0;
898 for (Instruction ins : treatment.allInstructions()) {
899 if (ins.type() == Instruction.Type.L2MODIFICATION) {
900 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
901 switch (l2ins.subtype()) {
902 case ETH_DST:
Saurav Das8a0732e2015-11-20 15:27:53 -0800903 outerTtb.setEthDst(((ModEtherInstruction) l2ins).mac());
Saurav Das822c4e22015-10-23 10:51:11 -0700904 break;
905 case ETH_SRC:
Saurav Das8a0732e2015-11-20 15:27:53 -0800906 outerTtb.setEthSrc(((ModEtherInstruction) l2ins).mac());
Saurav Das822c4e22015-10-23 10:51:11 -0700907 break;
908 case VLAN_ID:
909 vlanid = ((ModVlanIdInstruction) l2ins).vlanId();
Saurav Das8a0732e2015-11-20 15:27:53 -0800910 outerTtb.setVlanId(vlanid);
911 break;
912 case VLAN_POP:
913 innerTtb.popVlan();
Saurav Das822c4e22015-10-23 10:51:11 -0700914 break;
915 case DEC_MPLS_TTL:
916 case MPLS_LABEL:
917 case MPLS_POP:
918 case MPLS_PUSH:
919 case VLAN_PCP:
Saurav Das822c4e22015-10-23 10:51:11 -0700920 case VLAN_PUSH:
921 default:
922 break;
923 }
924 } else if (ins.type() == Instruction.Type.OUTPUT) {
925 portNum = ((OutputInstruction) ins).port().toLong();
Saurav Das8a0732e2015-11-20 15:27:53 -0800926 innerTtb.add(ins);
Saurav Das822c4e22015-10-23 10:51:11 -0700927 } else {
928 log.warn("Driver does not handle this type of TrafficTreatment"
929 + " instruction in nextObjectives: {}", ins.type());
930 }
931 }
932
Saurav Das8a0732e2015-11-20 15:27:53 -0800933 if (vlanid == null) {
934 //use the vlanid associated with the port
935 vlanid = port2Vlan.get(PortNumber.portNumber(portNum));
936 }
937
938 if (vlanid == null) {
939 // use metadata
940 for (Criterion metaCriterion : meta.criteria()) {
941 if (metaCriterion.type() == Type.VLAN_VID) {
942 vlanid = ((VlanIdCriterion) metaCriterion).vlanId();
943 }
944 }
945 }
946
947 if (vlanid == null) {
948 log.error("Driver cannot process an L2/L3 group chain without "
949 + "egress vlan information for dev: {} port:{}",
950 deviceId, portNum);
951 return null;
952 }
953
Saurav Das822c4e22015-10-23 10:51:11 -0700954 // assemble information for ofdpa l2interface group
Saurav Das822c4e22015-10-23 10:51:11 -0700955 Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum;
Saurav Das8a0732e2015-11-20 15:27:53 -0800956 // a globally unique groupkey that is different for ports in the same devices
957 // but different for the same portnumber on different devices. Also different
958 // for the various group-types created out of the same next objective.
959 int l2gk = 0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum);
960 final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk));
Saurav Das822c4e22015-10-23 10:51:11 -0700961
Saurav Das8a0732e2015-11-20 15:27:53 -0800962 // assemble information for outer group
963 GroupDescription outerGrpDesc = null;
964 if (mpls) {
965 // outer group is MPLSInteface
966 Integer mplsgroupId = MPLSINTERFACEMASK | (int) portNum;
967 // using mplsinterfacemask in groupkey to differentiate from l2interface
968 int mplsgk = MPLSINTERFACEMASK | (0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum));
969 final GroupKey mplsgroupkey = new DefaultGroupKey(appKryo.serialize(mplsgk));
970 outerTtb.group(new DefaultGroupId(l2groupId));
971 // create the mpls-interface group description to wait for the
972 // l2 interface group to be processed
973 GroupBucket mplsinterfaceGroupBucket =
974 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
975 outerGrpDesc = new DefaultGroupDescription(
976 deviceId,
977 GroupDescription.Type.INDIRECT,
978 new GroupBuckets(Collections.singletonList(
979 mplsinterfaceGroupBucket)),
980 mplsgroupkey,
981 mplsgroupId,
982 appId);
983 log.debug("Trying MPLS-Interface: device:{} gid:{} gkey:{} nextid:{}",
984 deviceId, Integer.toHexString(mplsgroupId),
985 mplsgroupkey, nextId);
986 } else {
987 // outer group is L3Unicast
988 Integer l3groupId = L3UNICASTMASK | (int) portNum;
989 int l3gk = L3UNICASTMASK | (0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum));
990 final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk));
991 outerTtb.group(new DefaultGroupId(l2groupId));
992 // create the l3unicast group description to wait for the
993 // l2 interface group to be processed
994 GroupBucket l3unicastGroupBucket =
995 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
996 outerGrpDesc = new DefaultGroupDescription(
997 deviceId,
998 GroupDescription.Type.INDIRECT,
999 new GroupBuckets(Collections.singletonList(
1000 l3unicastGroupBucket)),
1001 l3groupkey,
1002 l3groupId,
1003 appId);
1004 log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}",
1005 deviceId, Integer.toHexString(l3groupId),
1006 l3groupkey, nextId);
1007 }
Saurav Das822c4e22015-10-23 10:51:11 -07001008
Saurav Das8a0732e2015-11-20 15:27:53 -08001009 // store l2groupkey with the groupChainElem for the outer-group that depends on it
1010 GroupChainElem gce = new GroupChainElem(outerGrpDesc, 1);
1011 Set<GroupChainElem> gceSet = Collections.newSetFromMap(
1012 new ConcurrentHashMap<GroupChainElem, Boolean>());
1013 gceSet.add(gce);
1014 Set<GroupChainElem> retval = pendingGroups.putIfAbsent(l2groupkey, gceSet);
1015 if (retval != null) {
1016 retval.add(gce);
1017 }
Saurav Das822c4e22015-10-23 10:51:11 -07001018
Saurav Das8a0732e2015-11-20 15:27:53 -08001019 // create group description for the inner l2interfacegroup
1020 GroupBucket l2interfaceGroupBucket =
1021 DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build());
1022 GroupDescription l2groupDescription =
1023 new DefaultGroupDescription(
1024 deviceId,
1025 GroupDescription.Type.INDIRECT,
1026 new GroupBuckets(Collections.singletonList(
1027 l2interfaceGroupBucket)),
1028 l2groupkey,
1029 l2groupId,
1030 appId);
1031 log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}",
1032 deviceId, Integer.toHexString(l2groupId),
1033 l2groupkey, nextId);
1034 return new GroupInfo(l2groupDescription, outerGrpDesc);
Saurav Das822c4e22015-10-23 10:51:11 -07001035
Saurav Das822c4e22015-10-23 10:51:11 -07001036 }
1037
1038 /**
Saurav Das4f980082015-11-05 13:39:15 -08001039 * As per the OFDPA 2.0 TTP, packets are sent out of ports by using
Saurav Das8a0732e2015-11-20 15:27:53 -08001040 * a chain of groups. The broadcast Next Objective passed in by the application
Saurav Das4f980082015-11-05 13:39:15 -08001041 * has to be broken up into a group chain comprising of an
1042 * L2 Flood group whose buckets point to L2 Interface groups.
1043 *
1044 * @param nextObj the nextObjective of type BROADCAST
1045 */
1046 private void processBroadcastNextObjective(NextObjective nextObj) {
1047 // break up broadcast next objective to multiple groups
1048 Collection<TrafficTreatment> buckets = nextObj.next();
1049
1050 // each treatment is converted to an L2 interface group
Saurav Das4f980082015-11-05 13:39:15 -08001051 VlanId vlanid = null;
Saurav Das8a0732e2015-11-20 15:27:53 -08001052 List<GroupDescription> l2interfaceGroupDescs = new ArrayList<>();
1053 List<Deque<GroupKey>> allGroupKeys = new ArrayList<>();
Saurav Das4f980082015-11-05 13:39:15 -08001054 for (TrafficTreatment treatment : buckets) {
1055 TrafficTreatment.Builder newTreatment = DefaultTrafficTreatment.builder();
1056 PortNumber portNum = null;
1057 // ensure that the only allowed treatments are pop-vlan and output
1058 for (Instruction ins : treatment.allInstructions()) {
1059 if (ins.type() == Instruction.Type.L2MODIFICATION) {
1060 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
1061 switch (l2ins.subtype()) {
1062 case VLAN_POP:
1063 newTreatment.add(l2ins);
1064 break;
1065 default:
1066 log.debug("action {} not permitted for broadcast nextObj",
1067 l2ins.subtype());
1068 break;
1069 }
1070 } else if (ins.type() == Instruction.Type.OUTPUT) {
1071 portNum = ((OutputInstruction) ins).port();
1072 newTreatment.add(ins);
1073 } else {
1074 log.debug("TrafficTreatment of type {} not permitted in "
1075 + " broadcast nextObjective", ins.type());
1076 }
1077 }
1078
1079 // also ensure that all ports are in the same vlan
1080 VlanId thisvlanid = port2Vlan.get(portNum);
1081 if (vlanid == null) {
1082 vlanid = thisvlanid;
1083 } else {
1084 if (!vlanid.equals(thisvlanid)) {
1085 log.error("Driver requires all ports in a broadcast nextObj "
1086 + "to be in the same vlan. Different vlans found "
1087 + "{} and {}. Aborting group creation", vlanid, thisvlanid);
1088 return;
1089 }
1090 }
1091
Saurav Das8a0732e2015-11-20 15:27:53 -08001092 // assemble info for l2 interface group
1093 int l2gk = 0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum.toLong());
Saurav Das4f980082015-11-05 13:39:15 -08001094 final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk));
1095 Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) |
1096 (int) portNum.toLong();
Saurav Das8a0732e2015-11-20 15:27:53 -08001097 GroupBucket l2interfaceGroupBucket =
Saurav Das4f980082015-11-05 13:39:15 -08001098 DefaultGroupBucket.createIndirectGroupBucket(newTreatment.build());
Saurav Das8a0732e2015-11-20 15:27:53 -08001099 GroupDescription l2interfaceGroupDescription =
1100 new DefaultGroupDescription(
1101 deviceId,
1102 GroupDescription.Type.INDIRECT,
1103 new GroupBuckets(Collections.singletonList(
1104 l2interfaceGroupBucket)),
1105 l2groupkey,
1106 l2groupId,
1107 nextObj.appId());
1108 log.debug("Trying L2-Interface: device:{} gid:{} gkey:{} nextid:{}",
1109 deviceId, Integer.toHexString(l2groupId),
1110 l2groupkey, nextObj.id());
1111
1112 Deque<GroupKey> gkeyChain = new ArrayDeque<>();
1113 gkeyChain.addFirst(l2groupkey);
Saurav Das4f980082015-11-05 13:39:15 -08001114
1115 // store the info needed to create this group
Saurav Das8a0732e2015-11-20 15:27:53 -08001116 l2interfaceGroupDescs.add(l2interfaceGroupDescription);
1117 allGroupKeys.add(gkeyChain);
Saurav Das4f980082015-11-05 13:39:15 -08001118 }
1119
1120 // assemble info for l2 flood group
Saurav Das4f980082015-11-05 13:39:15 -08001121 Integer l2floodgroupId = L2FLOODMASK | (vlanid.toShort() << 16) | nextObj.id();
Saurav Das8a0732e2015-11-20 15:27:53 -08001122 int l2floodgk = L2FLOODMASK | nextObj.id() << 12;
1123 final GroupKey l2floodgroupkey = new DefaultGroupKey(appKryo.serialize(l2floodgk));
1124 // collection of group buckets pointing to all the l2 interface groups
1125 List<GroupBucket> l2floodBuckets = new ArrayList<>();
1126 for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) {
Saurav Das4f980082015-11-05 13:39:15 -08001127 TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder();
Saurav Das8a0732e2015-11-20 15:27:53 -08001128 ttb.group(new DefaultGroupId(l2intGrpDesc.givenGroupId()));
1129 GroupBucket abucket = DefaultGroupBucket.createAllGroupBucket(ttb.build());
1130 l2floodBuckets.add(abucket);
Saurav Das4f980082015-11-05 13:39:15 -08001131 }
Saurav Das8a0732e2015-11-20 15:27:53 -08001132 // create the l2flood group-description to wait for all the
1133 // l2interface groups to be processed
1134 GroupDescription l2floodGroupDescription =
1135 new DefaultGroupDescription(
1136 deviceId,
1137 GroupDescription.Type.ALL,
1138 new GroupBuckets(l2floodBuckets),
1139 l2floodgroupkey,
1140 l2floodgroupId,
1141 nextObj.appId());
1142 GroupChainElem gce = new GroupChainElem(l2floodGroupDescription,
1143 l2interfaceGroupDescs.size());
1144 log.debug("Trying L2-Flood: device:{} gid:{} gkey:{} nextid:{}",
1145 deviceId, Integer.toHexString(l2floodgroupId),
1146 l2floodgroupkey, nextObj.id());
Saurav Das4f980082015-11-05 13:39:15 -08001147
1148 // create objects for local and distributed storage
Saurav Das8a0732e2015-11-20 15:27:53 -08001149 allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(l2floodgroupkey));
1150 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj);
Saurav Das4f980082015-11-05 13:39:15 -08001151
1152 // store l2floodgroupkey with the ofdpaGroupChain for the nextObjective
1153 // that depends on it
1154 pendingNextObjectives.put(l2floodgroupkey, ofdpaGrp);
1155
Saurav Das8a0732e2015-11-20 15:27:53 -08001156 for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) {
Saurav Das4f980082015-11-05 13:39:15 -08001157 // store all l2groupkeys with the groupChainElem for the l2floodgroup
1158 // that depends on it
Saurav Das8a0732e2015-11-20 15:27:53 -08001159 Set<GroupChainElem> gceSet = Collections.newSetFromMap(
1160 new ConcurrentHashMap<GroupChainElem, Boolean>());
1161 gceSet.add(gce);
1162 Set<GroupChainElem> retval = pendingGroups.putIfAbsent(
1163 l2intGrpDesc.appCookie(), gceSet);
1164 if (retval != null) {
1165 retval.add(gce);
1166 }
Saurav Das4f980082015-11-05 13:39:15 -08001167
1168 // create and send groups for all l2 interface groups
Saurav Das8a0732e2015-11-20 15:27:53 -08001169 groupService.addGroup(l2intGrpDesc);
Saurav Das4f980082015-11-05 13:39:15 -08001170 }
1171 }
1172
Saurav Das8a0732e2015-11-20 15:27:53 -08001173 /**
1174 * Utility class for moving group information around.
1175 *
1176 */
Saurav Das4f980082015-11-05 13:39:15 -08001177 private class GroupInfo {
Saurav Das8a0732e2015-11-20 15:27:53 -08001178 private GroupDescription innerGrpDesc;
1179 private GroupDescription outerGrpDesc;
Saurav Das4f980082015-11-05 13:39:15 -08001180
Saurav Das8a0732e2015-11-20 15:27:53 -08001181 GroupInfo(GroupDescription innerGrpDesc, GroupDescription outerGrpDesc) {
1182 this.innerGrpDesc = innerGrpDesc;
1183 this.outerGrpDesc = outerGrpDesc;
Saurav Das4f980082015-11-05 13:39:15 -08001184 }
1185 }
1186
Saurav Das8a0732e2015-11-20 15:27:53 -08001187 /**
1188 * As per the OFDPA 2.0 TTP, packets are sent out of ports by using
1189 * a chain of groups. The hashed Next Objective passed in by the application
1190 * has to be broken up into a group chain comprising of an
1191 * L3 ECMP group as the top level group. Buckets of this group can point
1192 * to a variety of groups in a group chain, depending on the whether
1193 * MPLS labels are being pushed or not.
1194 * <p>
1195 * NOTE: We do not create MPLS ECMP groups as they are unimplemented in
1196 * OF-DPA 2.0 (even though it is in the spec). Therefore we do not
1197 * check the nextObjective meta.
1198 *
1199 * @param nextObj the nextObjective of type HASHED
1200 */
Saurav Das4f980082015-11-05 13:39:15 -08001201 private void processHashedNextObjective(NextObjective nextObj) {
Saurav Das8a0732e2015-11-20 15:27:53 -08001202 // break up hashed next objective to multiple groups
1203 Collection<TrafficTreatment> buckets = nextObj.next();
1204
1205 // storage for all group keys in the chain of groups created
1206 List<Deque<GroupKey>> allGroupKeys = new ArrayList<>();
1207 List<GroupInfo> unsentGroups = new ArrayList<>();
1208 for (TrafficTreatment bucket : buckets) {
1209 //figure out how many labels are pushed in each bucket
1210 int labelsPushed = 0;
1211 MplsLabel innermostLabel = null;
1212 for (Instruction ins : bucket.allInstructions()) {
1213 if (ins.type() == Instruction.Type.L2MODIFICATION) {
1214 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
1215 if (l2ins.subtype() == L2SubType.MPLS_PUSH) {
1216 labelsPushed++;
1217 }
1218 if (l2ins.subtype() == L2SubType.MPLS_LABEL) {
1219 if (innermostLabel == null) {
1220 innermostLabel = ((ModMplsLabelInstruction) l2ins).mplsLabel();
1221 }
1222 }
1223 }
1224 }
1225
1226 Deque<GroupKey> gkeyChain = new ArrayDeque<>();
1227 // XXX we only deal with 0 and 1 label push right now
1228 if (labelsPushed == 0) {
1229 GroupInfo nolabelGroupInfo = createL2L3Chain(bucket, nextObj.id(),
1230 nextObj.appId(), false,
1231 nextObj.meta());
1232 if (nolabelGroupInfo == null) {
1233 log.error("Could not process nextObj={} in dev:{}",
1234 nextObj.id(), deviceId);
1235 return;
1236 }
1237 gkeyChain.addFirst(nolabelGroupInfo.innerGrpDesc.appCookie());
1238 gkeyChain.addFirst(nolabelGroupInfo.outerGrpDesc.appCookie());
1239
1240 // we can't send the inner group description yet, as we have to
1241 // create the dependent ECMP group first. So we store..
1242 unsentGroups.add(nolabelGroupInfo);
1243
1244 } else if (labelsPushed == 1) {
1245 GroupInfo onelabelGroupInfo = createL2L3Chain(bucket, nextObj.id(),
1246 nextObj.appId(), true,
1247 nextObj.meta());
1248 if (onelabelGroupInfo == null) {
1249 log.error("Could not process nextObj={} in dev:{}",
1250 nextObj.id(), deviceId);
1251 return;
1252 }
1253 // we need to add another group to this chain - the L3VPN group
1254 TrafficTreatment.Builder l3vpnTtb = DefaultTrafficTreatment.builder();
1255 l3vpnTtb.pushMpls()
1256 .setMpls(innermostLabel)
1257 .setMplsBos(true)
1258 .copyTtlOut()
1259 .group(new DefaultGroupId(
1260 onelabelGroupInfo.outerGrpDesc.givenGroupId()));
1261 GroupBucket l3vpnGrpBkt =
1262 DefaultGroupBucket.createIndirectGroupBucket(l3vpnTtb.build());
1263 int l3vpngroupId = L3VPNMASK | l3vpnindex.incrementAndGet();
1264 int l3vpngk = L3VPNMASK | nextObj.id() << 12 | l3vpnindex.get();
1265 GroupKey l3vpngroupkey = new DefaultGroupKey(appKryo.serialize(l3vpngk));
1266 GroupDescription l3vpnGroupDesc =
1267 new DefaultGroupDescription(
1268 deviceId,
1269 GroupDescription.Type.INDIRECT,
1270 new GroupBuckets(Collections.singletonList(
1271 l3vpnGrpBkt)),
1272 l3vpngroupkey,
1273 l3vpngroupId,
1274 nextObj.appId());
1275 GroupChainElem l3vpnGce = new GroupChainElem(l3vpnGroupDesc, 1);
1276 Set<GroupChainElem> gceSet = Collections.newSetFromMap(
1277 new ConcurrentHashMap<GroupChainElem, Boolean>());
1278 gceSet.add(l3vpnGce);
1279 Set<GroupChainElem> retval = pendingGroups
1280 .putIfAbsent(onelabelGroupInfo.outerGrpDesc.appCookie(), gceSet);
1281 if (retval != null) {
1282 retval.add(l3vpnGce);
1283 }
1284
1285 gkeyChain.addFirst(onelabelGroupInfo.innerGrpDesc.appCookie());
1286 gkeyChain.addFirst(onelabelGroupInfo.outerGrpDesc.appCookie());
1287 gkeyChain.addFirst(l3vpngroupkey);
1288
1289 //now we can replace the outerGrpDesc with the one we just created
1290 onelabelGroupInfo.outerGrpDesc = l3vpnGroupDesc;
1291
1292 // we can't send the innermost group yet, as we have to create
1293 // the dependent ECMP group first. So we store ...
1294 unsentGroups.add(onelabelGroupInfo);
1295
1296 log.debug("Trying L3VPN: device:{} gid:{} gkey:{} nextId:{}",
1297 deviceId, Integer.toHexString(l3vpngroupId),
1298 l3vpngroupkey, nextObj.id());
1299
1300 } else {
1301 log.warn("Driver currently does not handle more than 1 MPLS "
1302 + "labels. Not processing nextObjective {}", nextObj);
1303 return;
1304 }
1305
1306 // all groups in this chain
1307 allGroupKeys.add(gkeyChain);
1308 }
1309
1310 // now we can create the outermost L3 ECMP group
1311 List<GroupBucket> l3ecmpGroupBuckets = new ArrayList<>();
1312 for (GroupInfo gi : unsentGroups) {
1313 // create ECMP bucket to point to the outer group
1314 TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder();
1315 ttb.group(new DefaultGroupId(gi.outerGrpDesc.givenGroupId()));
1316 GroupBucket sbucket = DefaultGroupBucket
1317 .createSelectGroupBucket(ttb.build());
1318 l3ecmpGroupBuckets.add(sbucket);
1319 }
1320 int l3ecmpGroupId = L3ECMPMASK | nextObj.id() << 12;
1321 GroupKey l3ecmpGroupKey = new DefaultGroupKey(appKryo.serialize(l3ecmpGroupId));
1322 GroupDescription l3ecmpGroupDesc =
1323 new DefaultGroupDescription(
1324 deviceId,
1325 GroupDescription.Type.SELECT,
1326 new GroupBuckets(l3ecmpGroupBuckets),
1327 l3ecmpGroupKey,
1328 l3ecmpGroupId,
1329 nextObj.appId());
1330 GroupChainElem l3ecmpGce = new GroupChainElem(l3ecmpGroupDesc,
1331 l3ecmpGroupBuckets.size());
1332
1333 // create objects for local and distributed storage
1334 allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(l3ecmpGroupKey));
1335 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj);
1336
1337 // store l3ecmpGroupKey with the ofdpaGroupChain for the nextObjective
1338 // that depends on it
1339 pendingNextObjectives.put(l3ecmpGroupKey, ofdpaGrp);
1340
1341 log.debug("Trying L3ECMP: device:{} gid:{} gkey:{} nextId:{}",
1342 deviceId, Integer.toHexString(l3ecmpGroupId),
1343 l3ecmpGroupKey, nextObj.id());
1344 // finally we are ready to send the innermost groups
1345 for (GroupInfo gi : unsentGroups) {
1346 log.debug("Sending innermost group {} in group chain on device {} ",
1347 Integer.toHexString(gi.innerGrpDesc.givenGroupId()), deviceId);
1348 Set<GroupChainElem> gceSet = Collections.newSetFromMap(
1349 new ConcurrentHashMap<GroupChainElem, Boolean>());
1350 gceSet.add(l3ecmpGce);
1351 Set<GroupChainElem> retval = pendingGroups
1352 .putIfAbsent(gi.outerGrpDesc.appCookie(), gceSet);
1353 if (retval != null) {
1354 retval.add(l3ecmpGce);
1355 }
1356
1357 groupService.addGroup(gi.innerGrpDesc);
1358 }
1359
Saurav Das4f980082015-11-05 13:39:15 -08001360 }
1361
1362 private void addBucketToGroup(NextObjective nextObjective) {
1363 // TODO Auto-generated method stub
1364 }
1365
Saurav Das8a0732e2015-11-20 15:27:53 -08001366 private void waitToAddBucketToGroup(NextObjective nextObjective) {
1367 // TODO Auto-generated method stub
1368 }
1369
Saurav Das4f980082015-11-05 13:39:15 -08001370 private void removeBucketFromGroup(NextObjective nextObjective) {
1371 // TODO Auto-generated method stub
1372 }
1373
1374 private void removeGroup(NextObjective nextObjective) {
1375 // TODO Auto-generated method stub
1376 }
1377
1378 /**
Saurav Das822c4e22015-10-23 10:51:11 -07001379 * Processes next element of a group chain. Assumption is that if this
1380 * group points to another group, the latter has already been created
1381 * and this driver has received notification for it. A second assumption is
1382 * that if there is another group waiting for this group then the appropriate
1383 * stores already have the information to act upon the notification for the
1384 * creating of this group.
Saurav Das4f980082015-11-05 13:39:15 -08001385 * <p>
1386 * The processing of the GroupChainElement depends on the number of groups
1387 * this element is waiting on. For all group types other than SIMPLE, a
1388 * GroupChainElement could be waiting on multiple groups.
Saurav Das822c4e22015-10-23 10:51:11 -07001389 *
1390 * @param gce the group chain element to be processed next
1391 */
1392 private void processGroupChain(GroupChainElem gce) {
Saurav Das4f980082015-11-05 13:39:15 -08001393 int waitOnGroups = gce.decrementAndGetGroupsWaitedOn();
1394 if (waitOnGroups != 0) {
Saurav Das8a0732e2015-11-20 15:27:53 -08001395 log.debug("GCE: {} not ready to be processed", gce);
Saurav Das4f980082015-11-05 13:39:15 -08001396 return;
1397 }
Saurav Das8a0732e2015-11-20 15:27:53 -08001398 log.debug("GCE: {} ready to be processed", gce);
1399 groupService.addGroup(gce.groupDescription);
Saurav Das4f980082015-11-05 13:39:15 -08001400 }
Saurav Das822c4e22015-10-23 10:51:11 -07001401
1402 private class GroupChecker implements Runnable {
1403 @Override
1404 public void run() {
1405 Set<GroupKey> keys = pendingGroups.keySet().stream()
1406 .filter(key -> groupService.getGroup(deviceId, key) != null)
1407 .collect(Collectors.toSet());
1408 Set<GroupKey> otherkeys = pendingNextObjectives.asMap().keySet().stream()
1409 .filter(otherkey -> groupService.getGroup(deviceId, otherkey) != null)
1410 .collect(Collectors.toSet());
1411 keys.addAll(otherkeys);
1412
1413 keys.stream().forEach(key -> {
1414 //first check for group chain
Saurav Das8a0732e2015-11-20 15:27:53 -08001415 Set<GroupChainElem> gceSet = pendingGroups.remove(key);
1416 if (gceSet != null) {
1417 for (GroupChainElem gce : gceSet) {
1418 log.info("Group service processed group key {} in device {}. "
1419 + "Processing next group in group chain with group id {}",
1420 key, deviceId,
1421 Integer.toHexString(gce.groupDescription.givenGroupId()));
1422 processGroupChain(gce);
1423 }
Saurav Das822c4e22015-10-23 10:51:11 -07001424 } else {
Saurav Das8a0732e2015-11-20 15:27:53 -08001425 OfdpaNextGroup obj = pendingNextObjectives.getIfPresent(key);
Saurav Das822c4e22015-10-23 10:51:11 -07001426 if (obj != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -08001427 log.info("Group service processed group key {} in device:{}. "
1428 + "Done implementing next objective: {} <<-->> gid:{}",
1429 key, deviceId, obj.nextObjective().id(),
1430 Integer.toHexString(groupService.getGroup(deviceId, key)
1431 .givenGroupId()));
Saurav Das822c4e22015-10-23 10:51:11 -07001432 pass(obj.nextObjective());
1433 pendingNextObjectives.invalidate(key);
1434 flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj);
1435 }
1436 }
1437 });
1438 }
1439 }
1440
1441 private class InnerGroupListener implements GroupListener {
1442 @Override
1443 public void event(GroupEvent event) {
Saurav Das8a0732e2015-11-20 15:27:53 -08001444 log.trace("received group event of type {}", event.type());
Saurav Das822c4e22015-10-23 10:51:11 -07001445 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
1446 GroupKey key = event.subject().appCookie();
1447 // first check for group chain
Saurav Das8a0732e2015-11-20 15:27:53 -08001448 Set<GroupChainElem> gceSet = pendingGroups.remove(key);
1449 if (gceSet != null) {
1450 for (GroupChainElem gce : gceSet) {
1451 log.info("group ADDED with group key {} .. "
1452 + "Processing next group in group chain with group key {}",
1453 key,
1454 gce.groupDescription.appCookie());
1455 processGroupChain(gce);
1456 }
Saurav Das822c4e22015-10-23 10:51:11 -07001457 } else {
Saurav Das8a0732e2015-11-20 15:27:53 -08001458 OfdpaNextGroup obj = pendingNextObjectives.getIfPresent(key);
Saurav Das822c4e22015-10-23 10:51:11 -07001459 if (obj != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -08001460 log.info("group ADDED with key {} in dev {}.. Done implementing next "
1461 + "objective: {} <<-->> gid:{}",
1462 key, deviceId, obj.nextObjective().id(),
1463 Integer.toHexString(groupService.getGroup(deviceId, key)
1464 .givenGroupId()));
Saurav Das822c4e22015-10-23 10:51:11 -07001465 pass(obj.nextObjective());
1466 pendingNextObjectives.invalidate(key);
1467 flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj);
1468 }
1469 }
1470 }
1471 }
1472 }
1473
1474 /**
Saurav Das8a0732e2015-11-20 15:27:53 -08001475 * Represents an entire group-chain that implements a Next-Objective from
1476 * the application. The objective is represented as a list of deques, where
1477 * each deque can is a separate chain of groups.
1478 * <p>
1479 * For example, an ECMP group with 3 buckets, where each bucket points to
1480 * a group chain of L3 Unicast and L2 interface groups will look like this:
1481 * <ul>
1482 * <li>List[0] is a Deque of GroupKeyECMP(first)-GroupKeyL3(middle)-GroupKeyL2(last)
1483 * <li>List[1] is a Deque of GroupKeyECMP(first)-GroupKeyL3(middle)-GroupKeyL2(last)
1484 * <li>List[2] is a Deque of GroupKeyECMP(first)-GroupKeyL3(middle)-GroupKeyL2(last)
1485 * </ul>
1486 * where the first element of each deque is the same, representing the
1487 * top level ECMP group, while every other element represents a unique groupKey.
1488 * <p>
1489 * Also includes information about the next objective that
1490 * resulted in this group-chain.
Saurav Das4f980082015-11-05 13:39:15 -08001491 *
Saurav Das822c4e22015-10-23 10:51:11 -07001492 */
Saurav Das8a0732e2015-11-20 15:27:53 -08001493 private class OfdpaNextGroup implements NextGroup {
Saurav Das822c4e22015-10-23 10:51:11 -07001494 private final NextObjective nextObj;
Saurav Das8a0732e2015-11-20 15:27:53 -08001495 private final List<Deque<GroupKey>> gkeys;
Saurav Das822c4e22015-10-23 10:51:11 -07001496
Saurav Das8a0732e2015-11-20 15:27:53 -08001497 public OfdpaNextGroup(List<Deque<GroupKey>> gkeys, NextObjective nextObj) {
Saurav Das822c4e22015-10-23 10:51:11 -07001498 this.gkeys = gkeys;
1499 this.nextObj = nextObj;
1500 }
1501
1502 @SuppressWarnings("unused")
Saurav Das8a0732e2015-11-20 15:27:53 -08001503 public List<Deque<GroupKey>> groupKey() {
Saurav Das822c4e22015-10-23 10:51:11 -07001504 return gkeys;
1505 }
1506
1507 public NextObjective nextObjective() {
1508 return nextObj;
1509 }
1510
1511 @Override
1512 public byte[] data() {
1513 return appKryo.serialize(gkeys);
1514 }
1515
1516 }
1517
1518 /**
1519 * Represents a group element that is part of a chain of groups.
1520 * Stores enough information to create a Group Description to add the group
1521 * to the switch by requesting the Group Service. Objects instantiating this
1522 * class are meant to be temporary and live as long as it is needed to wait for
1523 * preceding groups in the group chain to be created.
1524 */
1525 private class GroupChainElem {
Saurav Das8a0732e2015-11-20 15:27:53 -08001526 private GroupDescription groupDescription;
Saurav Das4f980082015-11-05 13:39:15 -08001527 private AtomicInteger waitOnGroups;
Saurav Das822c4e22015-10-23 10:51:11 -07001528
Saurav Das8a0732e2015-11-20 15:27:53 -08001529 GroupChainElem(GroupDescription groupDescription, int waitOnGroups) {
1530 this.groupDescription = groupDescription;
Saurav Das4f980082015-11-05 13:39:15 -08001531 this.waitOnGroups = new AtomicInteger(waitOnGroups);
Saurav Das822c4e22015-10-23 10:51:11 -07001532 }
1533
Saurav Das4f980082015-11-05 13:39:15 -08001534 /**
1535 * This methods atomically decrements the counter for the number of
1536 * groups this GroupChainElement is waiting on, for notifications from
1537 * the Group Service. When this method returns a value of 0, this
1538 * GroupChainElement is ready to be processed.
1539 *
1540 * @return integer indication of the number of notifications being waited on
1541 */
1542 int decrementAndGetGroupsWaitedOn() {
1543 return waitOnGroups.decrementAndGet();
Saurav Das822c4e22015-10-23 10:51:11 -07001544 }
1545
Saurav Das4f980082015-11-05 13:39:15 -08001546 @Override
1547 public String toString() {
Saurav Das8a0732e2015-11-20 15:27:53 -08001548 return (Integer.toHexString(groupDescription.givenGroupId()) +
1549 " groupKey: " + groupDescription.appCookie() +
1550 " waiting-on-groups: " + waitOnGroups.get() +
1551 " device: " + deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -07001552 }
1553
1554 }
1555
1556 //////////////////////////////////////
1557 // Test code to be used for future
1558 // static-flow-pusher app
1559 //////////////////////////////////////
1560
1561 public void processStaticFlows() {
1562 //processPortTable();
1563 processGroupTable();
1564 processVlanTable();
1565 processTmacTable();
1566 processIpTable();
1567 //processMcastTable();
1568 //processBridgingTable();
1569 processAclTable();
1570 sendPackets();
1571 processMplsTable();
1572 }
1573
1574 protected void processGroupTable() {
1575 TrafficTreatment.Builder act = DefaultTrafficTreatment.builder();
1576
1577 act.popVlan(); // to send out untagged packets
1578 act.setOutput(PortNumber.portNumber(24));
1579 GroupBucket bucket =
1580 DefaultGroupBucket.createIndirectGroupBucket(act.build());
1581 final GroupKey groupkey = new DefaultGroupKey(appKryo.serialize(500));
1582 Integer groupId = 0x00c80018; //l2 interface, vlan 200, port 24
1583 GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
1584 GroupDescription.Type.INDIRECT,
1585 new GroupBuckets(Collections.singletonList(bucket)),
1586 groupkey,
1587 groupId,
1588 driverId);
1589 groupService.addGroup(groupDescription);
1590
1591 TrafficTreatment.Builder act2 = DefaultTrafficTreatment.builder();
1592 act2.setOutput(PortNumber.portNumber(40));
1593 GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(act2.build());
1594 final GroupKey groupkey2 = new DefaultGroupKey(appKryo.serialize(502));
1595 Integer groupId2 = 0x00c50028; //l2 interface, vlan 197, port 40
1596 GroupDescription groupDescription2 = new DefaultGroupDescription(deviceId,
1597 GroupDescription.Type.INDIRECT,
1598 new GroupBuckets(Collections.singletonList(bucket2)),
1599 groupkey2,
1600 groupId2,
1601 driverId);
1602 groupService.addGroup(groupDescription2);
1603
1604 while (groupService.getGroup(deviceId, groupkey2) == null) {
1605 try {
1606 Thread.sleep(500);
1607 } catch (InterruptedException e) {
1608 // TODO Auto-generated catch block
1609 e.printStackTrace();
1610 }
1611 }
1612
1613 //Now for L3 Unicast group
1614 TrafficTreatment.Builder act3 = DefaultTrafficTreatment.builder();
1615 act3.setEthDst(MacAddress.valueOf(0x2020));
1616 act3.setEthSrc(MacAddress.valueOf(0x1010));
1617 act3.setVlanId(VlanId.vlanId((short) 200));
1618 act3.group(new DefaultGroupId(0x00c80018)); // point to L2 interface
1619 // MPLS interface group - does not work for popping single label
1620 //Integer secGroupId = MPLSINTERFACEMASK | 38; // 0x90000026
1621 Integer groupId3 = L3UNICASTMASK | 1; // 0x20000001
1622 GroupBucket bucket3 =
1623 DefaultGroupBucket.createIndirectGroupBucket(act3.build());
1624 final GroupKey groupkey3 = new DefaultGroupKey(appKryo.serialize(503));
1625 GroupDescription groupDescription3 = new DefaultGroupDescription(deviceId,
1626 GroupDescription.Type.INDIRECT,
1627 new GroupBuckets(Collections.singletonList(bucket3)),
1628 groupkey3,
1629 groupId3,
1630 driverId);
1631 groupService.addGroup(groupDescription3);
1632
1633 //Another L3 Unicast group
1634 TrafficTreatment.Builder act4 = DefaultTrafficTreatment.builder();
1635 act4.setEthDst(MacAddress.valueOf(0x3030));
1636 act4.setEthSrc(MacAddress.valueOf(0x1010));
1637 act4.setVlanId(VlanId.vlanId((short) 197));
1638 act4.group(new DefaultGroupId(0x00c50028)); // point to L2 interface
1639 Integer groupId4 = L3UNICASTMASK | 2; // 0x20000002
1640 GroupBucket bucket4 =
1641 DefaultGroupBucket.createIndirectGroupBucket(act4.build());
1642 final GroupKey groupkey4 = new DefaultGroupKey(appKryo.serialize(504));
1643 GroupDescription groupDescription4 = new DefaultGroupDescription(deviceId,
1644 GroupDescription.Type.INDIRECT,
1645 new GroupBuckets(Collections.singletonList(bucket4)),
1646 groupkey4,
1647 groupId4,
1648 driverId);
1649 groupService.addGroup(groupDescription4);
1650
1651 while (groupService.getGroup(deviceId, groupkey4) == null) {
1652 try {
1653 Thread.sleep(500);
1654 } catch (InterruptedException e) {
1655 // TODO Auto-generated catch block
1656 e.printStackTrace();
1657 }
1658 }
1659
1660 // L3 ecmp group
1661 TrafficTreatment.Builder act5 = DefaultTrafficTreatment.builder();
1662 act5.group(new DefaultGroupId(0x20000001));
1663 TrafficTreatment.Builder act6 = DefaultTrafficTreatment.builder();
1664 act6.group(new DefaultGroupId(0x20000002));
1665 GroupBucket buckete1 =
1666 DefaultGroupBucket.createSelectGroupBucket(act5.build());
1667 GroupBucket buckete2 =
1668 DefaultGroupBucket.createSelectGroupBucket(act6.build());
1669 List<GroupBucket> bktlist = new ArrayList<GroupBucket>();
1670 bktlist.add(buckete1);
1671 bktlist.add(buckete2);
1672 final GroupKey groupkey5 = new DefaultGroupKey(appKryo.serialize(505));
1673 Integer groupId5 = L3ECMPMASK | 5; // 0x70000005
1674 GroupDescription groupDescription5 = new DefaultGroupDescription(deviceId,
1675 GroupDescription.Type.SELECT,
1676 new GroupBuckets(bktlist),
1677 groupkey5,
1678 groupId5,
1679 driverId);
1680 groupService.addGroup(groupDescription5);
1681
1682
1683 }
1684
1685 @SuppressWarnings("deprecation")
1686 protected void processMplsTable() {
1687 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1688 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1689 selector.matchEthType(Ethernet.MPLS_UNICAST);
1690 selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); //255
1691 selector.matchMplsBos(true);
1692 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1693 treatment.decMplsTtl(); // nw_ttl does not work
1694 treatment.copyTtlIn();
1695 treatment.popMpls(Ethernet.TYPE_IPV4);
1696 treatment.deferred().group(new DefaultGroupId(0x20000001)); // point to L3 Unicast
1697 //treatment.deferred().group(new DefaultGroupId(0x70000005)); // point to L3 ECMP
1698 treatment.transition(ACL_TABLE);
1699 FlowRule test = DefaultFlowRule.builder().forDevice(deviceId)
1700 .withSelector(selector.build()).withTreatment(treatment.build())
1701 .withPriority(DEFAULT_PRIORITY).fromApp(driverId).makePermanent()
1702 .forTable(24).build();
1703 ops = ops.add(test);
1704
1705 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1706 @Override
1707 public void onSuccess(FlowRuleOperations ops) {
1708 log.info("Initialized mpls table");
1709 }
1710
1711 @Override
1712 public void onError(FlowRuleOperations ops) {
1713 log.info("Failed to initialize mpls table");
1714 }
1715 }));
1716
1717 }
1718
1719 protected void processPortTable() {
1720 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1721 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1722 selector.matchInPort(PortNumber.portNumber(0)); // should be maskable?
1723 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1724 treatment.transition(VLAN_TABLE);
1725 FlowRule tmisse = DefaultFlowRule.builder()
1726 .forDevice(deviceId)
1727 .withSelector(selector.build())
1728 .withTreatment(treatment.build())
1729 .withPriority(LOWEST_PRIORITY)
1730 .fromApp(driverId)
1731 .makePermanent()
1732 .forTable(PORT_TABLE).build();
1733 ops = ops.add(tmisse);
1734
1735 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1736 @Override
1737 public void onSuccess(FlowRuleOperations ops) {
1738 log.info("Initialized port table");
1739 }
1740
1741 @Override
1742 public void onError(FlowRuleOperations ops) {
1743 log.info("Failed to initialize port table");
1744 }
1745 }));
1746
1747 }
1748
1749 private void processVlanTable() {
1750 // Table miss entry is not required as ofdpa default is to drop
1751 // In OF terms, the absence of a t.m.e. also implies drop
1752 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1753 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1754 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1755 selector.matchInPort(PortNumber.portNumber(12));
1756 selector.matchVlanId(VlanId.vlanId((short) 100));
1757 treatment.transition(TMAC_TABLE);
1758 FlowRule rule = DefaultFlowRule.builder()
1759 .forDevice(deviceId)
1760 .withSelector(selector.build())
1761 .withTreatment(treatment.build())
1762 .withPriority(DEFAULT_PRIORITY)
1763 .fromApp(driverId)
1764 .makePermanent()
1765 .forTable(VLAN_TABLE).build();
1766 ops = ops.add(rule);
1767 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1768 @Override
1769 public void onSuccess(FlowRuleOperations ops) {
1770 log.info("Initialized vlan table");
1771 }
1772
1773 @Override
1774 public void onError(FlowRuleOperations ops) {
1775 log.info("Failed to initialize vlan table");
1776 }
1777 }));
1778 }
1779
1780 protected void processTmacTable() {
1781 //table miss entry
1782 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1783 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1784 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1785 selector.matchInPort(PortNumber.portNumber(12));
1786 selector.matchVlanId(VlanId.vlanId((short) 100));
1787 selector.matchEthType(Ethernet.TYPE_IPV4);
1788 selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
1789 treatment.transition(UNICAST_ROUTING_TABLE);
1790 FlowRule rule = DefaultFlowRule.builder()
1791 .forDevice(deviceId)
1792 .withSelector(selector.build())
1793 .withTreatment(treatment.build())
1794 .withPriority(DEFAULT_PRIORITY)
1795 .fromApp(driverId)
1796 .makePermanent()
1797 .forTable(TMAC_TABLE).build();
1798 ops = ops.add(rule);
1799
1800 selector.matchEthType(Ethernet.MPLS_UNICAST);
1801 treatment.transition(MPLS_TABLE_0);
1802 FlowRule rulempls = DefaultFlowRule.builder()
1803 .forDevice(deviceId)
1804 .withSelector(selector.build())
1805 .withTreatment(treatment.build())
1806 .withPriority(DEFAULT_PRIORITY)
1807 .fromApp(driverId)
1808 .makePermanent()
1809 .forTable(TMAC_TABLE).build();
1810 ops = ops.add(rulempls);
1811
1812 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1813 @Override
1814 public void onSuccess(FlowRuleOperations ops) {
1815 log.info("Initialized tmac table");
1816 }
1817
1818 @Override
1819 public void onError(FlowRuleOperations ops) {
1820 log.info("Failed to initialize tmac table");
1821 }
1822 }));
1823 }
1824
1825 protected void processIpTable() {
1826 //table miss entry
1827 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1828 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1829 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1830 selector.matchEthType(Ethernet.TYPE_IPV4);
1831 selector.matchIPDst(IpPrefix.valueOf("2.0.0.0/16"));
1832 treatment.deferred().group(new DefaultGroupId(0x20000001));
1833 treatment.transition(ACL_TABLE);
1834 FlowRule rule = DefaultFlowRule.builder()
1835 .forDevice(deviceId)
1836 .withSelector(selector.build())
1837 .withTreatment(treatment.build())
1838 .withPriority(30000)
1839 .fromApp(driverId)
1840 .makePermanent()
1841 .forTable(UNICAST_ROUTING_TABLE).build();
1842 ops = ops.add(rule);
1843 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1844 @Override
1845 public void onSuccess(FlowRuleOperations ops) {
1846 log.info("Initialized IP table");
1847 }
1848
1849 @Override
1850 public void onError(FlowRuleOperations ops) {
1851 log.info("Failed to initialize unicast IP table");
1852 }
1853 }));
1854 }
1855
1856 protected void processAclTable() {
1857 //table miss entry
1858 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1859 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1860 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1861 selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
1862 treatment.deferred().group(new DefaultGroupId(0x20000001));
1863 FlowRule rule = DefaultFlowRule.builder()
1864 .forDevice(deviceId)
1865 .withSelector(selector.build())
1866 .withTreatment(treatment.build())
1867 .withPriority(60000)
1868 .fromApp(driverId)
1869 .makePermanent()
1870 .forTable(ACL_TABLE).build();
1871 ops = ops.add(rule);
1872 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1873 @Override
1874 public void onSuccess(FlowRuleOperations ops) {
1875 log.info("Initialized Acl table");
1876 }
1877
1878 @Override
1879 public void onError(FlowRuleOperations ops) {
1880 log.info("Failed to initialize Acl table");
1881 }
1882 }));
1883 }
1884
1885 private void sendPackets() {
1886 Ethernet eth = new Ethernet();
1887 eth.setDestinationMACAddress("00:00:00:00:00:02");
1888 eth.setSourceMACAddress("00:00:00:11:22:33");
1889 eth.setVlanID((short) 100);
1890 eth.setEtherType(Ethernet.MPLS_UNICAST);
1891 MPLS mplsPkt = new MPLS();
1892 mplsPkt.setLabel(255);
1893 mplsPkt.setTtl((byte) 5);
1894
1895 IPv4 ipv4 = new IPv4();
1896
1897 ipv4.setDestinationAddress("4.0.5.6");
1898 ipv4.setSourceAddress("1.0.2.3");
1899 ipv4.setTtl((byte) 64);
1900 ipv4.setChecksum((short) 0);
1901
1902 UDP udp = new UDP();
1903 udp.setDestinationPort(666);
1904 udp.setSourcePort(333);
1905 udp.setPayload(new Data(new byte[]{(byte) 1, (byte) 2}));
1906 udp.setChecksum((short) 0);
1907
1908 ipv4.setPayload(udp);
1909 mplsPkt.setPayload(ipv4);
1910 eth.setPayload(mplsPkt);
1911
1912 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1913 .setOutput(PortNumber.portNumber(24))
1914 .build();
1915 OutboundPacket packet = new DefaultOutboundPacket(deviceId,
1916 treatment,
1917 ByteBuffer.wrap(eth.serialize()));
1918
1919
1920 Ethernet eth2 = new Ethernet();
1921 eth2.setDestinationMACAddress("00:00:00:00:00:02");
1922 eth2.setSourceMACAddress("00:00:00:11:22:33");
1923 eth2.setVlanID((short) 100);
1924 eth2.setEtherType(Ethernet.TYPE_IPV4);
1925
1926 IPv4 ipv42 = new IPv4();
1927 ipv42.setDestinationAddress("2.0.0.2");
1928 ipv42.setSourceAddress("1.0.9.9");
1929 ipv42.setTtl((byte) 64);
1930 ipv42.setChecksum((short) 0);
1931
1932 UDP udp2 = new UDP();
1933 udp2.setDestinationPort(999);
1934 udp2.setSourcePort(333);
1935 udp2.setPayload(new Data(new byte[]{(byte) 1, (byte) 2}));
1936 udp2.setChecksum((short) 0);
1937
1938 ipv42.setPayload(udp2);
1939 eth2.setPayload(ipv42);
1940
1941 TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
1942 .setOutput(PortNumber.portNumber(26))
1943 .build();
1944 OutboundPacket packet2 = new DefaultOutboundPacket(deviceId,
1945 treatment2,
1946 ByteBuffer.wrap(eth2.serialize()));
1947
1948
1949 log.info("Emitting packets now");
1950 packetService.emit(packet);
1951 packetService.emit(packet);
1952 packetService.emit(packet2);
1953 packetService.emit(packet);
1954 packetService.emit(packet);
1955 log.info("Done emitting packets");
1956 }
1957
1958 private class InternalPacketProcessor implements PacketProcessor {
1959
1960 @Override
1961 public void process(PacketContext context) {
1962
1963
1964 }
1965 }
1966
1967}