mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	server: Fix network statistics for vpc (#3944)
This contains 3 main changes (1) add NETWORK_STATS_ethX for all nics with public ips in VPC VRs (current: NETWORK_STATS_eth1) (2) DO NOT create records in user_statistics for each VPC tier (only one record per public nic per VPC VR) (3) send NetworkUsageCommand before unplugging a NIC with public IPs from VPC VR
This commit is contained in:
		
							parent
							
								
									76ba5c62d9
								
							
						
					
					
						commit
						63c91c1458
					
				| @ -26,6 +26,7 @@ import com.cloud.exception.InsufficientCapacityException; | ||||
| import com.cloud.exception.ResourceUnavailableException; | ||||
| import com.cloud.network.router.VirtualRouter; | ||||
| import com.cloud.user.Account; | ||||
| import com.cloud.vm.Nic; | ||||
| 
 | ||||
| public interface VirtualNetworkApplianceService { | ||||
|     /** | ||||
| @ -74,4 +75,6 @@ public interface VirtualNetworkApplianceService { | ||||
|      * @return | ||||
|      */ | ||||
|     boolean performRouterHealthChecks(long routerId); | ||||
| 
 | ||||
|     <T extends VirtualRouter> void collectNetworkStatistics(T router, Nic nic); | ||||
| } | ||||
|  | ||||
| @ -383,6 +383,7 @@ public class DomainRouterDaoImpl extends GenericDaoBase<DomainRouterVO, Long> im | ||||
|                 final RouterNetworkVO routerNtwkMap = new RouterNetworkVO(router.getId(), guestNetwork.getId(), guestNetwork.getGuestType()); | ||||
|                 _routerNetworkDao.persist(routerNtwkMap); | ||||
|                 //2) create user stats entry for the network | ||||
|                 if (router.getVpcId() == null) { | ||||
|                     UserStatisticsVO stats = | ||||
|                             _userStatsDao.findBy(router.getAccountId(), router.getDataCenterId(), guestNetwork.getId(), null, router.getId(), router.getType().toString()); | ||||
|                     if (stats == null) { | ||||
| @ -390,6 +391,7 @@ public class DomainRouterDaoImpl extends GenericDaoBase<DomainRouterVO, Long> im | ||||
|                                 new UserStatisticsVO(router.getAccountId(), router.getDataCenterId(), null, router.getId(), router.getType().toString(), guestNetwork.getId()); | ||||
|                         _userStatsDao.persist(stats); | ||||
|                     } | ||||
|                 } | ||||
|                 txn.commit(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -732,100 +732,7 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM | ||||
|                 s_logger.debug("Found " + routers.size() + " running routers. "); | ||||
| 
 | ||||
|                 for (final DomainRouterVO router : routers) { | ||||
|                     final String privateIP = router.getPrivateIpAddress(); | ||||
| 
 | ||||
|                     if (privateIP != null) { | ||||
|                         final boolean forVpc = router.getVpcId() != null; | ||||
|                         final List<? extends Nic> routerNics = _nicDao.listByVmId(router.getId()); | ||||
|                         for (final Nic routerNic : routerNics) { | ||||
|                             final Network network = _networkModel.getNetwork(routerNic.getNetworkId()); | ||||
|                             // Send network usage command for public nic in VPC VR | ||||
|                             // Send network usage command for isolated guest nic of non) VPC VR | ||||
| 
 | ||||
|                             //[TODO] Avoiding the NPE now, but I have to find out what is going on with the network. - Wilder Rodrigues | ||||
|                             if (network == null) { | ||||
|                                 s_logger.error("Could not find a network with ID => " + routerNic.getNetworkId() + ". It might be a problem!"); | ||||
|                                 continue; | ||||
|                             } | ||||
|                             if (forVpc && network.getTrafficType() == TrafficType.Public || !forVpc && network.getTrafficType() == TrafficType.Guest | ||||
|                                     && network.getGuestType() == Network.GuestType.Isolated) { | ||||
|                                 final NetworkUsageCommand usageCmd = new NetworkUsageCommand(privateIP, router.getHostName(), forVpc, routerNic.getIPv4Address()); | ||||
|                                 final String routerType = router.getType().toString(); | ||||
|                                 final UserStatisticsVO previousStats = _userStatsDao.findBy(router.getAccountId(), router.getDataCenterId(), network.getId(), | ||||
|                                         forVpc ? routerNic.getIPv4Address() : null, router.getId(), routerType); | ||||
|                                 NetworkUsageAnswer answer = null; | ||||
|                                 try { | ||||
|                                     answer = (NetworkUsageAnswer) _agentMgr.easySend(router.getHostId(), usageCmd); | ||||
|                                 } catch (final Exception e) { | ||||
|                                     s_logger.warn("Error while collecting network stats from router: " + router.getInstanceName() + " from host: " + router.getHostId(), e); | ||||
|                                     continue; | ||||
|                                 } | ||||
| 
 | ||||
|                                 if (answer != null) { | ||||
|                                     if (!answer.getResult()) { | ||||
|                                         s_logger.warn("Error while collecting network stats from router: " + router.getInstanceName() + " from host: " + router.getHostId() | ||||
|                                                 + "; details: " + answer.getDetails()); | ||||
|                                         continue; | ||||
|                                     } | ||||
|                                     try { | ||||
|                                         if (answer.getBytesReceived() == 0 && answer.getBytesSent() == 0) { | ||||
|                                             s_logger.debug("Recieved and Sent bytes are both 0. Not updating user_statistics"); | ||||
|                                             continue; | ||||
|                                         } | ||||
|                                         final NetworkUsageAnswer answerFinal = answer; | ||||
|                                         Transaction.execute(new TransactionCallbackNoReturn() { | ||||
|                                             @Override | ||||
|                                             public void doInTransactionWithoutResult(final TransactionStatus status) { | ||||
|                                                 final UserStatisticsVO stats = _userStatsDao.lock(router.getAccountId(), router.getDataCenterId(), network.getId(), | ||||
|                                                         forVpc ? routerNic.getIPv4Address() : null, router.getId(), routerType); | ||||
|                                                 if (stats == null) { | ||||
|                                                     s_logger.warn("unable to find stats for account: " + router.getAccountId()); | ||||
|                                                     return; | ||||
|                                                 } | ||||
| 
 | ||||
|                                                 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: " | ||||
|                                                             + answerFinal.getRouterName() + " Rcvd: " + answerFinal.getBytesReceived() + "Sent: " + answerFinal.getBytesSent()); | ||||
|                                                     return; | ||||
|                                                 } | ||||
| 
 | ||||
|                                                 if (stats.getCurrentBytesReceived() > answerFinal.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: " + answerFinal.getRouterName() + " Reported: " | ||||
|                                                                 + toHumanReadableSize(answerFinal.getBytesReceived()) + " Stored: " + toHumanReadableSize(stats.getCurrentBytesReceived())); | ||||
|                                                     } | ||||
|                                                     stats.setNetBytesReceived(stats.getNetBytesReceived() + stats.getCurrentBytesReceived()); | ||||
|                                                 } | ||||
|                                                 stats.setCurrentBytesReceived(answerFinal.getBytesReceived()); | ||||
|                                                 if (stats.getCurrentBytesSent() > answerFinal.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: " + answerFinal.getRouterName() + " Reported: " | ||||
|                                                                 + toHumanReadableSize(answerFinal.getBytesSent()) + " Stored: " + toHumanReadableSize(stats.getCurrentBytesSent())); | ||||
|                                                     } | ||||
|                                                     stats.setNetBytesSent(stats.getNetBytesSent() + stats.getCurrentBytesSent()); | ||||
|                                                 } | ||||
|                                                 stats.setCurrentBytesSent(answerFinal.getBytesSent()); | ||||
|                                                 if (!_dailyOrHourly) { | ||||
|                                                     // update agg bytes | ||||
|                                                     stats.setAggBytesSent(stats.getNetBytesSent() + stats.getCurrentBytesSent()); | ||||
|                                                     stats.setAggBytesReceived(stats.getNetBytesReceived() + stats.getCurrentBytesReceived()); | ||||
|                                                 } | ||||
|                                                 _userStatsDao.update(stats.getId(), stats); | ||||
|                                             } | ||||
|                                         }); | ||||
| 
 | ||||
|                                     } catch (final Exception e) { | ||||
|                                         s_logger.warn("Unable to update user statistics for account: " + router.getAccountId() + " Rx: " + toHumanReadableSize(answer.getBytesReceived()) + "; Tx: " | ||||
|                                                 + toHumanReadableSize(answer.getBytesSent())); | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     collectNetworkStatistics(router, null); | ||||
|                 } | ||||
|             } catch (final Exception e) { | ||||
|                 s_logger.warn("Error while collecting network stats", e); | ||||
| @ -3057,6 +2964,11 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM | ||||
|         // Collect network usage before stopping Vm | ||||
| 
 | ||||
|         final DomainRouterVO router = _routerDao.findById(profile.getVirtualMachine().getId()); | ||||
|         collectNetworkStatistics(router, null); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public <T extends VirtualRouter> void collectNetworkStatistics(final T router, final Nic nic) { | ||||
|         if (router == null) { | ||||
|             return; | ||||
|         } | ||||
| @ -3065,12 +2977,23 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM | ||||
| 
 | ||||
|         if (privateIP != null) { | ||||
|             final boolean forVpc = router.getVpcId() != null; | ||||
|             final List<? extends Nic> routerNics = _nicDao.listByVmId(router.getId()); | ||||
|             List<Nic> routerNics = new ArrayList<Nic>(); | ||||
|             if (nic != null) { | ||||
|                 routerNics.add(nic); | ||||
|             } else { | ||||
|                 routerNics.addAll(_nicDao.listByVmId(router.getId())); | ||||
|             } | ||||
|             for (final Nic routerNic : routerNics) { | ||||
|                 final Network network = _networkModel.getNetwork(routerNic.getNetworkId()); | ||||
|                 // Send network usage command for public nic in VPC VR | ||||
|                 // Send network usage command for isolated guest nic of non VPC | ||||
|                 // VR | ||||
| 
 | ||||
|                 //[TODO] Avoiding the NPE now, but I have to find out what is going on with the network. - Wilder Rodrigues | ||||
|                 if (network == null) { | ||||
|                     s_logger.error("Could not find a network with ID => " + routerNic.getNetworkId() + ". It might be a problem!"); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (forVpc && network.getTrafficType() == TrafficType.Public || !forVpc && network.getTrafficType() == TrafficType.Guest | ||||
|                         && network.getGuestType() == Network.GuestType.Isolated) { | ||||
|                     final NetworkUsageCommand usageCmd = new NetworkUsageCommand(privateIP, router.getHostName(), forVpc, routerNic.getIPv4Address()); | ||||
|  | ||||
| @ -40,6 +40,7 @@ import com.cloud.network.NetworkModel; | ||||
| import com.cloud.network.Networks.BroadcastDomainType; | ||||
| import com.cloud.network.Networks.IsolationType; | ||||
| import com.cloud.network.PublicIpAddress; | ||||
| import com.cloud.network.VpcVirtualNetworkApplianceService; | ||||
| import com.cloud.network.dao.FirewallRulesDao; | ||||
| import com.cloud.network.dao.IPAddressDao; | ||||
| import com.cloud.network.dao.IPAddressVO; | ||||
| @ -84,6 +85,7 @@ public class NicPlugInOutRules extends RuleApplier { | ||||
|         NetworkModel networkModel = visitor.getVirtualNetworkApplianceFactory().getNetworkModel(); | ||||
|         VirtualMachineManager itMgr = visitor.getVirtualNetworkApplianceFactory().getItMgr(); | ||||
|         NicDao nicDao = visitor.getVirtualNetworkApplianceFactory().getNicDao(); | ||||
|         VpcVirtualNetworkApplianceService routerService = visitor.getVirtualNetworkApplianceFactory().getRouterService(); | ||||
| 
 | ||||
|         // de-associate IPs before unplugging nics | ||||
|         if (!nicsToUnplug.isEmpty()) { | ||||
| @ -107,6 +109,12 @@ public class NicPlugInOutRules extends RuleApplier { | ||||
| 
 | ||||
|         // 1) Unplug the nics | ||||
|         for (Entry<String, PublicIpAddress> entry : nicsToUnplug.entrySet()) { | ||||
|             PublicIpAddress ip = entry.getValue(); | ||||
|             NicVO nic = nicDao.findByIp4AddressAndNetworkIdAndInstanceId(ip.getNetworkId(), _router.getId(), ip.getAddress().addr()); | ||||
|             if (nic != null) { | ||||
|                 s_logger.info("Collect network statistics for nic " + nic + " from router " + _router); | ||||
|                 routerService.collectNetworkStatistics(_router, nic); | ||||
|             } | ||||
|             Network publicNtwk = null; | ||||
|             try { | ||||
|                 publicNtwk = networkModel.getNetwork(entry.getValue().getNetworkId()); | ||||
|  | ||||
| @ -26,6 +26,7 @@ import com.cloud.dc.dao.HostPodDao; | ||||
| import com.cloud.dc.dao.VlanDao; | ||||
| import com.cloud.network.IpAddressManager; | ||||
| import com.cloud.network.NetworkModel; | ||||
| import com.cloud.network.VpcVirtualNetworkApplianceService; | ||||
| import com.cloud.network.dao.FirewallRulesDao; | ||||
| import com.cloud.network.dao.IPAddressDao; | ||||
| import com.cloud.network.dao.LoadBalancerDao; | ||||
| @ -98,6 +99,8 @@ public class VirtualNetworkApplianceFactory { | ||||
| 
 | ||||
|     @Inject | ||||
|     private NetworkTopologyContext _networkTopologyContext; | ||||
|     @Inject | ||||
|     private VpcVirtualNetworkApplianceService _routerService; | ||||
| 
 | ||||
|     public NetworkModel getNetworkModel() { | ||||
|         return _networkModel; | ||||
| @ -190,4 +193,8 @@ public class VirtualNetworkApplianceFactory { | ||||
|     public FirewallRulesDao getFirewallRulesDao() { | ||||
|         return _rulesDao; | ||||
|     } | ||||
| 
 | ||||
|     public VpcVirtualNetworkApplianceService getRouterService() { | ||||
|         return _routerService; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -41,6 +41,7 @@ import com.cloud.user.Account; | ||||
| import com.cloud.user.User; | ||||
| import com.cloud.utils.component.ManagerBase; | ||||
| import com.cloud.vm.DomainRouterVO; | ||||
| import com.cloud.vm.Nic; | ||||
| import com.cloud.vm.VirtualMachineProfile; | ||||
| 
 | ||||
| @Component | ||||
| @ -280,4 +281,10 @@ public class MockVpcVirtualNetworkApplianceManager extends ManagerBase implement | ||||
|         // TODO Auto-generated method stub | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public <T extends VirtualRouter> void collectNetworkStatistics(T router, Nic nic) { | ||||
|         // TODO Auto-generated method stub | ||||
|         return; | ||||
|     } | ||||
| } | ||||
| @ -476,11 +476,6 @@ class CsIP: | ||||
|                             "-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" % | ||||
|                             (self.dev, guestNetworkCidr, self.address['gateway'], self.dev)]) | ||||
| 
 | ||||
|             self.fw.append(["", "front", "-A NETWORK_STATS_%s -i %s -d %s" % | ||||
|                             ("eth1", "eth1", guestNetworkCidr)]) | ||||
|             self.fw.append(["", "front", "-A NETWORK_STATS_%s -o %s -s %s" % | ||||
|                             ("eth1", "eth1", guestNetworkCidr)]) | ||||
| 
 | ||||
|         if self.is_private_gateway(): | ||||
|             self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" % | ||||
|                             (self.address['network'], self.dev, self.dev)]) | ||||
| @ -518,6 +513,10 @@ class CsIP: | ||||
|                 ["mangle", "", "-A VPN_STATS_%s -i %s -m mark --mark 0x524/0xffffffff" % (self.dev, self.dev)]) | ||||
|             self.fw.append( | ||||
|                 ["", "front", "-A FORWARD -j NETWORK_STATS_%s" % self.dev]) | ||||
|             self.fw.append( | ||||
|                 ["", "front", "-A NETWORK_STATS_%s -s %s -o %s" % (self.dev, self.cl.get_vpccidr(), self.dev)]) | ||||
|             self.fw.append( | ||||
|                 ["", "front", "-A NETWORK_STATS_%s -d %s -i %s" % (self.dev, self.cl.get_vpccidr(), self.dev)]) | ||||
| 
 | ||||
|         self.fw.append(["", "front", "-A FORWARD -j NETWORK_STATS"]) | ||||
|         self.fw.append(["", "front", "-A INPUT -j NETWORK_STATS"]) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user