<commit_before>/*
 * 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.impl.behaviour.pipeliner;

import com.google.common.collect.Lists;
import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
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.impl.behaviour.FabricCapabilities;
import org.onosproject.pipelines.fabric.impl.behaviour.FabricConstants;

import java.util.Collection;
import java.util.List;

import static java.lang.String.format;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterion;

/**
 * ObjectiveTranslator implementation for FilteringObjective.
 */
class FilteringObjectiveTranslator
        extends AbstractObjectiveTranslator<FilteringObjective> {

    // Forwarding types from fabric.p4.
    static final byte FWD_MPLS = 1;
    static final byte FWD_IPV4_ROUTING = 2;
    static final byte FWD_IPV6_ROUTING = 3;

    private static final byte[] ONE = new byte[]{1};
    private static final byte[] ZERO = new byte[]{0};

    private static final short ETH_TYPE_EXACT_MASK = (short) 0xFFFF;

    private static final PiAction DENY = PiAction.builder()
            .withId(FabricConstants.FABRIC_INGRESS_FILTERING_DENY)
            .build();


    FilteringObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
        super(deviceId, capabilities);
    }

    @Override
    public ObjectiveTranslation doTranslate(FilteringObjective obj)
            throws FabricPipelinerException {

        final ObjectiveTranslation.Builder resultBuilder =
                ObjectiveTranslation.builder();

        if (obj.key() == null || obj.key().type() != Criterion.Type.IN_PORT) {
            throw new FabricPipelinerException(
                    format("Unsupported or missing filtering key: key=%s", obj.key()),
                    ObjectiveError.BADPARAMS);
        }

        final PortCriterion inPort = (PortCriterion) obj.key();

        final VlanIdCriterion outerVlan = (VlanIdCriterion) criterion(
                obj.conditions(), Criterion.Type.VLAN_VID);
        final VlanIdCriterion innerVlan = (VlanIdCriterion) criterion(
                obj.conditions(), Criterion.Type.INNER_VLAN_VID);
        final EthCriterion ethDst = (EthCriterion) criterion(
                obj.conditions(), Criterion.Type.ETH_DST);
        final EthCriterion ethDstMasked = (EthCriterion) criterion(
                obj.conditions(), Criterion.Type.ETH_DST_MASKED);

        ingressPortVlanRule(obj, inPort, outerVlan, innerVlan, resultBuilder);
        fwdClassifierRules(obj, inPort, ethDst, ethDstMasked, resultBuilder);

        return resultBuilder.build();
    }

    private void ingressPortVlanRule(
            FilteringObjective obj,
            Criterion inPortCriterion,
            VlanIdCriterion outerVlanCriterion,
            VlanIdCriterion innerVlanCriterion,
            ObjectiveTranslation.Builder resultBuilder)
            throws FabricPipelinerException {

        final boolean outerVlanValid = outerVlanCriterion != null
                && !outerVlanCriterion.vlanId().equals(VlanId.NONE);
        final boolean innerVlanValid = innerVlanCriterion != null
                && !innerVlanCriterion.vlanId().equals(VlanId.NONE);

        final PiCriterion piCriterion = PiCriterion.builder()
                .matchExact(FabricConstants.HDR_VLAN_IS_VALID, outerVlanValid ? ONE : ZERO)
                .build();

        final TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
                .add(inPortCriterion)
                .add(piCriterion);
        if (outerVlanValid) {
            selector.add(outerVlanCriterion);
        }
        if (innerVlanValid) {<commit_msg>Fixed removal of fwd classifier rules when double tagged hosts<commit_after>/*
 * 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.impl.behaviour.pipeliner;

import com.google.common.collect.Lists;
import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
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.flow.instructions.Instructions;
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.Objective;
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.impl.behaviour.FabricCapabilities;
import org.onosproject.pipelines.fabric.impl.behaviour.FabricConstants;
import org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils;

import java.util.Collection;
import java.util.List;

import static java.lang.String.format;
import static org.onosproject.net.flow.criteria.Criterion.Type.INNER_VLAN_VID;
import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterion;

/**
 * ObjectiveTranslator implementation for FilteringObjective.
 */
class FilteringObjectiveTranslator
        extends AbstractObjectiveTranslator<FilteringObjective> {

    // Forwarding types from fabric.p4.
    static final byte FWD_MPLS = 1;
    static final byte FWD_IPV4_ROUTING = 2;
    static final byte FWD_IPV6_ROUTING = 3;

    private static final byte[] ONE = new byte[]{1};
    private static final byte[] ZERO = new byte[]{0};

    private static final short ETH_TYPE_EXACT_MASK = (short) 0xFFFF;

    private static final PiAction DENY = PiAction.builder()
            .withId(FabricConstants.FABRIC_INGRESS_FILTERING_DENY)
            .build();


    FilteringObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
        super(deviceId, capabilities);
    }

    @Override
    public ObjectiveTranslation doTranslate(FilteringObjective obj)
            throws FabricPipelinerException {

        final ObjectiveTranslation.Builder resultBuilder =
                ObjectiveTranslation.builder();

        if (obj.key() == null || obj.key().type() != Criterion.Type.IN_PORT) {
            throw new FabricPipelinerException(
                    format("Unsupported or missing filtering key: key=%s", obj.key()),
                    ObjectiveError.BADPARAMS);
        }

        final PortCriterion inPort = (PortCriterion) obj.key();

        final VlanIdCriterion outerVlan = (VlanIdCriterion) criterion(
                obj.conditions(), Criterion.Type.VLAN_VID);
        final VlanIdCriterion innerVlan = (VlanIdCriterion) criterion(
                obj.conditions(), Criterion.Type.INNER_VLAN_VID);
        final EthCriterion ethDst = (EthCriterion) criterion(
                obj.conditions(), Criterion.Type.ETH_DST);
        final EthCriterion ethDstMasked = (EthCriterion) criterion(
                obj.conditions(), Criterion.Type.ETH_DST_MASKED);

        ingressPortVlanRule(obj, inPort, outerVlan, innerVlan, resultBuilder);
        if (shouldAddFwdClassifierRule(obj)) {
            fwdClassifierRules(obj, inPort, ethDst, ethDstMasked, resultBuilder);
        } else {
            log.debug("Skipping fwd classifier rules for device {}.", deviceId);
        }
        return resultBuilder.build();
    }

    private boolean shouldAddFwdClassifierRule(FilteringObjective obj) {
        // NOTE: in fabric pipeline the forwarding classifier acts similarly
        // to the TMAC table of OFDPA that matches on input port.

        // Forwarding classifier rules should be added to translation when:
        // - the operation is ADD OR
        // - it doesn't refer to double tagged traffic OR
        // - it refers to double tagged traffic
        //     and SR is triggering the removal of forwarding classifier rules.
        return obj.op() == Objective.Operation.ADD ||
                !isDoubleTagged(obj) ||
                (isDoubleTagged(obj) && isLastDoubleTaggedForPort(obj));
    }

    /**
     * Check if the given filtering objective is the last filtering objective
     * for a double-tagged host for a specific port.
     * <p>
     * {@see org.onosproject.segmentrouting.RoutingRulePopulator#buildDoubleTaggedFilteringObj()}
     * {@see org.onosproject.segmentrouting.RoutingRulePopulator#processDoubleTaggedFilter()}
     *
     * @param obj Filtering objective to check.
     * @return True if SR is signaling to remove the forwarding classifier rule,
     * false otherwise.
     */
    private boolean isLastDoubleTaggedForPort(FilteringObjective obj) {
        Instructions.MetadataInstruction meta = obj.meta().writeMetadata();
        // SR is setting this metadata when a double tagged filtering objective
        // is removed and no other hosts is sharing the same input port.
        return (meta != null && (meta.metadata() & meta.metadataMask()) == 1);
    }

    private boolean isDoubleTagged(FilteringObjective obj) {
        return obj.meta() != null &&
                FabricUtils.l2Instruction(obj.meta(), L2ModificationInstruction.L2SubType.VLAN_POP) != null &&
                FabricUtils.criterion(obj.conditions(), VLAN_VID) != null &&
                FabricUtils.criterion(obj.conditions(), INNER_VLAN_VID) != null;
    }

    private void ingressPortVlanRule(
            FilteringObjective obj,
            Criterion inPortCriterion,
            VlanIdCriterion outerVlanCriterion,
            VlanIdCriterion innerVlanCriterion,
            ObjectiveTranslation.Builder resultBuilder)
            throws FabricPipelinerException {

        final boolean outerVlanValid = outerVlanCriterion != null
                && !outerVlanCriterion.vlanId().equals(VlanId.NONE);
        final boolean innerVlanValid = innerVlanCriterion != null
                && !innerVlanCriterion.vlanId().equals(VlanId.NONE);

        final PiCriterion piCriterion = PiCriterion.builder()
                .matchExact(FabricConstants.HDR_VLAN_IS_VALID, outerVlanValid ? ONE : ZERO)
                .build();

        final TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
                .add(inPortCriterion)
                .add(piCriterion);
        if (outerVlanValid) {
            selector.add(outerVlanCriterion);
        }
        if (innerVlanValid) {
{'fraction_non_alphanumeric': 0.08660804606645398, 'fraction_numerical': 0.0030347832853474437, 'mean_word_length': 3.3331085637221847, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6006044', 'n_tokens_mistral': 3722, 'n_tokens_neox': 3598, 'n_words': 839}