private void setExternalConnection(OpenstackRouter osRouter, String osSubNetId) {
    if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
      log.debug("Source NAT is disabled");
      return;
    }

    OpenstackSubnet osSubNet = openstackService.subnet(osSubNetId);
    OpenstackNetwork osNet = openstackService.network(osSubNet.networkId());
    populateExternalRules(osNet, osSubNet);
  }
 private Set<OpenstackSubnet> routableSubNets(String osRouterId) {
   return openstackService
       .ports()
       .stream()
       .filter(
           p ->
               p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
                   && p.deviceId().equals(osRouterId))
       .map(p -> openstackService.subnet(p.fixedIps().keySet().stream().findFirst().get()))
       .collect(Collectors.toSet());
 }
 private OpenstackRouter openstackRouter(String routerId) {
   return openstackService
       .routers()
       .stream()
       .filter(r -> r.id().equals(routerId))
       .iterator()
       .next();
 }
  @Override
  public void addRouterInterface(OpenstackRouterInterface routerIface) {
    OpenstackRouter osRouter = openstackRouter(routerIface.id());
    OpenstackPort osPort = openstackService.port(routerIface.portId());
    if (osRouter == null || osPort == null) {
      log.warn("Failed to add router interface {}", routerIface);
      return;
    }

    setGatewayIcmp(Ip4Address.valueOf(openstackService.subnet(routerIface.subnetId()).gatewayIp()));

    setRoutes(osRouter, Optional.empty());
    if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
      String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
      setExternalConnection(osRouter, subnetId);
    }
    log.info("Connected {} to router {}", osPort.fixedIps(), osRouter.name());
  }
 private Optional<OpenstackPort> routerIfacePort(String osNetId) {
   // FIXME router interface is subnet specific, not network
   return openstackService
       .ports()
       .stream()
       .filter(
           p ->
               p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
                   && p.networkId().equals(osNetId))
       .findAny();
 }
  private void unsetExternalConnection(
      OpenstackRouter osRouter, String osNetId, String subNetCidr) {
    if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
      log.debug("Source NAT is disabled");
      return;
    }

    // FIXME router interface is subnet specific, not network
    OpenstackNetwork osNet = openstackService.network(osNetId);
    removeExternalRules(osNet, subNetCidr);
  }
  @Override
  public void removeRouterInterface(OpenstackRouterInterface routerIface) {
    OpenstackRouter osRouter = openstackService.router(routerIface.id());
    if (osRouter == null) {
      log.warn("Failed to remove router interface {}", routerIface);
      return;
    }

    OpenstackSubnet osSubnet = openstackService.subnet(routerIface.subnetId());
    OpenstackNetwork osNet = openstackService.network(osSubnet.networkId());

    unsetGatewayIcmp(
        Ip4Address.valueOf(openstackService.subnet(routerIface.subnetId()).gatewayIp()));

    unsetRoutes(osRouter, osSubnet);

    if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
      unsetExternalConnection(osRouter, osNet.id(), osSubnet.cidr());
    }
    log.info("Disconnected {} from router {}", osSubnet.cidr(), osRouter.name());
  }
  @Override
  public void updateRouter(OpenstackRouter osRouter) {
    if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
      openstackService
          .ports()
          .stream()
          .filter(
              osPort ->
                  osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
                      && osPort.deviceId().equals(osRouter.id()))
          .forEach(
              osPort -> {
                String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
                setExternalConnection(osRouter, subnetId);
              });

      log.info(
          "Connected external gateway {} to router {}",
          osRouter.gatewayExternalInfo().externalFixedIps(),
          osRouter.name());
    } else {
      openstackService
          .ports()
          .stream()
          .filter(
              osPort ->
                  osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
                      && osPort.deviceId().equals(osRouter.id()))
          .forEach(
              osPort -> {
                String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
                OpenstackSubnet osSubNet = openstackService.subnet(subnetId);
                unsetExternalConnection(osRouter, osPort.networkId(), osSubNet.cidr());
              });

      log.info("Disconnected external gateway from router {}", osRouter.name());
    }
  }
  private void reloadRoutingRules() {
    eventExecutor.execute(
        () ->
            openstackService
                .ports()
                .stream()
                .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
                .forEach(
                    osPort -> {
                      OpenstackRouter osRouter = openstackRouter(osPort.deviceId());

                      setGatewayIcmp(
                          Ip4Address.valueOf(
                              openstackService
                                  .subnet(osPort.fixedIps().keySet().stream().findAny().get())
                                  .gatewayIp()));

                      setRoutes(osRouter, Optional.empty());
                      if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
                        String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
                        setExternalConnection(osRouter, subnetId);
                      }
                    }));
  }
  private void populateRoutingRules(Host host, Set<OpenstackSubnet> osSubNets) {
    String osSubNetId = host.annotations().value(SUBNET_ID);
    if (osSubNetId == null) {
      return;
    }

    DeviceId localDevice = host.location().deviceId();
    PortNumber localPort = host.location().port();
    if (!nodeService.dataIp(localDevice).isPresent()) {
      log.warn("Failed to populate L3 rules");
      return;
    }

    Map<String, String> vniMap = new HashMap<>();
    openstackService.networks().stream().forEach(n -> vniMap.put(n.id(), n.segmentId()));

    // TODO improve pipeline, do we have to install access rules between networks
    // for every single VMs?
    osSubNets
        .stream()
        .filter(osSubNet -> !osSubNet.id().equals(osSubNetId))
        .forEach(
            osSubNet -> {
              populateRoutingRulestoSameNode(
                  host.ipAddresses().stream().findFirst().get().getIp4Address(),
                  host.mac(),
                  localPort,
                  localDevice,
                  Long.valueOf(vniMap.get(osSubNet.networkId())),
                  osSubNet.cidr());

              nodeService
                  .completeNodes()
                  .stream()
                  .filter(node -> node.type().equals(COMPUTE))
                  .filter(node -> !node.intBridge().equals(localDevice))
                  .forEach(
                      node ->
                          populateRoutingRulestoDifferentNode(
                              host.ipAddresses().stream().findFirst().get().getIp4Address(),
                              Long.valueOf(vniMap.get(osSubNet.networkId())),
                              node.intBridge(),
                              nodeService.dataIp(localDevice).get().getIp4Address(),
                              osSubNet.cidr()));
            });
  }
  private void removeRoutingRules(Host host, Set<OpenstackSubnet> osSubNets) {
    String osSubNetId = host.annotations().value(SUBNET_ID);
    if (osSubNetId == null) {
      return;
    }

    Map<String, String> vniMap = new HashMap<>();
    openstackService.networks().stream().forEach(n -> vniMap.put(n.id(), n.segmentId()));

    osSubNets
        .stream()
        .filter(osSubNet -> !osSubNet.id().equals(osSubNetId))
        .forEach(
            osSubNet -> {
              TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
              sBuilder
                  .matchEthType(Ethernet.TYPE_IPV4)
                  .matchIPDst(host.ipAddresses().stream().findFirst().get().toIpPrefix())
                  .matchIPSrc(IpPrefix.valueOf(osSubNet.cidr()))
                  .matchTunnelId(Long.valueOf(vniMap.get(osSubNet.networkId())));

              nodeService
                  .completeNodes()
                  .stream()
                  .filter(node -> node.type().equals(COMPUTE))
                  .forEach(
                      node ->
                          RulePopulatorUtil.removeRule(
                              flowObjectiveService,
                              appId,
                              node.intBridge(),
                              sBuilder.build(),
                              ForwardingObjective.Flag.SPECIFIC,
                              EW_ROUTING_RULE_PRIORITY));
            });
    log.debug("Removed routing rule from {} to {}", host, osSubNets);
  }