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