Saurav Das
Committed by Gerrit Code Review

Drivers for Centec and Pica8 switches

Change-Id: I390c70716560275af7ee8bd40e6d161b6ed3b58f
1 +package org.onosproject.driver.pipeline;
2 +
3 +
4 +import com.google.common.cache.Cache;
5 +import com.google.common.cache.CacheBuilder;
6 +import com.google.common.cache.RemovalCause;
7 +import com.google.common.cache.RemovalNotification;
8 +
9 +import org.onlab.osgi.ServiceDirectory;
10 +import org.onlab.packet.Ethernet;
11 +import org.onlab.packet.IPv4;
12 +import org.onlab.packet.VlanId;
13 +import org.onlab.util.KryoNamespace;
14 +import org.onosproject.core.ApplicationId;
15 +import org.onosproject.core.CoreService;
16 +import org.onosproject.net.DeviceId;
17 +import org.onosproject.net.behaviour.NextGroup;
18 +import org.onosproject.net.behaviour.Pipeliner;
19 +import org.onosproject.net.behaviour.PipelinerContext;
20 +import org.onosproject.net.driver.AbstractHandlerBehaviour;
21 +import org.onosproject.net.flow.DefaultFlowRule;
22 +import org.onosproject.net.flow.DefaultTrafficSelector;
23 +import org.onosproject.net.flow.DefaultTrafficTreatment;
24 +import org.onosproject.net.flow.FlowRule;
25 +import org.onosproject.net.flow.FlowRuleOperations;
26 +import org.onosproject.net.flow.FlowRuleOperationsContext;
27 +import org.onosproject.net.flow.FlowRuleService;
28 +import org.onosproject.net.flow.TrafficSelector;
29 +import org.onosproject.net.flow.TrafficTreatment;
30 +import org.onosproject.net.flow.criteria.Criterion;
31 +import org.onosproject.net.flow.criteria.Criteria;
32 +import org.onosproject.net.flow.criteria.EthCriterion;
33 +import org.onosproject.net.flow.criteria.PortCriterion;
34 +import org.onosproject.net.flow.criteria.EthTypeCriterion;
35 +import org.onosproject.net.flow.criteria.IPCriterion;
36 +import org.onosproject.net.flow.criteria.VlanIdCriterion;
37 +import org.onosproject.net.flow.instructions.Instruction;
38 +import org.onosproject.net.flow.instructions.L2ModificationInstruction;
39 +import org.onosproject.net.flowobjective.FilteringObjective;
40 +import org.onosproject.net.flowobjective.FlowObjectiveStore;
41 +import org.onosproject.net.flowobjective.ForwardingObjective;
42 +import org.onosproject.net.flowobjective.NextObjective;
43 +import org.onosproject.net.flowobjective.Objective;
44 +import org.onosproject.net.flowobjective.ObjectiveError;
45 +import org.onosproject.net.group.DefaultGroupBucket;
46 +import org.onosproject.net.group.DefaultGroupDescription;
47 +import org.onosproject.net.group.DefaultGroupKey;
48 +import org.onosproject.net.group.Group;
49 +import org.onosproject.net.group.GroupBucket;
50 +import org.onosproject.net.group.GroupBuckets;
51 +import org.onosproject.net.group.GroupDescription;
52 +import org.onosproject.net.group.GroupEvent;
53 +import org.onosproject.net.group.GroupKey;
54 +import org.onosproject.net.group.GroupListener;
55 +import org.onosproject.net.group.GroupService;
56 +import org.slf4j.Logger;
57 +
58 +import java.util.Collection;
59 +import java.util.Collections;
60 +import java.util.Set;
61 +import java.util.concurrent.Executors;
62 +import java.util.concurrent.ScheduledExecutorService;
63 +import java.util.concurrent.TimeUnit;
64 +import java.util.stream.Collectors;
65 +
66 +import static org.onlab.util.Tools.groupedThreads;
67 +import static org.slf4j.LoggerFactory.getLogger;
68 +
69 +/**
70 + * Driver for Centec's V350 switches.
71 + */
72 +public class CentecV350Pipeline extends AbstractHandlerBehaviour implements Pipeliner {
73 +
74 + protected static final int PORT_VLAN_TABLE = 0;
75 + protected static final int FILTER_TABLE = 1;
76 + // TMAC is configured in MAC Table to redirect packets to ROUTE_TABLE.
77 + protected static final int MAC_TABLE = 2;
78 + protected static final int ROUTE_TABLE = 3;
79 +
80 + private static final long DEFAULT_METADATA = 100;
81 +
82 + // Priority used in PORT_VLAN Table, the only priority accepted is PORT_VLAN_TABLE_PRIORITY.
83 + // The packet passed PORT+VLAN check will goto FILTER Table.
84 + private static final int PORT_VLAN_TABLE_PRIORITY = 0xffff;
85 +
86 + // Priority used in Filter Table.
87 + private static final int FILTER_TABLE_CONTROLLER_PRIORITY = 500;
88 + // TMAC priority should be lower than controller.
89 + private static final int FILTER_TABLE_TMAC_PRIORITY = 200;
90 + private static final int FILTER_TABLE_HIGHEST_PRIORITY = 0xffff;
91 +
92 + // Priority used in MAC Table.
93 + // We do exact matching for DMAC+metadata, so priority is ignored and required to be set to 0xffff.
94 + private static final int MAC_TABLE_PRIORITY = 0xffff;
95 +
96 + // Priority used in Route Table.
97 + // We do LPM matching in Route Table, so priority is ignored and required to be set to 0xffff.
98 + private static final int ROUTE_TABLE_PRIORITY = 0xffff;
99 +
100 + private static final short BGP_PORT = 179;
101 +
102 + private final Logger log = getLogger(getClass());
103 +
104 + private ServiceDirectory serviceDirectory;
105 + private FlowRuleService flowRuleService;
106 + private CoreService coreService;
107 + private GroupService groupService;
108 + private FlowObjectiveStore flowObjectiveStore;
109 + private DeviceId deviceId;
110 + private ApplicationId appId;
111 +
112 + private KryoNamespace appKryo = new KryoNamespace.Builder()
113 + .register(GroupKey.class)
114 + .register(DefaultGroupKey.class)
115 + .register(CentecV350Group.class)
116 + .register(byte[].class)
117 + .build();
118 +
119 + private Cache<GroupKey, NextObjective> pendingGroups;
120 +
121 + private ScheduledExecutorService groupChecker =
122 + Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
123 + "centec-V350-%d"));
124 +
125 + @Override
126 + public void init(DeviceId deviceId, PipelinerContext context) {
127 + this.serviceDirectory = context.directory();
128 + this.deviceId = deviceId;
129 +
130 + pendingGroups = CacheBuilder.newBuilder()
131 + .expireAfterWrite(20, TimeUnit.SECONDS)
132 + .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
133 + if (notification.getCause() == RemovalCause.EXPIRED) {
134 + fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
135 + }
136 + }).build();
137 +
138 + groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
139 +
140 + coreService = serviceDirectory.get(CoreService.class);
141 + flowRuleService = serviceDirectory.get(FlowRuleService.class);
142 + groupService = serviceDirectory.get(GroupService.class);
143 + flowObjectiveStore = context.store();
144 +
145 + groupService.addListener(new InnerGroupListener());
146 +
147 + appId = coreService.registerApplication(
148 + "org.onosproject.driver.CentecV350Pipeline");
149 +
150 + initializePipeline();
151 + }
152 +
153 + @Override
154 + public void filter(FilteringObjective filteringObjective) {
155 + if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
156 + processFilter(filteringObjective,
157 + filteringObjective.op() == Objective.Operation.ADD,
158 + filteringObjective.appId());
159 + } else {
160 + fail(filteringObjective, ObjectiveError.UNSUPPORTED);
161 + }
162 + }
163 +
164 + @Override
165 + public void forward(ForwardingObjective fwd) {
166 + Collection<FlowRule> rules;
167 + FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
168 +
169 + rules = processForward(fwd);
170 + switch (fwd.op()) {
171 + case ADD:
172 + rules.stream()
173 + .filter(rule -> rule != null)
174 + .forEach(flowBuilder::add);
175 + break;
176 + case REMOVE:
177 + rules.stream()
178 + .filter(rule -> rule != null)
179 + .forEach(flowBuilder::remove);
180 + break;
181 + default:
182 + fail(fwd, ObjectiveError.UNKNOWN);
183 + log.warn("Unknown forwarding type {}", fwd.op());
184 + }
185 +
186 +
187 + flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
188 + @Override
189 + public void onSuccess(FlowRuleOperations ops) {
190 + pass(fwd);
191 + }
192 +
193 + @Override
194 + public void onError(FlowRuleOperations ops) {
195 + fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
196 + }
197 + }));
198 +
199 + }
200 +
201 + @Override
202 + public void next(NextObjective nextObjective) {
203 + switch (nextObjective.type()) {
204 + case SIMPLE:
205 + Collection<TrafficTreatment> treatments = nextObjective.next();
206 + if (treatments.size() == 1) {
207 + TrafficTreatment treatment = treatments.iterator().next();
208 +
209 + // Since we do not support strip_vlan in PORT_VLAN table, we use mod_vlan
210 + // to modify the packet to desired vlan.
211 + // Note: if we use push_vlan here, the switch will add a second VLAN tag to the outgoing
212 + // packet, which is not what we want.
213 + TrafficTreatment.Builder treatmentWithoutPushVlan = DefaultTrafficTreatment.builder();
214 + VlanId modVlanId;
215 + for (Instruction ins : treatment.allInstructions()) {
216 + if (ins.type() == Instruction.Type.L2MODIFICATION) {
217 + L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
218 + switch (l2ins.subtype()) {
219 + case ETH_DST:
220 + treatmentWithoutPushVlan.setEthDst(
221 + ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac());
222 + break;
223 + case ETH_SRC:
224 + treatmentWithoutPushVlan.setEthSrc(
225 + ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac());
226 + break;
227 + case VLAN_ID:
228 + modVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
229 + treatmentWithoutPushVlan.setVlanId(modVlanId);
230 + break;
231 + default:
232 + break;
233 + }
234 + } else if (ins.type() == Instruction.Type.OUTPUT) {
235 + //long portNum = ((Instructions.OutputInstruction) ins).port().toLong();
236 + treatmentWithoutPushVlan.add(ins);
237 + } else {
238 + // Ignore the vlan_pcp action since it's does matter much.
239 + log.warn("Driver does not handle this type of TrafficTreatment"
240 + + " instruction in nextObjectives: {}", ins.type());
241 + }
242 + }
243 +
244 + GroupBucket bucket =
245 + DefaultGroupBucket.createIndirectGroupBucket(treatmentWithoutPushVlan.build());
246 + final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
247 + GroupDescription groupDescription
248 + = new DefaultGroupDescription(deviceId,
249 + GroupDescription.Type.INDIRECT,
250 + new GroupBuckets(Collections
251 + .singletonList(bucket)),
252 + key,
253 + null, // let group service determine group id
254 + nextObjective.appId());
255 + groupService.addGroup(groupDescription);
256 + pendingGroups.put(key, nextObjective);
257 + }
258 + break;
259 + case HASHED:
260 + case BROADCAST:
261 + case FAILOVER:
262 + fail(nextObjective, ObjectiveError.UNSUPPORTED);
263 + log.warn("Unsupported next objective type {}", nextObjective.type());
264 + break;
265 + default:
266 + fail(nextObjective, ObjectiveError.UNKNOWN);
267 + log.warn("Unknown next objective type {}", nextObjective.type());
268 + }
269 +
270 + }
271 +
272 + private Collection<FlowRule> processForward(ForwardingObjective fwd) {
273 + switch (fwd.flag()) {
274 + case SPECIFIC:
275 + return processSpecific(fwd);
276 + case VERSATILE:
277 + return processVersatile(fwd);
278 + default:
279 + fail(fwd, ObjectiveError.UNKNOWN);
280 + log.warn("Unknown forwarding flag {}", fwd.flag());
281 + }
282 + return Collections.emptySet();
283 + }
284 +
285 + private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
286 + log.warn("Driver does not support versatile forwarding objective");
287 + fail(fwd, ObjectiveError.UNSUPPORTED);
288 + return Collections.emptySet();
289 + }
290 +
291 + private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
292 + log.debug("Processing specific forwarding objective");
293 + TrafficSelector selector = fwd.selector();
294 + EthTypeCriterion ethType =
295 + (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
296 + if (ethType == null || ethType.ethType() != Ethernet.TYPE_IPV4) {
297 + fail(fwd, ObjectiveError.UNSUPPORTED);
298 + return Collections.emptySet();
299 + }
300 +
301 + // Must have metadata as key.
302 + TrafficSelector filteredSelector =
303 + DefaultTrafficSelector.builder()
304 + .matchEthType(Ethernet.TYPE_IPV4)
305 + .matchMetadata(DEFAULT_METADATA)
306 + .matchIPDst(
307 + ((IPCriterion)
308 + selector.getCriterion(Criterion.Type.IPV4_DST)).ip())
309 + .build();
310 +
311 + TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
312 +
313 + if (fwd.nextId() != null) {
314 + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
315 + GroupKey key = appKryo.deserialize(next.data());
316 + Group group = groupService.getGroup(deviceId, key);
317 + if (group == null) {
318 + log.warn("The group left!");
319 + fail(fwd, ObjectiveError.GROUPMISSING);
320 + return Collections.emptySet();
321 + }
322 + tb.group(group.id());
323 + }
324 +
325 + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
326 + .fromApp(fwd.appId())
327 + .withPriority(ROUTE_TABLE_PRIORITY)
328 + .forDevice(deviceId)
329 + .withSelector(filteredSelector)
330 + .withTreatment(tb.build());
331 +
332 + if (fwd.permanent()) {
333 + ruleBuilder.makePermanent();
334 + } else {
335 + ruleBuilder.makeTemporary(fwd.timeout());
336 + }
337 +
338 + ruleBuilder.forTable(ROUTE_TABLE);
339 +
340 + return Collections.singletonList(ruleBuilder.build());
341 +
342 + }
343 +
344 + private void processFilter(FilteringObjective filt, boolean install,
345 + ApplicationId applicationId) {
346 + PortCriterion p;
347 + if (!filt.key().equals(Criteria.dummy()) &&
348 + filt.key().type() == Criterion.Type.IN_PORT) {
349 + p = (PortCriterion) filt.key();
350 + } else {
351 + log.warn("No key defined in filtering objective from app: {}. Not"
352 + + "processing filtering objective", applicationId);
353 + fail(filt, ObjectiveError.UNKNOWN);
354 + return;
355 + }
356 +
357 + // Convert filtering conditions for switch-intfs into flow rules.
358 + FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
359 +
360 + for (Criterion c : filt.conditions()) {
361 + // Here we do a trick to install 2 flow rules to MAC_TABLE and ROUTE_TABLE.
362 + if (c.type() == Criterion.Type.ETH_DST) {
363 + EthCriterion e = (EthCriterion) c;
364 +
365 + // Install TMAC flow rule.
366 + log.debug("adding rule for Termination MAC in Filter Table: {}", e.mac());
367 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
368 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
369 + selector.matchEthDst(e.mac());
370 + // Add IPv4 matching explicitly since we will redirect it to ROUTE Table
371 + // through MAC table.
372 + selector.matchEthType(Ethernet.TYPE_IPV4);
373 + treatment.transition(MAC_TABLE);
374 + FlowRule rule = DefaultFlowRule.builder()
375 + .forDevice(deviceId)
376 + .withSelector(selector.build())
377 + .withTreatment(treatment.build())
378 + .withPriority(FILTER_TABLE_TMAC_PRIORITY)
379 + .fromApp(applicationId)
380 + .makePermanent()
381 + .forTable(FILTER_TABLE).build();
382 + ops = install ? ops.add(rule) : ops.remove(rule);
383 +
384 + // Must install another rule to direct the IPv4 packets that hit TMAC to
385 + // Route table.
386 + log.debug("adding rule for Termination MAC in MAC Table: {}", e.mac());
387 + selector = DefaultTrafficSelector.builder();
388 + treatment = DefaultTrafficTreatment.builder();
389 + selector.matchEthDst(e.mac());
390 + // MAC_Table must have metadata matching configured, use the default metadata.
391 + selector.matchMetadata(DEFAULT_METADATA);
392 + treatment.transition(ROUTE_TABLE);
393 + rule = DefaultFlowRule.builder()
394 + .forDevice(deviceId)
395 + .withSelector(selector.build())
396 + .withTreatment(treatment.build())
397 + .withPriority(MAC_TABLE_PRIORITY)
398 + .fromApp(applicationId)
399 + .makePermanent()
400 + .forTable(MAC_TABLE).build();
401 + ops = install ? ops.add(rule) : ops.remove(rule);
402 + } else if (c.type() == Criterion.Type.VLAN_VID) {
403 + VlanIdCriterion v = (VlanIdCriterion) c;
404 + log.debug("adding rule for VLAN: {}", v.vlanId());
405 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
406 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
407 + selector.matchVlanId(v.vlanId());
408 + selector.matchInPort(p.port());
409 + // Although the accepted packets will be sent to filter table, we must
410 + // explicitly set goto_table instruction here.
411 + treatment.transition(FILTER_TABLE);
412 + // We do not support strip vlan here, treatment.deferred().popVlan();
413 + // XXX: write_metadata seems not supported by ONOS now, use the switch CLI to
414 + // set default metadata written by PORT_VLAN Table.
415 + // PORT_VLAN table only accept 0xffff priority since it does exact match only.
416 + FlowRule rule = DefaultFlowRule.builder()
417 + .forDevice(deviceId)
418 + .withSelector(selector.build())
419 + .withTreatment(treatment.build())
420 + .withPriority(PORT_VLAN_TABLE_PRIORITY)
421 + .fromApp(applicationId)
422 + .makePermanent()
423 + .forTable(PORT_VLAN_TABLE).build();
424 + ops = install ? ops.add(rule) : ops.remove(rule);
425 + } else if (c.type() == Criterion.Type.IPV4_DST) {
426 + // TODO: not needed now? Why not?
427 + fail(filt, ObjectiveError.UNSUPPORTED);
428 + } else {
429 + log.warn("Driver does not currently process filtering condition"
430 + + " of type: {}", c.type());
431 + fail(filt, ObjectiveError.UNSUPPORTED);
432 + }
433 + }
434 +
435 + // apply filtering flow rules
436 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
437 + @Override
438 + public void onSuccess(FlowRuleOperations ops) {
439 + pass(filt);
440 + log.info("Applied filtering rules");
441 + }
442 +
443 + @Override
444 + public void onError(FlowRuleOperations ops) {
445 + fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
446 + log.info("Failed to apply filtering rules");
447 + }
448 + }));
449 + }
450 +
451 + private void pass(Objective obj) {
452 + if (obj.context().isPresent()) {
453 + obj.context().get().onSuccess(obj);
454 + }
455 + }
456 +
457 + private void fail(Objective obj, ObjectiveError error) {
458 + if (obj.context().isPresent()) {
459 + obj.context().get().onError(obj, error);
460 + }
461 + }
462 +
463 + private void initializePipeline() {
464 + // CENTEC_V350: PORT_VLAN_TABLE->FILTER_TABLE->MAC_TABLE(TMAC)->ROUTE_TABLE.
465 + processPortVlanTable(true);
466 + processFilterTable(true);
467 + }
468 +
469 + private void processPortVlanTable(boolean install) {
470 + // By default the packet are dropped, need install port+vlan by some ways.
471 +
472 + // XXX can we add table-miss-entry to drop? Code says drops by default
473 + // XXX TTP description says default goes to table1.
474 + // It also says that match is only on vlan -- not port-vlan -- which one is true?
475 + }
476 +
477 + private void processFilterTable(boolean install) {
478 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
479 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment
480 + .builder();
481 + FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
482 + FlowRule rule;
483 +
484 + // Punt ARP packets to controller by default.
485 + selector.matchEthType(Ethernet.TYPE_ARP);
486 + treatment.punt();
487 + rule = DefaultFlowRule.builder()
488 + .forDevice(deviceId)
489 + .withSelector(selector.build())
490 + .withTreatment(treatment.build())
491 + .withPriority(FILTER_TABLE_CONTROLLER_PRIORITY)
492 + .fromApp(appId)
493 + .makePermanent()
494 + .forTable(FILTER_TABLE).build();
495 + ops = install ? ops.add(rule) : ops.remove(rule);
496 +
497 + // Punt BGP packets to controller directly.
498 + selector = DefaultTrafficSelector.builder();
499 + treatment = DefaultTrafficTreatment.builder();
500 + selector.matchEthType(Ethernet.TYPE_IPV4)
501 + .matchIPProtocol(IPv4.PROTOCOL_TCP)
502 + .matchTcpSrc(BGP_PORT);
503 + treatment.punt();
504 + rule = DefaultFlowRule.builder()
505 + .forDevice(deviceId)
506 + .withPriority(FILTER_TABLE_HIGHEST_PRIORITY)
507 + .withSelector(selector.build())
508 + .withTreatment(treatment.build())
509 + .fromApp(appId)
510 + .makePermanent()
511 + .forTable(FILTER_TABLE).build();
512 + ops = install ? ops.add(rule) : ops.remove(rule);
513 +
514 + selector = DefaultTrafficSelector.builder();
515 + treatment = DefaultTrafficTreatment.builder();
516 + selector.matchEthType(Ethernet.TYPE_IPV4)
517 + .matchIPProtocol(IPv4.PROTOCOL_TCP)
518 + .matchTcpDst(BGP_PORT);
519 + treatment.punt();
520 + rule = DefaultFlowRule.builder()
521 + .forDevice(deviceId)
522 + .withPriority(FILTER_TABLE_HIGHEST_PRIORITY)
523 + .withSelector(selector.build())
524 + .withTreatment(treatment.build())
525 + .fromApp(appId)
526 + .makePermanent()
527 + .forTable(FILTER_TABLE).build();
528 +
529 + ops = install ? ops.add(rule) : ops.remove(rule);
530 +
531 + // Packet will be discard in PORT_VLAN table, no need to install rule in
532 + // filter table.
533 +
534 + // XXX does not tell me if packets are going to be dropped by default in
535 + // filter table or not? TTP says it will be dropped by default
536 +
537 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
538 + @Override
539 + public void onSuccess(FlowRuleOperations ops) {
540 + log.info("Provisioned filter table");
541 + }
542 +
543 + @Override
544 + public void onError(FlowRuleOperations ops) {
545 + log.info("Failed to provision filter table");
546 + }
547 + }));
548 + }
549 +
550 + private class InnerGroupListener implements GroupListener {
551 + @Override
552 + public void event(GroupEvent event) {
553 + if (event.type() == GroupEvent.Type.GROUP_ADDED) {
554 + GroupKey key = event.subject().appCookie();
555 +
556 + NextObjective obj = pendingGroups.getIfPresent(key);
557 + if (obj != null) {
558 + flowObjectiveStore.putNextGroup(obj.id(), new CentecV350Group(key));
559 + pass(obj);
560 + pendingGroups.invalidate(key);
561 + }
562 + }
563 + }
564 + }
565 +
566 +
567 + private class GroupChecker implements Runnable {
568 +
569 + @Override
570 + public void run() {
571 + Set<GroupKey> keys = pendingGroups.asMap().keySet().stream()
572 + .filter(key -> groupService.getGroup(deviceId, key) != null)
573 + .collect(Collectors.toSet());
574 +
575 + keys.stream().forEach(key -> {
576 + NextObjective obj = pendingGroups.getIfPresent(key);
577 + if (obj == null) {
578 + return;
579 + }
580 + pass(obj);
581 + pendingGroups.invalidate(key);
582 + log.info("Heard back from group service for group {}. "
583 + + "Applying pending forwarding objectives", obj.id());
584 + flowObjectiveStore.putNextGroup(obj.id(), new CentecV350Group(key));
585 + });
586 + }
587 + }
588 +
589 + private class CentecV350Group implements NextGroup {
590 +
591 + private final GroupKey key;
592 +
593 + public CentecV350Group(GroupKey key) {
594 + this.key = key;
595 + }
596 +
597 + @SuppressWarnings("unused")
598 + public GroupKey key() {
599 + return key;
600 + }
601 +
602 + @Override
603 + public byte[] data() {
604 + return appKryo.serialize(key);
605 + }
606 +
607 + }
608 +}
...@@ -815,6 +815,7 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli ...@@ -815,6 +815,7 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli
815 this.key = key; 815 this.key = key;
816 } 816 }
817 817
818 + @SuppressWarnings("unused")
818 public GroupKey key() { 819 public GroupKey key() {
819 return key; 820 return key;
820 } 821 }
......
1 +/*
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 + */
16 +package org.onosproject.driver.pipeline;
17 +
18 +import com.google.common.cache.Cache;
19 +import com.google.common.cache.CacheBuilder;
20 +import com.google.common.cache.RemovalCause;
21 +import com.google.common.cache.RemovalNotification;
22 +
23 +import org.onlab.osgi.ServiceDirectory;
24 +import org.onlab.packet.Ethernet;
25 +import org.onlab.packet.IPv4;
26 +import org.onlab.util.KryoNamespace;
27 +import org.onosproject.core.ApplicationId;
28 +import org.onosproject.core.CoreService;
29 +import org.onosproject.net.DeviceId;
30 +import org.onosproject.net.behaviour.NextGroup;
31 +import org.onosproject.net.behaviour.Pipeliner;
32 +import org.onosproject.net.behaviour.PipelinerContext;
33 +import org.onosproject.net.driver.AbstractHandlerBehaviour;
34 +import org.onosproject.net.flow.DefaultFlowRule;
35 +import org.onosproject.net.flow.DefaultTrafficSelector;
36 +import org.onosproject.net.flow.DefaultTrafficTreatment;
37 +import org.onosproject.net.flow.FlowRule;
38 +import org.onosproject.net.flow.FlowRuleOperations;
39 +import org.onosproject.net.flow.FlowRuleOperationsContext;
40 +import org.onosproject.net.flow.FlowRuleService;
41 +import org.onosproject.net.flow.TrafficSelector;
42 +import org.onosproject.net.flow.TrafficTreatment;
43 +import org.onosproject.net.flow.criteria.Criteria;
44 +import org.onosproject.net.flow.criteria.Criterion;
45 +import org.onosproject.net.flow.criteria.EthCriterion;
46 +import org.onosproject.net.flow.criteria.EthTypeCriterion;
47 +import org.onosproject.net.flow.criteria.IPCriterion;
48 +import org.onosproject.net.flow.criteria.IPProtocolCriterion;
49 +import org.onosproject.net.flow.criteria.PortCriterion;
50 +import org.onosproject.net.flow.criteria.VlanIdCriterion;
51 +import org.onosproject.net.flowobjective.FilteringObjective;
52 +import org.onosproject.net.flowobjective.FlowObjectiveStore;
53 +import org.onosproject.net.flowobjective.ForwardingObjective;
54 +import org.onosproject.net.flowobjective.NextObjective;
55 +import org.onosproject.net.flowobjective.Objective;
56 +import org.onosproject.net.flowobjective.ObjectiveError;
57 +import org.onosproject.net.group.DefaultGroupBucket;
58 +import org.onosproject.net.group.DefaultGroupDescription;
59 +import org.onosproject.net.group.DefaultGroupKey;
60 +import org.onosproject.net.group.Group;
61 +import org.onosproject.net.group.GroupBucket;
62 +import org.onosproject.net.group.GroupBuckets;
63 +import org.onosproject.net.group.GroupDescription;
64 +import org.onosproject.net.group.GroupEvent;
65 +import org.onosproject.net.group.GroupKey;
66 +import org.onosproject.net.group.GroupListener;
67 +import org.onosproject.net.group.GroupService;
68 +import org.slf4j.Logger;
69 +
70 +import java.util.Collection;
71 +import java.util.Collections;
72 +import java.util.Set;
73 +import java.util.concurrent.Executors;
74 +import java.util.concurrent.ScheduledExecutorService;
75 +import java.util.concurrent.TimeUnit;
76 +import java.util.stream.Collectors;
77 +
78 +import static org.onlab.util.Tools.groupedThreads;
79 +import static org.slf4j.LoggerFactory.getLogger;
80 +
81 +/**
82 + * Pica pipeline handler.
83 + */
84 +public class PicaPipeline extends AbstractHandlerBehaviour implements Pipeliner {
85 +
86 + protected static final int VLAN_TABLE = 252;
87 + protected static final int ETHTYPE_TABLE = 252;
88 + protected static final int IP_UNICAST_TABLE = 251;
89 + protected static final int ACL_TABLE = 251;
90 +
91 + private static final int CONTROLLER_PRIORITY = 255;
92 + private static final int DROP_PRIORITY = 0;
93 + private static final int HIGHEST_PRIORITY = 0xffff;
94 +
95 + private final Logger log = getLogger(getClass());
96 +
97 + private ServiceDirectory serviceDirectory;
98 + private FlowRuleService flowRuleService;
99 + private CoreService coreService;
100 + private GroupService groupService;
101 + private FlowObjectiveStore flowObjectiveStore;
102 + private DeviceId deviceId;
103 + private ApplicationId appId;
104 +
105 + private KryoNamespace appKryo = new KryoNamespace.Builder()
106 + .register(GroupKey.class)
107 + .register(DefaultGroupKey.class)
108 + .register(PicaGroup.class)
109 + .register(byte[].class)
110 + .build();
111 +
112 + private Cache<GroupKey, NextObjective> pendingGroups;
113 +
114 + private ScheduledExecutorService groupChecker =
115 + Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
116 + "ovs-pica-%d"));
117 +
118 + @Override
119 + public void init(DeviceId deviceId, PipelinerContext context) {
120 + this.serviceDirectory = context.directory();
121 + this.deviceId = deviceId;
122 +
123 + pendingGroups = CacheBuilder.newBuilder()
124 + .expireAfterWrite(20, TimeUnit.SECONDS)
125 + .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
126 + if (notification.getCause() == RemovalCause.EXPIRED) {
127 + fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
128 + }
129 + }).build();
130 +
131 + groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
132 +
133 + coreService = serviceDirectory.get(CoreService.class);
134 + flowRuleService = serviceDirectory.get(FlowRuleService.class);
135 + groupService = serviceDirectory.get(GroupService.class);
136 + flowObjectiveStore = context.store();
137 +
138 + groupService.addListener(new InnerGroupListener());
139 +
140 + appId = coreService.registerApplication(
141 + "org.onosproject.driver.OVSPicaPipeline");
142 +
143 + initializePipeline();
144 + }
145 +
146 + @Override
147 + public void filter(FilteringObjective filteringObjective) {
148 + if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
149 + processFilter(filteringObjective,
150 + filteringObjective.op() == Objective.Operation.ADD,
151 + filteringObjective.appId());
152 + } else {
153 + fail(filteringObjective, ObjectiveError.UNSUPPORTED);
154 + }
155 + }
156 +
157 + @Override
158 + public void forward(ForwardingObjective fwd) {
159 + Collection<FlowRule> rules;
160 + FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
161 +
162 + rules = processForward(fwd);
163 + switch (fwd.op()) {
164 + case ADD:
165 + rules.stream()
166 + .filter(rule -> rule != null)
167 + .forEach(flowBuilder::add);
168 + break;
169 + case REMOVE:
170 + rules.stream()
171 + .filter(rule -> rule != null)
172 + .forEach(flowBuilder::remove);
173 + break;
174 + default:
175 + fail(fwd, ObjectiveError.UNKNOWN);
176 + log.warn("Unknown forwarding type {}", fwd.op());
177 + }
178 +
179 +
180 + flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
181 + @Override
182 + public void onSuccess(FlowRuleOperations ops) {
183 + pass(fwd);
184 + }
185 +
186 + @Override
187 + public void onError(FlowRuleOperations ops) {
188 + fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
189 + }
190 + }));
191 +
192 + }
193 +
194 + @Override
195 + public void next(NextObjective nextObjective) {
196 + switch (nextObjective.type()) {
197 + case SIMPLE:
198 + Collection<TrafficTreatment> treatments = nextObjective.next();
199 + if (treatments.size() == 1) {
200 + TrafficTreatment treatment = treatments.iterator().next();
201 + GroupBucket bucket =
202 + DefaultGroupBucket.createIndirectGroupBucket(treatment);
203 + final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
204 + GroupDescription groupDescription
205 + = new DefaultGroupDescription(deviceId,
206 + GroupDescription.Type.INDIRECT,
207 + new GroupBuckets(Collections
208 + .singletonList(bucket)),
209 + key,
210 + null, // let group service determine group id
211 + nextObjective.appId());
212 + groupService.addGroup(groupDescription);
213 + pendingGroups.put(key, nextObjective);
214 + }
215 + break;
216 + case HASHED:
217 + case BROADCAST:
218 + case FAILOVER:
219 + fail(nextObjective, ObjectiveError.UNSUPPORTED);
220 + log.warn("Unsupported next objective type {}", nextObjective.type());
221 + break;
222 + default:
223 + fail(nextObjective, ObjectiveError.UNKNOWN);
224 + log.warn("Unknown next objective type {}", nextObjective.type());
225 + }
226 +
227 + }
228 +
229 + private Collection<FlowRule> processForward(ForwardingObjective fwd) {
230 + switch (fwd.flag()) {
231 + case SPECIFIC:
232 + return processSpecific(fwd);
233 + case VERSATILE:
234 + return processVersatile(fwd);
235 + default:
236 + fail(fwd, ObjectiveError.UNKNOWN);
237 + log.warn("Unknown forwarding flag {}", fwd.flag());
238 + }
239 + return Collections.emptySet();
240 + }
241 +
242 + private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
243 + log.debug("Processing versatile forwarding objective");
244 + TrafficSelector selector = fwd.selector();
245 +
246 + EthTypeCriterion ethType =
247 + (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
248 + if (ethType == null) {
249 + log.error("Versatile forwarding objective must include ethType");
250 + fail(fwd, ObjectiveError.UNKNOWN);
251 + return Collections.emptySet();
252 + }
253 + if (ethType.ethType() == Ethernet.TYPE_ARP) {
254 + log.warn("Driver automatically handles ARP packets by punting to controller "
255 + + " from ETHER table");
256 + pass(fwd);
257 + return Collections.emptySet();
258 + } else if (ethType.ethType() == Ethernet.TYPE_LLDP ||
259 + ethType.ethType() == Ethernet.TYPE_BSN) {
260 + log.warn("Driver currently does not currently handle LLDP packets");
261 + fail(fwd, ObjectiveError.UNSUPPORTED);
262 + return Collections.emptySet();
263 + } else if (ethType.ethType() == Ethernet.TYPE_IPV4) {
264 + IPCriterion ipSrc = (IPCriterion) selector
265 + .getCriterion(Criterion.Type.IPV4_SRC);
266 + IPCriterion ipDst = (IPCriterion) selector
267 + .getCriterion(Criterion.Type.IPV4_DST);
268 + IPProtocolCriterion ipProto = (IPProtocolCriterion) selector
269 + .getCriterion(Criterion.Type.IP_PROTO);
270 + if (ipSrc != null) {
271 + log.warn("Driver does not currently handle matching Src IP");
272 + fail(fwd, ObjectiveError.UNSUPPORTED);
273 + return Collections.emptySet();
274 + }
275 + if (ipDst != null) {
276 + log.error("Driver handles Dst IP matching as specific forwarding "
277 + + "objective, not versatile");
278 + fail(fwd, ObjectiveError.UNSUPPORTED);
279 + return Collections.emptySet();
280 + }
281 + if (ipProto != null && ipProto.protocol() == IPv4.PROTOCOL_TCP) {
282 + log.warn("Driver automatically punts all packets reaching the "
283 + + "LOCAL table to the controller");
284 + pass(fwd);
285 + return Collections.emptySet();
286 + }
287 + }
288 +
289 + log.warn("Driver does not support given versatile forwarding objective");
290 + fail(fwd, ObjectiveError.UNSUPPORTED);
291 + return Collections.emptySet();
292 + }
293 +
294 + private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
295 + log.debug("Processing specific forwarding objective");
296 + TrafficSelector selector = fwd.selector();
297 + EthTypeCriterion ethType =
298 + (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
299 + if (ethType == null || ethType.ethType() != Ethernet.TYPE_IPV4) {
300 + fail(fwd, ObjectiveError.UNSUPPORTED);
301 + return Collections.emptySet();
302 + }
303 +
304 + TrafficSelector filteredSelector =
305 + DefaultTrafficSelector.builder()
306 + .matchEthType(Ethernet.TYPE_IPV4)
307 + .matchIPDst(
308 + ((IPCriterion)
309 + selector.getCriterion(Criterion.Type.IPV4_DST)).ip())
310 + .build();
311 +
312 + TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
313 +
314 + if (fwd.nextId() != null) {
315 + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
316 + GroupKey key = appKryo.deserialize(next.data());
317 + Group group = groupService.getGroup(deviceId, key);
318 + if (group == null) {
319 + log.warn("The group left!");
320 + fail(fwd, ObjectiveError.GROUPMISSING);
321 + return Collections.emptySet();
322 + }
323 + tb.group(group.id());
324 + }
325 +
326 + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
327 + .fromApp(fwd.appId())
328 + .withPriority(fwd.priority())
329 + .forDevice(deviceId)
330 + .withSelector(filteredSelector)
331 + .withTreatment(tb.build());
332 +
333 + if (fwd.permanent()) {
334 + ruleBuilder.makePermanent();
335 + } else {
336 + ruleBuilder.makeTemporary(fwd.timeout());
337 + }
338 +
339 + ruleBuilder.forTable(IP_UNICAST_TABLE);
340 +
341 +
342 + return Collections.singletonList(ruleBuilder.build());
343 +
344 + }
345 +
346 + private void processFilter(FilteringObjective filt, boolean install,
347 + ApplicationId applicationId) {
348 + // This driver only processes filtering criteria defined with switch
349 + // ports as the key
350 + PortCriterion p;
351 + if (!filt.key().equals(Criteria.dummy()) &&
352 + filt.key().type() == Criterion.Type.IN_PORT) {
353 + p = (PortCriterion) filt.key();
354 + } else {
355 + log.warn("No key defined in filtering objective from app: {}. Not"
356 + + "processing filtering objective", applicationId);
357 + fail(filt, ObjectiveError.UNKNOWN);
358 + return;
359 + }
360 + // convert filtering conditions for switch-intfs into flowrules
361 + FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
362 + for (Criterion c : filt.conditions()) {
363 + if (c.type() == Criterion.Type.ETH_DST) {
364 + EthCriterion e = (EthCriterion) c;
365 + log.debug("adding rule for MAC: {}", e.mac());
366 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
367 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
368 + selector.matchEthDst(e.mac());
369 + treatment.transition(IP_UNICAST_TABLE);
370 + FlowRule rule = DefaultFlowRule.builder()
371 + .forDevice(deviceId)
372 + .withSelector(selector.build())
373 + .withTreatment(treatment.build())
374 + .withPriority(CONTROLLER_PRIORITY)
375 + .fromApp(applicationId)
376 + .makePermanent()
377 + .forTable(ETHTYPE_TABLE).build();
378 + ops = install ? ops.add(rule) : ops.remove(rule);
379 + } else if (c.type() == Criterion.Type.VLAN_VID) {
380 + VlanIdCriterion v = (VlanIdCriterion) c;
381 + log.debug("adding rule for VLAN: {}", v.vlanId());
382 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
383 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
384 + selector.matchVlanId(v.vlanId());
385 + selector.matchInPort(p.port());
386 + treatment.transition(ETHTYPE_TABLE);
387 + treatment.deferred().popVlan();
388 + FlowRule rule = DefaultFlowRule.builder()
389 + .forDevice(deviceId)
390 + .withSelector(selector.build())
391 + .withTreatment(treatment.build())
392 + .withPriority(CONTROLLER_PRIORITY)
393 + .fromApp(applicationId)
394 + .makePermanent()
395 + .forTable(VLAN_TABLE).build();
396 + ops = install ? ops.add(rule) : ops.remove(rule);
397 + } else if (c.type() == Criterion.Type.IPV4_DST) {
398 + IPCriterion ip = (IPCriterion) c;
399 + log.debug("adding rule for IP: {}", ip.ip());
400 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
401 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
402 + selector.matchEthType(Ethernet.TYPE_IPV4);
403 + selector.matchIPDst(ip.ip());
404 + treatment.transition(ACL_TABLE);
405 + FlowRule rule = DefaultFlowRule.builder()
406 + .forDevice(deviceId)
407 + .withSelector(selector.build())
408 + .withTreatment(treatment.build())
409 + .withPriority(HIGHEST_PRIORITY)
410 + .fromApp(applicationId)
411 + .makePermanent()
412 + .forTable(IP_UNICAST_TABLE).build();
413 +
414 + ops = install ? ops.add(rule) : ops.remove(rule);
415 + } else {
416 + log.warn("Driver does not currently process filtering condition"
417 + + " of type: {}", c.type());
418 + fail(filt, ObjectiveError.UNSUPPORTED);
419 + }
420 + }
421 + // apply filtering flow rules
422 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
423 + @Override
424 + public void onSuccess(FlowRuleOperations ops) {
425 + pass(filt);
426 + log.info("Applied filtering rules");
427 + }
428 +
429 + @Override
430 + public void onError(FlowRuleOperations ops) {
431 + fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
432 + log.info("Failed to apply filtering rules");
433 + }
434 + }));
435 + }
436 +
437 + private void pass(Objective obj) {
438 + if (obj.context().isPresent()) {
439 + obj.context().get().onSuccess(obj);
440 + }
441 + }
442 +
443 + private void fail(Objective obj, ObjectiveError error) {
444 + if (obj.context().isPresent()) {
445 + obj.context().get().onError(obj, error);
446 + }
447 + }
448 +
449 + private void initializePipeline() {
450 + processVlanTable(true);
451 + processEtherTable(true);
452 + processIpUnicastTable(true);
453 + //processACLTable(true);
454 + }
455 +
456 + private void processVlanTable(boolean install) {
457 + TrafficSelector.Builder selector;
458 + TrafficTreatment.Builder treatment;
459 + FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
460 + FlowRule rule;
461 +
462 +
463 + //Drop rule
464 + selector = DefaultTrafficSelector.builder();
465 + treatment = DefaultTrafficTreatment.builder();
466 +
467 + treatment.drop();
468 +
469 + rule = DefaultFlowRule.builder()
470 + .forDevice(deviceId)
471 + .withSelector(selector.build())
472 + .withTreatment(treatment.build())
473 + .withPriority(DROP_PRIORITY)
474 + .fromApp(appId)
475 + .makePermanent()
476 + .forTable(VLAN_TABLE).build();
477 +
478 + ops = install ? ops.add(rule) : ops.remove(rule);
479 +
480 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
481 + @Override
482 + public void onSuccess(FlowRuleOperations ops) {
483 + log.info("Provisioned vlan table");
484 + }
485 +
486 + @Override
487 + public void onError(FlowRuleOperations ops) {
488 + log.info("Failed to provision vlan table");
489 + }
490 + }));
491 + }
492 +
493 + private void processEtherTable(boolean install) {
494 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
495 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment
496 + .builder();
497 + FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
498 + FlowRule rule;
499 +
500 + selector.matchEthType(Ethernet.TYPE_ARP);
501 + treatment.punt();
502 +
503 + rule = DefaultFlowRule.builder()
504 + .forDevice(deviceId)
505 + .withSelector(selector.build())
506 + .withTreatment(treatment.build())
507 + .withPriority(CONTROLLER_PRIORITY)
508 + .fromApp(appId)
509 + .makePermanent()
510 + .forTable(ETHTYPE_TABLE).build();
511 +
512 + ops = install ? ops.add(rule) : ops.remove(rule);
513 +
514 + selector = DefaultTrafficSelector.builder();
515 + treatment = DefaultTrafficTreatment.builder();
516 +
517 + selector.matchEthType(Ethernet.TYPE_IPV4);
518 + treatment.transition(IP_UNICAST_TABLE);
519 +
520 + rule = DefaultFlowRule.builder()
521 + .forDevice(deviceId)
522 + .withPriority(CONTROLLER_PRIORITY)
523 + .withSelector(selector.build())
524 + .withTreatment(treatment.build())
525 + .fromApp(appId)
526 + .makePermanent()
527 + .forTable(ETHTYPE_TABLE).build();
528 +
529 + ops = install ? ops.add(rule) : ops.remove(rule);
530 +
531 + //Drop rule
532 + selector = DefaultTrafficSelector.builder();
533 + treatment = DefaultTrafficTreatment.builder();
534 +
535 + treatment.drop();
536 +
537 + rule = DefaultFlowRule.builder()
538 + .forDevice(deviceId)
539 + .withSelector(selector.build())
540 + .withTreatment(treatment.build())
541 + .withPriority(DROP_PRIORITY)
542 + .fromApp(appId)
543 + .makePermanent()
544 + .forTable(ETHTYPE_TABLE).build();
545 +
546 +
547 + ops = install ? ops.add(rule) : ops.remove(rule);
548 +
549 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
550 + @Override
551 + public void onSuccess(FlowRuleOperations ops) {
552 + log.info("Provisioned ether table");
553 + }
554 +
555 + @Override
556 + public void onError(FlowRuleOperations ops) {
557 + log.info("Failed to provision ether table");
558 + }
559 + }));
560 +
561 + }
562 +
563 +
564 + private void processIpUnicastTable(boolean install) {
565 + TrafficSelector.Builder selector;
566 + TrafficTreatment.Builder treatment;
567 + FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
568 + FlowRule rule;
569 +
570 + //Drop rule
571 + selector = DefaultTrafficSelector.builder();
572 + treatment = DefaultTrafficTreatment.builder();
573 +
574 + treatment.drop();
575 +
576 + rule = DefaultFlowRule.builder()
577 + .forDevice(deviceId)
578 + .withSelector(selector.build())
579 + .withTreatment(treatment.build())
580 + .withPriority(DROP_PRIORITY)
581 + .fromApp(appId)
582 + .makePermanent()
583 + .forTable(IP_UNICAST_TABLE).build();
584 +
585 + ops = install ? ops.add(rule) : ops.remove(rule);
586 +
587 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
588 + @Override
589 + public void onSuccess(FlowRuleOperations ops) {
590 + log.info("Provisioned FIB table");
591 + }
592 +
593 + @Override
594 + public void onError(FlowRuleOperations ops) {
595 + log.info("Failed to provision FIB table");
596 + }
597 + }));
598 + }
599 +
600 +
601 + private class InnerGroupListener implements GroupListener {
602 + @Override
603 + public void event(GroupEvent event) {
604 + if (event.type() == GroupEvent.Type.GROUP_ADDED) {
605 + GroupKey key = event.subject().appCookie();
606 +
607 + NextObjective obj = pendingGroups.getIfPresent(key);
608 + if (obj != null) {
609 + flowObjectiveStore.putNextGroup(obj.id(), new PicaGroup(key));
610 + pass(obj);
611 + pendingGroups.invalidate(key);
612 + }
613 + }
614 + }
615 + }
616 +
617 +
618 + private class GroupChecker implements Runnable {
619 +
620 + @Override
621 + public void run() {
622 + Set<GroupKey> keys = pendingGroups.asMap().keySet().stream()
623 + .filter(key -> groupService.getGroup(deviceId, key) != null)
624 + .collect(Collectors.toSet());
625 +
626 + keys.stream().forEach(key -> {
627 + NextObjective obj = pendingGroups.getIfPresent(key);
628 + if (obj == null) {
629 + return;
630 + }
631 + pass(obj);
632 + pendingGroups.invalidate(key);
633 + log.info("Heard back from group service for group {}. "
634 + + "Applying pending forwarding objectives", obj.id());
635 + flowObjectiveStore.putNextGroup(obj.id(), new PicaGroup(key));
636 + });
637 + }
638 + }
639 +
640 + private class PicaGroup implements NextGroup {
641 +
642 + private final GroupKey key;
643 +
644 + public PicaGroup(GroupKey key) {
645 + this.key = key;
646 + }
647 +
648 + @SuppressWarnings("unused")
649 + public GroupKey key() {
650 + return key;
651 + }
652 +
653 + @Override
654 + public byte[] data() {
655 + return appKryo.serialize(key);
656 + }
657 +
658 + }
659 +}
...@@ -15,13 +15,15 @@ ...@@ -15,13 +15,15 @@
15 ~ limitations under the License. 15 ~ limitations under the License.
16 --> 16 -->
17 <drivers> 17 <drivers>
18 - <driver name="default" manufacturer="ON.Lab" hwVersion="0.0.1" swVersion="0.0.1"> 18 + <driver name="default"
19 + manufacturer="ON.Lab" hwVersion="0.0.1" swVersion="0.0.1">
19 <behaviour api="org.onosproject.net.behaviour.Pipeliner" 20 <behaviour api="org.onosproject.net.behaviour.Pipeliner"
20 impl="org.onosproject.driver.pipeline.DefaultSingleTablePipeline"/> 21 impl="org.onosproject.driver.pipeline.DefaultSingleTablePipeline"/>
21 <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver" 22 <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
22 impl="org.onosproject.driver.handshaker.DefaultSwitchHandShaker"/> 23 impl="org.onosproject.driver.handshaker.DefaultSwitchHandShaker"/>
23 </driver> 24 </driver>
24 - <driver name="ovs" extends="default" manufacturer="Nicira, Inc\." hwVersion="Open vSwitch" swVersion="2\..*"> 25 + <driver name="ovs" extends="default"
26 + manufacturer="Nicira, Inc\." hwVersion="Open vSwitch" swVersion="2\..*">
25 <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver" 27 <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
26 impl="org.onosproject.driver.handshaker.NiciraSwitchHandShaker"/> 28 impl="org.onosproject.driver.handshaker.NiciraSwitchHandShaker"/>
27 </driver> 29 </driver>
...@@ -48,7 +50,8 @@ ...@@ -48,7 +50,8 @@
48 <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver" 50 <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
49 impl="org.onosproject.driver.handshaker.OFOpticalSwitchImplLINC13"/> 51 impl="org.onosproject.driver.handshaker.OFOpticalSwitchImplLINC13"/>
50 </driver> 52 </driver>
51 - <driver name="corsa" manufacturer="Corsa" hwVersion="Corsa Element" swVersion="2.3.1"> 53 + <driver name="corsa"
54 + manufacturer="Corsa" hwVersion="Corsa Element" swVersion="2.3.1">
52 <behaviour api="org.onosproject.net.behaviour.Pipeliner" 55 <behaviour api="org.onosproject.net.behaviour.Pipeliner"
53 impl="org.onosproject.driver.pipeline.CorsaPipeline"/> 56 impl="org.onosproject.driver.pipeline.CorsaPipeline"/>
54 <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver" 57 <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
...@@ -69,5 +72,15 @@ ...@@ -69,5 +72,15 @@
69 <behaviour api="org.onosproject.net.behaviour.Pipeliner" 72 <behaviour api="org.onosproject.net.behaviour.Pipeliner"
70 impl="org.onosproject.driver.pipeline.SoftRouterPipeline"/> 73 impl="org.onosproject.driver.pipeline.SoftRouterPipeline"/>
71 </driver> 74 </driver>
75 + <driver name="centec-V350" extends="default"
76 + manufacturer=".*Centec.*" hwVersion=".*" swVersion="3.1.*">
77 + <behaviour api="org.onosproject.net.behaviour.Pipeliner"
78 + impl="org.onosproject.driver.pipeline.CentecV350Pipeline"/>
79 + </driver>
80 + <driver name="pica" extends="default"
81 + manufacturer="Pica8, Inc." hwVersion="ly2" swVersion="PicOS 2.6">
82 + <behaviour api="org.onosproject.net.behaviour.Pipeliner"
83 + impl="org.onosproject.driver.pipeline.PicaPipeline"/>
84 + </driver>
72 </drivers> 85 </drivers>
73 86
......