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