[ONOS-7129] Pipeliner for fabric pipeline

Change-Id: I86b44694e1251611359e8ddc8be2533a741230cc
This commit is contained in:
Yi Tseng 2017-11-03 10:23:26 -07:00
parent fa4a1c7747
commit 0b80972fa9
14 changed files with 2200 additions and 0 deletions

View File

@ -1,8 +1,10 @@
COMPILE_DEPS = [
'//lib:CORE_DEPS',
'//lib:KRYO',
'//protocols/p4runtime/model:onos-protocols-p4runtime-model',
'//protocols/p4runtime/api:onos-protocols-p4runtime-api',
'//pipelines/basic:onos-pipelines-basic',
'//core/store/serializers:onos-core-serializers',
]
TEST_DEPS = [

View File

@ -22,6 +22,7 @@ import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.net.behaviour.Pipeliner;
import org.onosproject.net.device.PortStatisticsDiscovery;
import org.onosproject.net.pi.model.DefaultPiPipeconf;
import org.onosproject.net.pi.model.PiPipeconf;
@ -31,6 +32,7 @@ import org.onosproject.net.pi.model.PiPipelineModel;
import org.onosproject.net.pi.service.PiPipeconfService;
import org.onosproject.p4runtime.model.P4InfoParser;
import org.onosproject.p4runtime.model.P4InfoParserException;
import org.onosproject.pipelines.fabric.pipeliner.FabricPipeliner;
import java.net.URL;
import java.util.Collection;
@ -78,6 +80,7 @@ public class PipeconfLoader {
.withId(FABRIC_PIPECONF_ID)
.withPipelineModel(model)
.addBehaviour(PiPipelineInterpreter.class, FabricInterpreter.class)
.addBehaviour(Pipeliner.class, FabricPipeliner.class)
.addBehaviour(PortStatisticsDiscovery.class, FabricPortStatisticsDiscovery.class)
.addExtension(P4_INFO_TEXT, p4InfoUrl)
.addExtension(BMV2_JSON, jsonUrl)

View File

@ -0,0 +1,244 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import com.google.common.collect.Sets;
import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
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.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.EthCriterion;
import org.onosproject.net.flow.criteria.PiCriterion;
import org.onosproject.net.flow.criteria.PortCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.pipelines.fabric.FabricConstants;
import org.slf4j.Logger;
import java.util.Collection;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Handling filtering objective for fabric pipeliner.
*/
public class FabricFilteringPipeliner {
private static final Logger log = getLogger(FabricFilteringPipeliner.class);
// Forwarding types
private static final byte FWD_BRIDGING = 0;
private static final byte FWD_MPLS = 1;
private static final byte FWD_IPV4_UNICAST = 2;
private static final byte FWD_IPV4_MULTICAST = 3;
private static final byte FWD_IPV6_UNICAST = 4;
private static final byte FWD_IPV6_MULTICAST = 5;
private static final PiCriterion VLAN_VALID = PiCriterion.builder()
.matchExact(FabricConstants.HF_VLAN_TAG_IS_VALID_ID, new byte[]{1})
.build();
private static final PiCriterion VLAN_INVALID = PiCriterion.builder()
.matchExact(FabricConstants.HF_VLAN_TAG_IS_VALID_ID, new byte[]{0})
.build();
protected DeviceId deviceId;
public FabricFilteringPipeliner(DeviceId deviceId) {
this.deviceId = deviceId;
}
/**
* Translates filtering objective to flows and groups.
*
* @param filterObjective the filtering objective
* @return translation result, contains flows, groups or error it generated
*/
public PipelinerTranslationResult filter(FilteringObjective filterObjective) {
PipelinerTranslationResult.Builder resultBuilder = PipelinerTranslationResult.builder();
// maps selector and treatment from filtering objective to filtering
// control block.
if (filterObjective.type() == FilteringObjective.Type.DENY) {
log.warn("Unsupported filtering objective type {}", filterObjective.type());
resultBuilder.setError(ObjectiveError.UNSUPPORTED);
return resultBuilder.build();
}
if (filterObjective.key() == null ||
filterObjective.key().type() != Criterion.Type.IN_PORT) {
log.warn("Unsupported filter key {}", filterObjective.key());
resultBuilder.setError(ObjectiveError.BADPARAMS);
return resultBuilder.build();
}
PortCriterion inPortCriterion = (PortCriterion) filterObjective.key();
VlanIdCriterion vlanCriterion = filterObjective.conditions().stream()
.filter(criterion -> criterion.type() == Criterion.Type.VLAN_VID)
.map(criterion -> (VlanIdCriterion) criterion)
.findFirst()
.orElse(null);
EthCriterion ethDstCriterion = filterObjective.conditions().stream()
.filter(criterion -> criterion.type() == Criterion.Type.ETH_DST)
.map(criterion -> (EthCriterion) criterion)
.findFirst()
.orElse(null);
FlowRule inPortVlanTableRule = createInPortVlanTable(inPortCriterion, vlanCriterion,
filterObjective);
Collection<FlowRule> fwdClassifierRules = createFwdClassifierRules(inPortCriterion, ethDstCriterion,
filterObjective);
resultBuilder.addFlowRule(inPortVlanTableRule);
fwdClassifierRules.forEach(resultBuilder::addFlowRule);
return resultBuilder.build();
}
private FlowRule createInPortVlanTable(Criterion inPortCriterion,
VlanIdCriterion vlanCriterion,
FilteringObjective filterObjective) {
Criterion vlanIsVlalidCriterion;
TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
.add(inPortCriterion);
VlanId vlanId = null;
if (vlanCriterion != null) {
vlanId = vlanCriterion.vlanId();
}
vlanIsVlalidCriterion = VLAN_VALID;
if (vlanId == null || vlanId.equals(VlanId.NONE)) {
// untag vlan, match in port only
vlanIsVlalidCriterion = VLAN_INVALID;
}
selector.add(vlanIsVlalidCriterion);
// TODO: check if this treatment is valid or not
TrafficTreatment treatment = filterObjective.meta();
if (treatment == null) {
treatment = DefaultTrafficTreatment.emptyTreatment();
}
return DefaultFlowRule.builder()
.fromApp(filterObjective.appId())
.withPriority(filterObjective.priority())
.withSelector(selector.build())
.withTreatment(treatment)
.withPriority(filterObjective.priority())
.forTable(FabricConstants.TBL_INGRESS_PORT_VLAN_ID)
.forDevice(deviceId)
.makePermanent()
.build();
}
private Collection<FlowRule> createFwdClassifierRules(PortCriterion inPortCriterion,
EthCriterion ethDstCriterion,
FilteringObjective filterObjective) {
Collection<FlowRule> flowRules = Sets.newHashSet();
if (ethDstCriterion == null) {
// Bridging table, do nothing
return flowRules;
}
PortNumber port = inPortCriterion.port();
MacAddress dstMac = ethDstCriterion.mac();
if (dstMac.isMulticast()) {
flowRules.add(createMulticastFwdClassifierRule(port, dstMac, filterObjective));
return flowRules;
}
flowRules.addAll(createIpFwdClassifierRules(port, dstMac, filterObjective));
flowRules.add(createMplsFwdClassifierRule(port, dstMac, filterObjective));
return flowRules;
}
private FlowRule createMulticastFwdClassifierRule(PortNumber inPort, MacAddress dstMac,
FilteringObjective filterObjective) {
TrafficTreatment treatment;
short ethType;
if (dstMac.equals(MacAddress.IPV4_MULTICAST)) {
// Ipv4 multicast
treatment = createFwdClassifierTreatment(FWD_IPV4_MULTICAST);
ethType = Ethernet.TYPE_IPV4;
} else {
// IPv6 multicast
treatment = createFwdClassifierTreatment(FWD_IPV6_MULTICAST);
ethType = Ethernet.TYPE_IPV6;
}
return createFwdClassifierRule(inPort, ethType, dstMac, treatment, filterObjective);
}
private Collection<FlowRule> createIpFwdClassifierRules(PortNumber inPort,
MacAddress dstMac,
FilteringObjective filterObjective) {
Collection<FlowRule> flowRules = Sets.newHashSet();
TrafficTreatment treatment;
treatment = createFwdClassifierTreatment(FWD_IPV4_UNICAST);
flowRules.add(createFwdClassifierRule(inPort, Ethernet.TYPE_IPV4, dstMac, treatment, filterObjective));
treatment = createFwdClassifierTreatment(FWD_IPV6_UNICAST);
flowRules.add(createFwdClassifierRule(inPort, Ethernet.TYPE_IPV6, dstMac, treatment, filterObjective));
return flowRules;
}
private FlowRule createMplsFwdClassifierRule(PortNumber inPort,
MacAddress dstMac,
FilteringObjective filterObjective) {
TrafficTreatment treatment = createFwdClassifierTreatment(FWD_MPLS);
return createFwdClassifierRule(inPort, Ethernet.MPLS_UNICAST, dstMac, treatment, filterObjective);
}
private FlowRule createFwdClassifierRule(PortNumber inPort,
short ethType,
MacAddress dstMac,
TrafficTreatment treatment,
FilteringObjective filterObjective) {
TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
.matchInPort(inPort)
.matchEthDst(dstMac)
.matchEthType(ethType);
return DefaultFlowRule.builder()
.withSelector(selector.build())
.withTreatment(treatment)
.fromApp(filterObjective.appId())
.withPriority(filterObjective.priority())
.forDevice(deviceId)
.makePermanent()
.forTable(FabricConstants.TBL_FWD_CLASSIFIER_ID)
.build();
}
private TrafficTreatment createFwdClassifierTreatment(byte fwdType) {
PiActionParam param = new PiActionParam(FabricConstants.ACT_PRM_FWD_TYPE_ID,
ImmutableByteSequence.copyFrom(fwdType));
PiAction action = PiAction.builder()
.withId(FabricConstants.ACT_SET_FORWARDING_TYPE_ID)
.withParameter(param)
.build();
return DefaultTrafficTreatment.builder()
.piTableAction(action)
.build();
}
}

View File

@ -0,0 +1,211 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import com.google.common.collect.ImmutableSet;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.DeviceId;
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.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.EthCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.pipelines.fabric.FabricConstants;
import org.slf4j.Logger;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Handling forwarding objective for fabric pipeliner.
*/
public class FabricForwardingPipeliner {
private static final Logger log = getLogger(FabricForwardingPipeliner.class);
protected DeviceId deviceId;
public FabricForwardingPipeliner(DeviceId deviceId) {
this.deviceId = deviceId;
}
public PipelinerTranslationResult forward(ForwardingObjective forwardObjective) {
PipelinerTranslationResult.Builder resultBuilder = PipelinerTranslationResult.builder();
if (forwardObjective.flag() == ForwardingObjective.Flag.VERSATILE) {
processVersatileFwd(forwardObjective, resultBuilder);
} else {
processSpecificFwd(forwardObjective, resultBuilder);
}
return resultBuilder.build();
}
private void processVersatileFwd(ForwardingObjective fwd,
PipelinerTranslationResult.Builder resultBuilder) {
// program ACL table only
FlowRule flowRule = DefaultFlowRule.builder()
.withSelector(fwd.selector())
.withTreatment(fwd.treatment())
.forTable(FabricConstants.TBL_ACL_ID)
.withPriority(fwd.priority())
.forDevice(deviceId)
.makePermanent()
.fromApp(fwd.appId())
.build();
resultBuilder.addFlowRule(flowRule);
}
private void processSpecificFwd(ForwardingObjective fwd,
PipelinerTranslationResult.Builder resultBuilder) {
TrafficSelector selector = fwd.selector();
TrafficSelector meta = fwd.meta();
ImmutableSet.Builder<Criterion> criterionSetBuilder = ImmutableSet.builder();
criterionSetBuilder.addAll(selector.criteria());
if (meta != null) {
criterionSetBuilder.addAll(meta.criteria());
}
Set<Criterion> criteria = criterionSetBuilder.build();
VlanIdCriterion vlanIdCriterion = null;
EthCriterion ethDstCriterion = null;
for (Criterion criterion : criteria) {
switch (criterion.type()) {
case ETH_DST:
ethDstCriterion = (EthCriterion) criterion;
break;
case VLAN_VID:
vlanIdCriterion = (VlanIdCriterion) criterion;
break;
default:
log.warn("Unsupported criterion {}", criterion);
break;
}
}
ForwardingFunctionType forwardingFunctionType =
ForwardingFunctionType.getForwardingFunctionType(fwd);
switch (forwardingFunctionType) {
case L2_UNICAST:
processL2UnicastRule(vlanIdCriterion, ethDstCriterion, fwd, resultBuilder);
break;
case L2_BROADCAST:
processL2BroadcastRule(vlanIdCriterion, fwd, resultBuilder);
break;
case IPV4_UNICAST:
case IPV4_MULTICAST:
case IPV6_UNICAST:
case IPV6_MULTICAST:
case MPLS:
default:
log.warn("Unsupported forwarding function type {}", criteria);
resultBuilder.setError(ObjectiveError.UNSUPPORTED);
break;
}
}
// L2 Unicast: learnt mac address + vlan
private void processL2UnicastRule(VlanIdCriterion vlanIdCriterion,
EthCriterion ethDstCriterion,
ForwardingObjective fwd,
PipelinerTranslationResult.Builder resultBuilder) {
checkNotNull(vlanIdCriterion, "VlanId criterion should not be null");
checkNotNull(ethDstCriterion, "EthDst criterion should not be null");
if (fwd.nextId() == null) {
log.warn("Forwarding objective for L2 unicast should contains next id");
resultBuilder.setError(ObjectiveError.BADPARAMS);
return;
}
VlanId vlanId = vlanIdCriterion.vlanId();
MacAddress ethDst = ethDstCriterion.mac();
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchVlanId(vlanId)
.matchEthDst(ethDst)
.build();
TrafficTreatment treatment = buildSetNextIdTreatment(fwd.nextId());
FlowRule flowRule = DefaultFlowRule.builder()
.withSelector(selector)
.withTreatment(treatment)
.fromApp(fwd.appId())
.withPriority(fwd.priority())
.makePermanent()
.forDevice(deviceId)
.forTable(FabricConstants.TBL_BRIDGING_ID)
.build();
resultBuilder.addFlowRule(flowRule);
}
private void processL2BroadcastRule(VlanIdCriterion vlanIdCriterion,
ForwardingObjective fwd,
PipelinerTranslationResult.Builder resultBuilder) {
checkNotNull(vlanIdCriterion, "VlanId criterion should not be null");
if (fwd.nextId() == null) {
log.warn("Forwarding objective for L2 broadcast should contains next id");
resultBuilder.setError(ObjectiveError.BADPARAMS);
return;
}
VlanId vlanId = vlanIdCriterion.vlanId();
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchVlanId(vlanId)
.build();
TrafficTreatment treatment = buildSetNextIdTreatment(fwd.nextId());
FlowRule flowRule = DefaultFlowRule.builder()
.withSelector(selector)
.withTreatment(treatment)
.fromApp(fwd.appId())
.withPriority(fwd.priority())
.makePermanent()
.forDevice(deviceId)
.forTable(FabricConstants.TBL_BRIDGING_ID)
.build();
resultBuilder.addFlowRule(flowRule);
}
private static TrafficTreatment buildSetNextIdTreatment(Integer nextId) {
PiActionParam nextIdParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_ID_ID,
ImmutableByteSequence.copyFrom(nextId.byteValue()));
PiAction nextIdAction = PiAction.builder()
.withId(FabricConstants.ACT_SET_NEXT_ID_ID)
.withParameter(nextIdParam)
.build();
return DefaultTrafficTreatment.builder()
.piTableAction(nextIdAction)
.build();
}
}

View File

@ -0,0 +1,159 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import com.google.common.collect.ImmutableMap;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.DeviceId;
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.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.PiCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.pipelines.fabric.FabricConstants;
import org.slf4j.Logger;
import java.util.Map;
import static org.onosproject.pipelines.fabric.pipeliner.FabricPipeliner.fail;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Handling next objective for fabric pipeliner.
*/
public class FabricNextPipeliner {
private static final Logger log = getLogger(FabricNextPipeliner.class);
// Next types
private static final byte TBL_SIMPLE = 0;
private static final byte TBL_HASHED = 1;
private static final byte TBL_BROADCAST = 2;
private static final byte PUNT = 3;
private static final Map<NextObjective.Type, Byte> NEXT_TYPE_MAP =
ImmutableMap.<NextObjective.Type, Byte>builder()
.put(NextObjective.Type.SIMPLE, TBL_SIMPLE)
.put(NextObjective.Type.HASHED, TBL_HASHED)
.put(NextObjective.Type.BROADCAST, TBL_BROADCAST)
.build();
protected DeviceId deviceId;
public FabricNextPipeliner(DeviceId deviceId) {
this.deviceId = deviceId;
}
public PipelinerTranslationResult next(NextObjective nextObjective) {
PipelinerTranslationResult.Builder resultBuilder = PipelinerTranslationResult.builder();
FlowRule nextIdMappingRule = processNextIdMapping(nextObjective);
FlowRule nextRule = null;
switch (nextObjective.type()) {
case SIMPLE:
nextRule = processSimpleNext(nextObjective);
break;
default:
log.warn("Unsupported next type {}", nextObjective);
resultBuilder.setError(ObjectiveError.UNSUPPORTED);
break;
}
if (nextIdMappingRule != null && nextRule != null) {
resultBuilder.addFlowRule(nextIdMappingRule);
resultBuilder.addFlowRule(nextRule);
}
return resultBuilder.build();
}
private FlowRule processNextIdMapping(NextObjective next) {
// program the next id mapping table
TrafficSelector nextIdSelector = buildNextIdSelector(next.id());
TrafficTreatment setNextTypeTreatment = buildSetNextTypeTreatment(next.type());
return DefaultFlowRule.builder()
.withSelector(nextIdSelector)
.withTreatment(setNextTypeTreatment)
.forDevice(deviceId)
.forTable(FabricConstants.TBL_NEXT_ID_MAPPING_ID)
.makePermanent()
.withPriority(next.priority())
.fromApp(next.appId())
.build();
}
private FlowRule processSimpleNext(NextObjective next) {
if (next.next().size() > 1) {
log.warn("Only one treatment in simple next objective");
fail(next, ObjectiveError.BADPARAMS);
return null;
}
TrafficSelector selector = buildNextIdSelector(next.id());
TrafficTreatment treatment = next.next().iterator().next();
OutputInstruction outputInst = treatment.allInstructions()
.stream()
.filter(inst -> inst.type() == Instruction.Type.OUTPUT)
.map(inst -> (OutputInstruction) inst)
.findFirst()
.orElse(null);
if (outputInst == null) {
log.warn("At least one output instruction in simple next objective");
fail(next, ObjectiveError.BADPARAMS);
return null;
}
return DefaultFlowRule.builder()
.withSelector(selector)
.withTreatment(treatment)
.forTable(FabricConstants.TBL_SIMPLE_ID)
.makePermanent()
.withPriority(next.priority())
.forDevice(deviceId)
.fromApp(next.appId())
.build();
}
private TrafficSelector buildNextIdSelector(int nextId) {
byte[] nextIdVal = new byte[]{(byte) nextId};
PiCriterion nextIdCrriterion = PiCriterion.builder()
.matchExact(FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID, nextIdVal)
.build();
return DefaultTrafficSelector.builder()
.matchPi(nextIdCrriterion)
.build();
}
private TrafficTreatment buildSetNextTypeTreatment(NextObjective.Type nextType) {
byte nextTypeVal = NEXT_TYPE_MAP.getOrDefault(nextType, PUNT);
PiActionParam nextTypeParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_TYPE_ID,
ImmutableByteSequence.copyFrom(nextTypeVal));
PiAction nextTypeAction = PiAction.builder()
.withId(FabricConstants.ACT_SET_NEXT_TYPE_ID)
.withParameter(nextTypeParam)
.build();
return DefaultTrafficTreatment.builder()
.piTableAction(nextTypeAction)
.build();
}
}

View File

@ -0,0 +1,303 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.onlab.util.KryoNamespace;
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.FlowRule;
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.flow.FlowRuleOperationsContext;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
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.GroupDescription;
import org.onosproject.net.group.GroupEvent;
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.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Pipeliner for fabric pipeline.
*/
public class FabricPipeliner extends AbstractHandlerBehaviour implements Pipeliner {
private static final Logger log = getLogger(FabricPipeliner.class);
protected static final KryoNamespace KRYO = new KryoNamespace.Builder()
.register(KryoNamespaces.API)
.register(FabricNextGroup.class)
.build("FabricPipeliner");
// TODO: make this configurable
private static final long DEFAULT_INSTALLATION_TIME_OUT = 10;
protected DeviceId deviceId;
protected FlowRuleService flowRuleService;
protected GroupService groupService;
protected FlowObjectiveStore flowObjectiveStore;
protected FabricFilteringPipeliner pipelinerFilter;
protected FabricForwardingPipeliner pipelinerForward;
protected FabricNextPipeliner pipelinerNext;
@Override
public void init(DeviceId deviceId, PipelinerContext context) {
this.deviceId = deviceId;
this.flowRuleService = context.directory().get(FlowRuleService.class);
this.groupService = context.directory().get(GroupService.class);
this.flowObjectiveStore = context.directory().get(FlowObjectiveStore.class);
this.pipelinerFilter = new FabricFilteringPipeliner(deviceId);
this.pipelinerForward = new FabricForwardingPipeliner(deviceId);
this.pipelinerNext = new FabricNextPipeliner(deviceId);
}
@Override
public void filter(FilteringObjective filterObjective) {
PipelinerTranslationResult result = pipelinerFilter.filter(filterObjective);
if (result.error().isPresent()) {
fail(filterObjective, result.error().get());
return;
}
applyTranslationResult(filterObjective, result, success -> {
if (success) {
success(filterObjective);
} else {
fail(filterObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
}
});
}
@Override
public void forward(ForwardingObjective forwardObjective) {
PipelinerTranslationResult result = pipelinerForward.forward(forwardObjective);
if (result.error().isPresent()) {
fail(forwardObjective, result.error().get());
return;
}
applyTranslationResult(forwardObjective, result, success -> {
if (success) {
success(forwardObjective);
} else {
fail(forwardObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
}
});
}
@Override
public void next(NextObjective nextObjective) {
PipelinerTranslationResult result = pipelinerNext.next(nextObjective);
if (result.error().isPresent()) {
fail(nextObjective, result.error().get());
return;
}
applyTranslationResult(nextObjective, result, success -> {
if (!success) {
fail(nextObjective, ObjectiveError.GROUPINSTALLATIONFAILED);
return;
}
// Success, put next group to objective store
List<PortNumber> portNumbers = Lists.newArrayList();
nextObjective.next().forEach(treatment -> {
Instructions.OutputInstruction outputInst = treatment.allInstructions()
.stream()
.filter(inst -> inst.type() == Instruction.Type.OUTPUT)
.map(inst -> (Instructions.OutputInstruction) inst)
.findFirst()
.orElse(null);
if (outputInst != null) {
portNumbers.add(outputInst.port());
}
});
FabricNextGroup nextGroup = new FabricNextGroup(nextObjective.type(),
portNumbers);
flowObjectiveStore.putNextGroup(nextObjective.id(), nextGroup);
success(nextObjective);
});
}
@Override
public List<String> getNextMappings(NextGroup nextGroup) {
return null;
}
private void applyTranslationResult(Objective objective,
PipelinerTranslationResult result,
Consumer<Boolean> callback) {
Collection<GroupDescription> groups = result.groups();
Collection<FlowRule> flowRules = result.flowRules();
CompletableFuture.supplyAsync(() -> installGroups(objective, groups))
.thenApplyAsync(groupSuccess -> groupSuccess && installFlows(objective, flowRules))
.thenAcceptAsync(callback)
.exceptionally((ex) -> {
log.warn("Got unexpected exception while applying translation result {}",
result);
fail(objective, ObjectiveError.UNKNOWN);
return null;
});
}
private boolean installFlows(Objective objective, Collection<FlowRule> flowRules) {
if (flowRules.isEmpty()) {
return true;
}
CompletableFuture<Boolean> flowInstallFuture = new CompletableFuture<>();
FlowRuleOperationsContext ctx = new FlowRuleOperationsContext() {
@Override
public void onSuccess(FlowRuleOperations ops) {
flowInstallFuture.complete(true);
}
@Override
public void onError(FlowRuleOperations ops) {
log.warn("Failed to install flow rules: {}", flowRules);
flowInstallFuture.complete(false);
}
};
FlowRuleOperations ops = buildFlowRuleOps(objective, flowRules, ctx);
flowRuleService.apply(ops);
try {
return flowInstallFuture.get(DEFAULT_INSTALLATION_TIME_OUT, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
log.warn("Got exception while installing groups: {}", e);
return false;
}
}
private boolean installGroups(Objective objective, Collection<GroupDescription> groups) {
if (groups.isEmpty()) {
return true;
}
int numGroupsToBeInstalled = groups.size();
CompletableFuture<Boolean> groupInstallFuture = new CompletableFuture<>();
AtomicInteger numGroupsInstalled = new AtomicInteger(0);
GroupListener listener = new GroupListener() {
@Override
public void event(GroupEvent event) {
int currentNumGroupInstalled = numGroupsInstalled.incrementAndGet();
if (currentNumGroupInstalled == numGroupsToBeInstalled) {
// install completed
groupService.removeListener(this);
groupInstallFuture.complete(true);
}
}
@Override
public boolean isRelevant(GroupEvent event) {
return groups.contains(event.subject());
}
};
groupService.addListener(listener);
switch (objective.op()) {
case ADD:
groups.forEach(groupService::addGroup);
break;
case REMOVE:
groups.forEach(group -> groupService.removeGroup(deviceId, group.appCookie(), objective.appId()));
break;
default:
log.warn("Unsupported objective operation {}", objective.op());
groupService.removeListener(listener);
}
try {
return groupInstallFuture.get(DEFAULT_INSTALLATION_TIME_OUT, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
log.warn("Got exception while installing groups: {}", e);
return false;
}
}
static void fail(Objective objective, ObjectiveError error) {
objective.context().ifPresent(ctx -> ctx.onError(objective, error));
}
static void success(Objective objective) {
objective.context().ifPresent(ctx -> ctx.onSuccess(objective));
}
static FlowRuleOperations buildFlowRuleOps(Objective objective, Collection<FlowRule> flowRules,
FlowRuleOperationsContext ctx) {
FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
switch (objective.op()) {
case ADD:
flowRules.forEach(ops::add);
break;
case REMOVE:
flowRules.forEach(ops::remove);
break;
default:
log.warn("Unsupported op {} for {}", objective);
fail(objective, ObjectiveError.BADPARAMS);
return null;
}
return ops.build(ctx);
}
class FabricNextGroup implements NextGroup {
private NextObjective.Type type;
private Collection<PortNumber> outputPorts;
public FabricNextGroup(NextObjective.Type type, Collection<PortNumber> outputPorts) {
this.type = type;
this.outputPorts = ImmutableList.copyOf(outputPorts);
}
public NextObjective.Type type() {
return type;
}
public Collection<PortNumber> outputPorts() {
return outputPorts;
}
@Override
public byte[] data() {
return KRYO.serialize(this);
}
}
}

View File

@ -0,0 +1,122 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flowobjective.ForwardingObjective;
import java.util.Map;
import java.util.Set;
import static org.onosproject.net.flow.criteria.Criterion.Type.ETH_DST;
import static org.onosproject.net.flow.criteria.Criterion.Type.ETH_TYPE;
import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
import static org.onosproject.net.flow.criteria.Criterion.Type.IPV6_DST;
import static org.onosproject.net.flow.criteria.Criterion.Type.MPLS_BOS;
import static org.onosproject.net.flow.criteria.Criterion.Type.MPLS_LABEL;
import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
public enum ForwardingFunctionType {
/**
* L2 unicast, with vlan id + mac address criterion.
*/
L2_UNICAST,
/**
* L2 broadcast, with vlan id criterion only.
*/
L2_BROADCAST,
/**
* IPv4 unicast, with EtherType and IPv4 unicast destination address.
*/
IPV4_UNICAST,
/**
* IPv4 multicast, with EtherType and IPv4 multicast destination address.
*/
IPV4_MULTICAST,
/**
* IPv6 unicast, with EtherType and IPv6 unicast destination address.
*/
IPV6_UNICAST,
/**
* IPv6 multicast, with EtherType and IPv6 multicast destination address.
*/
IPV6_MULTICAST,
/**
* MPLS, with EtherType, MPLS label and MPLS BOS criterion.
*/
MPLS,
/**
* Unsupported type.
*/
UNSUPPORTED;
// Different criteria combinations for different FFT
private static final Set<Criterion.Type> L2_UNI_CRITERIA_TYPE =
ImmutableSet.of(VLAN_VID, ETH_DST);
private static final Set<Criterion.Type> L2_BRC_CRITERIA_TYPE =
ImmutableSet.of(VLAN_VID);
private static final Set<Criterion.Type> IPV4_UNI_CRITERIA_TYPE =
ImmutableSet.of(ETH_TYPE, IPV4_DST);
private static final Set<Criterion.Type> IPV4_MCAST_CRITERIA_TYPE =
ImmutableSet.of(ETH_TYPE, VLAN_VID, IPV4_DST);
private static final Set<Criterion.Type> IPV6_UNI_CRITERIA_TYPE =
ImmutableSet.of(ETH_TYPE, IPV6_DST);
private static final Set<Criterion.Type> IPV6_MCAST_CRITERIA_TYPE =
ImmutableSet.of(ETH_TYPE, VLAN_VID, IPV6_DST);
private static final Set<Criterion.Type> MPLS_UNI_CRITERIA_TYPE =
ImmutableSet.of(ETH_TYPE, MPLS_LABEL, MPLS_BOS);
private static final Map<Set<Criterion.Type>, ForwardingFunctionType> FFT_MAP =
ImmutableMap.<Set<Criterion.Type>, ForwardingFunctionType>builder()
.put(L2_UNI_CRITERIA_TYPE, L2_UNICAST)
.put(L2_BRC_CRITERIA_TYPE, L2_BROADCAST)
.put(IPV4_UNI_CRITERIA_TYPE, IPV4_UNICAST)
.put(IPV4_MCAST_CRITERIA_TYPE, IPV4_MULTICAST)
.put(IPV6_UNI_CRITERIA_TYPE, IPV6_UNICAST)
.put(IPV6_MCAST_CRITERIA_TYPE, IPV6_MULTICAST)
.put(MPLS_UNI_CRITERIA_TYPE, MPLS)
.build();
/**
* Gets forwarding function type of the forwarding objective.
*
* @param fwd the forwarding objective
* @return forwarding function type of the forwarding objective
*/
public static ForwardingFunctionType getForwardingFunctionType(ForwardingObjective fwd) {
Set<Criterion.Type> criteriaType = Sets.newHashSet();
fwd.selector().criteria().stream().map(Criterion::type)
.forEach(criteriaType::add);
if (fwd.meta() != null) {
fwd.meta().criteria().stream().map(Criterion::type)
.forEach(criteriaType::add);
}
return FFT_MAP.getOrDefault(criteriaType, UNSUPPORTED);
}
}

View File

@ -0,0 +1,154 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.group.GroupDescription;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
/**
* Translation results from fabric pipeliner.
*/
public final class PipelinerTranslationResult {
private Collection<FlowRule> flowRules;
private Collection<GroupDescription> groups;
private ObjectiveError error;
private PipelinerTranslationResult(Collection<FlowRule> flowRules,
Collection<GroupDescription> groups,
ObjectiveError error) {
this.flowRules = flowRules;
this.groups = groups;
this.error = error;
}
/**
* Gets flow rules from result.
*
* @return flow rules
*/
public Collection<FlowRule> flowRules() {
return flowRules;
}
/**
* Gets groups from result.
*
* @return groups
*/
public Collection<GroupDescription> groups() {
return groups;
}
/**
* Gets error from result.
*
* @return error of the result; empty if there is no error
*/
public Optional<ObjectiveError> error() {
return Optional.ofNullable(error);
}
/**
* Creates a new builder.
*
* @return the builder
*/
public static Builder builder() {
return new Builder();
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("flowRules", flowRules)
.add("groups", groups)
.add("error", error)
.toString();
}
@Override
public int hashCode() {
return Objects.hash(flowRules, groups, error);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final PipelinerTranslationResult other = (PipelinerTranslationResult) obj;
return Objects.equals(this.flowRules, other.flowRules)
&& Objects.equals(this.groups, other.groups)
&& Objects.equals(this.error, other.error);
}
/**
* Builder for PipelinerTranslationResult.
*/
public static final class Builder {
private ImmutableList.Builder<FlowRule> flowRules = ImmutableList.builder();
private ImmutableList.Builder<GroupDescription> groups = ImmutableList.builder();
private ObjectiveError error = null;
// Hide default constructor
private Builder() {
}
/**
* Adds flow rule to the result.
*
* @param flowRule the flow rule
*/
public void addFlowRule(FlowRule flowRule) {
flowRules.add(flowRule);
}
/**
* Adds group to the result.
*
* @param group the group
*/
public void addGroup(GroupDescription group) {
groups.add(group);
}
/**
* Sets objective error to the result.
*
* @param error the error
*/
public void setError(ObjectiveError error) {
this.error = error;
}
public PipelinerTranslationResult build() {
return new PipelinerTranslationResult(flowRules.build(),
groups.build(),
error);
}
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.
*/
/**
* Pipeliner for fabric.p4.
*/
package org.onosproject.pipelines.fabric.pipeliner;

View File

@ -0,0 +1,355 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import org.junit.Test;
import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.PortNumber;
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.TableId;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flowobjective.DefaultFilteringObjective;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.pipelines.fabric.FabricConstants;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Test cases for fabric.p4 pipeline filtering control block.
*/
public class FabricFilteringPipelinerTest extends FabricPipelinerTest {
/**
* Creates one rule for ingress_port_vlan table and 3 rules for
* fwd_classifier table (IPv4, IPv6 and MPLS unicast) when
* the condition is VLAN + MAC.
*/
@Test
public void testRouterMacAndVlanFilter() {
FilteringObjective filteringObjective = buildFilteringObjective(ROUTER_MAC);
PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
assertTrue(groupsInstalled.isEmpty());
// in port vlan flow rule
FlowRule actualFlowRule = flowRulesInstalled.get(0);
FlowRule flowRuleExpected = buildExpectedVlanInPortRule(PORT_1,
VlanId.NONE,
VLAN_100,
FabricConstants.TBL_INGRESS_PORT_VLAN_ID);
assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
// forwarding classifier ipv4
actualFlowRule = flowRulesInstalled.get(1);
flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
ROUTER_MAC,
Ethernet.TYPE_IPV4,
FWD_IPV4_UNICAST);
assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
// forwarding classifier ipv6
actualFlowRule = flowRulesInstalled.get(2);
flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
ROUTER_MAC,
Ethernet.TYPE_IPV6,
FWD_IPV6_UNICAST);
assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
// forwarding classifier mpls
actualFlowRule = flowRulesInstalled.get(3);
flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
ROUTER_MAC,
Ethernet.MPLS_UNICAST,
FWD_MPLS);
assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
}
/**
* Creates one rule for ingress_port_vlan table and one rule for
* fwd_classifier table (IPv4 multicast) when the condition is ipv4
* multicast mac address.
*/
@Test
public void testIpv4MulticastFwdClass() {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.pushVlan()
.setVlanId(VLAN_100)
.build();
FilteringObjective filteringObjective = DefaultFilteringObjective.builder()
.permit()
.withPriority(PRIORITY)
.withKey(Criteria.matchInPort(PORT_1))
.addCondition(Criteria.matchEthDst(MacAddress.IPV4_MULTICAST))
.addCondition(Criteria.matchVlanId(VlanId.NONE))
.withMeta(treatment)
.fromApp(APP_ID)
.makePermanent()
.add();
PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
assertTrue(groupsInstalled.isEmpty());
// in port vlan flow rule
FlowRule actualFlowRule = flowRulesInstalled.get(0);
FlowRule flowRuleExpected = buildExpectedVlanInPortRule(PORT_1,
VlanId.NONE,
VLAN_100,
FabricConstants.TBL_INGRESS_PORT_VLAN_ID);
assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
// forwarding classifier
actualFlowRule = flowRulesInstalled.get(1);
flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
MacAddress.IPV4_MULTICAST,
Ethernet.TYPE_IPV4,
FWD_IPV4_MULTICAST);
assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
}
/**
* Creates one rule for ingress_port_vlan table and one rule for
* fwd_classifier table (IPv6 multicast) when the condition is ipv6
* multicast mac address.
*/
@Test
public void testIpv6MulticastFwdClass() {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.pushVlan()
.setVlanId(VLAN_100)
.build();
FilteringObjective filteringObjective = DefaultFilteringObjective.builder()
.permit()
.withPriority(PRIORITY)
.withKey(Criteria.matchInPort(PORT_1))
.addCondition(Criteria.matchEthDst(MacAddress.IPV6_MULTICAST))
.addCondition(Criteria.matchVlanId(VlanId.NONE))
.withMeta(treatment)
.fromApp(APP_ID)
.makePermanent()
.add();
PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
assertTrue(groupsInstalled.isEmpty());
// in port vlan flow rule
FlowRule actualFlowRule = flowRulesInstalled.get(0);
FlowRule flowRuleExpected = buildExpectedVlanInPortRule(PORT_1,
VlanId.NONE,
VLAN_100,
FabricConstants.TBL_INGRESS_PORT_VLAN_ID);
assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
// forwarding classifier
actualFlowRule = flowRulesInstalled.get(1);
flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
MacAddress.IPV6_MULTICAST,
Ethernet.TYPE_IPV6,
FWD_IPV6_MULTICAST);
assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
}
/**
* Creates only one rule for ingress_port_vlan table if there is no condition
* of destination mac address.
* The packet will be handled by bridging table by default.
*/
@Test
public void testFwdBridging() {
FilteringObjective filteringObjective = buildFilteringObjective(null);
PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
assertTrue(groupsInstalled.isEmpty());
// in port vlan flow rule
FlowRule actualFlowRule = flowRulesInstalled.get(0);
FlowRule flowRuleExpected = buildExpectedVlanInPortRule(PORT_1,
VlanId.NONE,
VLAN_100,
FabricConstants.TBL_INGRESS_PORT_VLAN_ID);
assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
// No rules in forwarding classifier, will do default action: set fwd type to bridging
}
/**
* We supports only PERMIT type of filtering objective.
*/
@Test
public void testUnsupportedObjective() {
FilteringObjective filteringObjective = DefaultFilteringObjective.builder()
.deny()
.withKey(Criteria.matchInPort(PORT_1))
.addCondition(Criteria.matchVlanId(VLAN_100))
.fromApp(APP_ID)
.makePermanent()
.add();
PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
pipeliner.pipelinerFilter.filter(filteringObjective);
List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
assertTrue(flowRulesInstalled.isEmpty());
assertTrue(groupsInstalled.isEmpty());
assertTrue(result.error().isPresent());
ObjectiveError error = result.error().get();
assertEquals(ObjectiveError.UNSUPPORTED, error);
}
/**
* Incorrect filtering key or filtering conditions test.
*/
@Test
public void badParamTest() {
// Filtering objective should contains filtering key
FilteringObjective filteringObjective = DefaultFilteringObjective.builder()
.permit()
.addCondition(Criteria.matchVlanId(VLAN_100))
.fromApp(APP_ID)
.makePermanent()
.add();
PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
pipeliner.pipelinerFilter.filter(filteringObjective);
assertTrue(result.error().isPresent());
ObjectiveError error = result.error().get();
assertEquals(ObjectiveError.BADPARAMS, error);
// Filtering objective should use in_port as key
filteringObjective = DefaultFilteringObjective.builder()
.permit()
.withKey(Criteria.matchEthDst(ROUTER_MAC))
.addCondition(Criteria.matchVlanId(VLAN_100))
.withMeta(DefaultTrafficTreatment.emptyTreatment())
.fromApp(APP_ID)
.makePermanent()
.add();
result = pipeliner.pipelinerFilter.filter(filteringObjective);
pipeliner.pipelinerFilter.filter(filteringObjective);
assertTrue(result.error().isPresent());
error = result.error().get();
assertEquals(ObjectiveError.BADPARAMS, error);
}
/* Utilities */
private FilteringObjective buildFilteringObjective(MacAddress dstMac) {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.pushVlan()
.setVlanId(VLAN_100)
.build();
DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder()
.permit()
.withPriority(PRIORITY)
.withKey(Criteria.matchInPort(PORT_1));
if (dstMac != null) {
builder.addCondition(Criteria.matchEthDst(dstMac));
}
builder.addCondition(Criteria.matchVlanId(VlanId.NONE))
.withMeta(treatment)
.fromApp(APP_ID)
.makePermanent();
return builder.add();
}
private FlowRule buildExpectedVlanInPortRule(PortNumber inPort, VlanId vlanId,
VlanId internalVlan,
TableId tableId) {
TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
.matchInPort(inPort);
TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
if (vlanId == null || vlanId.equals(VlanId.NONE)) {
selector.matchPi(VLAN_INVALID);
treatment.pushVlan();
treatment.setVlanId(internalVlan);
} else {
selector.matchPi(VLAN_VALID);
selector.matchVlanId(vlanId);
}
return DefaultFlowRule.builder()
.withPriority(PRIORITY)
.withSelector(selector.build())
.withTreatment(treatment.build())
.fromApp(APP_ID)
.forDevice(DEVICE_ID)
.makePermanent()
.forTable(tableId)
.build();
}
private FlowRule buildExpectedFwdClassifierRule(PortNumber inPort,
MacAddress dstMac,
short ethType,
byte fwdClass) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthDst(dstMac)
.matchInPort(inPort)
.matchEthType(ethType)
.build();
PiActionParam classParam = new PiActionParam(FabricConstants.ACT_PRM_FWD_TYPE_ID,
ImmutableByteSequence.copyFrom(fwdClass));
PiAction fwdClassifierAction = PiAction.builder()
.withId(FabricConstants.ACT_SET_FORWARDING_TYPE_ID)
.withParameter(classParam)
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.piTableAction(fwdClassifierAction)
.build();
return DefaultFlowRule.builder()
.withPriority(PRIORITY)
.withSelector(selector)
.withTreatment(treatment)
.fromApp(APP_ID)
.forDevice(DEVICE_ID)
.makePermanent()
.forTable(FabricConstants.TBL_FWD_CLASSIFIER_ID)
.build();
}
}

View File

@ -0,0 +1,260 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import org.junit.Ignore;
import org.junit.Test;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.TpPort;
import org.onlab.packet.UDP;
import org.onlab.util.ImmutableByteSequence;
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.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.pi.model.PiTableId;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.pipelines.fabric.FabricConstants;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Test cases for fabric.p4 pipeline forwarding control block.
*/
public class FabricForwardingPipelineTest extends FabricPipelinerTest {
/**
* Test versatile flag of forwarding objective with ARP match.
*/
@Test
public void testAclArp() {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.wipeDeferred()
.punt()
.build();
// ARP
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_ARP)
.build();
ForwardingObjective fwd = DefaultForwardingObjective.builder()
.withSelector(selector)
.withPriority(PRIORITY)
.fromApp(APP_ID)
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withTreatment(treatment)
.add();
PipelinerTranslationResult result = pipeliner.pipelinerForward.forward(fwd);
List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
assertEquals(1, flowRulesInstalled.size());
assertTrue(groupsInstalled.isEmpty());
FlowRule actualFlowRule = flowRulesInstalled.get(0);
FlowRule expectedFlowRule = DefaultFlowRule.builder()
.forDevice(DEVICE_ID)
.forTable(FabricConstants.TBL_ACL_ID)
.withPriority(PRIORITY)
.makePermanent()
.withSelector(selector)
.withTreatment(treatment)
.fromApp(APP_ID)
.build();
assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
}
/**
* Test versatile flag of forwarding objective with DHCP match.
*/
@Test
public void testAclDhcp() {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.wipeDeferred()
.punt()
.build();
// DHCP
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_UDP)
.matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
.matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
.build();
ForwardingObjective fwd = DefaultForwardingObjective.builder()
.withSelector(selector)
.withPriority(PRIORITY)
.fromApp(APP_ID)
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withTreatment(treatment)
.add();
PipelinerTranslationResult result = pipeliner.pipelinerForward.forward(fwd);
List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
assertEquals(1, flowRulesInstalled.size());
assertTrue(groupsInstalled.isEmpty());
FlowRule actualFlowRule = flowRulesInstalled.get(0);
FlowRule expectedFlowRule = DefaultFlowRule.builder()
.forDevice(DEVICE_ID)
.forTable(FabricConstants.TBL_ACL_ID)
.withPriority(PRIORITY)
.makePermanent()
.withSelector(selector)
.withTreatment(treatment)
.fromApp(APP_ID)
.build();
assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
}
/**
* Test programming L2 unicast rule to bridging table.
*/
@Test
public void testL2Unicast() {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchVlanId(VLAN_100)
.matchEthDst(HOST_MAC)
.build();
testSpecificForward(FabricConstants.TBL_BRIDGING_ID, selector, selector, NEXT_ID_1);
}
@Test
public void testL2Broadcast() {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchVlanId(VLAN_100)
.build();
testSpecificForward(FabricConstants.TBL_BRIDGING_ID, selector, selector, NEXT_ID_1);
}
@Test
@Ignore
public void testIPv4Unicast() {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(IPV4_UNICAST_ADDR)
.build();
TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
.matchIPDst(IPV4_UNICAST_ADDR)
.build();
testSpecificForward(FabricConstants.TBL_UNICAST_V4_ID, expectedSelector, selector, NEXT_ID_1);
}
@Test
@Ignore
public void testIPv4Multicast() {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchVlanId(VLAN_100)
.matchIPDst(IPV4_MCAST_ADDR)
.build();
TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
.matchIPDst(IPV4_MCAST_ADDR)
.build();
testSpecificForward(FabricConstants.TBL_MULTICAST_V4_ID, expectedSelector, selector, NEXT_ID_1);
}
@Test
@Ignore
public void testIPv6Unicast() {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV6)
.matchIPDst(IPV6_UNICAST_ADDR)
.build();
TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
.matchIPDst(IPV6_UNICAST_ADDR)
.build();
testSpecificForward(FabricConstants.TBL_UNICAST_V6_ID, expectedSelector, selector, NEXT_ID_1);
}
@Test
@Ignore
public void testIPv6Multicast() {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV6)
.matchVlanId(VLAN_100)
.matchIPDst(IPV6_MCAST_ADDR)
.build();
TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
.matchIPDst(IPV6_MCAST_ADDR)
.build();
testSpecificForward(FabricConstants.TBL_MULTICAST_V6_ID, expectedSelector, selector, NEXT_ID_1);
}
@Test
@Ignore
public void testMpls() {
}
private void testSpecificForward(PiTableId expectedTableId, TrafficSelector expectedSelector,
TrafficSelector selector, Integer nextId) {
ForwardingObjective fwd = DefaultForwardingObjective.builder()
.withSelector(selector)
.withPriority(PRIORITY)
.fromApp(APP_ID)
.makePermanent()
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.nextStep(nextId)
.add();
PipelinerTranslationResult result = pipeliner.pipelinerForward.forward(fwd);
List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
assertEquals(1, flowRulesInstalled.size());
assertTrue(groupsInstalled.isEmpty());
FlowRule actualFlowRule = flowRulesInstalled.get(0);
PiActionParam nextIdParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_ID_ID,
ImmutableByteSequence.copyFrom(nextId.byteValue()));
PiAction setNextIdAction = PiAction.builder()
.withId(FabricConstants.ACT_SET_NEXT_ID_ID)
.withParameter(nextIdParam)
.build();
TrafficTreatment setNextIdTreatment = DefaultTrafficTreatment.builder()
.piTableAction(setNextIdAction)
.build();
FlowRule expectedFlowRule = DefaultFlowRule.builder()
.forDevice(DEVICE_ID)
.forTable(expectedTableId)
.withPriority(PRIORITY)
.makePermanent()
.withSelector(expectedSelector)
.withTreatment(setNextIdTreatment)
.fromApp(APP_ID)
.build();
assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
}
}

View File

@ -0,0 +1,151 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import org.junit.Ignore;
import org.junit.Test;
import org.onlab.util.ImmutableByteSequence;
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.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.PiCriterion;
import org.onosproject.net.flowobjective.DefaultNextObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.pipelines.fabric.FabricConstants;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Test cases for fabric.p4 pipeline next control block.
*/
public class FabricNextPipelinerTest extends FabricPipelinerTest {
/**
* Test program output rule for Simple table.
*/
@Test
public void testSimpleOutput() {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PORT_1)
.build();
testSimple(treatment);
}
/**
* Test program set vlan and output rule for Simple table.
*/
@Test
public void testSimpleOutputWithVlanTranslation() {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setVlanId(VLAN_100)
.setOutput(PORT_1)
.build();
testSimple(treatment);
}
private void testSimple(TrafficTreatment treatment) {
NextObjective nextObjective = DefaultNextObjective.builder()
.withId(NEXT_ID_1)
.withPriority(PRIORITY)
.addTreatment(treatment)
.withType(NextObjective.Type.SIMPLE)
.makePermanent()
.fromApp(APP_ID)
.add();
PipelinerTranslationResult result = pipeliner.pipelinerNext.next(nextObjective);
List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
assertEquals(2, flowRulesInstalled.size());
assertTrue(groupsInstalled.isEmpty());
FlowRule actualFlowRule;
FlowRule expectedFlowRule;
// Next id mapping table
actualFlowRule = flowRulesInstalled.get(0);
byte[] nextIdVal = new byte[]{NEXT_ID_1.byteValue()};
PiCriterion nextIdCriterion = PiCriterion.builder()
.matchExact(FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID, nextIdVal)
.build();
TrafficSelector nextIdSelector = DefaultTrafficSelector.builder()
.matchPi(nextIdCriterion)
.build();
PiActionParam setNextToSimpleParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_TYPE_ID,
ImmutableByteSequence.copyFrom(NEXT_TYPE_SIMPLE));
PiAction setNextToSimpleAction = PiAction.builder()
.withId(FabricConstants.ACT_SET_NEXT_TYPE_ID)
.withParameter(setNextToSimpleParam)
.build();
TrafficTreatment setNextTypeTreatment = DefaultTrafficTreatment.builder()
.piTableAction(setNextToSimpleAction)
.build();
expectedFlowRule = DefaultFlowRule.builder()
.forDevice(DEVICE_ID)
.fromApp(APP_ID)
.makePermanent()
// FIXME: currently next objective doesn't support priority, set priority to zero
.withPriority(0)
.forTable(FabricConstants.TBL_NEXT_ID_MAPPING_ID)
.withSelector(nextIdSelector)
.withTreatment(setNextTypeTreatment)
.build();
assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
// Simple table
actualFlowRule = flowRulesInstalled.get(1);
expectedFlowRule = DefaultFlowRule.builder()
.forDevice(DEVICE_ID)
.fromApp(APP_ID)
.makePermanent()
// FIXME: currently next objective doesn't support priority, ignore this
.withPriority(0)
.forTable(FabricConstants.TBL_SIMPLE_ID)
.withSelector(nextIdSelector)
.withTreatment(treatment)
.build();
assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
}
/**
* Test program ecmp output group for Hashed table.
*/
@Test
@Ignore
public void testHashedOutput() {
}
/**
* Test program output group for Broadcast table.
*/
@Test
@Ignore
public void testBroadcastOutput() {
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import org.junit.Before;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.TestApplicationId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.PipelinerContext;
import org.onosproject.net.flow.criteria.PiCriterion;
import org.onosproject.pipelines.fabric.FabricConstants;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
public abstract class FabricPipelinerTest {
static final ApplicationId APP_ID = TestApplicationId.create("FabricPipelinerTest");
static final DeviceId DEVICE_ID = DeviceId.deviceId("device:bmv2:11");
static final int PRIORITY = 100;
static final PortNumber PORT_1 = PortNumber.portNumber(1);
static final VlanId VLAN_100 = VlanId.vlanId("100");
static final MacAddress HOST_MAC = MacAddress.valueOf("00:00:00:00:00:01");
static final MacAddress ROUTER_MAC = MacAddress.valueOf("00:00:00:00:02:01");
static final IpPrefix IPV4_UNICAST_ADDR = IpPrefix.valueOf("10.0.0.1/32");
static final IpPrefix IPV4_MCAST_ADDR = IpPrefix.valueOf("224.0.0.1/32");
static final IpPrefix IPV6_UNICAST_ADDR = IpPrefix.valueOf("2000::1/32");
static final IpPrefix IPV6_MCAST_ADDR = IpPrefix.valueOf("ff00::1/32");
static final MplsLabel MPLS_10 = MplsLabel.mplsLabel(10);
static final Integer NEXT_ID_1 = 1;
// Forwarding types
static final byte FWD_BRIDGING = 0;
static final byte FWD_MPLS = 1;
static final byte FWD_IPV4_UNICAST = 2;
static final byte FWD_IPV4_MULTICAST = 3;
static final byte FWD_IPV6_UNICAST = 4;
static final byte FWD_IPV6_MULTICAST = 5;
// Next types
static final byte NEXT_TYPE_SIMPLE = 0;
static final byte NEXT_TYPE_HASHED = 1;
static final byte NEXT_TYPE_BROADCAST = 2;
static final byte NEXT_TYPE_PUNT = 3;
static final PiCriterion VLAN_VALID = PiCriterion.builder()
.matchExact(FabricConstants.HF_VLAN_TAG_IS_VALID_ID, new byte[]{1})
.build();
static final PiCriterion VLAN_INVALID = PiCriterion.builder()
.matchExact(FabricConstants.HF_VLAN_TAG_IS_VALID_ID, new byte[]{0})
.build();
FabricPipeliner pipeliner;
@Before
public void setup() {
pipeliner = new FabricPipeliner();
ServiceDirectory serviceDirectory = createNiceMock(ServiceDirectory.class);
PipelinerContext pipelinerContext = createNiceMock(PipelinerContext.class);
expect(pipelinerContext.directory()).andReturn(serviceDirectory).anyTimes();
replay(serviceDirectory, pipelinerContext);
pipeliner.init(DEVICE_ID, pipelinerContext);
}
}

View File

@ -0,0 +1,130 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.pipelines.fabric.pipeliner;
import org.junit.Ignore;
import org.junit.Test;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.TestApplicationId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for Forwarding class.
*/
public class ForwardingFunctionTypeTest {
private static final ApplicationId APP_ID = TestApplicationId.create("ForwardingFunctionTypeTest");
private static final VlanId VLAN_100 = VlanId.vlanId((short) 100);
private static final MacAddress MAC_ADDR = MacAddress.valueOf("00:00:00:00:00:01");
private static final IpPrefix IPV4_UNICAST_ADDR = IpPrefix.valueOf("10.0.0.1/32");
private static final IpPrefix IPV4_MCAST_ADDR = IpPrefix.valueOf("224.0.0.1/32");
private static final IpPrefix IPV6_UNICAST_ADDR = IpPrefix.valueOf("2000::1/32");
private static final IpPrefix IPV6_MCAST_ADDR = IpPrefix.valueOf("ff00::1/32");
private static final MplsLabel MPLS_10 = MplsLabel.mplsLabel(10);
private TrafficSelector selector;
/**
* Match Vlan + EthDst.
*/
@Test
public void testL2Unicast() {
selector = DefaultTrafficSelector.builder()
.matchVlanId(VLAN_100)
.matchEthDst(MAC_ADDR)
.build();
testFft(selector, ForwardingFunctionType.L2_UNICAST);
}
@Test
public void testL2Broadcast() {
selector = DefaultTrafficSelector.builder()
.matchVlanId(VLAN_100)
.build();
testFft(selector, ForwardingFunctionType.L2_BROADCAST);
}
@Test
@Ignore
public void testIpv4Unicast() {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(IPV4_UNICAST_ADDR)
.build();
testFft(selector, ForwardingFunctionType.IPV4_UNICAST);
}
@Test
@Ignore
public void testIpv4Multicast() {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(IPV4_MCAST_ADDR)
.build();
testFft(selector, ForwardingFunctionType.IPV4_MULTICAST);
}
@Test
@Ignore
public void testIpv6Unicast() {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV6)
.matchIPDst(IPV6_UNICAST_ADDR)
.build();
testFft(selector, ForwardingFunctionType.IPV6_UNICAST);
}
@Test
@Ignore
public void testIpv6Multicast() {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV6)
.matchIPDst(IPV6_MCAST_ADDR)
.build();
testFft(selector, ForwardingFunctionType.IPV4_MULTICAST);
}
@Test
@Ignore
public void testMplsUnicast() {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.MPLS_UNICAST)
.matchMplsLabel(MPLS_10)
.matchMplsBos(true)
.build();
testFft(selector, ForwardingFunctionType.MPLS);
}
private void testFft(TrafficSelector selector, ForwardingFunctionType expectedFft) {
ForwardingObjective fwd = DefaultForwardingObjective.builder()
.withSelector(selector)
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.nextStep(0)
.fromApp(APP_ID)
.add();
assertEquals(expectedFft,
ForwardingFunctionType.getForwardingFunctionType(fwd));
}
}