@Override
  @DB
  public void deallocate(
      Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm) {
    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "Deallocate network: networkId: " + nic.getNetworkId() + ", ip: " + nic.getIp4Address());
    }

    IPAddressVO ip =
        _ipAddressDao.findByIpAndSourceNetworkId(nic.getNetworkId(), nic.getIp4Address());
    if (ip != null) {
      Transaction txn = Transaction.currentTxn();
      txn.start();
      _networkMgr.markIpAsUnavailable(ip.getId());
      _ipAddressDao.unassignIpAddress(ip.getId());
      txn.commit();
    }
    nic.deallocate();
  }
  @Override
  public boolean release(
      NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, String reservationId) {

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

    NetworkVO network = _networkDao.findById(nic.getNetworkId());

    if (network != null
        && _networkModel.networkIsConfiguredForExternalNetworking(
            network.getDataCenterId(), network.getId())) {
      return true;
    } else {
      return super.release(nic, vm, reservationId);
    }
  }
  private boolean preparePxeInBasicZone(
      VirtualMachineProfile profile,
      NicProfile nic,
      DeployDestination dest,
      ReservationContext context)
      throws AgentUnavailableException, OperationTimedoutException {
    NetworkVO nwVO = _nwDao.findById(nic.getNetworkId());
    QueryBuilder<BaremetalPxeVO> sc = QueryBuilder.create(BaremetalPxeVO.class);
    sc.and(sc.entity().getDeviceType(), Op.EQ, BaremetalPxeType.KICK_START.toString());
    sc.and(sc.entity().getPhysicalNetworkId(), Op.EQ, nwVO.getPhysicalNetworkId());
    BaremetalPxeVO pxeVo = sc.find();
    if (pxeVo == null) {
      throw new CloudRuntimeException(
          "No kickstart PXE server found in pod: "
              + dest.getPod().getId()
              + ", you need to add it before starting VM");
    }
    VMTemplateVO template = _tmpDao.findById(profile.getTemplateId());
    List<String> tuple = parseKickstartUrl(profile);

    String ks = tuple.get(0);
    String kernel = tuple.get(1);
    String initrd = tuple.get(2);

    PrepareKickstartPxeServerCommand cmd = new PrepareKickstartPxeServerCommand();
    cmd.setKsFile(ks);
    cmd.setInitrd(initrd);
    cmd.setKernel(kernel);
    cmd.setMac(nic.getMacAddress());
    cmd.setTemplateUuid(template.getUuid());
    Answer aws = _agentMgr.send(pxeVo.getHostId(), cmd);
    if (!aws.getResult()) {
      s_logger.warn(
          "Unable to set host: "
              + dest.getHost().getId()
              + " to PXE boot because "
              + aws.getDetails());
      return false;
    }

    return true;
  }
  @Override
  public boolean finalizeCommandsOnStart(
      Commands cmds, VirtualMachineProfile<DomainRouterVO> profile) {
    DomainRouterVO elbVm = profile.getVirtualMachine();
    DataCenterVO dcVo = _dcDao.findById(elbVm.getDataCenterId());

    NicProfile controlNic = null;
    Long guestNetworkId = null;

    if (profile.getHypervisorType() == HypervisorType.VMware
        && dcVo.getNetworkType() == NetworkType.Basic) {
      // TODO this is a ugly to test hypervisor type here
      // for basic network mode, we will use the guest NIC for control NIC
      for (NicProfile nic : profile.getNics()) {
        if (nic.getTrafficType() == TrafficType.Guest && nic.getIp4Address() != null) {
          controlNic = nic;
          guestNetworkId = nic.getNetworkId();
        }
      }
    } else {
      for (NicProfile nic : profile.getNics()) {
        if (nic.getTrafficType() == TrafficType.Control && nic.getIp4Address() != null) {
          controlNic = nic;
        } else if (nic.getTrafficType() == TrafficType.Guest) {
          guestNetworkId = nic.getNetworkId();
        }
      }
    }

    if (controlNic == null) {
      s_logger.error("Control network doesn't exist for the ELB vm " + elbVm);
      return false;
    }

    cmds.addCommand(
        "checkSsh",
        new CheckSshCommand(profile.getInstanceName(), controlNic.getIp4Address(), 3922));

    // Re-apply load balancing rules
    List<LoadBalancerVO> lbs = _elbVmMapDao.listLbsForElbVm(elbVm.getId());
    List<LoadBalancingRule> lbRules = new ArrayList<LoadBalancingRule>();
    for (LoadBalancerVO lb : lbs) {
      List<LbDestination> dstList = _lbMgr.getExistingDestinations(lb.getId());
      List<LbStickinessPolicy> policyList = _lbMgr.getStickinessPolicies(lb.getId());
      List<LbHealthCheckPolicy> hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId());
      LoadBalancingRule loadBalancing =
          new LoadBalancingRule(lb, dstList, policyList, hcPolicyList);
      lbRules.add(loadBalancing);
    }

    s_logger.debug(
        "Found "
            + lbRules.size()
            + " load balancing rule(s) to apply as a part of ELB vm "
            + elbVm
            + " start.");
    if (!lbRules.isEmpty()) {
      createApplyLoadBalancingRulesCommands(lbRules, elbVm, cmds, guestNetworkId);
    }

    return true;
  }
  @Override
  public boolean finalizeVirtualMachineProfile(
      VirtualMachineProfile<DomainRouterVO> profile,
      DeployDestination dest,
      ReservationContext context) {
    DomainRouterVO elbVm = profile.getVirtualMachine();

    List<NicProfile> elbNics = profile.getNics();
    Long guestNtwkId = null;
    for (NicProfile routerNic : elbNics) {
      if (routerNic.getTrafficType() == TrafficType.Guest) {
        guestNtwkId = routerNic.getNetworkId();
        break;
      }
    }

    NetworkVO guestNetwork = _networkDao.findById(guestNtwkId);

    DataCenter dc = dest.getDataCenter();

    StringBuilder buf = profile.getBootArgsBuilder();
    buf.append(" template=domP type=" + _systemVmType);
    buf.append(" name=").append(profile.getHostName());
    NicProfile controlNic = null;
    String defaultDns1 = null;
    String defaultDns2 = null;

    for (NicProfile nic : profile.getNics()) {
      int deviceId = nic.getDeviceId();
      buf.append(" eth").append(deviceId).append("ip=").append(nic.getIp4Address());
      buf.append(" eth").append(deviceId).append("mask=").append(nic.getNetmask());
      if (nic.isDefaultNic()) {
        buf.append(" gateway=").append(nic.getGateway());
        defaultDns1 = nic.getDns1();
        defaultDns2 = nic.getDns2();
      }
      if (nic.getTrafficType() == TrafficType.Management) {
        buf.append(" localgw=").append(dest.getPod().getGateway());
      } else if (nic.getTrafficType() == TrafficType.Control) {
        //  control command is sent over management network in VMware
        if (dest.getHost().getHypervisorType() == HypervisorType.VMware) {
          if (s_logger.isInfoEnabled()) {
            s_logger.info(
                "Check if we need to add management server explicit route to ELB vm. pod cidr: "
                    + dest.getPod().getCidrAddress()
                    + "/"
                    + dest.getPod().getCidrSize()
                    + ", pod gateway: "
                    + dest.getPod().getGateway()
                    + ", management host: "
                    + _mgmtHost);
          }

          if (s_logger.isDebugEnabled()) {
            s_logger.debug("Added management server explicit route to ELB vm.");
          }
          // always add management explicit route, for basic networking setup
          buf.append(" mgmtcidr=").append(_mgmtCidr);
          buf.append(" localgw=").append(dest.getPod().getGateway());

          if (dc.getNetworkType() == NetworkType.Basic) {
            // ask elb vm to setup SSH on guest network
            buf.append(" sshonguest=true");
          }
        }

        controlNic = nic;
      }
    }
    String domain = guestNetwork.getNetworkDomain();
    if (domain != null) {
      buf.append(" domain=" + domain);
    }

    buf.append(" dns1=").append(defaultDns1);
    if (defaultDns2 != null) {
      buf.append(" dns2=").append(defaultDns2);
    }

    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Boot Args for " + profile + ": " + buf.toString());
    }

    if (controlNic == null) {
      throw new CloudRuntimeException("Didn't start a control port");
    }

    return true;
  }
  /**
   * @param router
   * @param add
   * @param privateNic
   * @return
   * @throws ResourceUnavailableException
   */
  protected boolean setupVpcPrivateNetwork(
      final VirtualRouter router, final boolean add, final NicProfile privateNic)
      throws ResourceUnavailableException {

    if (router.getState() == State.Running) {
      final PrivateIpVO ipVO =
          _privateIpDao.findByIpAndSourceNetworkId(
              privateNic.getNetworkId(), privateNic.getIPv4Address());
      final Network network = _networkDao.findById(privateNic.getNetworkId());
      final String netmask = NetUtils.getCidrNetmask(network.getCidr());
      final PrivateIpAddress ip =
          new PrivateIpAddress(
              ipVO,
              network.getBroadcastUri().toString(),
              network.getGateway(),
              netmask,
              privateNic.getMacAddress());

      final List<PrivateIpAddress> privateIps = new ArrayList<PrivateIpAddress>(1);
      privateIps.add(ip);
      final Commands cmds = new Commands(Command.OnError.Stop);
      _commandSetupHelper.createVpcAssociatePrivateIPCommands(router, privateIps, cmds, add);

      try {
        if (_nwHelper.sendCommandsToRouter(router, cmds)) {
          s_logger.debug(
              "Successfully applied ip association for ip " + ip + " in vpc network " + network);
          return true;
        } else {
          s_logger.warn("Failed to associate ip address " + ip + " in vpc network " + network);
          return false;
        }
      } catch (final Exception ex) {
        s_logger.warn(
            "Failed to send  "
                + (add ? "add " : "delete ")
                + " private network "
                + network
                + " commands to rotuer ");
        return false;
      }
    } else if (router.getState() == State.Stopped || router.getState() == State.Stopping) {
      s_logger.debug(
          "Router "
              + router.getInstanceName()
              + " is in "
              + router.getState()
              + ", so not sending setup private network command to the backend");
    } else {
      s_logger.warn(
          "Unable to setup private gateway, virtual router "
              + router
              + " is not in the right state "
              + router.getState());

      throw new ResourceUnavailableException(
          "Unable to setup Private gateway on the backend,"
              + " virtual router "
              + router
              + " is not in the right state",
          DataCenter.class,
          router.getDataCenterId());
    }
    return true;
  }