private ArpResolverMetadata resetFlowToRemove(
      final Ipv4Address gatewayIp, ArpResolverMetadata gatewayArpMetadata) {
    checkNotNull(gatewayIp);

    // If gatewayArpMetadata was not provided, look it up
    if (gatewayArpMetadata == null) {
      gatewayArpMetadata = gatewayToArpMetadataMap.get(gatewayIp);
    }
    if (gatewayArpMetadata != null && gatewayArpMetadata.getFlowToRemove() != null) {
      LOG.debug(
          "Flow to route ARP Reply to Controller from {} being removed from node {}",
          gatewayIp,
          gatewayArpMetadata.getFlowToRemove().getNode());
      flowService.removeFlow(gatewayArpMetadata.getFlowToRemove());
      gatewayArpMetadata.setFlowToRemove(null);
    }
    return gatewayArpMetadata;
  }
  private void sendGatewayArpRequest(
      final Node externalNetworkBridge,
      final Ipv4Address gatewayIp,
      final Ipv4Address sourceIpAddress,
      final MacAddress sourceMacAddress) {
    final ArpMessageAddress senderAddress =
        new ArpMessageAddress(sourceMacAddress, sourceIpAddress);

    // Build arp reply router flow
    final Flow arpReplyToControllerFlow = createArpReplyToControllerFlow(senderAddress, gatewayIp);

    final InstanceIdentifier<Node> nodeIid =
        InstanceIdentifier.builder(Nodes.class)
            .child(Node.class, externalNetworkBridge.getKey())
            .build();
    final InstanceIdentifier<Flow> flowIid = createFlowIid(arpReplyToControllerFlow, nodeIid);
    final NodeRef nodeRef = new NodeRef(nodeIid);

    // Install flow
    Future<RpcResult<AddFlowOutput>> addFlowResult =
        flowService.addFlow(
            new AddFlowInputBuilder(arpReplyToControllerFlow)
                .setFlowRef(new FlowRef(flowIid))
                .setNode(nodeRef)
                .build());
    // wait for flow installation
    Futures.addCallback(
        JdkFutureAdapters.listenInPoolThread(addFlowResult),
        new FutureCallback<RpcResult<AddFlowOutput>>() {

          @Override
          public void onSuccess(RpcResult<AddFlowOutput> result) {
            if (!result.isSuccessful()) {
              LOG.warn(
                  "Flow to route ARP Reply to Controller is not installed successfully : {} \nErrors: {}",
                  flowIid,
                  result.getErrors());
              return;
            }
            LOG.debug("Flow to route ARP Reply to Controller installed successfully : {}", flowIid);

            ArpResolverMetadata gatewayArpMetadata = gatewayToArpMetadataMap.get(gatewayIp);
            if (gatewayArpMetadata == null) {
              LOG.warn("No metadata found for gatewayIp: {}", gatewayIp);
              return;
            }

            // cache metadata
            gatewayArpMetadata.setFlowToRemove(
                new RemoveFlowInputBuilder(arpReplyToControllerFlow).setNode(nodeRef).build());

            // get MAC DA for ARP packets
            MacAddress arpRequestDestMacAddress = gatewayArpMetadata.getArpRequestDestMacAddress();

            // Send ARP request packets
            for (NodeConnector egressNc : externalNetworkBridge.getNodeConnector()) {
              KeyedInstanceIdentifier<NodeConnector, NodeConnectorKey> egressNcIid =
                  nodeIid.child(NodeConnector.class, new NodeConnectorKey(egressNc.getId()));
              ListenableFuture<RpcResult<Void>> futureSendArpResult =
                  arpSender.sendArp(
                      senderAddress, gatewayIp, arpRequestDestMacAddress, egressNcIid);
              Futures.addCallback(futureSendArpResult, logResult(gatewayIp, egressNcIid));
            }
          }

          @Override
          public void onFailure(Throwable t) {
            LOG.warn("ARP Reply to Controller flow was not created: {}", flowIid, t);
          }
        });
  }