| /* |
| * Copyright 2016-present Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.onosproject.driver.pipeline; |
| |
| import org.onlab.packet.MacAddress; |
| import org.onlab.packet.VlanId; |
| import org.onosproject.core.ApplicationId; |
| import org.onosproject.core.DefaultGroupId; |
| import org.onosproject.net.flow.DefaultTrafficTreatment; |
| 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.VlanIdCriterion; |
| import org.onosproject.net.flow.instructions.Instruction; |
| import org.onosproject.net.flow.instructions.Instructions; |
| import org.onosproject.net.flow.instructions.L2ModificationInstruction; |
| import org.onosproject.net.group.DefaultGroupBucket; |
| import org.onosproject.net.group.DefaultGroupDescription; |
| import org.onosproject.net.group.DefaultGroupKey; |
| import org.onosproject.net.group.GroupBucket; |
| import org.onosproject.net.group.GroupBuckets; |
| import org.onosproject.net.group.GroupDescription; |
| import org.onosproject.net.group.GroupKey; |
| import org.slf4j.Logger; |
| |
| import java.util.Collections; |
| |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| /** |
| * Group handler for CpqD OFDPA pipeline. |
| */ |
| public class CpqdOfdpa2GroupHandler extends Ofdpa2GroupHandler { |
| private final Logger log = getLogger(getClass()); |
| |
| @Override |
| protected GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId, |
| ApplicationId appId, boolean mpls, |
| TrafficSelector meta) { |
| // for the l2interface group, get vlan and port info |
| // for the outer group, get the src/dst mac, and vlan info |
| TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder(); |
| TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder(); |
| VlanId vlanid = null; |
| long portNum = 0; |
| boolean setVlan = false, popVlan = false; |
| MacAddress srcMac = MacAddress.ZERO; |
| MacAddress dstMac = MacAddress.ZERO; |
| for (Instruction ins : treatment.allInstructions()) { |
| if (ins.type() == Instruction.Type.L2MODIFICATION) { |
| L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; |
| switch (l2ins.subtype()) { |
| case ETH_DST: |
| dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac(); |
| outerTtb.setEthDst(dstMac); |
| break; |
| case ETH_SRC: |
| srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac(); |
| outerTtb.setEthSrc(srcMac); |
| break; |
| case VLAN_ID: |
| vlanid = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId(); |
| outerTtb.setVlanId(vlanid); |
| setVlan = true; |
| break; |
| case VLAN_POP: |
| innerTtb.popVlan(); |
| popVlan = true; |
| break; |
| case DEC_MPLS_TTL: |
| case MPLS_LABEL: |
| case MPLS_POP: |
| case MPLS_PUSH: |
| case VLAN_PCP: |
| case VLAN_PUSH: |
| default: |
| break; |
| } |
| } else if (ins.type() == Instruction.Type.OUTPUT) { |
| portNum = ((Instructions.OutputInstruction) ins).port().toLong(); |
| innerTtb.add(ins); |
| } else { |
| log.warn("Driver does not handle this type of TrafficTreatment" |
| + " instruction in nextObjectives: {}", ins.type()); |
| } |
| } |
| |
| if (vlanid == null && meta != null) { |
| // use metadata if available |
| Criterion vidCriterion = meta.getCriterion(Criterion.Type.VLAN_VID); |
| if (vidCriterion != null) { |
| vlanid = ((VlanIdCriterion) vidCriterion).vlanId(); |
| } |
| // if vlan is not set, use the vlan in metadata for outerTtb |
| if (vlanid != null && !setVlan) { |
| outerTtb.setVlanId(vlanid); |
| } |
| } |
| |
| if (vlanid == null) { |
| log.error("Driver cannot process an L2/L3 group chain without " |
| + "egress vlan information for dev: {} port:{}", |
| deviceId, portNum); |
| return null; |
| } |
| |
| if (!setVlan && !popVlan) { |
| // untagged outgoing port |
| TrafficTreatment.Builder temp = DefaultTrafficTreatment.builder(); |
| temp.popVlan(); |
| innerTtb.build().allInstructions().forEach(i -> temp.add(i)); |
| innerTtb = temp; |
| } |
| |
| // assemble information for ofdpa l2interface group |
| int l2groupId = L2_INTERFACE_TYPE | (vlanid.toShort() << 16) | (int) portNum; |
| // a globally unique groupkey that is different for ports in the same device, |
| // but different for the same portnumber on different devices. Also different |
| // for the various group-types created out of the same next objective. |
| int l2gk = l2InterfaceGroupKey(deviceId, vlanid, portNum); |
| final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk)); |
| |
| // assemble information for outer group |
| GroupDescription outerGrpDesc = null; |
| if (mpls) { |
| // outer group is MPLSInteface |
| int mplsInterfaceIndex = getNextAvailableIndex(); |
| int mplsgroupId = MPLS_INTERFACE_TYPE | (SUBTYPE_MASK & mplsInterfaceIndex); |
| final GroupKey mplsgroupkey = new DefaultGroupKey( |
| Ofdpa2Pipeline.appKryo.serialize(mplsInterfaceIndex)); |
| outerTtb.group(new DefaultGroupId(l2groupId)); |
| // create the mpls-interface group description to wait for the |
| // l2 interface group to be processed |
| GroupBucket mplsinterfaceGroupBucket = |
| DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build()); |
| outerGrpDesc = new DefaultGroupDescription( |
| deviceId, |
| GroupDescription.Type.INDIRECT, |
| new GroupBuckets(Collections.singletonList( |
| mplsinterfaceGroupBucket)), |
| mplsgroupkey, |
| mplsgroupId, |
| appId); |
| log.debug("Trying MPLS-Interface: device:{} gid:{} gkey:{} nextid:{}", |
| deviceId, Integer.toHexString(mplsgroupId), |
| mplsgroupkey, nextId); |
| } else { |
| // outer group is L3Unicast |
| int l3unicastIndex = getNextAvailableIndex(); |
| int l3groupId = L3_UNICAST_TYPE | (TYPE_MASK & l3unicastIndex); |
| final GroupKey l3groupkey = new DefaultGroupKey( |
| Ofdpa2Pipeline.appKryo.serialize(l3unicastIndex)); |
| outerTtb.group(new DefaultGroupId(l2groupId)); |
| // create the l3unicast group description to wait for the |
| // l2 interface group to be processed |
| GroupBucket l3unicastGroupBucket = |
| DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build()); |
| outerGrpDesc = new DefaultGroupDescription( |
| deviceId, |
| GroupDescription.Type.INDIRECT, |
| new GroupBuckets(Collections.singletonList( |
| l3unicastGroupBucket)), |
| l3groupkey, |
| l3groupId, |
| appId); |
| log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}", |
| deviceId, Integer.toHexString(l3groupId), |
| l3groupkey, nextId); |
| } |
| |
| // store l2groupkey with the groupChainElem for the outer-group that depends on it |
| GroupChainElem gce = new GroupChainElem(outerGrpDesc, 1, false); |
| updatePendingGroups(l2groupkey, gce); |
| |
| // create group description for the inner l2interfacegroup |
| GroupBucket l2InterfaceGroupBucket = |
| DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build()); |
| GroupDescription l2groupDescription = |
| new DefaultGroupDescription( |
| deviceId, |
| GroupDescription.Type.INDIRECT, |
| new GroupBuckets(Collections.singletonList( |
| l2InterfaceGroupBucket)), |
| l2groupkey, |
| l2groupId, |
| appId); |
| log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}", |
| deviceId, Integer.toHexString(l2groupId), |
| l2groupkey, nextId); |
| return new GroupInfo(l2groupDescription, outerGrpDesc); |
| } |
| } |