OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ksync_flow_memory.cc
Go to the documentation of this file.
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>
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>
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 KSyncFlowMemory::KSyncFlowMemory(KSync *ksync, uint32_t minor_id) :
46  KSyncMemory(ksync, minor_id) {
47  table_path_ = FLOW_TABLE_DEV;
49 }
50 
53  proto->Register(boost::bind(&KSyncFlowMemory::GetFlowKey, this, _1, _2, _3));
54 
56 }
57 
58 int KSyncFlowMemory::EncodeReq(struct nl_client *cl, uint32_t attr_len) {
59  int encode_len, error;
60 
61  vr_flow_table_data info;
62  info.set_ftable_op(flow_op::FLOW_TABLE_GET);
63  info.set_ftable_size(0);
64  info.set_ftable_dev(0);
65  info.set_ftable_file_path("");
66  info.set_ftable_processed(0);
67  info.set_ftable_hold_oflows(0);
68  info.set_ftable_added(0);
69  info.set_ftable_cpus(0);
70  info.set_ftable_created(0);
71  info.set_ftable_oflow_entries(0);
72  encode_len = info.WriteBinary(nl_get_buf_ptr(cl) + attr_len,
73  nl_get_buf_len(cl), &error);
74  return encode_len;
75 }
76 
78  return sizeof(vr_flow_entry);
79 }
80 
83  flow_table_ = static_cast<vr_flow_entry *>(table_);
84 }
85 
86 void KSyncFlowMemory::CreateProtoAuditEntry(uint32_t idx, uint8_t gen_id) {
87  const vr_flow_entry *ventry = GetKernelFlowEntry(idx, false);
88  // Audit and remove entry if its still in HOLD state
89  if (ventry && ventry->fe_gen_id == gen_id &&
90  ventry->fe_action == VR_FLOW_ACTION_HOLD) {
91  IpAddress sip, dip;
92  VrFlowToIp(ventry, &sip, &dip);
93  FlowKey key(ventry->fe_key.flow_nh_id, sip, dip,
94  ventry->fe_key.flow_proto,
95  ntohs(ventry->fe_key.flow_sport),
96  ntohs(ventry->fe_key.flow_dport));
97 
98  FlowProto *proto = ksync_->agent()->pkt()->get_flow_proto();
99  proto->CreateAuditEntry(key, idx, gen_id);
100  }
101 }
102 
105  return;
106 }
107 
110  return;
111 }
112 
115  hold_flow_counter_ = 0;
116  return;
117 }
118 
119 bool KSyncFlowMemory::IsInactiveEntry(uint32_t audit_idx, uint8_t &gen_id) {
120  const vr_flow_entry *vflow_entry =
121  GetKernelFlowEntry(audit_idx, false);
122  if (vflow_entry && vflow_entry->fe_action == VR_FLOW_ACTION_HOLD) {
123  gen_id = vflow_entry->fe_gen_id;
124  return true;
125  }
126  return false;
127 }
128 
129 void KSyncFlowMemory::VrFlowToIp(const vr_flow_entry *kflow, IpAddress *sip,
130  IpAddress *dip) {
131  if (kflow->fe_key.flow_family == AF_INET) {
132  *sip = Ip4Address(ntohl(kflow->fe_key.key_u.ip4_key.ip4_sip));
133  *dip = Ip4Address(ntohl(kflow->fe_key.key_u.ip4_key.ip4_dip));
134  } else {
135  const unsigned char *k_sip = kflow->fe_key.key_u.ip6_key.ip6_sip;
136  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  for (int i = 0; i < 16; i++) {
140  sbytes[i] = k_sip[i];
141  dbytes[i] = k_dip[i];
142  }
143  *sip = Ip6Address(sbytes);
144  *dip = Ip6Address(dbytes);
145  }
146 }
147 
148 void KSyncFlowMemory::KFlow2FlowKey(const vr_flow_entry *kflow,
149  FlowKey *key) const {
150  key->nh = kflow->fe_key.flow4_nh_id;
151  Address::Family family = (kflow->fe_key.flow_family == AF_INET)?
153  VrFlowToIp(kflow, &key->src_addr, &key->dst_addr);
154  key->src_port = ntohs(kflow->fe_key.flow4_sport);
155  key->dst_port = ntohs(kflow->fe_key.flow4_dport);
156  key->protocol = kflow->fe_key.flow4_proto;
157  key->family = family;
158 }
159 
160 const vr_flow_entry *KSyncFlowMemory::GetValidKFlowEntry(const FlowKey &key,
161  uint32_t idx,
162  uint8_t gen_id) const {
163  const vr_flow_entry *kflow = GetKernelFlowEntry(idx, false);
164  if (!kflow) {
165  return NULL;
166  }
167  if (key.protocol == IPPROTO_TCP) {
168  FlowKey rhs;
169  KFlow2FlowKey(kflow, &rhs);
170  if (!key.IsEqual(rhs)) {
171  return NULL;
172  }
173  if (kflow->fe_gen_id != gen_id) {
174  return NULL;
175  }
176  }
177  return kflow;
178 }
179 
180 const vr_flow_entry *KSyncFlowMemory::GetKernelFlowEntry
181  (uint32_t idx, bool ignore_active_status) const {
182  if (idx == FlowEntry::kInvalidFlowHandle) {
183  return NULL;
184  }
185 
186  if (idx >= table_entries_count_) {
187  /* if index is outside the range of flow table entries return NULL */
188  return NULL;
189  }
190 
191  if (ignore_active_status) {
192  return &flow_table_[idx];
193  }
194 
195  if (flow_table_[idx].fe_flags & VR_FLOW_FLAG_ACTIVE) {
196  return &flow_table_[idx];
197  }
198  return NULL;
199 }
200 
201 bool KSyncFlowMemory::GetFlowKey(uint32_t index, FlowKey *key, bool *is_nat_flow) {
202  const vr_flow_entry *kflow = GetKernelFlowEntry(index, false);
203  if (!kflow) {
204  return false;
205  }
206  key->nh = kflow->fe_key.flow4_nh_id;
207  Address::Family family = (kflow->fe_key.flow_family == AF_INET)?
209  VrFlowToIp(kflow, &key->src_addr, &key->dst_addr);
210  key->src_port = ntohs(kflow->fe_key.flow4_sport);
211  key->dst_port = ntohs(kflow->fe_key.flow4_dport);
212  key->protocol = kflow->fe_key.flow4_proto;
213  key->family = family;
214  if (kflow->fe_action == VR_FLOW_ACTION_NAT) {
215  *is_nat_flow = true;
216  } else {
217  *is_nat_flow = false;
218  }
219  return true;
220 }
221 
222 bool KSyncFlowMemory::IsEvictionMarked(const vr_flow_entry *entry,
223  uint16_t flags) const {
224  if (!entry) {
225  return false;
226  }
227  if (flags & VR_FLOW_FLAG_EVICTED) {
228  return true;
229  }
230  return false;
231 }
232 
233 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  const vr_flow_entry *kflow = GetValidKFlowEntry(key, idx, gen_id);
238  if (!kflow) {
239  return NULL;
240  }
241  *stat = kflow->fe_stats;
242  kflow = GetValidKFlowEntry(key, idx, gen_id);
243  return kflow;
244 }
245 
246 void KSyncFlowMemory::ReadFlowInfo(const vr_flow_entry *kflow,
247  vr_flow_stats *stat, KFlowData *info) const {
248  *stat = kflow->fe_stats;
249  info->underlay_src_port = kflow->fe_udp_src_port;
250  info->tcp_flags = kflow->fe_tcp_flags;
251  info->flags = kflow->fe_flags;
252 }
253 
254 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  const vr_flow_entry *kflow = GetKernelFlowEntry(idx, false);
261  if (!kflow) {
262  return NULL;
263  }
264  if (key.protocol == IPPROTO_TCP) {
265  FlowKey rhs;
266  KFlow2FlowKey(kflow, &rhs);
267  if (!key.IsEqual(rhs)) {
268  return NULL;
269  }
270 
271  ReadFlowInfo(kflow, stats, info);
272 
273  if (kflow->fe_gen_id != gen_id) {
274  return NULL;
275  }
276  } else {
277  ReadFlowInfo(kflow, stats, info);
278  }
279  return kflow;
280 }
281 
284  memset(table_, 0, kTestFlowTableSize);
287  audit_timeout_ = 100 * 1000; // timout immediately.
288  SetTableSize();
289 }
290 
293 }
294 
295 void vr_flow_req::Process(SandeshContext *context) {
296  AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
297  ioc->FlowMsgHandler(this);
298 }
299 
300 void vr_flow_response::Process(SandeshContext *context) {
301  AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
302  ioc->FlowResponseHandler(this);
303 }
304 
305 void vr_flow_table_data::Process(SandeshContext *context) {
306  AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
307  ioc->FlowTableInfoHandler(this);
308 }
IpAddress src_addr
Definition: flow_entry.h:213
ServicesModule * services() const
Definition: agent.cc:973
bool GetFlowKey(uint32_t index, FlowKey *key, bool *is_nat_flow)
const vr_flow_entry * GetKFlowStatsAndInfo(const FlowKey &key, uint32_t idx, uint8_t gen_id, vr_flow_stats *stats, KFlowData *info) const
Agent * agent() const
Definition: ksync_init.h:39
IpAddress dst_addr
Definition: flow_entry.h:214
std::string table_path_
Definition: ksync_memory.h:73
Family
Definition: address.h:24
virtual void Shutdown()
boost::asio::ip::address IpAddress
Definition: address.h:13
AgentStats * stats() const
Definition: agent.cc:881
virtual int EncodeReq(nl_client *nl, uint32_t attr_len)
uint32_t table_entries_count_
Definition: ksync_memory.h:80
const vr_flow_entry * flow_table_
uint32_t audit_yield_
Definition: ksync_memory.h:85
virtual void FlowResponseHandler(vr_flow_response *req)
Definition: ksync_sock.h:66
virtual void Init()
Definition: ksync_memory.cc:69
uint8_t protocol
Definition: flow_entry.h:215
virtual int get_entry_size()
static void FlowMmapFree()
virtual void FlowTableInfoHandler(vr_flow_table_data *r)
Definition: ksync_sock.h:67
static void VrFlowToIp(const vr_flow_entry *kflow, IpAddress *sip, IpAddress *dip)
uint32_t hold_flow_counter_
uint16_t tcp_flags
void KFlow2FlowKey(const vr_flow_entry *entry, FlowKey *key) const
bool IsEqual(const FlowKey &key) const
Definition: flow_entry.h:176
const vr_flow_entry * GetKFlowStats(const FlowKey &key, uint32_t idx, uint8_t gen_id, vr_flow_stats *stats) const
boost::asio::ip::address_v6 Ip6Address
Definition: address.h:15
virtual void SetTableSize()
void * table_
Definition: ksync_memory.h:71
void set_flow_table_size(uint32_t count)
Definition: agent.cc:1106
void update_hold_flow_count(uint32_t value)
Definition: agent_stats.h:96
virtual void Init()
virtual void FlowMsgHandler(vr_flow_req *req)=0
virtual bool IsInactiveEntry(uint32_t idx, uint8_t &gen_id)
uint32_t audit_timeout_
Definition: ksync_memory.h:84
IcmpErrorProto * icmp_error_proto() const
Definition: services_init.h:38
KSyncFlowMemory(KSync *ksync, uint32_t minor_id)
boost::asio::ip::address_v4 Ip4Address
Definition: address.h:14
FlowProto * get_flow_proto() const
Definition: pkt_init.h:43
uint16_t src_port
Definition: flow_entry.h:216
const vr_flow_entry * GetKernelFlowEntry(uint32_t idx, bool ignore_active_status) const
Address::Family family
Definition: flow_entry.h:211
void Register(FlowIndexToKeyFn fn)
uint16_t dst_port
Definition: flow_entry.h:217
const vr_flow_entry * GetValidKFlowEntry(const FlowKey &key, uint32_t idx, uint8_t gen_id) const
KSync * ksync_
Definition: ksync_memory.h:70
bool IsEvictionMarked(const vr_flow_entry *entry, uint16_t flags) const
static const uint32_t kInvalidFlowHandle
Definition: flow_entry.h:521
void ReadFlowInfo(const vr_flow_entry *k_flow, vr_flow_stats *stats, KFlowData *info) const
static vr_flow_entry * FlowMmapAlloc(int size)
virtual void InitTest()
void CreateAuditEntry(const FlowKey &key, uint32_t flow_handle, uint8_t gen_id)
Definition: flow_proto.cc:619
static const int kTestFlowTableSize
PktModule * pkt() const
Definition: agent.cc:965
uint16_t underlay_src_port
uint32_t nh
Definition: flow_entry.h:212
virtual void CreateProtoAuditEntry(uint32_t index, uint8_t gen_id)
void UpdateAgentHoldFlowCounter()