| /* |
| * Copyright 2015 Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.onosproject.provider.of.group.impl; |
| |
| import org.onlab.packet.Ip4Address; |
| import org.onlab.packet.Ip6Address; |
| import org.onosproject.core.GroupId; |
| import org.onosproject.net.PortNumber; |
| import org.onosproject.net.flow.TrafficTreatment; |
| import org.onosproject.net.flow.instructions.Instruction; |
| import org.onosproject.net.flow.instructions.Instructions; |
| import org.onosproject.net.flow.instructions.L0ModificationInstruction; |
| import org.onosproject.net.flow.instructions.L2ModificationInstruction; |
| import org.onosproject.net.flow.instructions.L3ModificationInstruction; |
| import org.onosproject.net.group.GroupBucket; |
| import org.onosproject.net.group.GroupBuckets; |
| import org.onosproject.net.group.GroupDescription; |
| import org.projectfloodlight.openflow.protocol.OFBucket; |
| import org.projectfloodlight.openflow.protocol.OFFactory; |
| import org.projectfloodlight.openflow.protocol.OFGroupAdd; |
| import org.projectfloodlight.openflow.protocol.OFGroupDelete; |
| import org.projectfloodlight.openflow.protocol.OFGroupMod; |
| import org.projectfloodlight.openflow.protocol.OFGroupType; |
| import org.projectfloodlight.openflow.protocol.action.OFAction; |
| import org.projectfloodlight.openflow.protocol.action.OFActionGroup; |
| import org.projectfloodlight.openflow.protocol.action.OFActionOutput; |
| import org.projectfloodlight.openflow.protocol.oxm.OFOxm; |
| import org.projectfloodlight.openflow.types.CircuitSignalID; |
| import org.projectfloodlight.openflow.types.EthType; |
| import org.projectfloodlight.openflow.types.IPv4Address; |
| import org.projectfloodlight.openflow.types.IPv6Address; |
| import org.projectfloodlight.openflow.types.IPv6FlowLabel; |
| import org.projectfloodlight.openflow.types.MacAddress; |
| import org.projectfloodlight.openflow.types.OFBooleanValue; |
| import org.projectfloodlight.openflow.types.OFGroup; |
| import org.projectfloodlight.openflow.types.OFPort; |
| import org.projectfloodlight.openflow.types.OFVlanVidMatch; |
| import org.projectfloodlight.openflow.types.U32; |
| import org.projectfloodlight.openflow.types.VlanPcp; |
| import org.slf4j.Logger; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Optional; |
| |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| /* |
| * Builder for GroupMod. |
| */ |
| public final class GroupModBuilder { |
| |
| private GroupBuckets buckets; |
| private GroupId groupId; |
| private GroupDescription.Type type; |
| private OFFactory factory; |
| private Long xid; |
| |
| private final Logger log = getLogger(getClass()); |
| |
| private static final int OFPCML_NO_BUFFER = 0xffff; |
| |
| private GroupModBuilder(GroupBuckets buckets, GroupId groupId, |
| GroupDescription.Type type, OFFactory factory, |
| Optional<Long> xid) { |
| this.buckets = buckets; |
| this.groupId = groupId; |
| this.type = type; |
| this.factory = factory; |
| this.xid = xid.orElse((long) 0); |
| } |
| |
| /** |
| * Creates a builder for GroupMod. |
| * |
| * @param buckets GroupBuckets object |
| * @param groupId Group Id to create |
| * @param type Group type |
| * @param factory OFFactory object |
| * @param xid transaction ID |
| * @return GroupModBuilder object |
| */ |
| public static GroupModBuilder builder(GroupBuckets buckets, GroupId groupId, |
| GroupDescription.Type type, OFFactory factory, |
| Optional<Long> xid) { |
| |
| return new GroupModBuilder(buckets, groupId, type, factory, xid); |
| } |
| |
| /** |
| * Builds the GroupAdd OF message. |
| * |
| * @return GroupAdd OF message |
| */ |
| public OFGroupAdd buildGroupAdd() { |
| |
| List<OFBucket> ofBuckets = new ArrayList<OFBucket>(); |
| for (GroupBucket bucket: buckets.buckets()) { |
| List<OFAction> actions = buildActions(bucket.treatment()); |
| |
| OFBucket.Builder bucketBuilder = factory.buildBucket(); |
| bucketBuilder.setActions(actions); |
| if (type == GroupDescription.Type.SELECT) { |
| bucketBuilder.setWeight(1); |
| } |
| bucketBuilder.setWatchGroup(OFGroup.ANY); |
| bucketBuilder.setWatchPort(OFPort.ANY); |
| OFBucket ofBucket = bucketBuilder.build(); |
| ofBuckets.add(ofBucket); |
| } |
| |
| OFGroupAdd groupMsg = factory.buildGroupAdd() |
| .setGroup(OFGroup.of(groupId.id())) |
| .setBuckets(ofBuckets) |
| .setGroupType(getOFGroupType(type)) |
| .setXid(xid) |
| .build(); |
| |
| return groupMsg; |
| } |
| |
| /** |
| * Builds the GroupMod OF message. |
| * |
| * @return GroupMod OF message |
| */ |
| public OFGroupMod buildGroupMod() { |
| List<OFBucket> ofBuckets = new ArrayList<OFBucket>(); |
| for (GroupBucket bucket: buckets.buckets()) { |
| List<OFAction> actions = buildActions(bucket.treatment()); |
| |
| OFBucket.Builder bucketBuilder = factory.buildBucket(); |
| bucketBuilder.setActions(actions); |
| if (type == GroupDescription.Type.SELECT) { |
| bucketBuilder.setWeight(1); |
| } |
| bucketBuilder.setWatchGroup(OFGroup.ANY); |
| bucketBuilder.setWatchPort(OFPort.ANY); |
| OFBucket ofBucket = bucketBuilder.build(); |
| ofBuckets.add(ofBucket); |
| } |
| |
| OFGroupMod groupMsg = factory.buildGroupModify() |
| .setGroup(OFGroup.of(groupId.id())) |
| .setBuckets(ofBuckets) |
| .setGroupType(getOFGroupType(type)) |
| .setXid(xid) |
| .build(); |
| |
| return groupMsg; |
| } |
| |
| /** |
| * Builds the GroupDel OF message. |
| * |
| * @return GroupDel OF message |
| */ |
| public OFGroupDelete buildGroupDel() { |
| |
| OFGroupDelete groupMsg = factory.buildGroupDelete() |
| .setGroup(OFGroup.of(groupId.id())) |
| .setGroupType(OFGroupType.SELECT) |
| .setXid(xid) |
| .build(); |
| |
| return groupMsg; |
| } |
| |
| private List<OFAction> buildActions(TrafficTreatment treatment) { |
| if (treatment == null) { |
| return Collections.emptyList(); |
| } |
| |
| List<OFAction> actions = new LinkedList<>(); |
| for (Instruction i : treatment.allInstructions()) { |
| switch (i.type()) { |
| case DROP: |
| log.warn("Saw drop action; assigning drop action"); |
| return Collections.emptyList(); |
| case L0MODIFICATION: |
| actions.add(buildL0Modification(i)); |
| break; |
| case L2MODIFICATION: |
| actions.add(buildL2Modification(i)); |
| break; |
| case L3MODIFICATION: |
| actions.add(buildL3Modification(i)); |
| break; |
| case OUTPUT: |
| Instructions.OutputInstruction out = |
| (Instructions.OutputInstruction) i; |
| OFActionOutput.Builder action = factory.actions().buildOutput() |
| .setPort(OFPort.of((int) out.port().toLong())); |
| if (out.port().equals(PortNumber.CONTROLLER)) { |
| action.setMaxLen(OFPCML_NO_BUFFER); |
| } |
| actions.add(action.build()); |
| break; |
| case GROUP: |
| Instructions.GroupInstruction grp = |
| (Instructions.GroupInstruction) i; |
| OFActionGroup.Builder actgrp = factory.actions().buildGroup() |
| .setGroup(OFGroup.of(grp.groupId().id())); |
| actions.add(actgrp.build()); |
| break; |
| default: |
| log.warn("Instruction type {} not yet implemented.", i.type()); |
| } |
| } |
| |
| return actions; |
| } |
| |
| private OFAction buildL0Modification(Instruction i) { |
| L0ModificationInstruction l0m = (L0ModificationInstruction) i; |
| switch (l0m.subtype()) { |
| case LAMBDA: |
| L0ModificationInstruction.ModLambdaInstruction ml = |
| (L0ModificationInstruction.ModLambdaInstruction) i; |
| return factory.actions().circuit(factory.oxms().ochSigidBasic( |
| new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1))); |
| default: |
| log.warn("Unimplemented action type {}.", l0m.subtype()); |
| break; |
| } |
| return null; |
| } |
| |
| private OFAction buildL2Modification(Instruction i) { |
| L2ModificationInstruction l2m = (L2ModificationInstruction) i; |
| L2ModificationInstruction.ModEtherInstruction eth; |
| OFOxm<?> oxm = null; |
| switch (l2m.subtype()) { |
| case ETH_DST: |
| eth = (L2ModificationInstruction.ModEtherInstruction) l2m; |
| oxm = factory.oxms().ethDst(MacAddress.of(eth.mac().toLong())); |
| break; |
| case ETH_SRC: |
| eth = (L2ModificationInstruction.ModEtherInstruction) l2m; |
| oxm = factory.oxms().ethSrc(MacAddress.of(eth.mac().toLong())); |
| break; |
| case VLAN_ID: |
| L2ModificationInstruction.ModVlanIdInstruction vlanId = |
| (L2ModificationInstruction.ModVlanIdInstruction) l2m; |
| oxm = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanId.vlanId().toShort())); |
| break; |
| case VLAN_PCP: |
| L2ModificationInstruction.ModVlanPcpInstruction vlanPcp = |
| (L2ModificationInstruction.ModVlanPcpInstruction) l2m; |
| oxm = factory.oxms().vlanPcp(VlanPcp.of(vlanPcp.vlanPcp())); |
| break; |
| case VLAN_POP: |
| return factory.actions().popVlan(); |
| case VLAN_PUSH: |
| L2ModificationInstruction.PushHeaderInstructions pushVlanInstruction |
| = (L2ModificationInstruction.PushHeaderInstructions) l2m; |
| return factory.actions().pushVlan( |
| EthType.of(pushVlanInstruction.ethernetType().toShort())); |
| case MPLS_PUSH: |
| L2ModificationInstruction.PushHeaderInstructions pushHeaderInstructions = |
| (L2ModificationInstruction.PushHeaderInstructions) l2m; |
| return factory.actions().pushMpls(EthType.of(pushHeaderInstructions |
| .ethernetType().toShort())); |
| case MPLS_POP: |
| L2ModificationInstruction.PushHeaderInstructions popHeaderInstructions = |
| (L2ModificationInstruction.PushHeaderInstructions) l2m; |
| return factory.actions().popMpls(EthType.of(popHeaderInstructions |
| .ethernetType().toShort())); |
| case MPLS_LABEL: |
| L2ModificationInstruction.ModMplsLabelInstruction mplsLabel = |
| (L2ModificationInstruction.ModMplsLabelInstruction) l2m; |
| oxm = factory.oxms().mplsLabel(U32.of(mplsLabel.mplsLabel().toInt())); |
| break; |
| case MPLS_BOS: |
| L2ModificationInstruction.ModMplsBosInstruction mplsBos = |
| (L2ModificationInstruction.ModMplsBosInstruction) l2m; |
| oxm = factory.oxms() |
| .mplsBos(mplsBos.mplsBos() ? OFBooleanValue.TRUE |
| : OFBooleanValue.FALSE); |
| break; |
| case DEC_MPLS_TTL: |
| return factory.actions().decMplsTtl(); |
| default: |
| log.warn("Unimplemented action type {}.", l2m.subtype()); |
| break; |
| } |
| |
| if (oxm != null) { |
| return factory.actions().buildSetField().setField(oxm).build(); |
| } |
| return null; |
| } |
| |
| private OFAction buildL3Modification(Instruction i) { |
| L3ModificationInstruction l3m = (L3ModificationInstruction) i; |
| L3ModificationInstruction.ModIPInstruction ip; |
| Ip4Address ip4; |
| Ip6Address ip6; |
| OFOxm<?> oxm = null; |
| switch (l3m.subtype()) { |
| case IPV4_SRC: |
| ip = (L3ModificationInstruction.ModIPInstruction) i; |
| ip4 = ip.ip().getIp4Address(); |
| oxm = factory.oxms().ipv4Src(IPv4Address.of(ip4.toInt())); |
| break; |
| case IPV4_DST: |
| ip = (L3ModificationInstruction.ModIPInstruction) i; |
| ip4 = ip.ip().getIp4Address(); |
| oxm = factory.oxms().ipv4Dst(IPv4Address.of(ip4.toInt())); |
| break; |
| case IPV6_SRC: |
| ip = (L3ModificationInstruction.ModIPInstruction) i; |
| ip6 = ip.ip().getIp6Address(); |
| oxm = factory.oxms().ipv6Src(IPv6Address.of(ip6.toOctets())); |
| break; |
| case IPV6_DST: |
| ip = (L3ModificationInstruction.ModIPInstruction) i; |
| ip6 = ip.ip().getIp6Address(); |
| oxm = factory.oxms().ipv6Dst(IPv6Address.of(ip6.toOctets())); |
| break; |
| case IPV6_FLABEL: |
| L3ModificationInstruction.ModIPv6FlowLabelInstruction flowLabelInstruction = |
| (L3ModificationInstruction.ModIPv6FlowLabelInstruction) i; |
| int flowLabel = flowLabelInstruction.flowLabel(); |
| oxm = factory.oxms().ipv6Flabel(IPv6FlowLabel.of(flowLabel)); |
| break; |
| case DEC_TTL: |
| return factory.actions().decNwTtl(); |
| case TTL_IN: |
| return factory.actions().copyTtlIn(); |
| case TTL_OUT: |
| return factory.actions().copyTtlOut(); |
| default: |
| log.warn("Unimplemented action type {}.", l3m.subtype()); |
| break; |
| } |
| |
| if (oxm != null) { |
| return factory.actions().buildSetField().setField(oxm).build(); |
| } |
| return null; |
| } |
| |
| private OFGroupType getOFGroupType(GroupDescription.Type groupType) { |
| switch (groupType) { |
| case INDIRECT: |
| return OFGroupType.INDIRECT; |
| case SELECT: |
| return OFGroupType.SELECT; |
| case FAILOVER: |
| return OFGroupType.FF; |
| case ALL: |
| return OFGroupType.ALL; |
| default: |
| log.error("Unsupported group type : {}", groupType); |
| break; |
| } |
| return null; |
| } |
| } |
| |