Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <uve/vn_uve_entry.h>
6 : #include <uve/agent_uve_stats.h>
7 :
8 20 : VnUveEntry::VnUveEntry(Agent *agent, const VnEntry *vn)
9 40 : : VnUveEntryBase(agent, vn), port_bitmap_(), inter_vn_stats_(), mutex_(),
10 20 : in_bytes_(0), out_bytes_(0), prev_stats_update_time_(0),
11 40 : prev_in_bytes_(0), prev_out_bytes_(0) {
12 20 : }
13 :
14 6 : VnUveEntry::VnUveEntry(Agent *agent)
15 12 : : VnUveEntryBase(agent, NULL), port_bitmap_(), inter_vn_stats_(), mutex_(),
16 6 : in_bytes_(0), out_bytes_(0), prev_stats_update_time_(0),
17 12 : prev_in_bytes_(0), prev_out_bytes_(0) {
18 6 : }
19 :
20 26 : VnUveEntry::~VnUveEntry() {
21 26 : }
22 :
23 88 : void VnUveEntry::UpdatePortBitmap(uint8_t proto, uint16_t sport,
24 : uint16_t dport) {
25 88 : std::scoped_lock lock(mutex_);
26 88 : if (deleted_ && !renewed_) {
27 : /* Skip updates on VnUveEntry if it is marked for delete */
28 0 : return;
29 : }
30 88 : port_bitmap_.AddPort(proto, sport, dport);
31 88 : }
32 :
33 24 : void VnUveEntry::UpdateInterVnStats(const string &dst_vn, uint64_t bytes,
34 : uint64_t pkts, bool outgoing) {
35 24 : std::scoped_lock lock(mutex_);
36 24 : if (deleted_ && !renewed_) {
37 : /* Skip updates on VnUveEntry if it is marked for delete */
38 0 : return;
39 : }
40 24 : VnStatsPtr key(new VnStats(dst_vn, 0, 0, false));
41 24 : VnStatsSet::iterator stats_it = inter_vn_stats_.find(key);
42 24 : if (stats_it == inter_vn_stats_.end()) {
43 4 : VnStatsPtr stats(new VnStats(dst_vn, bytes, pkts, outgoing));
44 4 : inter_vn_stats_.insert(stats);
45 4 : } else {
46 20 : VnStatsPtr stats_ptr(*stats_it);
47 20 : VnStats *stats = stats_ptr.get();
48 20 : if (outgoing) {
49 11 : stats->out_bytes_ += bytes;
50 11 : stats->out_pkts_ += pkts;
51 : } else {
52 9 : stats->in_bytes_ += bytes;
53 9 : stats->in_pkts_ += pkts;
54 : }
55 20 : }
56 24 : if (outgoing) {
57 13 : out_bytes_ += bytes;
58 : } else {
59 11 : in_bytes_ += bytes;
60 : }
61 24 : }
62 :
63 : /* Remove all the elements of map entry value which is a set */
64 0 : void VnUveEntry::ClearInterVnStats() {
65 0 : std::scoped_lock lock(mutex_);
66 0 : VnStatsSet::iterator stats_it = inter_vn_stats_.begin();
67 0 : VnStatsSet::iterator del_it;
68 0 : while(stats_it != inter_vn_stats_.end()) {
69 0 : del_it = stats_it;
70 0 : stats_it++;
71 0 : inter_vn_stats_.erase(del_it);
72 : }
73 0 : }
74 :
75 0 : bool VnUveEntry::SetVnPortBitmap(UveVirtualNetworkAgent &uve) {
76 0 : bool changed = false;
77 0 : std::scoped_lock lock(mutex_);
78 :
79 0 : vector<uint32_t> tcp_sport;
80 0 : if (port_bitmap_.tcp_sport_.Sync(tcp_sport)) {
81 0 : uve.set_tcp_sport_bitmap(tcp_sport);
82 0 : changed = true;
83 : }
84 :
85 0 : vector<uint32_t> tcp_dport;
86 0 : if (port_bitmap_.tcp_dport_.Sync(tcp_dport)) {
87 0 : uve.set_tcp_dport_bitmap(tcp_dport);
88 0 : changed = true;
89 : }
90 :
91 0 : vector<uint32_t> udp_sport;
92 0 : if (port_bitmap_.udp_sport_.Sync(udp_sport)) {
93 0 : uve.set_udp_sport_bitmap(udp_sport);
94 0 : changed = true;
95 : }
96 :
97 0 : vector<uint32_t> udp_dport;
98 0 : if (port_bitmap_.udp_dport_.Sync(udp_dport)) {
99 0 : uve.set_udp_dport_bitmap(udp_dport);
100 0 : changed = true;
101 : }
102 0 : return changed;
103 0 : }
104 :
105 0 : bool VnUveEntry::UveVnFipCountChanged(int32_t size) const {
106 0 : if (!uve_info_.__isset.associated_fip_count) {
107 0 : return true;
108 : }
109 0 : if (size != uve_info_.get_associated_fip_count()) {
110 0 : return true;
111 : }
112 0 : return false;
113 : }
114 :
115 0 : bool VnUveEntry::UveVnInBandChanged(uint64_t in_band) const {
116 0 : if (!uve_info_.__isset.in_bandwidth_usage) {
117 0 : return true;
118 : }
119 0 : if (in_band != uve_info_.get_in_bandwidth_usage()) {
120 0 : return true;
121 : }
122 0 : return false;
123 : }
124 :
125 0 : bool VnUveEntry::UveVnOutBandChanged(uint64_t out_band) const {
126 0 : if (!uve_info_.__isset.out_bandwidth_usage) {
127 0 : return true;
128 : }
129 0 : if (out_band != uve_info_.get_out_bandwidth_usage()) {
130 0 : return true;
131 : }
132 0 : return false;
133 : }
134 :
135 0 : bool VnUveEntry::UveVnVrfStatsChanged(const vector<UveVrfStats> &vlist) const {
136 0 : if (!uve_info_.__isset.vrf_stats_list) {
137 0 : return true;
138 : }
139 0 : if (vlist != uve_info_.get_vrf_stats_list()) {
140 0 : return true;
141 : }
142 0 : return false;
143 : }
144 :
145 0 : bool VnUveEntry::UveInterVnInStatsChanged(const vector<UveInterVnStats>
146 : &new_list) const {
147 0 : if (!uve_info_.__isset.in_stats) {
148 0 : return true;
149 : }
150 0 : if (new_list != uve_info_.get_in_stats()) {
151 0 : return true;
152 : }
153 0 : return false;
154 : }
155 :
156 0 : bool VnUveEntry::UveInterVnOutStatsChanged(const vector<UveInterVnStats>
157 : &new_list) const {
158 0 : if (!uve_info_.__isset.out_stats) {
159 0 : return true;
160 : }
161 0 : if (new_list != uve_info_.get_out_stats()) {
162 0 : return true;
163 : }
164 0 : return false;
165 : }
166 :
167 0 : bool VnUveEntry::UpdateVnFlowCount(const VnEntry *vn,
168 : UveVirtualNetworkAgent &s_vn) {
169 : /* Ingress and Egress flow counts should be sent always regardless of
170 : * whether it has changed or not. This is required for collector to do
171 : * anomaly detection. The anomaly detection done at collector is based on
172 : * streaming of UVE messages */
173 : uint32_t in_count, out_count;
174 0 : agent_->pkt()->get_flow_proto()->VnFlowCounters(vn, &in_count, &out_count);
175 0 : s_vn.set_ingress_flow_count(in_count);
176 0 : uve_info_.set_ingress_flow_count(in_count); //required only for UT
177 :
178 0 : s_vn.set_egress_flow_count(out_count);
179 0 : uve_info_.set_egress_flow_count(out_count); //required only for UT
180 0 : return true;
181 : }
182 :
183 0 : bool VnUveEntry::UpdateVnFipCount(int count, UveVirtualNetworkAgent &s_vn) {
184 0 : if (UveVnFipCountChanged(count)) {
185 0 : s_vn.set_associated_fip_count(count);
186 0 : uve_info_.set_associated_fip_count(count);
187 0 : return true;
188 : }
189 0 : return false;
190 : }
191 :
192 0 : bool VnUveEntry::PopulateInterVnStats(UveVirtualNetworkAgent &s_vn) {
193 0 : bool changed = false;
194 : /* Aggregate/total current stats are sent in the following fields */
195 0 : vector<UveInterVnStats> in_list;
196 0 : vector<UveInterVnStats> out_list;
197 : /* Only diff since previous dispatch, is sent as part of the following
198 : * list */
199 0 : vector<InterVnStats> vn_stats_list;
200 :
201 : {
202 0 : std::scoped_lock lock(mutex_);
203 0 : VnStatsSet::iterator it = inter_vn_stats_.begin();
204 : VnStats *stats;
205 0 : VnStatsPtr stats_ptr;
206 0 : while (it != inter_vn_stats_.end()) {
207 0 : stats_ptr = *it;
208 0 : stats = stats_ptr.get();
209 0 : UveInterVnStats uve_stats;
210 0 : uve_stats.set_other_vn(stats->dst_vn_);
211 :
212 0 : uve_stats.set_tpkts(stats->in_pkts_);
213 0 : uve_stats.set_bytes(stats->in_bytes_);
214 0 : in_list.push_back(uve_stats);
215 :
216 0 : uve_stats.set_tpkts(stats->out_pkts_);
217 0 : uve_stats.set_bytes(stats->out_bytes_);
218 0 : out_list.push_back(uve_stats);
219 :
220 0 : InterVnStats diff_stats;
221 0 : diff_stats.set_other_vn(stats->dst_vn_);
222 0 : diff_stats.set_vrouter(agent_->agent_name());
223 0 : diff_stats.set_in_tpkts(stats->in_pkts_ - stats->prev_in_pkts_);
224 0 : diff_stats.set_in_bytes(stats->in_bytes_ - stats->prev_in_bytes_);
225 0 : diff_stats.set_out_tpkts(stats->out_pkts_ - stats->prev_out_pkts_);
226 0 : diff_stats.set_out_bytes(stats->out_bytes_ -
227 0 : stats->prev_out_bytes_);
228 0 : vn_stats_list.push_back(diff_stats);
229 :
230 0 : stats->prev_in_pkts_ = stats->in_pkts_;
231 0 : stats->prev_in_bytes_ = stats->in_bytes_;
232 0 : stats->prev_out_pkts_ = stats->out_pkts_;
233 0 : stats->prev_out_bytes_ = stats->out_bytes_;
234 0 : it++;
235 0 : }
236 0 : }
237 0 : if (!in_list.empty()) {
238 0 : if (UveInterVnInStatsChanged(in_list)) {
239 0 : s_vn.set_in_stats(in_list);
240 0 : uve_info_.set_in_stats(in_list);
241 0 : changed = true;
242 : }
243 : }
244 0 : if (!out_list.empty()) {
245 0 : if (UveInterVnOutStatsChanged(out_list)) {
246 0 : s_vn.set_out_stats(out_list);
247 0 : uve_info_.set_out_stats(out_list);
248 0 : changed = true;
249 : }
250 : }
251 0 : if (!vn_stats_list.empty()) {
252 0 : s_vn.set_vn_stats(vn_stats_list);
253 0 : changed = true;
254 : }
255 0 : return changed;
256 0 : }
257 :
258 0 : void VnUveEntry::BuildArpStats(const StatsManager::VrfStats *s,
259 : UveVrfStats &vrf_stats) const {
260 0 : UveArpStats as;
261 :
262 0 : UveVmiStats vs;
263 0 : UveArpResponses ar1;
264 0 : ar1.set_proxies(s->arp_virtual_proxy);
265 0 : ar1.set_stitches(s->arp_virtual_stitch);
266 0 : ar1.set_floods(s->arp_virtual_flood);
267 0 : vs.set_stats(ar1);
268 0 : as.set_from_vm_interface(vs);
269 :
270 0 : UvePhyIntfStats ps;
271 0 : UveArpResponses ar2;
272 0 : ar2.set_proxies(s->arp_tor_proxy);
273 0 : ar2.set_stitches(s->arp_physical_stitch);
274 0 : ar2.set_floods(s->arp_physical_flood);
275 0 : ps.set_stats(ar2);
276 0 : as.set_from_physical_interface(ps);
277 :
278 0 : vrf_stats.set_arp_packet_counts(as);
279 0 : }
280 :
281 0 : void VnUveEntry::BuildNhStats(const StatsManager::VrfStats *s,
282 : UveVrfStats &vrf_stats) const {
283 0 : UveNhStats nhs;
284 0 : nhs.set_discards(s->discards);
285 0 : nhs.set_resolves(s->resolves);
286 0 : nhs.set_l3_receives(s->receives);
287 0 : nhs.set_l2_receives(s->l2_receives);
288 0 : nhs.set_local_vm_l3_forwards(s->encaps);
289 0 : nhs.set_local_vm_l2_forwards(s->l2_encaps);
290 0 : nhs.set_vrf_translates(s->vrf_translates);
291 0 : nhs.set_ecmp_forwards(s->ecmp_composites);
292 :
293 0 : UveTunnelNhStats tns;
294 0 : tns.set_udp_encaps(s->udp_tunnels);
295 0 : tns.set_mpls_over_udp_encaps(s->udp_mpls_tunnels);
296 0 : tns.set_mpls_over_gre_encaps(s->gre_mpls_tunnels);
297 0 : tns.set_vxlan_encaps(s->vxlan_tunnels);
298 0 : nhs.set_tunnel_nh_stats(tns);
299 :
300 0 : UveMulticastNhStats mns;
301 0 : mns.set_source_replication_forwards(s->evpn_composites);
302 0 : mns.set_edge_replication_forwards(s->fabric_composites);
303 0 : mns.set_local_vm_l3_forwards(s->encap_composites);
304 0 : mns.set_total_multicast_forwards(s->l2_mcast_composites);
305 0 : nhs.set_comp_nh_stats(mns);
306 0 : vrf_stats.set_nh_packet_counts(nhs);
307 0 : }
308 :
309 0 : bool VnUveEntry::FillVrfStats(int vrf_id, UveVirtualNetworkAgent &s_vn) {
310 0 : bool changed = false;
311 0 : UveVrfStats vrf_stats;
312 0 : vector<UveVrfStats> vlist;
313 :
314 0 : AgentUveStats *uve = static_cast<AgentUveStats *>(agent_->uve());
315 0 : StatsManager::VrfStats *s = uve->stats_manager()->GetVrfStats(vrf_id);
316 0 : if (s != NULL) {
317 0 : vrf_stats.set_name(s->name);
318 0 : vrf_stats.set_diag_packet_count(s->diags);
319 0 : vrf_stats.set_unknown_unicast_floods(s->uuc_floods);
320 :
321 0 : BuildArpStats(s, vrf_stats);
322 :
323 0 : UveOffloadStats os;
324 0 : os.set_gro(s->gros);
325 0 : vrf_stats.set_offload_packet_counts(os);
326 :
327 0 : BuildNhStats(s, vrf_stats);
328 :
329 0 : vlist.push_back(vrf_stats);
330 0 : if (UveVnVrfStatsChanged(vlist)) {
331 0 : s_vn.set_vrf_stats_list(vlist);
332 0 : uve_info_.set_vrf_stats_list(vlist);
333 0 : changed = true;
334 : }
335 0 : }
336 0 : return changed;
337 0 : }
338 :
339 0 : bool VnUveEntry::UpdateVrfStats(const VnEntry *vn,
340 : UveVirtualNetworkAgent &s_vn) {
341 0 : bool changed = false;
342 0 : VrfEntry *vrf = vn->GetVrf();
343 0 : if (vrf) {
344 0 : changed = FillVrfStats(vrf->vrf_id(), s_vn);
345 : } else {
346 0 : vector<UveVrfStats> vlist;
347 0 : if (UveVnVrfStatsChanged(vlist)) {
348 0 : s_vn.set_vrf_stats_list(vlist);
349 0 : uve_info_.set_vrf_stats_list(vlist);
350 0 : changed = true;
351 : }
352 0 : }
353 :
354 0 : return changed;
355 : }
356 :
357 0 : bool VnUveEntry::FrameVnStatsMsg(const VnEntry *vn,
358 : UveVirtualNetworkAgent &uve) {
359 0 : bool changed = false;
360 0 : assert(!deleted_);
361 0 : uve.set_name(vn->GetName());
362 :
363 0 : if (UpdateVrfStats(vn, uve)) {
364 0 : changed = true;
365 : }
366 :
367 0 : int fip_count = 0;
368 0 : InterfaceSet::iterator it = interface_tree_.begin();
369 0 : while (it != interface_tree_.end()) {
370 0 : const Interface *intf = *it;
371 0 : ++it;
372 :
373 0 : const VmInterface *vm_port = static_cast<const VmInterface *>(intf);
374 0 : fip_count += vm_port->GetFloatingIpCount();
375 : }
376 :
377 0 : uint64_t diff_in_bytes = 0;
378 0 : uint64_t diff_out_bytes = 0;
379 :
380 0 : uint64_t diff_seconds = 0;
381 0 : uint64_t cur_time = UTCTimestampUsec();
382 0 : bool send_bandwidth = false;
383 : uint64_t in_band, out_band;
384 0 : uint64_t b_intvl = agent_->uve()->bandwidth_intvl();
385 0 : if (prev_stats_update_time_ == 0) {
386 0 : in_band = out_band = 0;
387 0 : send_bandwidth = true;
388 0 : prev_stats_update_time_ = cur_time;
389 : } else {
390 0 : diff_seconds = (cur_time - prev_stats_update_time_) / b_intvl;
391 0 : if (diff_seconds > 0) {
392 0 : diff_in_bytes = in_bytes_ - prev_in_bytes_;
393 0 : diff_out_bytes = out_bytes_ - prev_out_bytes_;
394 0 : in_band = (diff_in_bytes * 8)/diff_seconds;
395 0 : out_band = (diff_out_bytes * 8)/diff_seconds;
396 0 : prev_stats_update_time_ = cur_time;
397 0 : prev_in_bytes_ = in_bytes_;
398 0 : prev_out_bytes_ = out_bytes_;
399 0 : send_bandwidth = true;
400 : }
401 : }
402 0 : if (send_bandwidth && UveVnInBandChanged(in_band)) {
403 0 : uve.set_in_bandwidth_usage(in_band);
404 0 : uve_info_.set_in_bandwidth_usage(in_band);
405 0 : changed = true;
406 : }
407 :
408 0 : if (send_bandwidth && UveVnOutBandChanged(out_band)) {
409 0 : uve.set_out_bandwidth_usage(out_band);
410 0 : uve_info_.set_out_bandwidth_usage(out_band);
411 0 : changed = true;
412 : }
413 :
414 0 : if (UpdateVnFlowCount(vn, uve)) {
415 0 : changed = true;
416 : }
417 :
418 0 : if (UpdateVnFipCount(fip_count, uve)) {
419 0 : changed = true;
420 : }
421 :
422 : /* VM interface list for VN is sent whenever any VM is added or
423 : * removed from VN. That message has only two fields set - vn name
424 : * and virtualmachine_list */
425 :
426 0 : if (PopulateInterVnStats(uve)) {
427 0 : changed = true;
428 : }
429 :
430 0 : if (SetVnPortBitmap(uve)) {
431 0 : changed = true;
432 : }
433 :
434 0 : return changed;
435 : }
436 :
437 6 : void VnUveEntry::Reset() {
438 6 : VnUveEntryBase::Reset();
439 6 : port_bitmap_.Reset();
440 6 : inter_vn_stats_.clear();
441 6 : ace_stats_.clear();
442 6 : ace_stats_changed_ = false;
443 6 : prev_stats_update_time_ = 0;
444 6 : prev_in_bytes_ = 0;
445 6 : prev_out_bytes_ = 0;
446 6 : }
447 :
448 54 : void VnUveEntry::UpdateVnAceStats(const std::string &ace_uuid) {
449 54 : VnAceStats key(ace_uuid);
450 54 : ace_stats_changed_ = true;
451 54 : VnAceStatsSet::const_iterator it = ace_stats_.find(key);
452 54 : if (it != ace_stats_.end()) {
453 44 : it->count++;
454 44 : return;
455 : }
456 10 : key.count = 1;
457 10 : ace_stats_.insert(key);
458 54 : }
459 :
460 0 : bool VnUveEntry::FrameVnAceStatsMsg(const VnEntry *vn,
461 : UveVirtualNetworkAgent &uve) {
462 0 : if (!ace_stats_changed_) {
463 0 : return false;
464 : }
465 0 : std::vector<NetworkPolicyRuleStats> list;
466 0 : bool changed = false;
467 0 : VnAceStatsSet::iterator it = ace_stats_.begin();
468 : /* Build the updated list */
469 0 : while (it != ace_stats_.end()) {
470 0 : uint64_t diff_count = it->count - it->prev_count;
471 0 : if (diff_count) {
472 : //Update prev_count
473 0 : it->prev_count = it->count;
474 0 : NetworkPolicyRuleStats item;
475 0 : item.set_rule(it->ace_uuid);
476 0 : item.set_count(diff_count);
477 0 : list.push_back(item);
478 0 : changed = true;
479 0 : }
480 0 : ++it;
481 : }
482 : /* If all the entries in the list has 0 diff_stats, then UVE won't be
483 : * sent */
484 0 : if (changed) {
485 0 : uve.set_name(vn->GetName());
486 0 : uve.set_policy_rule_stats(list);
487 0 : ace_stats_changed_ = false;
488 0 : return true;
489 : }
490 0 : return false;
491 0 : }
|