aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java')
-rw-r--r--framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java1101
1 files changed, 0 insertions, 1101 deletions
diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
deleted file mode 100644
index dba4557a..00000000
--- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
+++ /dev/null
@@ -1,1101 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.driver.pipeline;
-
-import static org.onlab.util.Tools.groupedThreads;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.RemovalCause;
-import com.google.common.cache.RemovalNotification;
-
-import org.onlab.osgi.ServiceDirectory;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onlab.util.KryoNamespace;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.behaviour.NextGroup;
-import org.onosproject.net.behaviour.Pipeliner;
-import org.onosproject.net.behaviour.PipelinerContext;
-import org.onosproject.net.driver.AbstractHandlerBehaviour;
-import org.onosproject.net.flow.DefaultFlowRule;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.FlowRuleOperations;
-import org.onosproject.net.flow.FlowRuleOperationsContext;
-import org.onosproject.net.flow.FlowRuleService;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.criteria.Criteria;
-import org.onosproject.net.flow.criteria.Criterion;
-import org.onosproject.net.flow.criteria.Criterion.Type;
-import org.onosproject.net.flow.criteria.EthCriterion;
-import org.onosproject.net.flow.criteria.EthTypeCriterion;
-import org.onosproject.net.flow.criteria.IPCriterion;
-import org.onosproject.net.flow.criteria.MplsCriterion;
-import org.onosproject.net.flow.criteria.PortCriterion;
-import org.onosproject.net.flow.criteria.VlanIdCriterion;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
-import org.onosproject.net.flowobjective.FilteringObjective;
-import org.onosproject.net.flowobjective.FlowObjectiveStore;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.flowobjective.NextObjective;
-import org.onosproject.net.flowobjective.Objective;
-import org.onosproject.net.flowobjective.ObjectiveError;
-import org.onosproject.net.group.DefaultGroupBucket;
-import org.onosproject.net.group.DefaultGroupDescription;
-import org.onosproject.net.group.DefaultGroupKey;
-import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupBucket;
-import org.onosproject.net.group.GroupBuckets;
-import org.onosproject.net.group.GroupDescription;
-import org.onosproject.net.group.GroupEvent;
-import org.onosproject.net.group.GroupKey;
-import org.onosproject.net.group.GroupListener;
-import org.onosproject.net.group.GroupService;
-import org.onosproject.store.serializers.KryoNamespaces;
-import org.slf4j.Logger;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-/**
- * Driver for SPRING-OPEN pipeline.
- */
-public class SpringOpenTTP extends AbstractHandlerBehaviour
- implements Pipeliner {
-
- // Default table ID - compatible with CpqD switch
- private static final int TABLE_VLAN = 0;
- private static final int TABLE_TMAC = 1;
- private static final int TABLE_IPV4_UNICAST = 2;
- private static final int TABLE_MPLS = 3;
- private static final int TABLE_DMAC = 4;
- private static final int TABLE_ACL = 5;
- private static final int TABLE_SMAC = 6;
-
- /**
- * Set the default values. These variables will get overwritten based on the
- * switch vendor type
- */
- protected int vlanTableId = TABLE_VLAN;
- protected int tmacTableId = TABLE_TMAC;
- protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST;
- protected int mplsTableId = TABLE_MPLS;
- protected int dstMacTableId = TABLE_DMAC;
- protected int aclTableId = TABLE_ACL;
- protected int srcMacTableId = TABLE_SMAC;
-
- protected final Logger log = getLogger(getClass());
-
- private ServiceDirectory serviceDirectory;
- private FlowRuleService flowRuleService;
- private CoreService coreService;
- protected GroupService groupService;
- protected FlowObjectiveStore flowObjectiveStore;
- protected DeviceId deviceId;
- private ApplicationId appId;
-
- private Cache<GroupKey, NextObjective> pendingGroups;
-
- private ScheduledExecutorService groupChecker = Executors
- .newScheduledThreadPool(2,
- groupedThreads("onos/pipeliner",
- "spring-open-%d"));
- protected KryoNamespace appKryo = new KryoNamespace.Builder()
- .register(KryoNamespaces.API)
- .register(GroupKey.class)
- .register(DefaultGroupKey.class)
- .register(TrafficTreatment.class)
- .register(SpringOpenGroup.class)
- .register(byte[].class)
- .build();
-
- @Override
- public void init(DeviceId deviceId, PipelinerContext context) {
- this.serviceDirectory = context.directory();
- this.deviceId = deviceId;
-
- pendingGroups = CacheBuilder
- .newBuilder()
- .expireAfterWrite(20, TimeUnit.SECONDS)
- .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
- if (notification.getCause() == RemovalCause.EXPIRED) {
- fail(notification.getValue(),
- ObjectiveError.GROUPINSTALLATIONFAILED);
- }
- }).build();
-
- groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500,
- TimeUnit.MILLISECONDS);
-
- coreService = serviceDirectory.get(CoreService.class);
- flowRuleService = serviceDirectory.get(FlowRuleService.class);
- groupService = serviceDirectory.get(GroupService.class);
- flowObjectiveStore = context.store();
-
- groupService.addListener(new InnerGroupListener());
-
- appId = coreService
- .registerApplication("org.onosproject.driver.SpringOpenTTP");
-
- setTableMissEntries();
- log.info("Spring Open TTP driver initialized");
- }
-
- @Override
- public void filter(FilteringObjective filteringObjective) {
- if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
- log.debug("processing PERMIT filter objective");
- processFilter(filteringObjective,
- filteringObjective.op() == Objective.Operation.ADD,
- filteringObjective.appId());
- } else {
- log.debug("filter objective other than PERMIT not supported");
- fail(filteringObjective, ObjectiveError.UNSUPPORTED);
- }
- }
-
- @Override
- public void forward(ForwardingObjective fwd) {
- Collection<FlowRule> rules;
- FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
-
- rules = processForward(fwd);
- switch (fwd.op()) {
- case ADD:
- rules.stream().filter(rule -> rule != null)
- .forEach(flowBuilder::add);
- break;
- case REMOVE:
- rules.stream().filter(rule -> rule != null)
- .forEach(flowBuilder::remove);
- break;
- default:
- fail(fwd, ObjectiveError.UNKNOWN);
- log.warn("Unknown forwarding type {}", fwd.op());
- }
-
- flowRuleService.apply(flowBuilder
- .build(new FlowRuleOperationsContext() {
- @Override
- public void onSuccess(FlowRuleOperations ops) {
- pass(fwd);
- log.debug("Provisioned tables in {} successfully with "
- + "forwarding rules", deviceId);
- }
-
- @Override
- public void onError(FlowRuleOperations ops) {
- fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
- log.warn("Failed to provision tables in {} with "
- + "forwarding rules", deviceId);
- }
- }));
-
- }
-
- @Override
- public void next(NextObjective nextObjective) {
- NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
- switch (nextObjective.op()) {
- case ADD:
- if (nextGroup != null) {
- log.warn("Cannot add next {} that already exists in device {}",
- nextObjective.id(), deviceId);
- return;
- }
- log.debug("Processing NextObjective id{} in dev{} - add group",
- nextObjective.id(), deviceId);
- addGroup(nextObjective);
- break;
- case ADD_TO_EXISTING:
- if (nextGroup != null) {
- log.debug("Processing NextObjective id{} in dev{} - add bucket",
- nextObjective.id(), deviceId);
- addBucketToGroup(nextObjective);
- } else {
- log.warn("Cannot add to group that does not exist");
- }
- break;
- case REMOVE:
- if (nextGroup == null) {
- log.warn("Cannot remove next {} that does not exist in device {}",
- nextObjective.id(), deviceId);
- return;
- }
- log.debug("Processing NextObjective id{} in dev{} - remove group",
- nextObjective.id(), deviceId);
- removeGroup(nextObjective);
- break;
- case REMOVE_FROM_EXISTING:
- if (nextGroup == null) {
- log.warn("Cannot remove from next {} that does not exist in device {}",
- nextObjective.id(), deviceId);
- return;
- }
- log.debug("Processing NextObjective id{} in dev{} - remove bucket",
- nextObjective.id(), deviceId);
- removeBucketFromGroup(nextObjective);
- break;
- default:
- log.warn("Unsupported operation {}", nextObjective.op());
- }
- }
-
- private void removeGroup(NextObjective nextObjective) {
- log.debug("removeGroup in {}: for next objective id {}",
- deviceId, nextObjective.id());
- final GroupKey key = new DefaultGroupKey(
- appKryo.serialize(nextObjective.id()));
- groupService.removeGroup(deviceId, key, appId);
- }
-
- private void addGroup(NextObjective nextObjective) {
- log.debug("addGroup with type{} for nextObjective id {}",
- nextObjective.type(), nextObjective.id());
- List<GroupBucket> buckets;
- switch (nextObjective.type()) {
- case SIMPLE:
- Collection<TrafficTreatment> treatments = nextObjective.next();
- if (treatments.size() == 1) {
- // Spring Open TTP converts simple nextObjective to flow-actions
- // in a dummy group
- TrafficTreatment treatment = nextObjective.next().iterator().next();
- log.debug("Converting SIMPLE group for next objective id {} " +
- "to {} flow-actions in device:{}", nextObjective.id(),
- treatment.allInstructions().size(), deviceId);
- flowObjectiveStore.putNextGroup(nextObjective.id(),
- new SpringOpenGroup(null, treatment));
- }
- break;
- case HASHED:
- // we convert MPLS ECMP groups to flow-actions for a single
- // bucket(output port).
- boolean mplsEcmp = false;
- if (nextObjective.meta() != null) {
- for (Criterion c : nextObjective.meta().criteria()) {
- if (c.type() == Type.MPLS_LABEL) {
- mplsEcmp = true;
- }
- }
- }
- if (mplsEcmp) {
- // covert to flow-actions in a dummy group by choosing the first bucket
- log.debug("Converting HASHED group for next objective id {} " +
- "to flow-actions in device:{}", nextObjective.id(),
- deviceId);
- TrafficTreatment treatment = nextObjective.next().iterator().next();
- flowObjectiveStore.putNextGroup(nextObjective.id(),
- new SpringOpenGroup(null, treatment));
- } else {
- // process as ECMP group
- buckets = nextObjective
- .next()
- .stream()
- .map((treatment) -> DefaultGroupBucket
- .createSelectGroupBucket(treatment))
- .collect(Collectors.toList());
- if (!buckets.isEmpty()) {
- final GroupKey key = new DefaultGroupKey(
- appKryo.serialize(nextObjective.id()));
- GroupDescription groupDescription = new DefaultGroupDescription(
- deviceId,
- GroupDescription.Type.SELECT,
- new GroupBuckets(buckets),
- key,
- null,
- nextObjective.appId());
- log.debug("Creating HASHED group for next objective id {}"
- + " in dev:{}", nextObjective.id(), deviceId);
- pendingGroups.put(key, nextObjective);
- groupService.addGroup(groupDescription);
- }
- }
- break;
- case BROADCAST:
- buckets = nextObjective
- .next()
- .stream()
- .map((treatment) -> DefaultGroupBucket
- .createAllGroupBucket(treatment))
- .collect(Collectors.toList());
- if (!buckets.isEmpty()) {
- final GroupKey key = new DefaultGroupKey(
- appKryo.serialize(nextObjective
- .id()));
- GroupDescription groupDescription = new DefaultGroupDescription(
- deviceId,
- GroupDescription.Type.ALL,
- new GroupBuckets(buckets),
- key,
- null,
- nextObjective.appId());
- log.debug("Creating BROADCAST group for next objective id {} "
- + "in device {}", nextObjective.id(), deviceId);
- pendingGroups.put(key, nextObjective);
- groupService.addGroup(groupDescription);
- }
- break;
- case FAILOVER:
- log.debug("FAILOVER next objectives not supported");
- fail(nextObjective, ObjectiveError.UNSUPPORTED);
- log.warn("Unsupported next objective type {}", nextObjective.type());
- break;
- default:
- fail(nextObjective, ObjectiveError.UNKNOWN);
- log.warn("Unknown next objective type {}", nextObjective.type());
- }
- }
-
- private void addBucketToGroup(NextObjective nextObjective) {
- log.debug("addBucketToGroup in {}: for next objective id {}",
- deviceId, nextObjective.id());
- Collection<TrafficTreatment> treatments = nextObjective.next();
- TrafficTreatment treatment = treatments.iterator().next();
- final GroupKey key = new DefaultGroupKey(
- appKryo.serialize(nextObjective
- .id()));
- Group group = groupService.getGroup(deviceId, key);
- if (group == null) {
- log.warn("Group is not found in {} for {}", deviceId, key);
- return;
- }
- GroupBucket bucket;
- if (group.type() == GroupDescription.Type.INDIRECT) {
- bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
- } else if (group.type() == GroupDescription.Type.SELECT) {
- bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
- } else if (group.type() == GroupDescription.Type.ALL) {
- bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
- } else {
- log.warn("Unsupported Group type {}", group.type());
- return;
- }
- GroupBuckets bucketsToAdd = new GroupBuckets(Collections.singletonList(bucket));
- log.debug("Adding buckets to group id {} of next objective id {} in device {}",
- group.id(), nextObjective.id(), deviceId);
- groupService.addBucketsToGroup(deviceId, key, bucketsToAdd, key, appId);
- }
-
- private void removeBucketFromGroup(NextObjective nextObjective) {
- log.debug("removeBucketFromGroup in {}: for next objective id {}",
- deviceId, nextObjective.id());
- NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
- if (nextGroup != null) {
- Collection<TrafficTreatment> treatments = nextObjective.next();
- TrafficTreatment treatment = treatments.iterator().next();
- final GroupKey key = new DefaultGroupKey(
- appKryo.serialize(nextObjective
- .id()));
- Group group = groupService.getGroup(deviceId, key);
- if (group == null) {
- log.warn("Group is not found in {} for {}", deviceId, key);
- return;
- }
- GroupBucket bucket;
- if (group.type() == GroupDescription.Type.INDIRECT) {
- bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
- } else if (group.type() == GroupDescription.Type.SELECT) {
- bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
- } else if (group.type() == GroupDescription.Type.ALL) {
- bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
- } else {
- log.warn("Unsupported Group type {}", group.type());
- return;
- }
- GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket));
- log.debug("Removing buckets from group id {} of next objective id {} in device {}",
- group.id(), nextObjective.id(), deviceId);
- groupService.removeBucketsFromGroup(deviceId, key, removeBuckets, key, appId);
- }
- }
-
- private Collection<FlowRule> processForward(ForwardingObjective fwd) {
- switch (fwd.flag()) {
- case SPECIFIC:
- return processSpecific(fwd);
- case VERSATILE:
- return processVersatile(fwd);
- default:
- fail(fwd, ObjectiveError.UNKNOWN);
- log.warn("Unknown forwarding flag {}", fwd.flag());
- }
- return Collections.emptySet();
- }
-
- private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
- log.debug("Processing versatile forwarding objective in dev:{}", deviceId);
- TrafficSelector selector = fwd.selector();
- EthTypeCriterion ethType =
- (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
- if (ethType == null) {
- log.error("Versatile forwarding objective must include ethType");
- fail(fwd, ObjectiveError.UNKNOWN);
- return Collections.emptySet();
- }
-
- if (fwd.treatment() == null && fwd.nextId() == null) {
- log.error("VERSATILE forwarding objective needs next objective ID "
- + "or treatment.");
- return Collections.emptySet();
- }
- // emulation of ACL table (for versatile fwd objective) requires
- // overriding any previous instructions
- TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
- .builder();
- treatmentBuilder.wipeDeferred();
-
- if (fwd.nextId() != null) {
- NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
- if (next != null) {
- SpringOpenGroup soGroup = appKryo.deserialize(next.data());
- if (soGroup.dummy) {
- // need to convert to flow-actions
- for (Instruction ins : soGroup.treatment.allInstructions()) {
- treatmentBuilder.add(ins);
- }
- } else {
- GroupKey key = soGroup.key;
- Group group = groupService.getGroup(deviceId, key);
- if (group == null) {
- log.warn("The group left!");
- fail(fwd, ObjectiveError.GROUPMISSING);
- return Collections.emptySet();
- }
- treatmentBuilder.deferred().group(group.id());
- log.debug("Adding OUTGROUP action");
- }
- }
- }
-
- if (fwd.treatment() != null) {
- if (fwd.treatment().allInstructions().size() == 1 &&
- fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
- OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
- if (o.port() == PortNumber.CONTROLLER) {
- treatmentBuilder.punt();
- } else {
- treatmentBuilder.add(o);
- }
- } else {
- for (Instruction ins : fwd.treatment().allInstructions()) {
- treatmentBuilder.add(ins);
- }
- }
- }
-
- FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
- .fromApp(fwd.appId()).withPriority(fwd.priority())
- .forDevice(deviceId).withSelector(fwd.selector())
- .withTreatment(treatmentBuilder.build());
-
- if (fwd.permanent()) {
- ruleBuilder.makePermanent();
- } else {
- ruleBuilder.makeTemporary(fwd.timeout());
- }
-
- ruleBuilder.forTable(aclTableId);
- return Collections.singletonList(ruleBuilder.build());
- }
-
- private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) {
- TrafficSelector selector = fwd.selector();
- EthTypeCriterion ethType = (EthTypeCriterion) selector
- .getCriterion(Criterion.Type.ETH_TYPE);
- if ((ethType == null) ||
- ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
- (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST))) {
- return false;
- }
- return true;
- }
-
- private boolean isSupportedEthDstObjective(ForwardingObjective fwd) {
- TrafficSelector selector = fwd.selector();
- EthCriterion ethDst = (EthCriterion) selector
- .getCriterion(Criterion.Type.ETH_DST);
- VlanIdCriterion vlanId = (VlanIdCriterion) selector
- .getCriterion(Criterion.Type.VLAN_VID);
- if (ethDst == null && vlanId == null) {
- return false;
- }
- return true;
- }
-
- protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
- log.debug("Processing specific fwd objective:{} in dev:{} with next:{}",
- fwd.id(), deviceId, fwd.nextId());
- boolean isEthTypeObj = isSupportedEthTypeObjective(fwd);
- boolean isEthDstObj = isSupportedEthDstObjective(fwd);
-
- if (isEthTypeObj) {
- return processEthTypeSpecificObjective(fwd);
- } else if (isEthDstObj) {
- return processEthDstSpecificObjective(fwd);
- } else {
- log.warn("processSpecific: Unsupported "
- + "forwarding objective criteria");
- fail(fwd, ObjectiveError.UNSUPPORTED);
- return Collections.emptySet();
- }
- }
-
- protected Collection<FlowRule>
- processEthTypeSpecificObjective(ForwardingObjective fwd) {
- TrafficSelector selector = fwd.selector();
- EthTypeCriterion ethType = (EthTypeCriterion) selector
- .getCriterion(Criterion.Type.ETH_TYPE);
-
- TrafficSelector.Builder filteredSelectorBuilder =
- DefaultTrafficSelector.builder();
- int forTableId = -1;
- if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
- filteredSelectorBuilder = filteredSelectorBuilder
- .matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(((IPCriterion) selector
- .getCriterion(Criterion.Type.IPV4_DST))
- .ip());
- forTableId = ipv4UnicastTableId;
- log.debug("processing IPv4 specific forwarding objective:{} in dev:{}",
- fwd.id(), deviceId);
- } else {
- filteredSelectorBuilder = filteredSelectorBuilder
- .matchEthType(Ethernet.MPLS_UNICAST)
- .matchMplsLabel(((MplsCriterion)
- selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
- //TODO: Add Match for BoS
- //if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) {
- //}
- forTableId = mplsTableId;
- log.debug("processing MPLS specific forwarding objective:{} in dev:{}",
- fwd.id(), deviceId);
- }
-
- TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
- .builder();
- if (fwd.treatment() != null) {
- for (Instruction i : fwd.treatment().allInstructions()) {
- treatmentBuilder.add(i);
- }
- }
-
- if (fwd.nextId() != null) {
- NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
- if (next != null) {
- SpringOpenGroup soGroup = appKryo.deserialize(next.data());
- if (soGroup.dummy) {
- log.debug("Adding {} flow-actions for fwd. obj. {} -> next:{} "
- + "in dev: {}", soGroup.treatment.allInstructions().size(),
- fwd.id(), fwd.nextId(), deviceId);
- for (Instruction ins : soGroup.treatment.allInstructions()) {
- treatmentBuilder.add(ins);
- }
- } else {
- GroupKey key = soGroup.key;
- Group group = groupService.getGroup(deviceId, key);
- if (group == null) {
- log.warn("The group left!");
- fail(fwd, ObjectiveError.GROUPMISSING);
- return Collections.emptySet();
- }
- treatmentBuilder.deferred().group(group.id());
- log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} "
- + "for next:{} in dev: {}", group.id(), fwd.id(),
- fwd.nextId(), deviceId);
- }
- } else {
- log.warn("processSpecific: No associated next objective object");
- fail(fwd, ObjectiveError.GROUPMISSING);
- return Collections.emptySet();
- }
- }
-
- TrafficSelector filteredSelector = filteredSelectorBuilder.build();
- TrafficTreatment treatment = treatmentBuilder.transition(aclTableId)
- .build();
-
- FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
- .fromApp(fwd.appId()).withPriority(fwd.priority())
- .forDevice(deviceId).withSelector(filteredSelector)
- .withTreatment(treatment);
-
- if (fwd.permanent()) {
- ruleBuilder.makePermanent();
- } else {
- ruleBuilder.makeTemporary(fwd.timeout());
- }
-
- ruleBuilder.forTable(forTableId);
- return Collections.singletonList(ruleBuilder.build());
-
- }
-
- protected Collection<FlowRule>
- processEthDstSpecificObjective(ForwardingObjective fwd) {
- List<FlowRule> rules = new ArrayList<>();
-
- // Build filtered selector
- TrafficSelector selector = fwd.selector();
- EthCriterion ethCriterion = (EthCriterion) selector
- .getCriterion(Criterion.Type.ETH_DST);
- VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
- .getCriterion(Criterion.Type.VLAN_VID);
- TrafficSelector.Builder filteredSelectorBuilder =
- DefaultTrafficSelector.builder();
- // Do not match MacAddress for subnet broadcast entry
- if (!ethCriterion.mac().equals(MacAddress.NONE)) {
- filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
- log.debug("processing L2 forwarding objective:{} in dev:{}",
- fwd.id(), deviceId);
- } else {
- log.debug("processing L2 Broadcast forwarding objective:{} "
- + "in dev:{} for vlan:{}",
- fwd.id(), deviceId, vlanIdCriterion.vlanId());
- }
- filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
- TrafficSelector filteredSelector = filteredSelectorBuilder.build();
-
- // Build filtered treatment
- TrafficTreatment.Builder treatmentBuilder =
- DefaultTrafficTreatment.builder();
- if (fwd.treatment() != null) {
- treatmentBuilder.deferred();
- fwd.treatment().allInstructions().forEach(treatmentBuilder::add);
- }
- if (fwd.nextId() != null) {
- NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
- if (next != null) {
- SpringOpenGroup soGrp = appKryo.deserialize(next.data());
- if (soGrp.dummy) {
- log.debug("Adding {} flow-actions for fwd. obj. {} "
- + "in dev: {}", soGrp.treatment.allInstructions().size(),
- fwd.id(), deviceId);
- for (Instruction ins : soGrp.treatment.allInstructions()) {
- treatmentBuilder.deferred().add(ins);
- }
- } else {
- GroupKey key = soGrp.key;
- Group group = groupService.getGroup(deviceId, key);
- if (group == null) {
- log.warn("The group left!");
- fail(fwd, ObjectiveError.GROUPMISSING);
- return Collections.emptySet();
- }
- treatmentBuilder.deferred().group(group.id());
- log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} "
- + "in dev: {}", group.id(), fwd.id(), deviceId);
- }
- }
- }
- treatmentBuilder.immediate().transition(aclTableId);
- TrafficTreatment filteredTreatment = treatmentBuilder.build();
-
- // Build bridging table entries
- FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
- flowRuleBuilder.fromApp(fwd.appId())
- .withPriority(fwd.priority())
- .forDevice(deviceId)
- .withSelector(filteredSelector)
- .withTreatment(filteredTreatment)
- .forTable(dstMacTableId);
- if (fwd.permanent()) {
- flowRuleBuilder.makePermanent();
- } else {
- flowRuleBuilder.makeTemporary(fwd.timeout());
- }
- rules.add(flowRuleBuilder.build());
-
- /*
- // TODO Emulate source MAC table behavior
- // Do not install source MAC table entry for subnet broadcast
- if (!ethCriterion.mac().equals(MacAddress.NONE)) {
- // Build filtered selector
- selector = fwd.selector();
- ethCriterion = (EthCriterion) selector.getCriterion(Criterion.Type.ETH_DST);
- filteredSelectorBuilder = DefaultTrafficSelector.builder();
- filteredSelectorBuilder.matchEthSrc(ethCriterion.mac());
- filteredSelector = filteredSelectorBuilder.build();
-
- // Build empty treatment. Apply existing instruction if match.
- treatmentBuilder = DefaultTrafficTreatment.builder();
- filteredTreatment = treatmentBuilder.build();
-
- // Build bridging table entries
- flowRuleBuilder = DefaultFlowRule.builder();
- flowRuleBuilder.fromApp(fwd.appId())
- .withPriority(fwd.priority())
- .forDevice(deviceId)
- .withSelector(filteredSelector)
- .withTreatment(filteredTreatment)
- .forTable(srcMacTableId)
- .makePermanent();
- rules.add(flowRuleBuilder.build());
- }
- */
-
- return rules;
- }
-
- /*
- * Note: CpqD switches do not handle MPLS-related operation properly
- * for a packet with VLAN tag. We pop VLAN here as a workaround.
- * Side effect: HostService learns redundant hosts with same MAC but
- * different VLAN. No known side effect on the network reachability.
- */
- protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion,
- VlanIdCriterion vlanIdCriterion,
- FilteringObjective filt,
- VlanId assignedVlan,
- ApplicationId applicationId) {
- //handling untagged packets via assigned VLAN
- if (vlanIdCriterion.vlanId() == VlanId.NONE) {
- vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
- }
-
- List<FlowRule> rules = new ArrayList<>();
- TrafficSelector.Builder selectorIp = DefaultTrafficSelector
- .builder();
- TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
- .builder();
- selectorIp.matchEthDst(ethCriterion.mac());
- selectorIp.matchEthType(Ethernet.TYPE_IPV4);
- selectorIp.matchVlanId(vlanIdCriterion.vlanId());
- treatmentIp.popVlan();
- treatmentIp.transition(ipv4UnicastTableId);
- FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
- .withSelector(selectorIp.build())
- .withTreatment(treatmentIp.build())
- .withPriority(filt.priority()).fromApp(applicationId)
- .makePermanent().forTable(tmacTableId).build();
- log.debug("adding IP ETH rule for MAC: {}", ethCriterion.mac());
- rules.add(ruleIp);
-
- TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
- .builder();
- TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
- .builder();
- selectorMpls.matchEthDst(ethCriterion.mac());
- selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
- selectorMpls.matchVlanId(vlanIdCriterion.vlanId());
- treatmentMpls.popVlan();
- treatmentMpls.transition(mplsTableId);
- FlowRule ruleMpls = DefaultFlowRule.builder()
- .forDevice(deviceId).withSelector(selectorMpls.build())
- .withTreatment(treatmentMpls.build())
- .withPriority(filt.priority()).fromApp(applicationId)
- .makePermanent().forTable(tmacTableId).build();
- log.debug("adding MPLS ETH rule for MAC: {}", ethCriterion.mac());
- rules.add(ruleMpls);
-
- return rules;
- }
-
- protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion,
- FilteringObjective filt,
- VlanId assignedVlan,
- ApplicationId applicationId) {
- List<FlowRule> rules = new ArrayList<>();
- log.debug("adding rule for VLAN: {}", vlanIdCriterion.vlanId());
- TrafficSelector.Builder selector = DefaultTrafficSelector
- .builder();
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment
- .builder();
- PortCriterion p = (PortCriterion) filt.key();
- if (vlanIdCriterion.vlanId() != VlanId.NONE) {
- selector.matchVlanId(vlanIdCriterion.vlanId());
- selector.matchInPort(p.port());
- treatment.deferred().popVlan();
- } else {
- selector.matchInPort(p.port());
- treatment.immediate().pushVlan().setVlanId(assignedVlan);
- }
- treatment.transition(tmacTableId);
- FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
- .withSelector(selector.build())
- .withTreatment(treatment.build())
- .withPriority(filt.priority()).fromApp(applicationId)
- .makePermanent().forTable(vlanTableId).build();
- rules.add(rule);
-
- return rules;
- }
-
- private void processFilter(FilteringObjective filt, boolean install,
- ApplicationId applicationId) {
- // This driver only processes filtering criteria defined with switch
- // ports as the key
- if (filt.key().equals(Criteria.dummy())
- || filt.key().type() != Criterion.Type.IN_PORT) {
- log.warn("No key defined in filtering objective from app: {}. Not"
- + "processing filtering objective", applicationId);
- fail(filt, ObjectiveError.UNKNOWN);
- return;
- }
-
- EthCriterion ethCriterion = null;
- VlanIdCriterion vlanIdCriterion = null;
-
- // convert filtering conditions for switch-intfs into flowrules
- FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-
- for (Criterion criterion : filt.conditions()) {
- if (criterion.type() == Criterion.Type.ETH_DST) {
- ethCriterion = (EthCriterion) criterion;
- } else if (criterion.type() == Criterion.Type.VLAN_VID) {
- vlanIdCriterion = (VlanIdCriterion) criterion;
- } else if (criterion.type() == Criterion.Type.IPV4_DST) {
- log.debug("driver does not process IP filtering rules as it " +
- "sends all misses in the IP table to the controller");
- } else {
- log.warn("Driver does not currently process filtering condition"
- + " of type: {}", criterion.type());
- fail(filt, ObjectiveError.UNSUPPORTED);
- }
- }
-
- VlanId assignedVlan = null;
- if (vlanIdCriterion != null && vlanIdCriterion.vlanId() == VlanId.NONE) {
- // Assign a VLAN ID to untagged packets
- if (filt.meta() == null) {
- log.error("Missing metadata in filtering objective required "
- + "for vlan assignment in dev {}", deviceId);
- fail(filt, ObjectiveError.BADPARAMS);
- return;
- }
- for (Instruction i : filt.meta().allInstructions()) {
- if (i instanceof ModVlanIdInstruction) {
- assignedVlan = ((ModVlanIdInstruction) i).vlanId();
- }
- }
- if (assignedVlan == null) {
- log.error("Driver requires an assigned vlan-id to tag incoming "
- + "untagged packets. Not processing vlan filters on "
- + "device {}", deviceId);
- fail(filt, ObjectiveError.BADPARAMS);
- return;
- }
- }
-
- if (ethCriterion == null) {
- log.debug("filtering objective missing dstMac, cannot program TMAC table");
- } else {
- for (FlowRule tmacRule : processEthDstFilter(ethCriterion,
- vlanIdCriterion,
- filt,
- assignedVlan,
- applicationId)) {
- log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
- tmacRule, deviceId);
- ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
- }
- }
-
- if (ethCriterion == null || vlanIdCriterion == null) {
- log.debug("filtering objective missing dstMac or vlan, cannot program"
- + "Vlan Table");
- } else {
- for (FlowRule vlanRule : processVlanIdFilter(vlanIdCriterion,
- filt,
- assignedVlan,
- applicationId)) {
- log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
- vlanRule, deviceId);
- ops = install ? ops.add(vlanRule) : ops.remove(vlanRule);
- }
- }
-
- // apply filtering flow rules
- flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
- @Override
- public void onSuccess(FlowRuleOperations ops) {
- pass(filt);
- log.debug("Provisioned tables in {} with fitering "
- + "rules", deviceId);
- }
-
- @Override
- public void onError(FlowRuleOperations ops) {
- fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
- log.warn("Failed to provision tables in {} with "
- + "fitering rules", deviceId);
- }
- }));
- }
-
- protected void setTableMissEntries() {
- // set all table-miss-entries
- populateTableMissEntry(vlanTableId, true, false, false, -1);
- populateTableMissEntry(tmacTableId, false, false, true, dstMacTableId);
- populateTableMissEntry(ipv4UnicastTableId, false, true, true, aclTableId);
- populateTableMissEntry(mplsTableId, false, true, true, aclTableId);
- populateTableMissEntry(dstMacTableId, false, false, true, aclTableId);
- populateTableMissEntry(aclTableId, false, false, false, -1);
- }
-
- protected void populateTableMissEntry(int tableToAdd,
- boolean toControllerNow,
- boolean toControllerWrite,
- boolean toTable, int tableToSend) {
- TrafficSelector selector = DefaultTrafficSelector.builder().build();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- if (toControllerNow) {
- tBuilder.setOutput(PortNumber.CONTROLLER);
- }
-
- if (toControllerWrite) {
- tBuilder.deferred().setOutput(PortNumber.CONTROLLER);
- }
-
- if (toTable) {
- tBuilder.transition(tableToSend);
- }
-
- FlowRule flow = DefaultFlowRule.builder().forDevice(deviceId)
- .withSelector(selector).withTreatment(tBuilder.build())
- .withPriority(0).fromApp(appId).makePermanent()
- .forTable(tableToAdd).build();
-
- flowRuleService.applyFlowRules(flow);
- }
-
- private void pass(Objective obj) {
- if (obj.context().isPresent()) {
- obj.context().get().onSuccess(obj);
- }
- }
-
- protected void fail(Objective obj, ObjectiveError error) {
- if (obj.context().isPresent()) {
- obj.context().get().onError(obj, error);
- }
- }
-
- private class InnerGroupListener implements GroupListener {
- @Override
- public void event(GroupEvent event) {
- if (event.type() == GroupEvent.Type.GROUP_ADDED) {
- log.trace("InnerGroupListener: Group ADDED "
- + "event received in device {}", deviceId);
- GroupKey key = event.subject().appCookie();
-
- NextObjective obj = pendingGroups.getIfPresent(key);
- if (obj != null) {
- log.debug("Group verified: dev:{} gid:{} <<->> nextId:{}",
- deviceId, event.subject().id(), obj.id());
- flowObjectiveStore
- .putNextGroup(obj.id(),
- new SpringOpenGroup(key, null));
- pass(obj);
- pendingGroups.invalidate(key);
- }
- } else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) {
- log.warn("InnerGroupListener: Group ADD "
- + "failed event received in device {}", deviceId);
- }
- }
- }
-
- private class GroupChecker implements Runnable {
-
- @Override
- public void run() {
- Set<GroupKey> keys = pendingGroups
- .asMap()
- .keySet()
- .stream()
- .filter(key -> groupService.getGroup(deviceId, key) != null)
- .collect(Collectors.toSet());
-
- keys.stream()
- .forEach(key -> {
- NextObjective obj = pendingGroups
- .getIfPresent(key);
- if (obj == null) {
- return;
- }
- log.debug("Group verified: dev:{} gid:{} <<->> nextId:{}",
- deviceId,
- groupService.getGroup(deviceId, key).id(),
- obj.id());
- pass(obj);
- pendingGroups.invalidate(key);
- flowObjectiveStore.putNextGroup(
- obj.id(),
- new SpringOpenGroup(key, null));
- });
- }
- }
-
- /**
- * SpringOpenGroup can either serve as storage for a GroupKey which can be
- * used to fetch the group from the Group Service, or it can be serve as storage
- * for Traffic Treatments which can be used as flow actions. In the latter
- * case, we refer to this as a dummy group.
- *
- */
- private class SpringOpenGroup implements NextGroup {
- private final boolean dummy;
- private final GroupKey key;
- private final TrafficTreatment treatment;
-
- /**
- * Storage for a GroupKey or a TrafficTreatment. One of the params
- * to this constructor must be null.
- * @param key represents a GroupKey
- * @param treatment represents flow actions in a dummy group
- */
- public SpringOpenGroup(GroupKey key, TrafficTreatment treatment) {
- if (key == null) {
- this.key = new DefaultGroupKey(new byte[]{0});
- this.treatment = treatment;
- this.dummy = true;
- } else {
- this.key = key;
- this.treatment = DefaultTrafficTreatment.builder().build();
- this.dummy = false;
- }
- }
-
- @SuppressWarnings("unused")
- public GroupKey key() {
- return key;
- }
-
- @Override
- public byte[] data() {
- return appKryo.serialize(this);
- }
-
- }
-}