<commit_before>package org.batfish.bdp;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nullable;
import org.apache.commons.collections4.map.LRUMap;
import org.batfish.common.BatfishException;
import org.batfish.common.Version;
import org.batfish.common.plugin.DataPlanePlugin;
import org.batfish.common.util.CommonUtil;
import org.batfish.datamodel.AbstractRoute;
import org.batfish.datamodel.BgpProcess;
import org.batfish.datamodel.Configuration;
import org.batfish.datamodel.Edge;
import org.batfish.datamodel.FilterResult;
import org.batfish.datamodel.Flow;
import org.batfish.datamodel.FlowDisposition;
import org.batfish.datamodel.FlowTrace;
import org.batfish.datamodel.FlowTraceHop;
import org.batfish.datamodel.Interface;
import org.batfish.datamodel.Ip;
import org.batfish.datamodel.IpAccessList;
import org.batfish.datamodel.LineAction;
import org.batfish.datamodel.Prefix;
import org.batfish.datamodel.Route;
import org.batfish.datamodel.RouteBuilder;
import org.batfish.datamodel.RoutingProtocol;
import org.batfish.datamodel.SourceNat;
import org.batfish.datamodel.Topology;
import org.batfish.datamodel.answers.Answer;
import org.batfish.datamodel.answers.BdpAnswerElement;
import org.batfish.datamodel.collections.AdvertisementSet;
import org.batfish.datamodel.collections.EdgeSet;
import org.batfish.datamodel.collections.IbgpTopology;
import org.batfish.datamodel.collections.NodeInterfacePair;
import org.batfish.datamodel.collections.RouteSet;

public class BdpDataPlanePlugin extends DataPlanePlugin {

  /**
   * Set to true to debug all iterations, including during oscillation. Ignores max recorded
   * iterations value.
   */
  private static boolean DEBUG_ALL_ITERATIONS = false;

  private static final int DEBUG_MAX_RECORDED_ITERATIONS = 12;

  /**
   * Set to true to debug oscillation. Make sure to set max recorded iterations to minimum necessary
   * value.
   */
  private static boolean DEBUG_REPEAT_ITERATIONS = false;

  private static final String TRACEROUTE_INGRESS_NODE_INTERFACE_NAME =
      "traceroute_source_interface";

  private static final String TRACEROUTE_INGRESS_NODE_NAME = "traceroute_source_node";

  private final Map<BdpDataPlane, Map<Flow, Set<FlowTrace>>> _flowTraces;

  public BdpDataPlanePlugin() {
    _flowTraces = new HashMap<>();
  }

  /**
   * Applies the given list of source NAT rules to the given flow and returns the new transformed
   * flow. If {@code sourceNats} is null, empty, or does not contain any ACL rules matching the
   * {@link Flow}, the original flow is returned.
   *
   * <p>Each {@link SourceNat} is expected to be valid: it must have a NAT IP or pool.
   */
  static Flow applySourceNat(Flow flow, @Nullable List<SourceNat> sourceNats) {
    if (CommonUtil.isNullOrEmpty(sourceNats)) {
      return flow;
    }

    for (SourceNat sourceNat : sourceNats) {
      IpAccessList acl = sourceNat.getAcl();
      if (acl != null) {
        FilterResult result = acl.filter(flow);
        if (result.getAction() == LineAction.REJECT) {
          // This ACL does not match the flow.
          continue;
        }
      }

      Ip natPoolStartIp = sourceNat.getPoolIpFirst();
      if (natPoolStartIp == null) {
        throw new BatfishException(
            String.format(
                "Error processing Source NAT rule %s: missing NAT address or pool",
                sourceNat));
      }
      Flow.Builder transformedFlowBuilder = new Flow.Builder(flow);
      transformedFlowBuilder.setSrcIp(natPoolStartIp);
      return transformedFlowBuilder.build();
    }

    // No NAT rule matched.
    return flow;
  }

  private void collectFlowTraces(
      BdpDataPlane dp,
      String currentNodeName,
      Set<Edge> visitedEdges,
      List<FlowTraceHop> hopsSoFar,
      Set<FlowTrace> flowTraces,
      Flow originalFlow,
      Flow transformedFlow) {
    Ip dstIp = transformedFlow.getDstIp();
    Set<String> dstIpOwners = dp._ipOwners.get(dstIp);
    if (dstIpOwners != null && dstIpOwners.contains(currentNodeName)) {
      FlowTrace trace =
          new FlowTrace(FlowDisposition.ACCEPTED, hopsSoFar, FlowDisposition.ACCEPTED.toString());<commit_msg>format<commit_after>package org.batfish.bdp;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nullable;
import org.apache.commons.collections4.map.LRUMap;
import org.batfish.common.BatfishException;
import org.batfish.common.Version;
import org.batfish.common.plugin.DataPlanePlugin;
import org.batfish.common.util.CommonUtil;
import org.batfish.datamodel.AbstractRoute;
import org.batfish.datamodel.BgpProcess;
import org.batfish.datamodel.Configuration;
import org.batfish.datamodel.Edge;
import org.batfish.datamodel.FilterResult;
import org.batfish.datamodel.Flow;
import org.batfish.datamodel.FlowDisposition;
import org.batfish.datamodel.FlowTrace;
import org.batfish.datamodel.FlowTraceHop;
import org.batfish.datamodel.Interface;
import org.batfish.datamodel.Ip;
import org.batfish.datamodel.IpAccessList;
import org.batfish.datamodel.LineAction;
import org.batfish.datamodel.Prefix;
import org.batfish.datamodel.Route;
import org.batfish.datamodel.RouteBuilder;
import org.batfish.datamodel.RoutingProtocol;
import org.batfish.datamodel.SourceNat;
import org.batfish.datamodel.Topology;
import org.batfish.datamodel.answers.Answer;
import org.batfish.datamodel.answers.BdpAnswerElement;
import org.batfish.datamodel.collections.AdvertisementSet;
import org.batfish.datamodel.collections.EdgeSet;
import org.batfish.datamodel.collections.IbgpTopology;
import org.batfish.datamodel.collections.NodeInterfacePair;
import org.batfish.datamodel.collections.RouteSet;

public class BdpDataPlanePlugin extends DataPlanePlugin {

  /**
   * Set to true to debug all iterations, including during oscillation. Ignores max recorded
   * iterations value.
   */
  private static boolean DEBUG_ALL_ITERATIONS = false;

  private static final int DEBUG_MAX_RECORDED_ITERATIONS = 12;

  /**
   * Set to true to debug oscillation. Make sure to set max recorded iterations to minimum necessary
   * value.
   */
  private static boolean DEBUG_REPEAT_ITERATIONS = false;

  private static final String TRACEROUTE_INGRESS_NODE_INTERFACE_NAME =
      "traceroute_source_interface";

  private static final String TRACEROUTE_INGRESS_NODE_NAME = "traceroute_source_node";

  private final Map<BdpDataPlane, Map<Flow, Set<FlowTrace>>> _flowTraces;

  public BdpDataPlanePlugin() {
    _flowTraces = new HashMap<>();
  }

  /**
   * Applies the given list of source NAT rules to the given flow and returns the new transformed
   * flow. If {@code sourceNats} is null, empty, or does not contain any ACL rules matching the
   * {@link Flow}, the original flow is returned.
   *
   * <p>Each {@link SourceNat} is expected to be valid: it must have a NAT IP or pool.
   */
  static Flow applySourceNat(Flow flow, @Nullable List<SourceNat> sourceNats) {
    if (CommonUtil.isNullOrEmpty(sourceNats)) {
      return flow;
    }

    for (SourceNat sourceNat : sourceNats) {
      IpAccessList acl = sourceNat.getAcl();
      if (acl != null) {
        FilterResult result = acl.filter(flow);
        if (result.getAction() == LineAction.REJECT) {
          // This ACL does not match the flow.
          continue;
        }
      }

      Ip natPoolStartIp = sourceNat.getPoolIpFirst();
      if (natPoolStartIp == null) {
        throw new BatfishException(
            String.format(
                "Error processing Source NAT rule %s: missing NAT address or pool", sourceNat));
      }
      Flow.Builder transformedFlowBuilder = new Flow.Builder(flow);
      transformedFlowBuilder.setSrcIp(natPoolStartIp);
      return transformedFlowBuilder.build();
    }

    // No NAT rule matched.
    return flow;
  }

  private void collectFlowTraces(
      BdpDataPlane dp,
      String currentNodeName,
      Set<Edge> visitedEdges,
      List<FlowTraceHop> hopsSoFar,
      Set<FlowTrace> flowTraces,
      Flow originalFlow,
      Flow transformedFlow) {
    Ip dstIp = transformedFlow.getDstIp();
    Set<String> dstIpOwners = dp._ipOwners.get(dstIp);
    if (dstIpOwners != null && dstIpOwners.contains(currentNodeName)) {
      FlowTrace trace =
          new FlowTrace(FlowDisposition.ACCEPTED, hopsSoFar, FlowDisposition.ACCEPTED.toString());
{'fraction_non_alphanumeric': 0.09078014184397164, 'fraction_numerical': 0.0006546644844517185, 'mean_word_length': 4.1235326998323085, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '4265334', 'n_tokens_mistral': 2944, 'n_tokens_neox': 2792, 'n_words': 661}