@Override
  public void reserve(
      NicProfile nic,
      Network config,
      VirtualMachineProfile<? extends VirtualMachine> vm,
      DeployDestination dest,
      ReservationContext context)
      throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException {
    assert nic.getTrafficType() == TrafficType.Control;

    if (dest.getHost().getHypervisorType() == HypervisorType.VmWare
        && vm.getType() == VirtualMachine.Type.DomainRouter) {
      super.reserve(nic, config, vm, dest, context);

      String mac = _networkMgr.getNextAvailableMacAddressInNetwork(config.getId());
      nic.setMacAddress(mac);
      return;
    }

    String ip =
        _dcDao.allocateLinkLocalIpAddress(
            dest.getDataCenter().getId(),
            dest.getPod().getId(),
            nic.getId(),
            context.getReservationId());
    nic.setIp4Address(ip);
    nic.setMacAddress(NetUtils.long2Mac(NetUtils.ip2Long(ip) | (14l << 40)));
    nic.setNetmask("255.255.0.0");
    nic.setFormat(AddressFormat.Ip4);
    nic.setGateway(NetUtils.getLinkLocalGateway());
  }
  @Override
  public NicProfile allocate(
      Network config, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm)
      throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException {

    if (_networkModel.networkIsConfiguredForExternalNetworking(
            config.getDataCenterId(), config.getId())
        && nic != null
        && nic.getRequestedIpv4() != null) {
      throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic);
    }

    NicProfile profile = super.allocate(config, nic, vm);

    boolean _isEnabled = Boolean.parseBoolean(_configDao.getValue(Config.OvsTunnelNetwork.key()));
    if (_isEnabled) {
      return null;
    }

    if (_networkModel.networkIsConfiguredForExternalNetworking(
        config.getDataCenterId(), config.getId())) {
      profile.setStrategy(ReservationStrategy.Start);
      /* We won't clear IP address, because router may set gateway as it IP, and it would be updated properly later */
      // profile.setIp4Address(null);
      profile.setGateway(null);
      profile.setNetmask(null);
    }

    return profile;
  }
  @Override
  public void reserve(
      NicProfile nic,
      Network config,
      VirtualMachineProfile<? extends VirtualMachine> vm,
      DeployDestination dest,
      ReservationContext context)
      throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException {
    assert (nic.getReservationStrategy() == ReservationStrategy.Start)
        : "What can I do for nics that are not allocated at start? ";
    boolean _isEnabled = Boolean.parseBoolean(_configDao.getValue(Config.OvsTunnelNetwork.key()));
    if (_isEnabled) {
      return;
    }

    DataCenter dc = _dcDao.findById(config.getDataCenterId());

    if (_networkModel.networkIsConfiguredForExternalNetworking(
        config.getDataCenterId(), config.getId())) {
      nic.setBroadcastUri(config.getBroadcastUri());
      nic.setIsolationUri(config.getBroadcastUri());
      nic.setDns1(dc.getDns1());
      nic.setDns2(dc.getDns2());
      nic.setNetmask(NetUtils.cidr2Netmask(config.getCidr()));
      long cidrAddress = NetUtils.ip2Long(config.getCidr().split("/")[0]);
      int cidrSize = getGloballyConfiguredCidrSize();
      nic.setGateway(config.getGateway());

      if (nic.getIp4Address() == null) {
        String guestIp = _networkMgr.acquireGuestIpAddress(config, null);
        if (guestIp == null) {
          throw new InsufficientVirtualNetworkCapcityException(
              "Unable to acquire guest IP address for network " + config,
              DataCenter.class,
              dc.getId());
        }

        nic.setIp4Address(guestIp);
      } else {
        long ipMask =
            NetUtils.ip2Long(nic.getIp4Address()) & ~(0xffffffffffffffffl << (32 - cidrSize));
        nic.setIp4Address(NetUtils.long2Ip(cidrAddress | ipMask));
      }
    } else {
      super.reserve(nic, config, vm, dest, context);
    }
  }
  @Override
  @DB
  public void deallocate(
      Network config, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm) {
    super.deallocate(config, nic, vm);

    if (Boolean.parseBoolean(_configDao.getValue(Config.OvsTunnelNetwork.key()))) {
      return;
    }

    if (_networkModel.networkIsConfiguredForExternalNetworking(
        config.getDataCenterId(), config.getId())) {
      nic.setIp4Address(null);
      nic.setGateway(null);
      nic.setNetmask(null);
      nic.setBroadcastUri(null);
      nic.setIsolationUri(null);
    }
  }
  @Override
  public boolean release(
      NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, String reservationId) {
    assert nic.getTrafficType() == TrafficType.Control;

    if (vm.getHypervisorType() == HypervisorType.VmWare
        && vm.getType() == VirtualMachine.Type.DomainRouter) {
      super.release(nic, vm, reservationId);
      return true;
    }

    _dcDao.releaseLinkLocalIpAddress(nic.getId(), reservationId);
    nic.setIp4Address(null);
    nic.setMacAddress(null);
    nic.setNetmask(null);
    nic.setFormat(null);
    nic.setGateway(null);

    return true;
  }
  protected void getIp(
      NicProfile nic,
      DataCenter dc,
      VirtualMachineProfile<? extends VirtualMachine> vm,
      Network network)
      throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException,
          ConcurrentOperationException {
    if (nic.getIp4Address() == null) {
      PublicIp ip =
          _networkMgr.assignPublicIpAddress(
              dc.getId(),
              vm.getOwner(),
              dc.getNetworkType().equals(NetworkType.Basic)
                  ? VlanType.DirectAttached
                  : VlanType.VirtualNetwork,
              null);
      nic.setIp4Address(ip.getAddress().toString());
      nic.setGateway(ip.getGateway());
      nic.setNetmask(ip.getNetmask());
      if (ip.getVlanTag() != null && ip.getVlanTag().equalsIgnoreCase("untagged")) {
        nic.setIsolationUri(URI.create("vlan://untagged"));
        nic.setBroadcastUri(URI.create("vlan://untagged"));
        nic.setBroadcastType(BroadcastDomainType.Native);
      } else if (ip.getVlanTag() != null) {
        nic.setIsolationUri(IsolationType.Vlan.toUri(ip.getVlanTag()));
        nic.setBroadcastUri(IsolationType.Vlan.toUri(ip.getVlanTag()));
        nic.setBroadcastType(BroadcastDomainType.Vlan);
      }

      nic.setFormat(AddressFormat.Ip4);
      nic.setReservationId(String.valueOf(ip.getVlanTag()));
      nic.setMacAddress(ip.getMacAddress());
    }
    nic.setDns1(dc.getDns1());
    nic.setDns2(dc.getDns2());
  }