@Override
 public boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId) {
   List<FirewallRuleVO> rules =
       _firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.LoadBalancing);
   if (rules != null) s_logger.debug("Found " + rules.size() + " lb rules to cleanup");
   for (FirewallRule rule : rules) {
     boolean result = deleteLoadBalancerRule(rule.getId(), true, caller, callerUserId);
     if (result == false) {
       s_logger.warn("Unable to remove load balancer rule " + rule.getId());
       return false;
     }
   }
   return true;
 }
  @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
  public boolean revokeRelatedFirewallRule(long ruleId, boolean apply) {
    FirewallRule fwRule = _firewallDao.findByRelatedId(ruleId);

    if (fwRule == null) {
      s_logger.trace(
          "No related firewall rule exists for rule id=" + ruleId + " so returning true here");
      return true;
    }

    s_logger.debug(
        "Revoking Firewall rule id="
            + fwRule.getId()
            + " as a part of rule delete id="
            + ruleId
            + " with apply="
            + apply);
    return revokeFirewallRule(fwRule.getId(), apply);
  }
  @Override
  @DB
  public void destroyRemoteAccessVpn(long ipId, Account caller)
      throws ResourceUnavailableException {
    RemoteAccessVpnVO vpn = _remoteAccessVpnDao.findById(ipId);
    if (vpn == null) {
      s_logger.debug("vpn id=" + ipId + " does not exists ");
      return;
    }

    _accountMgr.checkAccess(caller, null, true, vpn);

    Network network = _networkMgr.getNetwork(vpn.getNetworkId());

    vpn.setState(RemoteAccessVpn.State.Removed);
    _remoteAccessVpnDao.update(vpn.getServerAddressId(), vpn);

    boolean success = false;
    try {
      for (RemoteAccessVPNServiceProvider element : _vpnServiceProviders) {
        if (element.stopVpn(network, vpn)) {
          success = true;
          break;
        }
      }
    } finally {
      if (success) {
        // Cleanup corresponding ports
        List<? extends FirewallRule> vpnFwRules = _rulesDao.listByIpAndPurpose(ipId, Purpose.Vpn);
        Transaction txn = Transaction.currentTxn();

        boolean applyFirewall = false;
        List<FirewallRuleVO> fwRules = new ArrayList<FirewallRuleVO>();
        // if related firewall rule is created for the first vpn port, it would be created for the 2
        // other ports as well, so need to cleanup the backend
        if (_rulesDao.findByRelatedId(vpnFwRules.get(0).getId()) != null) {
          applyFirewall = true;
        }

        if (applyFirewall) {
          txn.start();

          for (FirewallRule vpnFwRule : vpnFwRules) {
            // don't apply on the backend yet; send all 3 rules in a banch
            _firewallMgr.revokeRelatedFirewallRule(vpnFwRule.getId(), false);
            fwRules.add(_rulesDao.findByRelatedId(vpnFwRule.getId()));
          }

          s_logger.debug(
              "Marked "
                  + fwRules.size()
                  + " firewall rules as Revoked as a part of disable remote access vpn");

          txn.commit();

          // now apply vpn rules on the backend
          s_logger.debug(
              "Reapplying firewall rules for ip id="
                  + ipId
                  + " as a part of disable remote access vpn");
          success = _firewallMgr.applyIngressFirewallRules(ipId, caller);
        }

        if (success) {
          try {
            txn.start();
            _remoteAccessVpnDao.remove(ipId);
            // Stop billing of VPN users when VPN is removed. VPN_User_ADD events will be generated
            // when VPN is created again
            List<VpnUserVO> vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId());
            for (VpnUserVO user : vpnUsers) {
              // VPN_USER_REMOVE event is already generated for users in Revoke state
              if (user.getState() != VpnUser.State.Revoke) {
                UsageEventUtils.publishUsageEvent(
                    EventTypes.EVENT_VPN_USER_REMOVE,
                    user.getAccountId(),
                    0,
                    user.getId(),
                    user.getUsername(),
                    user.getClass().getName(),
                    user.getUuid());
              }
            }
            if (vpnFwRules != null) {
              for (FirewallRule vpnFwRule : vpnFwRules) {
                _rulesDao.remove(vpnFwRule.getId());
                s_logger.debug(
                    "Successfully removed firewall rule with ip id="
                        + vpnFwRule.getSourceIpAddressId()
                        + " and port "
                        + vpnFwRule.getSourcePortStart()
                        + " as a part of vpn cleanup");
              }
            }
            txn.commit();
          } catch (Exception ex) {
            txn.rollback();
            s_logger.warn("Unable to release the three vpn ports from the firewall rules", ex);
          }
        }
      }
    }
  }
  @Override
  public void removeRule(FirewallRule rule) {

    // remove the rule
    _firewallDao.remove(rule.getId());
  }
  @Override
  public void detectRulesConflict(FirewallRule newRule) throws NetworkRuleConflictException {
    List<FirewallRuleVO> rules;
    if (newRule.getSourceIpAddressId() != null) {
      rules = _firewallDao.listByIpAndPurposeAndNotRevoked(newRule.getSourceIpAddressId(), null);
      assert (rules.size() >= 1)
          : "For network rules, we now always first persist the rule and then check for "
              + "network conflicts so we should at least have one rule at this point.";
    } else {
      // fetches only firewall egress rules.
      rules =
          _firewallDao.listByNetworkPurposeTrafficTypeAndNotRevoked(
              newRule.getNetworkId(), Purpose.Firewall, newRule.getTrafficType());
      assert (rules.size() >= 1);
    }

    for (FirewallRuleVO rule : rules) {
      if (rule.getId() == newRule.getId()) {
        continue; // Skips my own rule.
      }

      boolean oneOfRulesIsFirewall =
          ((rule.getPurpose() == Purpose.Firewall || newRule.getPurpose() == Purpose.Firewall)
              && ((newRule.getPurpose() != rule.getPurpose())
                  || (!newRule.getProtocol().equalsIgnoreCase(rule.getProtocol()))));

      // if both rules are firewall and their cidrs are different, we can skip port ranges
      // verification
      boolean bothRulesFirewall =
          (rule.getPurpose() == newRule.getPurpose() && rule.getPurpose() == Purpose.Firewall);
      boolean duplicatedCidrs = false;
      if (bothRulesFirewall) {
        // Verify that the rules have different cidrs
        _firewallDao.loadSourceCidrs(rule);
        _firewallDao.loadSourceCidrs((FirewallRuleVO) newRule);

        List<String> ruleCidrList = rule.getSourceCidrList();
        List<String> newRuleCidrList = newRule.getSourceCidrList();

        if (ruleCidrList == null || newRuleCidrList == null) {
          continue;
        }

        Collection<String> similar = new HashSet<String>(ruleCidrList);
        similar.retainAll(newRuleCidrList);

        if (similar.size() > 0) {
          duplicatedCidrs = true;
        }
      }

      if (!oneOfRulesIsFirewall) {
        if (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() != Purpose.StaticNat) {
          throw new NetworkRuleConflictException(
              "There is 1 to 1 Nat rule specified for the ip address id="
                  + newRule.getSourceIpAddressId());
        } else if (rule.getPurpose() != Purpose.StaticNat
            && newRule.getPurpose() == Purpose.StaticNat) {
          throw new NetworkRuleConflictException(
              "There is already firewall rule specified for the ip address id="
                  + newRule.getSourceIpAddressId());
        }
      }

      if (rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) {
        throw new NetworkRuleConflictException(
            "New rule is for a different network than what's specified in rule " + rule.getXid());
      }

      if (newRule.getProtocol().equalsIgnoreCase(NetUtils.ICMP_PROTO)
          && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())) {
        if (newRule.getIcmpCode().longValue() == rule.getIcmpCode().longValue()
            && newRule.getIcmpType().longValue() == rule.getIcmpType().longValue()
            && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())
            && duplicatedCidrs) {
          throw new InvalidParameterValueException(
              "New rule conflicts with existing rule id=" + rule.getId());
        }
      }

      boolean notNullPorts =
          (newRule.getSourcePortStart() != null
              && newRule.getSourcePortEnd() != null
              && rule.getSourcePortStart() != null
              && rule.getSourcePortEnd() != null);
      if (!notNullPorts) {
        continue;
      } else if (!oneOfRulesIsFirewall
          && !(bothRulesFirewall && !duplicatedCidrs)
          && ((rule.getSourcePortStart().intValue() <= newRule.getSourcePortStart().intValue()
                  && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortStart().intValue())
              || (rule.getSourcePortStart().intValue() <= newRule.getSourcePortEnd().intValue()
                  && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortEnd().intValue())
              || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortStart().intValue()
                  && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortStart().intValue())
              || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortEnd().intValue()
                  && newRule.getSourcePortEnd().intValue()
                      >= rule.getSourcePortEnd().intValue()))) {

        // we allow port forwarding rules with the same parameters but different protocols
        boolean allowPf =
            (rule.getPurpose() == Purpose.PortForwarding
                && newRule.getPurpose() == Purpose.PortForwarding
                && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol()));
        boolean allowStaticNat =
            (rule.getPurpose() == Purpose.StaticNat
                && newRule.getPurpose() == Purpose.StaticNat
                && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol()));

        if (!(allowPf || allowStaticNat || oneOfRulesIsFirewall)) {
          throw new NetworkRuleConflictException(
              "The range specified, "
                  + newRule.getSourcePortStart()
                  + "-"
                  + newRule.getSourcePortEnd()
                  + ", conflicts with rule "
                  + rule.getId()
                  + " which has "
                  + rule.getSourcePortStart()
                  + "-"
                  + rule.getSourcePortEnd());
        }
      }
    }

    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "No network rule conflicts detected for "
              + newRule
              + " against "
              + (rules.size() - 1)
              + " existing rules");
    }
  }