@Test public void testBuildDispositionStep() { String node = "node"; String iface = "iface"; Ip ip = Ip.parse("1.1.1.1"); NetworkFactory nf = new NetworkFactory(); Configuration c = nf.configurationBuilder() .setHostname(node) .setConfigurationFormat(ConfigurationFormat.CISCO_IOS) .build(); Vrf vrf = nf.vrfBuilder().setOwner(c).build(); Flow flow = Flow.builder() .setDstIp(ip) .setIngressNode(c.getHostname()) .setIngressVrf(vrf.getName()) .build(); ImmutableMap<String, Configuration> configs = ImmutableMap.of(c.getHostname(), c); TracerouteEngineImplContext ctxt = new TracerouteEngineImplContext( MockDataPlane.builder().build(), Topology.EMPTY, ImmutableSet.of(), ImmutableSet.of(), ImmutableMap.of(), false, configs); List<TraceAndReverseFlow> traces = new ArrayList<>(); FlowTracer flowTracer = new FlowTracer( ctxt, c, null, new Node(c.getHostname()), new LegacyTraceRecorder(traces::add), NodeInterfacePair.of(node, iface), new ArrayList<>(), flow, vrf.getName(), new ArrayList<>(), ImmutableList.of(), new Stack<>(), flow, 0, 0); { FlowDisposition disposition = FlowDisposition.INSUFFICIENT_INFO; Step<?> step = flowTracer.buildArpFailureStep(iface, ip, disposition); assertThat(step, instanceOf(ArpErrorStep.class)); ArpErrorStep dispositionStep = (ArpErrorStep) step; assertThat(dispositionStep.getAction(), equalTo(StepAction.INSUFFICIENT_INFO)); assertThat( dispositionStep.getDetail().getOutputInterface(), equalTo(NodeInterfacePair.of(node, iface))); assertThat(dispositionStep.getDetail().getResolvedNexthopIp(), equalTo(ip)); } { FlowDisposition disposition = FlowDisposition.NEIGHBOR_UNREACHABLE; Step<?> step = flowTracer.buildArpFailureStep(iface, ip, disposition); assertThat(step, instanceOf(ArpErrorStep.class)); ArpErrorStep dispositionStep = (ArpErrorStep) step; assertThat(dispositionStep.getAction(), equalTo(StepAction.NEIGHBOR_UNREACHABLE)); assertThat( dispositionStep.getDetail().getOutputInterface(), equalTo(NodeInterfacePair.of(node, iface))); assertThat(dispositionStep.getDetail().getResolvedNexthopIp(), equalTo(ip)); } { FlowDisposition disposition = FlowDisposition.DELIVERED_TO_SUBNET; Step<?> step = flowTracer.buildArpFailureStep(iface, ip, disposition); assertThat(step, instanceOf(DeliveredStep.class)); DeliveredStep dispositionStep = (DeliveredStep) step; assertThat(dispositionStep.getAction(), equalTo(StepAction.DELIVERED_TO_SUBNET)); assertThat( dispositionStep.getDetail().getOutputInterface(), equalTo(NodeInterfacePair.of(node, iface))); assertThat(dispositionStep.getDetail().getResolvedNexthopIp(), equalTo(ip)); } { FlowDisposition disposition = FlowDisposition.EXITS_NETWORK; Step<?> step = flowTracer.buildArpFailureStep(iface, ip, disposition); assertThat(step, instanceOf(DeliveredStep.class)); DeliveredStep dispositionStep = (DeliveredStep) step; assertThat(dispositionStep.getAction(), equalTo(StepAction.EXITS_NETWORK)); assertThat( dispositionStep.getDetail().getOutputInterface(), equalTo(NodeInterfacePair.of(node, iface))); assertThat(dispositionStep.getDetail().getResolvedNexthopIp(), equalTo(ip)); } }
@VisibleForTesting Step<?> buildArpFailureStep(String outInterface, Ip resolvedNhIp, FlowDisposition disposition) { switch (disposition) { case INSUFFICIENT_INFO: case NEIGHBOR_UNREACHABLE: return buildArpErrorStep( outInterface, resolvedNhIp, getFinalActionForDisposition(disposition)); case DELIVERED_TO_SUBNET: case EXITS_NETWORK: return buildDeliveredStep( outInterface, resolvedNhIp, getFinalActionForDisposition(disposition)); default: throw new BatfishException( "the disposition is must be insufficient info, neighbor unreachable, delivered to subnet or exits network."); } }
FlowTracer { @VisibleForTesting Step<?> buildArpFailureStep(String outInterface, Ip resolvedNhIp, FlowDisposition disposition) { switch (disposition) { case INSUFFICIENT_INFO: case NEIGHBOR_UNREACHABLE: return buildArpErrorStep( outInterface, resolvedNhIp, getFinalActionForDisposition(disposition)); case DELIVERED_TO_SUBNET: case EXITS_NETWORK: return buildDeliveredStep( outInterface, resolvedNhIp, getFinalActionForDisposition(disposition)); default: throw new BatfishException( "the disposition is must be insufficient info, neighbor unreachable, delivered to subnet or exits network."); } } }
FlowTracer { @VisibleForTesting Step<?> buildArpFailureStep(String outInterface, Ip resolvedNhIp, FlowDisposition disposition) { switch (disposition) { case INSUFFICIENT_INFO: case NEIGHBOR_UNREACHABLE: return buildArpErrorStep( outInterface, resolvedNhIp, getFinalActionForDisposition(disposition)); case DELIVERED_TO_SUBNET: case EXITS_NETWORK: return buildDeliveredStep( outInterface, resolvedNhIp, getFinalActionForDisposition(disposition)); default: throw new BatfishException( "the disposition is must be insufficient info, neighbor unreachable, delivered to subnet or exits network."); } } @VisibleForTesting  FlowTracer(
      TracerouteEngineImplContext tracerouteContext,
      Configuration currentConfig,
      @Nullable String ingressInterface,
      Node currentNode,
      TraceRecorder traceRecorder,
      @Nullable NodeInterfacePair lastHopNodeAndOutgoingInterface,
      List<FirewallSessionTraceInfo> newSessions,
      Flow originalFlow,
      @Nonnull String vrfName,
      List<HopInfo> hops,
      List<Step<?>> steps,
      Stack<Breadcrumb> breadcrumbs,
      Flow currentFlow,
      int origNewSessionsSize,
      int origBreadcrumbsSize); }
FlowTracer { @VisibleForTesting Step<?> buildArpFailureStep(String outInterface, Ip resolvedNhIp, FlowDisposition disposition) { switch (disposition) { case INSUFFICIENT_INFO: case NEIGHBOR_UNREACHABLE: return buildArpErrorStep( outInterface, resolvedNhIp, getFinalActionForDisposition(disposition)); case DELIVERED_TO_SUBNET: case EXITS_NETWORK: return buildDeliveredStep( outInterface, resolvedNhIp, getFinalActionForDisposition(disposition)); default: throw new BatfishException( "the disposition is must be insufficient info, neighbor unreachable, delivered to subnet or exits network."); } } @VisibleForTesting  FlowTracer(
      TracerouteEngineImplContext tracerouteContext,
      Configuration currentConfig,
      @Nullable String ingressInterface,
      Node currentNode,
      TraceRecorder traceRecorder,
      @Nullable NodeInterfacePair lastHopNodeAndOutgoingInterface,
      List<FirewallSessionTraceInfo> newSessions,
      Flow originalFlow,
      @Nonnull String vrfName,
      List<HopInfo> hops,
      List<Step<?>> steps,
      Stack<Breadcrumb> breadcrumbs,
      Flow currentFlow,
      int origNewSessionsSize,
      int origBreadcrumbsSize);  }
FlowTracer { @VisibleForTesting Step<?> buildArpFailureStep(String outInterface, Ip resolvedNhIp, FlowDisposition disposition) { switch (disposition) { case INSUFFICIENT_INFO: case NEIGHBOR_UNREACHABLE: return buildArpErrorStep( outInterface, resolvedNhIp, getFinalActionForDisposition(disposition)); case DELIVERED_TO_SUBNET: case EXITS_NETWORK: return buildDeliveredStep( outInterface, resolvedNhIp, getFinalActionForDisposition(disposition)); default: throw new BatfishException( "the disposition is must be insufficient info, neighbor unreachable, delivered to subnet or exits network."); } } @VisibleForTesting  FlowTracer(
      TracerouteEngineImplContext tracerouteContext,
      Configuration currentConfig,
      @Nullable String ingressInterface,
      Node currentNode,
      TraceRecorder traceRecorder,
      @Nullable NodeInterfacePair lastHopNodeAndOutgoingInterface,
      List<FirewallSessionTraceInfo> newSessions,
      Flow originalFlow,
      @Nonnull String vrfName,
      List<HopInfo> hops,
      List<Step<?>> steps,
      Stack<Breadcrumb> breadcrumbs,
      Flow currentFlow,
      int origNewSessionsSize,
      int origBreadcrumbsSize);   }