Line data Source code
1 : /* 2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. 3 : * Copyright Contributors to the OpenSDN project 4 : */ 5 : 6 : #include <oper/interface_common.h> 7 : #include <uve/interface_uve_stats_table.h> 8 : #include <uve/agent_uve_stats.h> 9 : 10 4 : InterfaceUveStatsTable::InterfaceUveStatsTable(Agent *agent, 11 4 : uint32_t default_intvl) 12 4 : : InterfaceUveTable(agent, default_intvl) { 13 4 : } 14 : 15 6 : InterfaceUveStatsTable::~InterfaceUveStatsTable() { 16 6 : } 17 : 18 0 : bool InterfaceUveStatsTable::FrameInterfaceObjectLog(UveInterfaceEntry* entry, 19 : EndpointSecurityStats *obj) const { 20 0 : assert(!entry->deleted_); 21 0 : const VmInterface *vm_intf = entry->intf_; 22 0 : if (vm_intf->cfg_name().empty()) { 23 0 : return false; 24 : } 25 0 : entry->FillEndpointStats(agent_, obj); 26 0 : return true; 27 : } 28 : 29 0 : bool InterfaceUveStatsTable::FrameInterfaceStatsMsg(UveInterfaceEntry* entry, 30 : VMIStats *uve) const { 31 0 : uint64_t in_band = 0, out_band = 0; 32 0 : bool diff_fip_list_non_zero = false; 33 0 : VmInterfaceStats if_stats; 34 0 : vector<VmFloatingIPStats> agg_fip_list; 35 0 : vector<VmFloatingIPStats> diff_fip_list; 36 : 37 0 : const VmInterface *vm_intf = entry->intf_; 38 0 : assert(!entry->deleted_); 39 0 : if (vm_intf->cfg_name().empty()) { 40 0 : return false; 41 : } 42 0 : uve->set_name(vm_intf->cfg_name()); 43 0 : entry->SetVMIStatsVnVm(uve); 44 : 45 0 : const Interface *intf = static_cast<const Interface *>(vm_intf); 46 0 : AgentUveStats *agent_uve = static_cast<AgentUveStats *>(agent_->uve()); 47 : StatsManager::InterfaceStats *s = 48 0 : agent_uve->stats_manager()->GetInterfaceStats(intf); 49 0 : if (s == NULL) { 50 0 : return false; 51 : } 52 : 53 0 : AgentDropStats ds; 54 0 : agent_uve->stats_manager()->BuildDropStats(s->drop_stats, ds); 55 0 : uve->set_raw_drop_stats(ds); 56 : 57 : /* Send aggregate interface stats always */ 58 0 : if_stats.set_in_pkts(s->in_pkts); 59 0 : if_stats.set_in_bytes(s->in_bytes); 60 0 : if_stats.set_out_pkts(s->out_pkts); 61 0 : if_stats.set_out_bytes(s->out_bytes); 62 0 : uve->set_raw_if_stats(if_stats); 63 : 64 : /* Compute bandwidth only if there is change in statistics */ 65 : uint64_t in_b, out_b; 66 0 : s->GetDiffStats(&in_b, &out_b); 67 0 : if ((in_b != 0) || (out_b != 0)) { 68 0 : in_band = GetVmPortBandwidth(s, true); 69 0 : out_band = GetVmPortBandwidth(s, false); 70 : } 71 : 72 0 : if (entry->InBandChanged(in_band)) { 73 0 : uve->set_in_bw_usage(in_band); 74 0 : entry->uve_stats_.set_in_bw_usage(in_band); 75 : } 76 0 : if (entry->OutBandChanged(out_band)) { 77 0 : uve->set_out_bw_usage(out_band); 78 0 : entry->uve_stats_.set_out_bw_usage(out_band); 79 : } 80 0 : s->stats_time = UTCTimestampUsec(); 81 : 82 : /* Make sure that update of prev_in_bytes and prev_out_bytes are done only 83 : * after GetVmPortBandwidth is done for both directions as they get used 84 : * in those APIs. */ 85 0 : s->UpdatePrevStats(); 86 : 87 0 : PortBucketBitmap map; 88 0 : L4PortBitmap &port_bmap = entry->port_bitmap_; 89 0 : port_bmap.Encode(map); 90 0 : if (entry->PortBitmapChanged(map)) { 91 0 : uve->set_port_bucket_bmap(map); 92 0 : entry->uve_stats_.set_port_bucket_bmap(map); 93 : } 94 : 95 0 : FrameFipStatsMsg(vm_intf, agg_fip_list, diff_fip_list, 96 : diff_fip_list_non_zero); 97 0 : if (entry->FipAggStatsChanged(agg_fip_list)) { 98 0 : uve->set_fip_agg_stats(agg_fip_list); 99 0 : entry->uve_stats_.set_fip_agg_stats(agg_fip_list); 100 : } 101 : /* Diff stats need not be sent if the value of the stats is 0. 102 : * If any of the entry in diff_fip_list has non-zero stats, then 103 : * diff_fip_list_non_zero is expected to be true */ 104 0 : if (diff_fip_list_non_zero) { 105 0 : uve->set_fip_diff_stats(diff_fip_list); 106 : } 107 : 108 0 : VrouterFlowRate flow_rate; 109 0 : uint64_t created = 0, aged = 0; 110 0 : uint32_t active_flows = 0; 111 0 : agent_->pkt()->get_flow_proto()->InterfaceFlowCount(vm_intf, &created, 112 : &aged, &active_flows); 113 0 : bool built = agent_uve->stats_manager()->BuildFlowRate(s->added, s->deleted, 114 0 : s->flow_info, 115 : flow_rate); 116 0 : if (built) { 117 0 : flow_rate.set_active_flows(active_flows); 118 0 : uve->set_flow_rate(flow_rate); 119 : } 120 : /* Populate TagSet and policy-list in UVE */ 121 0 : entry->FillTagSetAndPolicyList(uve); 122 : 123 0 : return true; 124 0 : } 125 : 126 0 : void InterfaceUveStatsTable::SendInterfaceStatsMsg(UveInterfaceEntry* entry) { 127 0 : if (entry->deleted_) { 128 0 : return; 129 : } 130 0 : VMIStats uve; 131 : 132 0 : bool send = FrameInterfaceStatsMsg(entry, &uve); 133 0 : if (send) { 134 0 : DispatchVMIStatsMsg(uve); 135 : } 136 0 : EndpointSecurityStats *obj_log = ENDPOINT_SECURITY_STATS_CREATE(); 137 0 : send = FrameInterfaceObjectLog(entry, obj_log); 138 0 : if (send) { 139 0 : DispatchInterfaceObjectLog(obj_log); 140 : } 141 0 : } 142 : 143 0 : void InterfaceUveStatsTable::SendInterfaceStats(void) { 144 0 : InterfaceMap::iterator it = interface_tree_.begin(); 145 0 : while (it != interface_tree_.end()) { 146 0 : UveInterfaceEntry* entry = it->second.get(); 147 : { 148 0 : std::scoped_lock lock(entry->mutex_); 149 0 : SendInterfaceStatsMsg(entry); 150 0 : } 151 0 : it++; 152 : } 153 0 : } 154 : 155 0 : uint64_t InterfaceUveStatsTable::GetVmPortBandwidth 156 : (StatsManager::InterfaceStats *s, bool dir_in) const { 157 0 : if (s->stats_time == 0) { 158 0 : return 0; 159 : } 160 : uint64_t bits; 161 0 : if (dir_in) { 162 0 : bits = (s->in_bytes - s->prev_in_bytes) * 8; 163 : } else { 164 0 : bits = (s->out_bytes - s->prev_out_bytes) * 8; 165 : } 166 0 : uint64_t cur_time = UTCTimestampUsec(); 167 0 : uint64_t b_intvl = agent_->uve()->bandwidth_intvl(); 168 0 : uint64_t diff_seconds = (cur_time - s->stats_time) / b_intvl; 169 0 : if (diff_seconds == 0) { 170 0 : return 0; 171 : } 172 0 : return bits/diff_seconds; 173 : } 174 : 175 22 : void InterfaceUveStatsTable::UpdateFloatingIpStats(const FipInfo &fip_info) { 176 22 : Interface *intf = dynamic_cast<Interface *> 177 22 : (agent_->interface_table()->FindActiveEntry(&fip_info.fip_vmi_)); 178 22 : if (intf == NULL) { 179 0 : return; 180 : } 181 22 : std::scoped_lock lock(interface_tree_mutex_); 182 22 : VmInterface *vmi = static_cast<VmInterface *>(intf); 183 22 : InterfaceMap::iterator intf_it = interface_tree_.find(vmi->cfg_name()); 184 : 185 : /* 186 : * 1. VM interface with floating-ip becomes active 187 : * 2. Flow is created on this interface and interface floating ip info is 188 : * stored in flow record 189 : * 3. VM Interface is disassociated from VM 190 : * 4. VM Interface info is removed from interface_tree_ because of 191 : * disassociation 192 : * 5. FlowStats collection task initiates export of flow stats 193 : * 6. Since interface is absent in interface_tree_ we cannot update 194 : * stats in this case 195 : */ 196 22 : if (intf_it != interface_tree_.end()) { 197 22 : UveInterfaceEntry *entry = intf_it->second.get(); 198 22 : entry->UpdateFloatingIpStats(fip_info); 199 : } 200 22 : } 201 : 202 0 : bool InterfaceUveStatsTable::FrameFipStatsMsg(const VmInterface *itf, 203 : vector<VmFloatingIPStats> &fip_list, 204 : vector<VmFloatingIPStats> &diff_list, 205 : bool &diff_list_send) const { 206 0 : bool changed = false; 207 0 : diff_list_send = false; 208 0 : InterfaceMap::const_iterator it = interface_tree_.find(itf->cfg_name()); 209 : 210 0 : if (it != interface_tree_.end()) { 211 0 : UveInterfaceEntry *entry = it->second.get(); 212 0 : changed = entry->FillFloatingIpStats(fip_list, diff_list, 213 : diff_list_send); 214 : } 215 0 : return changed; 216 : } 217 : 218 : 219 150 : void InterfaceUveStatsTable::UpdatePortBitmap 220 : (const string &name, uint8_t proto, uint16_t sport, uint16_t dport) { 221 150 : std::scoped_lock lock(interface_tree_mutex_); 222 150 : InterfaceMap::const_iterator it = interface_tree_.find(name); 223 : 224 150 : if (it != interface_tree_.end()) { 225 150 : UveInterfaceEntry *entry = it->second.get(); 226 150 : entry->UpdatePortBitmap(proto, sport, dport); 227 : } 228 150 : } 229 : 230 0 : InterfaceUveTable::FloatingIp * InterfaceUveStatsTable::FipEntry 231 : (uint32_t fip, const string &vn, Interface *intf) { 232 0 : std::scoped_lock lock(interface_tree_mutex_); 233 0 : VmInterface *vmi = static_cast<VmInterface *>(intf); 234 0 : InterfaceMap::iterator intf_it = interface_tree_.find(vmi->cfg_name()); 235 : 236 0 : if (intf_it == interface_tree_.end()) { 237 0 : return NULL; 238 : } 239 : 240 0 : UveInterfaceEntry *entry = intf_it->second.get(); 241 0 : return entry->FipEntry(fip, vn); 242 0 : } 243 : 244 179 : void InterfaceUveStatsTable::IncrInterfaceAceStats 245 : (const FlowUveStatsRequest *req) { 246 179 : if (!req->sg_info_valid()) { 247 10 : return; 248 : } 249 169 : InterfaceMap::iterator intf_it = interface_tree_.find(req->interface()); 250 : 251 169 : if (intf_it != interface_tree_.end()) { 252 169 : UveInterfaceEntry *entry = intf_it->second.get(); 253 169 : entry->UpdateInterfaceAceStats(req->sg_rule_uuid()); 254 : } 255 : } 256 : 257 208 : bool InterfaceUveStatsTable::IncrInterfaceEndpointHits(const string &itf, 258 : const FlowUveFwPolicyInfo &info) { 259 208 : if (!info.is_valid_) { 260 66 : return false; 261 : } 262 142 : InterfaceMap::iterator intf_it = interface_tree_.find(itf); 263 : 264 142 : if (intf_it != interface_tree_.end()) { 265 142 : UveInterfaceEntry *entry = intf_it->second.get(); 266 : /* We don't send EndpointSecurityStats objectlog for deleted interfaces. 267 : * So, there is no need to update stats on deleted interfaces */ 268 142 : if (entry->deleted_) { 269 128 : return false; 270 : } 271 14 : entry->UpdateInterfaceFwPolicyStats(info); 272 14 : return true; 273 : } 274 0 : return false; 275 : } 276 : 277 0 : void InterfaceUveStatsTable::SendInterfaceAceStats(const string &name, 278 : UveInterfaceEntry *entry) { 279 0 : VMIStats uve; 280 0 : if (entry->FrameInterfaceAceStatsMsg(name, &uve)) { 281 0 : DispatchVMIStatsMsg(uve); 282 : } 283 0 : } 284 : 285 43 : void InterfaceUveStatsTable::UpdateVmiTagBasedStats(const EndpointStatsInfo 286 : &info) { 287 43 : std::scoped_lock lock(interface_tree_mutex_); 288 43 : InterfaceMap::iterator intf_it = interface_tree_.find(info.vmi->cfg_name()); 289 43 : if (intf_it != interface_tree_.end()) { 290 27 : UveInterfaceEntry *entry = intf_it->second.get(); 291 27 : entry->UpdateSecurityPolicyStats(info); 292 : } 293 43 : } 294 : 295 0 : void InterfaceUveStatsTable::BuildInterfaceUveInfo(InterfaceUveInfoResp *r) { 296 : 297 : vector<InterfaceUveInfo> &list = 298 0 : const_cast<std::vector<InterfaceUveInfo>&>(r->get_resp_list()); 299 0 : std::scoped_lock lock(interface_tree_mutex_); 300 0 : InterfaceMap::iterator intf_it = interface_tree_.begin(); 301 0 : while (intf_it != interface_tree_.end()) { 302 0 : InterfaceUveInfo item; 303 0 : UveInterfaceEntry *entry = intf_it->second.get(); 304 0 : ++intf_it; 305 0 : entry->BuildInterfaceUveInfo(&item); 306 0 : list.push_back(item); 307 0 : } 308 : 309 0 : } 310 : 311 0 : void InterfaceUveInfoReq::HandleRequest() const { 312 0 : InterfaceUveInfoResp *resp = new InterfaceUveInfoResp(); 313 0 : Agent *agent = Agent::GetInstance(); 314 : InterfaceUveStatsTable *table = static_cast<InterfaceUveStatsTable *> 315 0 : (agent->uve()->interface_uve_table()); 316 0 : table->BuildInterfaceUveInfo(resp); 317 0 : resp->set_context(context()); 318 0 : resp->Response(); 319 0 : return; 320 : }