From b87800c15968368c8d6271f575ceb08bf565e947 Mon Sep 17 00:00:00 2001 From: kishan Date: Mon, 6 Aug 2012 03:19:58 +0530 Subject: [PATCH] bug CS-15852: Added VPN network usage. Uses vpn mark 0x525 to match VPN packets --- .../cloud/agent/api/NetworkUsageCommand.java | 9 +++ .../xen/resource/XenServer56Resource.java | 2 + .../config/opt/cloud/bin/vpc_netusage.sh | 41 +++++++++- .../VirtualNetworkApplianceManagerImpl.java | 78 ++++++++++++++++++- .../network/vpn/Site2SiteVpnManagerImpl.java | 11 ++- 5 files changed, 137 insertions(+), 4 deletions(-) diff --git a/api/src/com/cloud/agent/api/NetworkUsageCommand.java b/api/src/com/cloud/agent/api/NetworkUsageCommand.java index 14621ffd1dc..324e1a590eb 100644 --- a/api/src/com/cloud/agent/api/NetworkUsageCommand.java +++ b/api/src/com/cloud/agent/api/NetworkUsageCommand.java @@ -54,6 +54,15 @@ public class NetworkUsageCommand extends Command { this.vpcCIDR = vpcCIDR; } + public NetworkUsageCommand(String privateIP, String domRName, String option, boolean forVpc, String gatewayIP) + { + this.privateIP = privateIP; + this.domRName = domRName; + this.forVpc = forVpc; + this.gatewayIP = gatewayIP; + this.option = option; + } + public String getPrivateIP() { return privateIP; } diff --git a/core/src/com/cloud/hypervisor/xen/resource/XenServer56Resource.java b/core/src/com/cloud/hypervisor/xen/resource/XenServer56Resource.java index 0bc18500b3c..15237c18905 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/XenServer56Resource.java +++ b/core/src/com/cloud/hypervisor/xen/resource/XenServer56Resource.java @@ -180,6 +180,8 @@ public class XenServer56Resource extends CitrixResourceBase { args += " -v " + vpcCIDR; } else if (option.equals("reset")) { args += "-r"; + } else if (option.equals("vpn")) { + args += "-n"; } else { return new NetworkUsageAnswer(cmd, "success", 0L, 0L); } diff --git a/patches/systemvm/debian/config/opt/cloud/bin/vpc_netusage.sh b/patches/systemvm/debian/config/opt/cloud/bin/vpc_netusage.sh index 8ec44a1b90e..c70080b5010 100755 --- a/patches/systemvm/debian/config/opt/cloud/bin/vpc_netusage.sh +++ b/patches/systemvm/debian/config/opt/cloud/bin/vpc_netusage.sh @@ -15,6 +15,7 @@ source /root/func.sh source /opt/cloud/bin/vpc_func.sh +vpnoutmark="0x525" lock="biglock" locked=$(getLockFile $lock) if [ "$locked" != "1" ] @@ -42,6 +43,22 @@ create_usage_rules () { return $? } +create_vpn_usage_rules () { + iptables -N VPN_STATS_$ethDev > /dev/null + iptables -I FORWARD -j VPN_STATS_$ethDev > /dev/null + iptables-save|grep "VPN_STATS_$ethDev -i $ethDev" > /dev/null + if [ $? -gt 0 ] + then + iptables -A VPN_STATS_$ethDev -i $ethDev -m mark --mark $vpnoutmark > /dev/null + fi + iptables-save|grep "VPN_STATS_$ethDev -o $ethDev" > /dev/null + if [ $? -gt 0 ] + then + iptables -A VPN_STATS_$ethDev -o $ethDev -m mark --mark $vpnoutmark > /dev/null + fi + return $? +} + get_usage () { iptables -L NETWORK_STATS_$ethDev -n -v -x | awk '$1 ~ /^[0-9]+$/ { printf "%s:", $2}'; > /dev/null if [ $? -gt 0 ] @@ -51,6 +68,16 @@ get_usage () { fi } +get_vpn_usage () { + iptables -L VPN_STATS_$ethDev -n -v -x | awk '$1 ~ /^[0-9]+$/ { printf "%s:", $2}'; > /dev/null + if [ $? -gt 0 ] + then + printf $? + return 1 + fi +} + + reset_usage () { iptables -Z NETWORK_STATS_$ethDev > /dev/null if [ $? -gt 0 -a $? -ne 2 ] @@ -65,9 +92,10 @@ cflag= gflag= rflag= lflag= +vflag= +nflag= - -while getopts 'cgrl:v:' OPTION +while getopts 'cgnrl:v:' OPTION do case $OPTION in c) cflag=1 @@ -82,6 +110,8 @@ do v) vflag=1 vcidr="$OPTARG" ;; + n) nflag=1 + ;; i) #Do nothing, since it's parameter for host script ;; ?) usage @@ -94,6 +124,7 @@ ethDev=$(getEthByIp $publicIp) if [ "$cflag" == "1" ] then create_usage_rules + create_vpn_usage_rules unlock_exit 0 $lock $locked fi @@ -103,6 +134,12 @@ then unlock_exit $? $lock $locked fi +if [ "$nflag" == "1" ] +then + get_vpn_usage + unlock_exit $? $lock $locked +fi + if [ "$rflag" == "1" ] then reset_usage diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index dde3ab09f04..21e3b56dcc4 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -132,6 +132,7 @@ import com.cloud.network.RemoteAccessVpn; import com.cloud.network.Site2SiteCustomerGateway; import com.cloud.network.Site2SiteVpnConnection; import com.cloud.network.Site2SiteVpnConnectionVO; +import com.cloud.network.Site2SiteVpnGatewayVO; import com.cloud.network.SshKeysDistriMonitor; import com.cloud.network.VirtualNetworkApplianceService; import com.cloud.network.VirtualRouterProvider; @@ -763,10 +764,10 @@ VirtualMachineGuru, Listener { String privateIP = router.getPrivateIpAddress(); if (privateIP != null) { + boolean forVpc = router.getVpcId() != null; List routerNics = _nicDao.listByVmId(router.getId()); for (Nic routerNic : routerNics) { Network network = _networkMgr.getNetwork(routerNic.getNetworkId()); - boolean forVpc = router.getVpcId() != null; if ((forVpc && network.getTrafficType() == TrafficType.Public) || (!forVpc && network.getTrafficType() == TrafficType.Guest)) { final NetworkUsageCommand usageCmd = new NetworkUsageCommand(privateIP, router.getHostName(), forVpc, routerNic.getIp4Address()); @@ -838,6 +839,81 @@ VirtualMachineGuru, Listener { txn.close(); } } + if(forVpc){ + //Get VPN gateway + Site2SiteVpnGatewayVO s2sVpn = _s2sVpnGatewayDao.findByVpcId(router.getVpcId()); + if(s2sVpn != null){ + final NetworkUsageCommand vpnUsageCmd = new NetworkUsageCommand(privateIP, router.getHostName(), "vpn", forVpc, routerNic.getIp4Address()); + previousStats = _statsDao.findBy(s2sVpn.getAccountId(), router.getDataCenterIdToDeployIn(), network.getId(), + routerNic.getIp4Address(), s2sVpn.getId(), "VPNGateway"); + answer = null; + try { + answer = (NetworkUsageAnswer) _agentMgr.easySend(router.getHostId(), vpnUsageCmd); + } catch (Exception e) { + s_logger.warn("Error while collecting vpn network stats from router: "+router.getInstanceName()+" from host: "+router.getHostId(), e); + continue; + } + + if (answer != null) { + if (!answer.getResult()) { + s_logger.warn("Error while collecting vpn network stats from router: "+router.getInstanceName()+" from host: "+router.getHostId() + "; details: " + answer.getDetails()); + continue; + } + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + if ((answer.getBytesReceived() == 0) && (answer.getBytesSent() == 0)) { + s_logger.debug("Recieved and Sent bytes are both 0. Not updating user_statistics"); + continue; + } + txn.start(); + UserStatisticsVO stats = _statsDao.lock(s2sVpn.getAccountId(), router.getDataCenterIdToDeployIn(), network.getId(), + routerNic.getIp4Address(), s2sVpn.getId(), "VPNGateway"); + if (stats == null) { + s_logger.warn("unable to find vpn stats for account: " + router.getAccountId()+" vpc Id: "+router.getVpcId()); + continue; + } + + if(previousStats != null + && ((previousStats.getCurrentBytesReceived() != stats.getCurrentBytesReceived()) + || (previousStats.getCurrentBytesSent() != stats.getCurrentBytesSent()))){ + s_logger.debug("Router stats changed from the time NetworkUsageCommand was sent. " + + "Ignoring current answer. Router: "+answer.getRouterName()+" Rcvd: " + + answer.getBytesReceived()+ "Sent: " +answer.getBytesSent()); + continue; + } + + if (stats.getCurrentBytesReceived() > answer.getBytesReceived()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Received # of bytes that's less than the last one. " + + "Assuming something went wrong and persisting it. Router: " + + answer.getRouterName()+" Reported: " + answer.getBytesReceived() + + " Stored: " + stats.getCurrentBytesReceived()); + } + stats.setNetBytesReceived(stats.getNetBytesReceived() + stats.getCurrentBytesReceived()); + } + stats.setCurrentBytesReceived(answer.getBytesReceived()); + if (stats.getCurrentBytesSent() > answer.getBytesSent()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Received # of bytes that's less than the last one. " + + "Assuming something went wrong and persisting it. Router: " + + answer.getRouterName()+" Reported: " + answer.getBytesSent() + + " Stored: " + stats.getCurrentBytesSent()); + } + stats.setNetBytesSent(stats.getNetBytesSent() + stats.getCurrentBytesSent()); + } + stats.setCurrentBytesSent(answer.getBytesSent()); + _statsDao.update(stats.getId(), stats); + txn.commit(); + } catch (Exception e) { + txn.rollback(); + s_logger.warn("Unable to update user statistics for account: " + router.getAccountId() + + " Rx: " + answer.getBytesReceived() + "; Tx: " + answer.getBytesSent()); + } finally { + txn.close(); + } + } + } + } } } } diff --git a/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java b/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java index fc784132087..003d948a654 100644 --- a/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java @@ -49,7 +49,9 @@ import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.UserContext; +import com.cloud.user.UserStatisticsVO; import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserStatisticsDao; import com.cloud.utils.IdentityProxy; import com.cloud.utils.Ternary; import com.cloud.utils.component.Inject; @@ -77,7 +79,7 @@ public class Site2SiteVpnManagerImpl implements Site2SiteVpnManager, Manager { @Inject AccountDao _accountDao; @Inject VpcManager _vpcMgr; @Inject AccountManager _accountMgr; - + @Inject UserStatisticsDao _statsDao = null; String _name; @Override @@ -129,6 +131,13 @@ public class Site2SiteVpnManagerImpl implements Site2SiteVpnManager, Manager { Site2SiteVpnGatewayVO gw = new Site2SiteVpnGatewayVO(owner.getAccountId(), owner.getDomainId(), ips.get(0).getId(), vpcId); _vpnGatewayDao.persist(gw); + UserStatisticsVO stats = _statsDao.findBy(owner.getAccountId(), vpc.getZoneId(), ips.get(0).getSourceNetworkId(), + ips.get(0).getAddress().toString(), gw.getId(), "VPNGateway"); + if (stats == null) { + stats = new UserStatisticsVO(owner.getAccountId(), vpc.getZoneId(), ips.get(0).getAddress().toString(), gw.getId(), + "VPNGateway", ips.get(0).getSourceNetworkId()); + _statsDao.persist(stats); + } return gw; }