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