/*
* Copyright (c) 2013, 2015 Ericsson. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.opendaylight.openflowplugin.api.OFConstants;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.action.data.ActionConvertorData;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.Convertor;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.ConvertorProcessor;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.OrderComparator;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionDatapathIdConvertorData;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.ApplyActionsCase;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.ClearActionsCase;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.GoToTableCase;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.MeterCase;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.WriteActionsCase;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.WriteMetadataCase;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchInjector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.VlanCfi;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.instructions.grouping.Instruction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.FlowModCommand;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MatchTypeBase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumber;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.TableId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.OxmMatchType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowModInputBuilder;
/**
* Converts the SAL Flow to OF Flow. It checks if there is a set-vlan-id (1.0) action made on OF1.3.
* If yes its handled separately.
*
*
* Example usage:
*
* {@code
* VersionDatapathIdConvertorData data = new VersionDatapathIdConvertorData(version);
* data.setDatapathId(datapathId);
* Optional> ofFlow = convertorManager.convert(salFlow, data);
* }
*
*/
public class FlowConvertor extends Convertor, VersionDatapathIdConvertorData> {
/**
* Default idle timeout.
*/
public static final Integer DEFAULT_IDLE_TIMEOUT = 0;
/**
* Default hard timeout.
*/
public static final Integer DEFAULT_HARD_TIMEOUT = 0;
/**
* Default priority.
*/
public static final Integer DEFAULT_PRIORITY = Integer.parseInt("8000", 16);
/**
* flow flag: remove.
*/
public static final boolean DEFAULT_OFPFF_FLOW_REM = false;
/**
* flow flag: check overlap.
*/
public static final boolean DEFAULT_OFPFF_CHECK_OVERLAP = false;
/**
* flow flag: reset counts.
*/
public static final boolean DEFAULT_OFPFF_RESET_COUNTS = false;
/**
* flow flag: don't keep track of packet counts.
*/
public static final boolean DEFAULT_OFPFF_NO_PKT_COUNTS = false;
/**
* flow flag: don't keep track of byte counts.
*/
public static final boolean DEFAULT_OFPFF_NO_BYT_COUNTS = false;
/**
* flow flag: emergency [OFP-1.0].
*/
public static final boolean DEFAULT_OFPFF_EMERGENCY = false;
/**
* OxmMatch type.
*/
public static final Class extends MatchTypeBase> DEFAULT_MATCH_TYPE = OxmMatchType.class;
/**
* default match entries - empty.
*/
public static final List DEFAULT_MATCH_ENTRIES = ImmutableList.of();
// Default values for when things are null
private static final TableId DEFAULT_TABLE_ID = new TableId(0L);
private static final Long DEFAULT_BUFFER_ID = OFConstants.OFP_NO_BUFFER;
private static final Long OFPP_ANY = Long.parseLong("ffffffff", 16);
private static final Long DEFAULT_OUT_PORT = OFPP_ANY;
private static final Long OFPG_ANY = Long.parseLong("ffffffff", 16);
private static final Long DEFAULT_OUT_GROUP = OFPG_ANY;
private static final Integer PUSH_VLAN = 0x8100;
private static final Ordering INSTRUCTION_ORDERING = Ordering.from(OrderComparator.build());
private static final VlanMatch VLAN_MATCH_FALSE;
private static final VlanMatch VLAN_MATCH_TRUE;
private static final ConvertorProcessor PROCESSOR =
new ConvertorProcessor()
.addCase(new ApplyActionsCase())
.addCase(new ClearActionsCase())
.addCase(new GoToTableCase())
.addCase(new MeterCase())
.addCase(new WriteActionsCase())
.addCase(new WriteMetadataCase());
private static final List> TYPES = Arrays.asList(Flow.class, AddFlowInput.class,
RemoveFlowInput.class, UpdatedFlow.class);
static {
final VlanId zeroVlan = new VlanId(0);
VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder();
VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
vlanIdBuilder.setVlanIdPresent(false);
vlanIdBuilder.setVlanId(zeroVlan);
vlanMatchBuilder.setVlanId(vlanIdBuilder.build());
VLAN_MATCH_FALSE = vlanMatchBuilder.build();
VlanMatchBuilder vlanMatchBuilder2 = new VlanMatchBuilder();
VlanIdBuilder vlanIdBuilder2 = new VlanIdBuilder();
vlanIdBuilder2.setVlanIdPresent(true);
vlanIdBuilder2.setVlanId(zeroVlan);
vlanMatchBuilder2.setVlanId(vlanIdBuilder2.build());
VLAN_MATCH_TRUE = vlanMatchBuilder2.build();
}
private FlowModInputBuilder toFlowModInput(Flow flow, VersionDatapathIdConvertorData versionConverterData) {
FlowModInputBuilder flowMod = new FlowModInputBuilder();
salToOFFlowCookie(flow, flowMod);
salToOFFlowCookieMask(flow, flowMod);
salToOFFlowTableId(flow, flowMod);
salToOFFlowCommand(flow, flowMod);
salToOFFlowIdleTimeout(flow, flowMod);
salToOFFlowHardTimeout(flow, flowMod);
salToOFFlowPriority(flow, flowMod);
salToOFFlowBufferId(flow, flowMod);
salToOFFlowOutPort(flow, flowMod);
salToOFFlowOutGroup(flow, flowMod);
// convert and inject flowFlags
final Optional