mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-04 19:56:49 +02:00
[ONOS-7129] Pipeliner for fabric pipeline
Change-Id: I86b44694e1251611359e8ddc8be2533a741230cc
This commit is contained in:
parent
fa4a1c7747
commit
0b80972fa9
@ -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 = [
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user