blob: 847bb2dde4bfb0e88348fc0445317b20028ca86d [file] [log] [blame]
/*
* 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 static org.slf4j.LoggerFactory.getLogger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip6Address;
import org.onosproject.core.GroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.driver.DefaultDriverData;
import org.onosproject.net.driver.DefaultDriverHandler;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.ExtensionTreatment;
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.onosproject.openflow.controller.ExtensionTreatmentInterpreter;
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.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.U64;
import org.projectfloodlight.openflow.types.VlanPcp;
import org.slf4j.Logger;
/*
* Builder for GroupMod.
*/
public final class GroupModBuilder {
private GroupBuckets buckets;
private GroupId groupId;
private GroupDescription.Type type;
private OFFactory factory;
private Long xid;
private Optional<DriverService> driverService;
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);
}
private GroupModBuilder(GroupBuckets buckets, GroupId groupId,
GroupDescription.Type type, OFFactory factory,
Optional<Long> xid, Optional<DriverService> driverService) {
this.buckets = buckets;
this.groupId = groupId;
this.type = type;
this.factory = factory;
this.xid = xid.orElse((long) 0);
this.driverService = driverService;
}
/**
* 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);
}
/**
* 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
* @param driverService driver Service
* @return GroupModBuilder object
*/
public static GroupModBuilder builder(GroupBuckets buckets, GroupId groupId,
GroupDescription.Type type, OFFactory factory,
Optional<Long> xid, Optional<DriverService> driverService) {
return new GroupModBuilder(buckets, groupId, type, factory, xid, driverService);
}
/**
* 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);
}
if (type == GroupDescription.Type.FAILOVER && bucket.watchPort() != null) {
bucketBuilder.setWatchPort(OFPort.of((int) bucket.watchPort().toLong()));
} else {
bucketBuilder.setWatchPort(OFPort.ANY);
}
if (type == GroupDescription.Type.FAILOVER && bucket.watchGroup() != null) {
bucketBuilder.setWatchGroup(OFGroup.of(bucket.watchGroup().id()));
} else {
bucketBuilder.setWatchGroup(OFGroup.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 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;
case EXTENSION:
Instructions.ExtensionInstructionWrapper wrapper =
(Instructions.ExtensionInstructionWrapper) i;
actions.add(buildExtensionAction(
wrapper.extensionInstruction(), wrapper.deviceId()));
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()) {
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.label().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();
case TUNNEL_ID:
L2ModificationInstruction.ModTunnelIdInstruction tunnelId =
(L2ModificationInstruction.ModTunnelIdInstruction) l2m;
oxm = factory.oxms().tunnelId(U64.of(tunnelId.tunnelId()));
break;
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;
}
private OFAction buildExtensionAction(ExtensionTreatment i, DeviceId deviceId) {
if (!driverService.isPresent()) {
log.error("No driver service present");
return null;
}
Driver driver = driverService.get().getDriver(deviceId);
if (driver.hasBehaviour(ExtensionTreatmentInterpreter.class)) {
DefaultDriverHandler handler =
new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
ExtensionTreatmentInterpreter interpreter = handler.behaviour(ExtensionTreatmentInterpreter.class);
return interpreter.mapInstruction(factory, i);
}
return null;
}
}