/
interface_uve_stats_table.cc
227 lines (197 loc) · 7.55 KB
/
interface_uve_stats_table.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/*
* Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
*/
#include <oper/interface_common.h>
#include <uve/interface_uve_stats_table.h>
#include <uve/agent_uve_stats.h>
InterfaceUveStatsTable::InterfaceUveStatsTable(Agent *agent,
uint32_t default_intvl)
: InterfaceUveTable(agent, default_intvl) {
}
InterfaceUveStatsTable::~InterfaceUveStatsTable() {
}
bool InterfaceUveStatsTable::FrameInterfaceStatsMsg(UveInterfaceEntry* entry,
UveVMInterfaceAgent *uve) const {
uint64_t in_band = 0, out_band = 0;
bool changed = false, diff_fip_list_non_zero = false;
VmInterfaceStats if_stats;
vector<VmFloatingIPStats> agg_fip_list;
vector<VmFloatingIPStats> diff_fip_list;
const VmInterface *vm_intf = entry->intf_;
assert(!entry->deleted_);
if (vm_intf->cfg_name().empty()) {
return false;
}
uve->set_name(vm_intf->cfg_name());
entry->SetVnVmInfo(uve);
const Interface *intf = static_cast<const Interface *>(vm_intf);
AgentUveStats *agent_uve = static_cast<AgentUveStats *>(agent_->uve());
StatsManager::InterfaceStats *s =
agent_uve->stats_manager()->GetInterfaceStats(intf);
if (s == NULL) {
return false;
}
/* Only diff since previous send needs to be sent as we export
* stats via StatsOracle infra provided by analytics module */
uint64_t in_b, in_p, out_b, out_p;
s->GetDiffStats(&in_b, &in_p, &out_b, &out_p);
if ((in_b != 0) || (in_p != 0) || (out_b != 0) || (out_p != 0)) {
if_stats.set_in_pkts(in_p);
if_stats.set_in_bytes(in_b);
if_stats.set_out_pkts(out_p);
if_stats.set_out_bytes(out_b);
uve->set_if_stats(if_stats);
changed = true;
in_band = GetVmPortBandwidth(s, true);
out_band = GetVmPortBandwidth(s, false);
}
if (entry->InBandChanged(in_band)) {
uve->set_in_bw_usage(in_band);
entry->uve_info_.set_in_bw_usage(in_band);
changed = true;
}
if (entry->OutBandChanged(out_band)) {
uve->set_out_bw_usage(out_band);
entry->uve_info_.set_out_bw_usage(out_band);
changed = true;
}
s->stats_time = UTCTimestampUsec();
/* Make sure that update of prev_in_bytes and prev_out_bytes are done only
* after GetVmPortBandwidth is done for both directions as they get used
* in those APIs. */
s->UpdatePrevStats();
PortBucketBitmap map;
L4PortBitmap &port_bmap = entry->port_bitmap_;
port_bmap.Encode(map);
if (entry->PortBitmapChanged(map)) {
uve->set_port_bucket_bmap(map);
entry->uve_info_.set_port_bucket_bmap(map);
changed = true;
}
FrameFipStatsMsg(vm_intf, agg_fip_list, diff_fip_list,
diff_fip_list_non_zero);
if (entry->FipAggStatsChanged(agg_fip_list)) {
uve->set_fip_agg_stats(agg_fip_list);
entry->uve_info_.set_fip_agg_stats(agg_fip_list);
changed = true;
}
/* Diff stats need not be sent if the value of the stats is 0.
* If any of the entry in diff_fip_list has non-zero stats, then
* diff_fip_list_non_zero is expected to be true */
if (diff_fip_list_non_zero) {
uve->set_fip_diff_stats(diff_fip_list);
changed = true;
}
return changed;
}
void InterfaceUveStatsTable::SendInterfaceStatsMsg(UveInterfaceEntry* entry) {
if (entry->deleted_) {
return;
}
UveVMInterfaceAgent uve;
bool send = FrameInterfaceStatsMsg(entry, &uve);
if (send) {
DispatchInterfaceMsg(uve);
}
}
void InterfaceUveStatsTable::SendInterfaceStats(void) {
InterfaceMap::iterator it = interface_tree_.begin();
while (it != interface_tree_.end()) {
UveInterfaceEntry* entry = it->second.get();
SendInterfaceStatsMsg(entry);
it++;
}
}
uint64_t InterfaceUveStatsTable::GetVmPortBandwidth
(StatsManager::InterfaceStats *s, bool dir_in) const {
if (s->stats_time == 0) {
return 0;
}
uint64_t bits;
if (dir_in) {
bits = (s->in_bytes - s->prev_in_bytes) * 8;
} else {
bits = (s->out_bytes - s->prev_out_bytes) * 8;
}
uint64_t cur_time = UTCTimestampUsec();
uint64_t b_intvl = agent_->uve()->bandwidth_intvl();
uint64_t diff_seconds = (cur_time - s->stats_time) / b_intvl;
if (diff_seconds == 0) {
return 0;
}
return bits/diff_seconds;
}
void InterfaceUveStatsTable::UpdateFloatingIpStats(const FipInfo &fip_info) {
Interface *intf = dynamic_cast<Interface *>
(agent_->interface_table()->FindActiveEntry(&fip_info.fip_vmi_));
if (intf == NULL) {
return;
}
tbb::mutex::scoped_lock lock(interface_tree_mutex_);
VmInterface *vmi = static_cast<VmInterface *>(intf);
InterfaceMap::iterator intf_it = interface_tree_.find(vmi->cfg_name());
/*
* 1. VM interface with floating-ip becomes active
* 2. Flow is created on this interface and interface floating ip info is
* stored in flow record
* 3. VM Interface is disassociated from VM
* 4. VM Interface info is removed from interface_tree_ because of
* disassociation
* 5. FlowStats collection task initiates export of flow stats
* 6. Since interface is absent in interface_tree_ we cannot update
* stats in this case
*/
if (intf_it != interface_tree_.end()) {
UveInterfaceEntry *entry = intf_it->second.get();
entry->UpdateFloatingIpStats(fip_info);
}
}
bool InterfaceUveStatsTable::FrameFipStatsMsg(const VmInterface *itf,
vector<VmFloatingIPStats> &fip_list,
vector<VmFloatingIPStats> &diff_list,
bool &diff_list_send) const {
bool changed = false;
diff_list_send = false;
InterfaceMap::const_iterator it = interface_tree_.find(itf->cfg_name());
if (it != interface_tree_.end()) {
UveInterfaceEntry *entry = it->second.get();
changed = entry->FillFloatingIpStats(fip_list, diff_list,
diff_list_send);
}
return changed;
}
void InterfaceUveStatsTable::UpdatePortBitmap
(const string &name, uint8_t proto, uint16_t sport, uint16_t dport) {
tbb::mutex::scoped_lock lock(interface_tree_mutex_);
InterfaceMap::const_iterator it = interface_tree_.find(name);
if (it != interface_tree_.end()) {
UveInterfaceEntry *entry = it->second.get();
entry->UpdatePortBitmap(proto, sport, dport);
}
}
InterfaceUveTable::FloatingIp * InterfaceUveStatsTable::FipEntry
(uint32_t fip, const string &vn, Interface *intf) {
VmInterface *vmi = static_cast<VmInterface *>(intf);
InterfaceMap::iterator intf_it = interface_tree_.find(vmi->cfg_name());
assert (intf_it != interface_tree_.end());
UveInterfaceEntry *entry = intf_it->second.get();
return entry->FipEntry(fip, vn);
}
void InterfaceUveStatsTable::IncrInterfaceAceStats(const std::string &itf,
const std::string &u) {
if (itf.empty() || u.empty()) {
return;
}
InterfaceMap::iterator intf_it = interface_tree_.find(itf);
if (intf_it != interface_tree_.end()) {
UveInterfaceEntry *entry = intf_it->second.get();
entry->UpdateInterfaceAceStats(u);
}
}
void InterfaceUveStatsTable::SendInterfaceAceStats(const string &name,
UveInterfaceEntry *entry) {
UveVMInterfaceAgent uve;
if (entry->FrameInterfaceAceStatsMsg(name, &uve)) {
DispatchInterfaceMsg(uve);
}
}