Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <sstream>
6 : #include <fstream>
7 : #include <uve/vrouter_uve_entry.h>
8 : #include <cfg/cfg_init.h>
9 : #include <init/agent_param.h>
10 : #include <oper/interface_common.h>
11 : #include <oper/interface.h>
12 : #include <oper/vm.h>
13 : #include <oper/vn.h>
14 : #include <oper/mirror_table.h>
15 : #include <controller/controller_peer.h>
16 : #include <uve/agent_uve_stats.h>
17 : #include <uve/vrouter_uve_entry.h>
18 : #include <cmn/agent_stats.h>
19 : #include <base/cpuinfo.h>
20 : #include <base/util.h>
21 : #include <cmn/agent_cmn.h>
22 : #include <vrouter/flow_stats/flow_stats_manager.h>
23 :
24 : using namespace std;
25 :
26 6 : VrouterUveEntry::VrouterUveEntry(Agent *agent)
27 6 : : VrouterUveEntryBase(agent), bandwidth_count_(0), port_bitmap_(),
28 6 : flow_info_(), vrf_walk_id_(DBTableWalker::kInvalidWalkerId) {
29 6 : start_time_ = UTCTimestampUsec();
30 6 : }
31 :
32 9 : VrouterUveEntry::~VrouterUveEntry() {
33 9 : }
34 :
35 0 : bool VrouterUveEntry::SendVrouterMsg() {
36 : static bool first = true;
37 0 : VrouterStatsAgent stats;
38 :
39 0 : VrouterUveEntryBase::SendVrouterMsg();
40 :
41 0 : stats.set_name(agent_->agent_name());
42 :
43 0 : if (prev_stats_.get_in_tpkts() !=
44 0 : agent_->stats()->in_pkts() || first) {
45 0 : stats.set_in_tpkts(agent_->stats()->in_pkts());
46 0 : prev_stats_.set_in_tpkts(agent_->stats()->in_pkts());
47 : }
48 :
49 0 : if (prev_stats_.get_in_bytes() !=
50 0 : agent_->stats()->in_bytes() || first) {
51 0 : stats.set_in_bytes(agent_->stats()->in_bytes());
52 0 : prev_stats_.set_in_bytes(agent_->stats()->in_bytes());
53 : }
54 :
55 0 : if (prev_stats_.get_out_tpkts() !=
56 0 : agent_->stats()->out_pkts() || first) {
57 0 : stats.set_out_tpkts(agent_->stats()->out_pkts());
58 0 : prev_stats_.set_out_tpkts(agent_->stats()->out_pkts());
59 : }
60 :
61 0 : if (prev_stats_.get_out_bytes() !=
62 0 : agent_->stats()->out_bytes() || first) {
63 0 : stats.set_out_bytes(agent_->stats()->out_bytes());
64 0 : prev_stats_.set_out_bytes(agent_->stats()->out_bytes());
65 : }
66 :
67 0 : if (prev_stats_.get_exception_packets() !=
68 0 : agent_->stats()->pkt_exceptions() || first) {
69 0 : stats.set_exception_packets(agent_->stats()->pkt_exceptions());
70 0 : prev_stats_.set_exception_packets(agent_->stats()->pkt_exceptions());
71 : }
72 :
73 0 : if (prev_stats_.get_exception_packets_dropped() !=
74 0 : agent_->stats()->pkt_dropped() || first) {
75 0 : stats.set_exception_packets_dropped(agent_->stats()->pkt_dropped());
76 0 : prev_stats_.set_exception_packets_dropped(agent_->stats()->
77 : pkt_dropped());
78 : }
79 :
80 0 : uint64_t e_pkts_allowed = (agent_->stats()->pkt_exceptions() -
81 0 : agent_->stats()->pkt_dropped());
82 0 : if (prev_stats_.get_exception_packets_allowed() != e_pkts_allowed) {
83 0 : stats.set_exception_packets_allowed(e_pkts_allowed);
84 0 : prev_stats_.set_exception_packets_allowed(e_pkts_allowed);
85 : }
86 :
87 0 : if (prev_stats_.get_total_flows() !=
88 0 : agent_->stats()->flow_created() || first) {
89 0 : stats.set_total_flows(agent_->stats()->flow_created());
90 0 : prev_stats_.set_total_flows(agent_->stats()->
91 : flow_created());
92 : }
93 :
94 0 : if (prev_stats_.get_aged_flows() !=
95 0 : agent_->stats()->flow_aged() || first) {
96 0 : stats.set_aged_flows(agent_->stats()->flow_aged());
97 0 : prev_stats_.set_aged_flows(agent_->stats()->flow_aged());
98 : }
99 0 : map<string, PhyIfStats> phy_if_list;
100 0 : map<string, PhyIfInfo> phy_if_info;
101 0 : map<string, AgentDropStats> phy_if_ds;
102 0 : BuildPhysicalInterfaceList(phy_if_list, phy_if_info, phy_if_ds);
103 0 : stats.set_raw_phy_if_stats(phy_if_list);
104 0 : stats.set_raw_phy_if_drop_stats(phy_if_ds);
105 :
106 0 : if (prev_stats_.get_phy_if_info() != phy_if_info) {
107 0 : stats.set_phy_if_info(phy_if_info);
108 0 : prev_stats_.set_phy_if_info(phy_if_info);
109 : }
110 :
111 0 : bandwidth_count_++;
112 0 : if (first) {
113 0 : InitPrevStats();
114 : //First sample of bandwidth is sent after 1.5, 5.5 and 10.5 minutes
115 0 : bandwidth_count_ = 0;
116 : }
117 : // 1 minute bandwidth
118 0 : if (bandwidth_count_ && ((bandwidth_count_ % bandwidth_mod_1min) == 0)) {
119 0 : vector<AgentIfBandwidth> phy_if_blist;
120 0 : double in_util = 0, out_util = 0;
121 0 : map<string,uint64_t> inb,outb;
122 0 : BuildPhysicalInterfaceBandwidth(inb, outb, 1, in_util, out_util);
123 : /* One minute bandwidth has 'tags' annotation and has to be sent
124 : * always regardless of change in bandwidth or not */
125 0 : stats.set_phy_band_in_bps(inb);
126 0 : stats.set_phy_band_out_bps(outb);
127 0 : if (in_util != prev_stats_.get_total_in_bandwidth_utilization()) {
128 0 : stats.set_total_in_bandwidth_utilization(in_util);
129 0 : prev_stats_.set_total_in_bandwidth_utilization(in_util);
130 : }
131 0 : if (out_util != prev_stats_.get_total_out_bandwidth_utilization()) {
132 0 : stats.set_total_out_bandwidth_utilization(out_util);
133 0 : prev_stats_.set_total_out_bandwidth_utilization(out_util);
134 : }
135 0 : }
136 :
137 : // 5 minute bandwidth
138 0 : if (bandwidth_count_ && ((bandwidth_count_ % bandwidth_mod_5min) == 0)) {
139 0 : vector<AgentIfBandwidth> phy_if_blist;
140 0 : BuildPhysicalInterfaceBandwidth(phy_if_blist, 5);
141 0 : if (prev_stats_.get_phy_if_5min_usage() != phy_if_blist) {
142 0 : stats.set_phy_if_5min_usage(phy_if_blist);
143 0 : prev_stats_.set_phy_if_5min_usage(phy_if_blist);
144 : }
145 0 : }
146 :
147 0 : VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE, boost::uuids::nil_uuid(),
148 0 : agent_->vhost_interface_name());
149 0 : const Interface *vhost = static_cast<const Interface *>
150 0 : (agent_->interface_table()->FindActiveEntry(&key));
151 0 : AgentUveStats *uve = static_cast<AgentUveStats *>(agent_->uve());
152 : const StatsManager::InterfaceStats *s =
153 0 : uve->stats_manager()->GetInterfaceStats(vhost);
154 0 : if (s != NULL) {
155 0 : AgentIfStats vhost_stats;
156 0 : AgentDropStats vhost_ds;
157 0 : vhost_stats.set_name(agent_->vhost_interface_name());
158 0 : vhost_stats.set_in_pkts(s->in_pkts);
159 0 : vhost_stats.set_in_bytes(s->in_bytes);
160 0 : vhost_stats.set_out_pkts(s->out_pkts);
161 0 : vhost_stats.set_out_bytes(s->out_bytes);
162 0 : vhost_stats.set_speed(s->speed);
163 0 : vhost_stats.set_duplexity(s->duplexity);
164 0 : uve->stats_manager()->BuildDropStats(s->drop_stats, vhost_ds);
165 0 : stats.set_raw_vhost_stats(vhost_stats);
166 0 : stats.set_raw_vhost_drop_stats(vhost_ds);
167 0 : }
168 :
169 0 : SetVrouterPortBitmap(stats);
170 :
171 0 : AgentDropStats ds;
172 0 : FetchDropStats(ds);
173 0 : stats.set_raw_drop_stats(ds);
174 :
175 0 : if (first) {
176 0 : stats.set_uptime(start_time_);
177 : }
178 0 : AgentStats::FlowCounters &added = agent_->stats()->added();
179 0 : AgentStats::FlowCounters &deleted = agent_->stats()->deleted();
180 0 : uint32_t active_flows = agent_->pkt()->get_flow_proto()->FlowCount();
181 :
182 0 : VrouterFlowRate flow_rate;
183 0 : bool built = uve->stats_manager()->BuildFlowRate(added, deleted, flow_info_,
184 : flow_rate);
185 0 : if (built) {
186 0 : flow_rate.set_active_flows(active_flows);
187 0 : stats.set_flow_rate(flow_rate);
188 : }
189 :
190 0 : DispatchVrouterStatsMsg(stats);
191 0 : first = false;
192 :
193 : //Send VrouterControlStats UVE
194 0 : SendVrouterControlStats();
195 0 : return true;
196 0 : }
197 :
198 0 : uint64_t VrouterUveEntry::CalculateBandwitdh(uint64_t bytes, int speed_mbps,
199 : int diff_seconds,
200 : double *utilization_bps) const {
201 0 : if (utilization_bps) *utilization_bps = 0;
202 0 : if (bytes == 0 || speed_mbps == 0) {
203 0 : return 0;
204 : }
205 0 : uint64_t bits = bytes * 8;
206 0 : if (diff_seconds == 0) {
207 0 : return 0;
208 : }
209 : /* Compute bandwidth in bps */
210 0 : uint64_t bps = bits/diff_seconds;
211 :
212 : /* Compute network utilization in percentage */
213 0 : uint64_t speed_bps = speed_mbps * 1024 * 1024;
214 0 : double bps_double = bits/diff_seconds;
215 0 : if (utilization_bps) *utilization_bps = (bps_double * 100)/speed_bps;
216 0 : return bps;
217 : }
218 :
219 0 : uint64_t VrouterUveEntry::GetBandwidthUsage(StatsManager::InterfaceStats *s,
220 : bool dir_in, int mins,
221 : double *util) const {
222 :
223 : uint64_t bytes;
224 0 : if (dir_in) {
225 0 : switch (mins) {
226 0 : case 1:
227 0 : bytes = s->in_bytes - s->prev_in_bytes;
228 0 : s->prev_in_bytes = s->in_bytes;
229 0 : break;
230 0 : default:
231 0 : bytes = s->in_bytes - s->prev_5min_in_bytes;
232 0 : s->prev_5min_in_bytes = s->in_bytes;
233 0 : break;
234 : }
235 : } else {
236 0 : switch (mins) {
237 0 : case 1:
238 0 : bytes = s->out_bytes - s->prev_out_bytes;
239 0 : s->prev_out_bytes = s->out_bytes;
240 0 : break;
241 0 : default:
242 0 : bytes = s->out_bytes - s->prev_5min_out_bytes;
243 0 : s->prev_5min_out_bytes = s->out_bytes;
244 0 : break;
245 : }
246 : }
247 0 : return CalculateBandwitdh(bytes, s->speed, (mins * 60), util);
248 : }
249 :
250 0 : bool VrouterUveEntry::BuildPhysicalInterfaceList(map<string, PhyIfStats> &list,
251 : map<string, PhyIfInfo> &info,
252 : map<string, AgentDropStats> &dsmap)
253 : const {
254 0 : bool changed = false;
255 0 : PhysicalInterfaceSet::const_iterator it = phy_intf_set_.begin();
256 0 : while (it != phy_intf_set_.end()) {
257 0 : const Interface *intf = *it;
258 0 : ++it;
259 0 : AgentUveStats *uve = static_cast<AgentUveStats *>(agent_->uve());
260 : StatsManager::InterfaceStats *s =
261 0 : uve->stats_manager()->GetInterfaceStats(intf);
262 0 : if (s == NULL) {
263 0 : continue;
264 : }
265 0 : PhyIfStats phy_stat_entry;
266 0 : phy_stat_entry.set_in_pkts(s->in_pkts);
267 0 : phy_stat_entry.set_in_bytes(s->in_bytes);
268 0 : phy_stat_entry.set_out_pkts(s->out_pkts);
269 0 : phy_stat_entry.set_out_bytes(s->out_bytes);
270 0 : list.insert(make_pair(intf->name(), phy_stat_entry));
271 :
272 0 : PhyIfInfo phy_if_info;
273 0 : phy_if_info.set_speed(s->speed);
274 0 : phy_if_info.set_duplexity(s->duplexity);
275 0 : info.insert(make_pair(intf->name(), phy_if_info));
276 :
277 0 : AgentDropStats ds;
278 0 : uve->stats_manager()->BuildDropStats(s->drop_stats, ds);
279 0 : dsmap.insert(make_pair(intf->name(), ds));
280 0 : changed = true;
281 0 : }
282 0 : return changed;
283 : }
284 :
285 0 : bool VrouterUveEntry::BuildPhysicalInterfaceBandwidth
286 : (vector<AgentIfBandwidth> &phy_if_list, uint8_t mins) const {
287 : uint64_t in_band, out_band;
288 0 : bool changed = false;
289 :
290 0 : PhysicalInterfaceSet::const_iterator it = phy_intf_set_.begin();
291 0 : while (it != phy_intf_set_.end()) {
292 0 : const Interface *intf = *it;
293 0 : AgentUveStats *uve = static_cast<AgentUveStats *>(agent_->uve());
294 : StatsManager::InterfaceStats *s =
295 0 : uve->stats_manager()->GetInterfaceStats(intf);
296 0 : if (s == NULL) {
297 0 : continue;
298 : }
299 0 : AgentIfBandwidth phy_stat_entry;
300 0 : phy_stat_entry.set_name(intf->name());
301 0 : in_band = GetBandwidthUsage(s, true, mins, NULL);
302 0 : out_band = GetBandwidthUsage(s, false, mins, NULL);
303 0 : phy_stat_entry.set_in_bandwidth_usage(in_band);
304 0 : phy_stat_entry.set_out_bandwidth_usage(out_band);
305 0 : phy_if_list.push_back(phy_stat_entry);
306 0 : changed = true;
307 0 : ++it;
308 0 : }
309 0 : return changed;
310 : }
311 :
312 0 : bool VrouterUveEntry::BuildPhysicalInterfaceBandwidth
313 : (map<string,uint64_t> &imp, map<string,uint64_t> &omp,
314 : uint8_t mins, double &in_avg_util,
315 : double &out_avg_util) const {
316 : uint64_t in_band, out_band;
317 : double in_util, out_util;
318 0 : bool changed = false;
319 0 : int num_intfs = 0;
320 0 : in_avg_util = 0;
321 0 : out_avg_util = 0;
322 :
323 0 : PhysicalInterfaceSet::const_iterator it = phy_intf_set_.begin();
324 0 : while (it != phy_intf_set_.end()) {
325 0 : const Interface *intf = *it;
326 0 : ++it;
327 0 : AgentUveStats *uve = static_cast<AgentUveStats *>(agent_->uve());
328 : StatsManager::InterfaceStats *s =
329 0 : uve->stats_manager()->GetInterfaceStats(intf);
330 0 : if (s == NULL) {
331 0 : continue;
332 : }
333 0 : AgentIfBandwidth phy_stat_entry;
334 0 : phy_stat_entry.set_name(intf->name());
335 0 : in_band = GetBandwidthUsage(s, true, mins, &in_util);
336 0 : out_band = GetBandwidthUsage(s, false, mins, &out_util);
337 0 : imp.insert(make_pair(intf->name(),in_band));
338 0 : omp.insert(make_pair(intf->name(),out_band));
339 0 : changed = true;
340 0 : in_avg_util += in_util;
341 0 : out_avg_util += out_util;
342 0 : num_intfs++;
343 0 : }
344 0 : if (num_intfs) {
345 0 : in_avg_util /= num_intfs;
346 0 : out_avg_util /= num_intfs;
347 : }
348 0 : return changed;
349 : }
350 :
351 0 : void VrouterUveEntry::InitPrevStats() const {
352 0 : PhysicalInterfaceSet::const_iterator it = phy_intf_set_.begin();
353 0 : while (it != phy_intf_set_.end()) {
354 0 : const Interface *intf = *it;
355 0 : AgentUveStats *uve = static_cast<AgentUveStats *>(agent_->uve());
356 : StatsManager::InterfaceStats *s =
357 0 : uve->stats_manager()->GetInterfaceStats(intf);
358 0 : if (s == NULL) {
359 0 : continue;
360 : }
361 0 : s->prev_in_bytes = s->in_bytes;
362 0 : s->prev_5min_in_bytes = s->in_bytes;
363 0 : s->prev_out_bytes = s->out_bytes;
364 0 : s->prev_5min_out_bytes = s->out_bytes;
365 0 : ++it;
366 : }
367 0 : }
368 :
369 0 : void VrouterUveEntry::FetchDropStats(AgentDropStats &ds) const {
370 0 : AgentUveStats *uve = static_cast<AgentUveStats *>(agent_->uve());
371 0 : const vr_drop_stats_req &req = uve->stats_manager()->drop_stats();
372 0 : uve->stats_manager()->BuildDropStats(req, ds);
373 0 : }
374 :
375 0 : void VrouterUveEntry::FetchIFMapStats(AgentUve::DerivedStatsMap *ds) const {
376 0 : IFMapAgentParser *parser = agent_->cfg()->cfg_parser();
377 0 : if (parser) {
378 0 : ds->insert(AgentUve::DerivedStatsPair("node_update_parse_errors",
379 0 : parser->node_update_parse_errors()));
380 0 : ds->insert(AgentUve::DerivedStatsPair("link_update_parse_errors",
381 0 : parser->link_update_parse_errors()));
382 0 : ds->insert(AgentUve::DerivedStatsPair("node_delete_parse_errors",
383 0 : parser->node_delete_parse_errors()));
384 0 : ds->insert(AgentUve::DerivedStatsPair("link_delete_parse_errors",
385 0 : parser->link_delete_parse_errors()));
386 : }
387 0 : }
388 :
389 0 : void VrouterUveEntry::BuildXmppStatsList
390 : (std::map<std::string, AgentXmppStats> *xstats) const {
391 0 : for (int count = 0; count < MAX_XMPP_SERVERS; count++) {
392 0 : AgentXmppStats peer;
393 0 : if (!agent_->controller_ifmap_xmpp_server(count).empty()) {
394 0 : AgentXmppChannel *ch = agent_->controller_xmpp_channel(count);
395 0 : if (ch == NULL) {
396 0 : continue;
397 : }
398 0 : XmppChannel *xc = ch->GetXmppChannel();
399 0 : if (xc == NULL) {
400 0 : continue;
401 : }
402 0 : peer.set_reconnects(agent_->stats()->xmpp_reconnects(count));
403 0 : peer.set_in_msgs(agent_->stats()->xmpp_in_msgs(count));
404 0 : peer.set_out_msgs(agent_->stats()->xmpp_out_msgs(count));
405 0 : xstats->insert(std::make_pair(
406 0 : agent_->controller_ifmap_xmpp_server(count),
407 : peer));
408 : }
409 0 : }
410 0 : }
411 :
412 0 : bool VrouterUveEntry::SetVrouterPortBitmap(VrouterStatsAgent &vr_stats) {
413 0 : bool changed = false;
414 :
415 0 : vector<uint32_t> tcp_sport;
416 0 : if (port_bitmap_.tcp_sport_.Sync(tcp_sport)) {
417 0 : vr_stats.set_tcp_sport_bitmap(tcp_sport);
418 0 : changed = true;
419 : }
420 :
421 0 : vector<uint32_t> tcp_dport;
422 0 : if (port_bitmap_.tcp_dport_.Sync(tcp_dport)) {
423 0 : vr_stats.set_tcp_dport_bitmap(tcp_dport);
424 0 : changed = true;
425 : }
426 :
427 0 : vector<uint32_t> udp_sport;
428 0 : if (port_bitmap_.udp_sport_.Sync(udp_sport)) {
429 0 : vr_stats.set_udp_sport_bitmap(udp_sport);
430 0 : changed = true;
431 : }
432 :
433 0 : vector<uint32_t> udp_dport;
434 0 : if (port_bitmap_.udp_dport_.Sync(udp_dport)) {
435 0 : vr_stats.set_udp_dport_bitmap(udp_dport);
436 0 : changed = true;
437 : }
438 0 : return changed;
439 0 : }
440 :
441 44 : void VrouterUveEntry::UpdateBitmap(uint8_t proto, uint16_t sport,
442 : uint16_t dport) {
443 44 : port_bitmap_.AddPort(proto, sport, dport);
444 44 : }
445 :
446 0 : void VrouterUveEntry::VrfWalkDone(DBTableBase *base, RouteTableSizeMapPtr list){
447 0 : vrf_walk_id_ = DBTableWalker::kInvalidWalkerId;
448 0 : BuildAndSendVrouterControlStats(list);
449 0 : }
450 :
451 0 : bool VrouterUveEntry::AppendVrf(DBTablePartBase *part, DBEntryBase *entry,
452 : RouteTableSizeMapPtr list) {
453 0 : VrfEntry *vrf = static_cast<VrfEntry *>(entry);
454 :
455 0 : if (!vrf->IsDeleted()) {
456 0 : RouteTableSize value;
457 0 : value.set_inet4_unicast(vrf->GetInet4UnicastRouteTable()->Size());
458 0 : value.set_inet4_multicast(vrf->GetInet4MulticastRouteTable()->Size());
459 0 : value.set_evpn(vrf->GetEvpnRouteTable()->Size());
460 0 : value.set_bridge(vrf->GetBridgeRouteTable()->Size());
461 0 : value.set_inet6_unicast(vrf->GetInet6UnicastRouteTable()->Size());
462 0 : list.get()->insert(RouteTableSizePair(vrf->GetName(), value));
463 0 : }
464 0 : return true;
465 : }
466 :
467 0 : bool VrouterUveEntry::StartVrfWalk() {
468 0 : if (vrf_walk_id_ != DBTableWalker::kInvalidWalkerId) {
469 0 : return false;
470 : }
471 :
472 0 : RouteTableSizeMapPtr list(new RouteTableSizeMap());
473 0 : DBTableWalker *walker = agent_->db()->GetWalker();
474 0 : vrf_walk_id_ = walker->WalkTable(agent_->vrf_table(), NULL,
475 0 : boost::bind(&VrouterUveEntry::AppendVrf, this, _1, _2, list),
476 0 : boost::bind(&VrouterUveEntry::VrfWalkDone, this, _1, list));
477 0 : return true;
478 0 : }
479 :
480 0 : void VrouterUveEntry::DispatchVrouterControlStats
481 : (const VrouterControlStats &uve) const {
482 0 : VrouterControlStatsTrace::Send(uve);
483 0 : }
484 :
485 0 : void VrouterUveEntry::SendVrouterControlStats() {
486 : /* We do VRF walk to collect route table sizes. In Walk Done API we trigger
487 : * building of all attributes of VrouterControlStats UVE and send it*/
488 0 : StartVrfWalk();
489 0 : }
490 :
491 0 : void VrouterUveEntry::BuildAndSendVrouterControlStats(RouteTableSizeMapPtr
492 : list) {
493 0 : VrouterControlStats stats;
494 0 : stats.set_name(agent_->agent_name());
495 :
496 0 : std::map<std::string, AgentXmppStats> xstats;
497 0 : BuildXmppStatsList(&xstats);
498 0 : stats.set_raw_xmpp_stats(xstats);
499 :
500 0 : AgentUve::DerivedStatsMap ifmap_stats;
501 0 : FetchIFMapStats(&ifmap_stats);
502 0 : stats.set_raw_ifmap_stats(ifmap_stats);
503 :
504 0 : stats.set_raw_rt_table_size(*(list.get()));
505 0 : DispatchVrouterControlStats(stats);
506 0 : }
|