Line data Source code
1 : /*
2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <sys/socket.h>
6 : #if defined(__linux__)
7 : #include <linux/netlink.h>
8 : #endif
9 : #include <fcntl.h>
10 : #include <sys/mman.h>
11 : #include <sys/types.h>
12 : #include <sys/ipc.h>
13 : #include <sys/shm.h>
14 : #include <asm/types.h>
15 : #include <boost/asio.hpp>
16 :
17 : #include <base/timer.h>
18 : #include <base/task_trigger.h>
19 : #include <base/address_util.h>
20 : #include <cmn/agent_cmn.h>
21 : #include <services/services_init.h>
22 : #include <uve/stats_collector.h>
23 : #include <services/icmp_error_proto.h>
24 : #include <pkt/flow_proto.h>
25 : #include <ksync/ksync_index.h>
26 : #include <ksync/ksync_entry.h>
27 : #include <ksync/ksync_object.h>
28 : #include <ksync/ksync_netlink.h>
29 : #include <ksync/ksync_sock.h>
30 : #include <ksync/ksync_sock_user.h>
31 : #include <vrouter/flow_stats/flow_stats_collector.h>
32 :
33 : #include <vr_types.h>
34 : #include <nl_util.h>
35 : #include <vr_flow.h>
36 : #include <vr_genetlink.h>
37 :
38 : #include "ksync_init.h"
39 : #include "ksync_flow_memory.h"
40 : #include "sandesh_ksync.h"
41 :
42 : using namespace boost::asio::ip;
43 : static const int kTestFlowTableSize = 131072 * sizeof(vr_flow_entry);
44 :
45 3 : KSyncFlowMemory::KSyncFlowMemory(KSync *ksync, uint32_t minor_id) :
46 3 : KSyncMemory(ksync, minor_id) {
47 3 : table_path_ = FLOW_TABLE_DEV;
48 3 : hold_flow_counter_ = 0;
49 3 : }
50 :
51 0 : void KSyncFlowMemory::Init() {
52 0 : IcmpErrorProto *proto = ksync_->agent()->services()->icmp_error_proto();
53 0 : proto->Register(boost::bind(&KSyncFlowMemory::GetFlowKey, this, _1, _2, _3));
54 :
55 0 : KSyncMemory::Init();
56 0 : }
57 :
58 0 : int KSyncFlowMemory::EncodeReq(struct nl_client *cl, uint32_t attr_len) {
59 : int encode_len, error;
60 :
61 0 : vr_flow_table_data info;
62 0 : info.set_ftable_op(flow_op::FLOW_TABLE_GET);
63 0 : info.set_ftable_size(0);
64 0 : info.set_ftable_dev(0);
65 0 : info.set_ftable_file_path("");
66 0 : info.set_ftable_processed(0);
67 0 : info.set_ftable_hold_oflows(0);
68 0 : info.set_ftable_added(0);
69 0 : info.set_ftable_cpus(0);
70 0 : info.set_ftable_created(0);
71 0 : info.set_ftable_oflow_entries(0);
72 0 : encode_len = info.WriteBinary(nl_get_buf_ptr(cl) + attr_len,
73 : nl_get_buf_len(cl), &error);
74 0 : return encode_len;
75 0 : }
76 :
77 3 : int KSyncFlowMemory::get_entry_size() {
78 3 : return sizeof(vr_flow_entry);
79 : }
80 :
81 3 : void KSyncFlowMemory::SetTableSize() {
82 3 : ksync_->agent()->set_flow_table_size(table_entries_count_);
83 3 : flow_table_ = static_cast<vr_flow_entry *>(table_);
84 3 : }
85 :
86 0 : void KSyncFlowMemory::CreateProtoAuditEntry(uint32_t idx, uint8_t gen_id) {
87 0 : const vr_flow_entry *ventry = GetKernelFlowEntry(idx, false);
88 : // Audit and remove entry if its still in HOLD state
89 0 : if (ventry && ventry->fe_gen_id == gen_id &&
90 0 : ventry->fe_action == VR_FLOW_ACTION_HOLD) {
91 0 : IpAddress sip, dip;
92 0 : VrFlowToIp(ventry, &sip, &dip);
93 0 : FlowKey key(ventry->fe_key.flow_nh_id, sip, dip,
94 0 : ventry->fe_key.flow_proto,
95 0 : ntohs(ventry->fe_key.flow_sport),
96 0 : ntohs(ventry->fe_key.flow_dport));
97 :
98 0 : FlowProto *proto = ksync_->agent()->pkt()->get_flow_proto();
99 0 : proto->CreateAuditEntry(key, idx, gen_id);
100 : }
101 0 : }
102 :
103 0 : void KSyncFlowMemory::DecrementHoldFlowCounter() {
104 0 : hold_flow_counter_--;
105 0 : return;
106 : }
107 :
108 0 : void KSyncFlowMemory::IncrementHoldFlowCounter() {
109 0 : hold_flow_counter_++;
110 0 : return;
111 : }
112 :
113 0 : void KSyncFlowMemory::UpdateAgentHoldFlowCounter() {
114 0 : ksync_->agent()->stats()->update_hold_flow_count(hold_flow_counter_);
115 0 : hold_flow_counter_ = 0;
116 0 : return;
117 : }
118 :
119 0 : bool KSyncFlowMemory::IsInactiveEntry(uint32_t audit_idx, uint8_t &gen_id) {
120 : const vr_flow_entry *vflow_entry =
121 0 : GetKernelFlowEntry(audit_idx, false);
122 0 : if (vflow_entry && vflow_entry->fe_action == VR_FLOW_ACTION_HOLD) {
123 0 : gen_id = vflow_entry->fe_gen_id;
124 0 : return true;
125 : }
126 0 : return false;
127 : }
128 :
129 0 : void KSyncFlowMemory::VrFlowToIp(const vr_flow_entry *kflow, IpAddress *sip,
130 : IpAddress *dip) {
131 0 : if (kflow->fe_key.flow_family == AF_INET) {
132 0 : *sip = Ip4Address(ntohl(kflow->fe_key.key_u.ip4_key.ip4_sip));
133 0 : *dip = Ip4Address(ntohl(kflow->fe_key.key_u.ip4_key.ip4_dip));
134 : } else {
135 0 : const unsigned char *k_sip = kflow->fe_key.key_u.ip6_key.ip6_sip;
136 0 : const unsigned char *k_dip = kflow->fe_key.key_u.ip6_key.ip6_dip;
137 : Ip6Address::bytes_type sbytes;
138 : Ip6Address::bytes_type dbytes;
139 0 : for (int i = 0; i < 16; i++) {
140 0 : sbytes[i] = k_sip[i];
141 0 : dbytes[i] = k_dip[i];
142 : }
143 0 : *sip = Ip6Address(sbytes);
144 0 : *dip = Ip6Address(dbytes);
145 : }
146 0 : }
147 :
148 0 : void KSyncFlowMemory::KFlow2FlowKey(const vr_flow_entry *kflow,
149 : FlowKey *key) const {
150 0 : key->nh = kflow->fe_key.flow4_nh_id;
151 0 : Address::Family family = (kflow->fe_key.flow_family == AF_INET)?
152 : Address::INET : Address::INET6;
153 0 : VrFlowToIp(kflow, &key->src_addr, &key->dst_addr);
154 0 : key->src_port = ntohs(kflow->fe_key.flow4_sport);
155 0 : key->dst_port = ntohs(kflow->fe_key.flow4_dport);
156 0 : key->protocol = kflow->fe_key.flow4_proto;
157 0 : key->family = family;
158 0 : }
159 :
160 63 : const vr_flow_entry *KSyncFlowMemory::GetValidKFlowEntry(const FlowKey &key,
161 : uint32_t idx,
162 : uint8_t gen_id) const {
163 63 : const vr_flow_entry *kflow = GetKernelFlowEntry(idx, false);
164 63 : if (!kflow) {
165 25 : return NULL;
166 : }
167 38 : if (key.protocol == IPPROTO_TCP) {
168 0 : FlowKey rhs;
169 0 : KFlow2FlowKey(kflow, &rhs);
170 0 : if (!key.IsEqual(rhs)) {
171 0 : return NULL;
172 : }
173 0 : if (kflow->fe_gen_id != gen_id) {
174 0 : return NULL;
175 : }
176 : }
177 38 : return kflow;
178 : }
179 :
180 145 : const vr_flow_entry *KSyncFlowMemory::GetKernelFlowEntry
181 : (uint32_t idx, bool ignore_active_status) const {
182 145 : if (idx == FlowEntry::kInvalidFlowHandle) {
183 3 : return NULL;
184 : }
185 :
186 142 : if (idx >= table_entries_count_) {
187 : /* if index is outside the range of flow table entries return NULL */
188 0 : return NULL;
189 : }
190 :
191 142 : if (ignore_active_status) {
192 0 : return &flow_table_[idx];
193 : }
194 :
195 142 : if (flow_table_[idx].fe_flags & VR_FLOW_FLAG_ACTIVE) {
196 91 : return &flow_table_[idx];
197 : }
198 51 : return NULL;
199 : }
200 :
201 0 : bool KSyncFlowMemory::GetFlowKey(uint32_t index, FlowKey *key, bool *is_nat_flow) {
202 0 : const vr_flow_entry *kflow = GetKernelFlowEntry(index, false);
203 0 : if (!kflow) {
204 0 : return false;
205 : }
206 0 : key->nh = kflow->fe_key.flow4_nh_id;
207 0 : Address::Family family = (kflow->fe_key.flow_family == AF_INET)?
208 : Address::INET : Address::INET6;
209 0 : VrFlowToIp(kflow, &key->src_addr, &key->dst_addr);
210 0 : key->src_port = ntohs(kflow->fe_key.flow4_sport);
211 0 : key->dst_port = ntohs(kflow->fe_key.flow4_dport);
212 0 : key->protocol = kflow->fe_key.flow4_proto;
213 0 : key->family = family;
214 0 : if (kflow->fe_action == VR_FLOW_ACTION_NAT) {
215 0 : *is_nat_flow = true;
216 : } else {
217 0 : *is_nat_flow = false;
218 : }
219 0 : return true;
220 : }
221 :
222 0 : bool KSyncFlowMemory::IsEvictionMarked(const vr_flow_entry *entry,
223 : uint16_t flags) const {
224 0 : if (!entry) {
225 0 : return false;
226 : }
227 0 : if (flags & VR_FLOW_FLAG_EVICTED) {
228 0 : return true;
229 : }
230 0 : return false;
231 : }
232 :
233 44 : const vr_flow_entry *KSyncFlowMemory::GetKFlowStats(const FlowKey &key,
234 : uint32_t idx,
235 : uint8_t gen_id,
236 : vr_flow_stats *stat) const {
237 44 : const vr_flow_entry *kflow = GetValidKFlowEntry(key, idx, gen_id);
238 44 : if (!kflow) {
239 25 : return NULL;
240 : }
241 19 : *stat = kflow->fe_stats;
242 19 : kflow = GetValidKFlowEntry(key, idx, gen_id);
243 19 : return kflow;
244 : }
245 :
246 53 : void KSyncFlowMemory::ReadFlowInfo(const vr_flow_entry *kflow,
247 : vr_flow_stats *stat, KFlowData *info) const {
248 53 : *stat = kflow->fe_stats;
249 53 : info->underlay_src_port = kflow->fe_udp_src_port;
250 53 : info->tcp_flags = kflow->fe_tcp_flags;
251 53 : info->flags = kflow->fe_flags;
252 53 : }
253 :
254 82 : const vr_flow_entry *KSyncFlowMemory::GetKFlowStatsAndInfo(const FlowKey &key,
255 : uint32_t idx,
256 : uint8_t gen_id,
257 : vr_flow_stats *stats,
258 : KFlowData *info)
259 : const {
260 82 : const vr_flow_entry *kflow = GetKernelFlowEntry(idx, false);
261 82 : if (!kflow) {
262 29 : return NULL;
263 : }
264 53 : if (key.protocol == IPPROTO_TCP) {
265 0 : FlowKey rhs;
266 0 : KFlow2FlowKey(kflow, &rhs);
267 0 : if (!key.IsEqual(rhs)) {
268 0 : return NULL;
269 : }
270 :
271 0 : ReadFlowInfo(kflow, stats, info);
272 :
273 0 : if (kflow->fe_gen_id != gen_id) {
274 0 : return NULL;
275 : }
276 : } else {
277 53 : ReadFlowInfo(kflow, stats, info);
278 : }
279 53 : return kflow;
280 : }
281 :
282 3 : void KSyncFlowMemory::InitTest() {
283 3 : table_ = KSyncSockTypeMap::FlowMmapAlloc(kTestFlowTableSize);
284 3 : memset(table_, 0, kTestFlowTableSize);
285 3 : table_entries_count_ = kTestFlowTableSize / get_entry_size();
286 3 : audit_yield_ = table_entries_count_;
287 3 : audit_timeout_ = 100 * 1000; // timout immediately.
288 3 : SetTableSize();
289 3 : }
290 :
291 3 : void KSyncFlowMemory::Shutdown() {
292 3 : KSyncSockTypeMap::FlowMmapFree();
293 3 : }
294 :
295 144 : void vr_flow_req::Process(SandeshContext *context) {
296 144 : AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
297 144 : ioc->FlowMsgHandler(this);
298 144 : }
299 :
300 144 : void vr_flow_response::Process(SandeshContext *context) {
301 144 : AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
302 144 : ioc->FlowResponseHandler(this);
303 144 : }
304 :
305 0 : void vr_flow_table_data::Process(SandeshContext *context) {
306 0 : AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
307 0 : ioc->FlowTableInfoHandler(this);
308 0 : }
|