@Override
  public boolean applyRules(
      List<? extends FirewallRule> rules, boolean continueOnError, boolean updateRulesInDB)
      throws ResourceUnavailableException {
    boolean success = true;
    if (rules == null || rules.size() == 0) {
      s_logger.debug("There are no rules to forward to the network elements");
      return true;
    }
    Purpose purpose = rules.get(0).getPurpose();
    if (!_ipAddrMgr.applyRules(rules, purpose, this, continueOnError)) {
      s_logger.warn("Rules are not completely applied");
      return false;
    } else {
      if (updateRulesInDB) {
        for (FirewallRule rule : rules) {
          if (rule.getState() == FirewallRule.State.Revoke) {
            FirewallRuleVO relatedRule = _firewallDao.findByRelatedId(rule.getId());
            if (relatedRule != null) {
              s_logger.warn(
                  "Can't remove the firewall rule id="
                      + rule.getId()
                      + " as it has related firewall rule id="
                      + relatedRule.getId()
                      + "; leaving it in Revoke state");
              success = false;
            } else {
              removeRule(rule);
              if (rule.getSourceIpAddressId() != null) {
                // if the rule is the last one for the ip address assigned to VPC, unassign it from
                // the network
                IpAddress ip = _ipAddressDao.findById(rule.getSourceIpAddressId());
                _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), rule.getNetworkId());
              }
            }
          } else if (rule.getState() == FirewallRule.State.Add) {
            FirewallRuleVO ruleVO = _firewallDao.findById(rule.getId());
            ruleVO.setState(FirewallRule.State.Active);
            _firewallDao.update(ruleVO.getId(), ruleVO);
          }
        }
      }
    }

    return success;
  }
  @Override
  @DB
  public NicProfile createPrivateNicProfileForGateway(
      final VpcGateway privateGateway, final VirtualRouter router) {
    final Network privateNetwork = _networkModel.getNetwork(privateGateway.getNetworkId());

    PrivateIpVO ipVO =
        _privateIpDao.allocateIpAddress(
            privateNetwork.getDataCenterId(),
            privateNetwork.getId(),
            privateGateway.getIp4Address());

    final Long vpcId = privateGateway.getVpcId();
    final Vpc activeVpc = _vpcMgr.getActiveVpc(vpcId);
    if (activeVpc.isRedundant() && ipVO == null) {
      ipVO = _privateIpDao.findByIpAndVpcId(vpcId, privateGateway.getIp4Address());
    }

    Nic privateNic = null;

    if (ipVO != null) {
      privateNic =
          _nicDao.findByIp4AddressAndNetworkId(ipVO.getIpAddress(), privateNetwork.getId());
    }

    NicProfile privateNicProfile = new NicProfile();

    if (privateNic != null) {
      privateNicProfile =
          new NicProfile(
              privateNic,
              privateNetwork,
              privateNic.getBroadcastUri(),
              privateNic.getIsolationUri(),
              _networkModel.getNetworkRate(privateNetwork.getId(), router.getId()),
              _networkModel.isSecurityGroupSupportedInNetwork(privateNetwork),
              _networkModel.getNetworkTag(router.getHypervisorType(), privateNetwork));

      if (router.getIsRedundantRouter()) {
        String newMacAddress =
            NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ipVO.getMacAddress()));
        privateNicProfile.setMacAddress(newMacAddress);
      }
    } else {
      final String netmask = NetUtils.getCidrNetmask(privateNetwork.getCidr());
      final PrivateIpAddress ip =
          new PrivateIpAddress(
              ipVO,
              privateNetwork.getBroadcastUri().toString(),
              privateNetwork.getGateway(),
              netmask,
              NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ipVO.getMacAddress())));

      final URI netUri = BroadcastDomainType.fromString(ip.getBroadcastUri());
      privateNicProfile.setIPv4Address(ip.getIpAddress());
      privateNicProfile.setIPv4Gateway(ip.getGateway());
      privateNicProfile.setIPv4Netmask(ip.getNetmask());
      privateNicProfile.setIsolationUri(netUri);
      privateNicProfile.setBroadcastUri(netUri);
      // can we solve this in setBroadcastUri()???
      // or more plugable construct is desirable
      privateNicProfile.setBroadcastType(BroadcastDomainType.getSchemeValue(netUri));
      privateNicProfile.setFormat(AddressFormat.Ip4);
      privateNicProfile.setReservationId(String.valueOf(ip.getBroadcastUri()));
      privateNicProfile.setMacAddress(ip.getMacAddress());
    }

    return privateNicProfile;
  }
  protected Pair<Map<String, PublicIpAddress>, Map<String, PublicIpAddress>>
      getNicsToChangeOnRouter(
          final List<? extends PublicIpAddress> publicIps, final VirtualRouter router) {
    // 1) check which nics need to be plugged/unplugged and plug/unplug them

    final Map<String, PublicIpAddress> nicsToPlug = new HashMap<String, PublicIpAddress>();
    final Map<String, PublicIpAddress> nicsToUnplug = new HashMap<String, PublicIpAddress>();

    // find out nics to unplug
    for (final PublicIpAddress ip : publicIps) {
      final long publicNtwkId = ip.getNetworkId();

      // if ip is not associated to any network, and there are no firewall
      // rules, release it on the backend
      if (!_vpcMgr.isIpAllocatedToVpc(ip)) {
        ip.setState(IpAddress.State.Releasing);
      }

      if (ip.getState() == IpAddress.State.Releasing) {
        final Nic nic =
            _nicDao.findByIp4AddressAndNetworkIdAndInstanceId(
                publicNtwkId, router.getId(), ip.getAddress().addr());
        if (nic != null) {
          nicsToUnplug.put(ip.getVlanTag(), ip);
          s_logger.debug(
              "Need to unplug the nic for ip="
                  + ip
                  + "; vlan="
                  + ip.getVlanTag()
                  + " in public network id ="
                  + publicNtwkId);
        }
      }
    }

    // find out nics to plug
    for (final PublicIpAddress ip : publicIps) {
      final URI broadcastUri = BroadcastDomainType.Vlan.toUri(ip.getVlanTag());
      final long publicNtwkId = ip.getNetworkId();

      // if ip is not associated to any network, and there are no firewall
      // rules, release it on the backend
      if (!_vpcMgr.isIpAllocatedToVpc(ip)) {
        ip.setState(IpAddress.State.Releasing);
      }

      if (ip.getState() == IpAddress.State.Allocated
          || ip.getState() == IpAddress.State.Allocating) {
        // nic has to be plugged only when there are no nics for this
        // vlan tag exist on VR
        final Nic nic =
            _nicDao.findByNetworkIdInstanceIdAndBroadcastUri(
                publicNtwkId, router.getId(), broadcastUri.toString());

        if (nic == null && nicsToPlug.get(ip.getVlanTag()) == null) {
          nicsToPlug.put(ip.getVlanTag(), ip);
          s_logger.debug(
              "Need to plug the nic for ip="
                  + ip
                  + "; vlan="
                  + ip.getVlanTag()
                  + " in public network id ="
                  + publicNtwkId);
        } else {
          final PublicIpAddress nicToUnplug = nicsToUnplug.get(ip.getVlanTag());
          if (nicToUnplug != null) {
            final NicVO nicVO =
                _nicDao.findByIp4AddressAndNetworkIdAndInstanceId(
                    publicNtwkId, router.getId(), nicToUnplug.getAddress().addr());
            nicVO.setIPv4Address(ip.getAddress().addr());
            _nicDao.update(nicVO.getId(), nicVO);
            s_logger.debug(
                "Updated the nic " + nicVO + " with the new ip address " + ip.getAddress().addr());
            nicsToUnplug.remove(ip.getVlanTag());
          }
        }
      }
    }

    final Pair<Map<String, PublicIpAddress>, Map<String, PublicIpAddress>> nicsToChange =
        new Pair<Map<String, PublicIpAddress>, Map<String, PublicIpAddress>>(
            nicsToPlug, nicsToUnplug);
    return nicsToChange;
  }