5 #include <sys/socket.h>
7 #include <linux/netlink.h>
11 #include <sys/types.h>
14 #include <asm/types.h>
15 #include <boost/asio.hpp>
16 #include <boost/asio/buffer.hpp>
26 #include <ksync/ksync_types.h>
27 #include <vrouter/ksync/agent_ksync_types.h>
34 #include <vr_genetlink.h>
39 #include <oper/agent_types.h>
50 using namespace boost::asio::ip;
55 return VR_FLOW_DR_UNAVIALABLE_INTF;
57 return VR_FLOW_DR_IPv4_FWD_DIS;
59 return VR_FLOW_DR_UNAVAILABLE_VRF;
61 return VR_FLOW_DR_NO_SRC_ROUTE;
63 return VR_FLOW_DR_NO_DST_ROUTE;
65 return VR_FLOW_DR_AUDIT_ENTRY;
67 return VR_FLOW_DR_VRF_CHANGE;
69 return VR_FLOW_DR_NO_REVERSE_FLOW;
71 return VR_FLOW_DR_REVERSE_FLOW_CHANGE;
73 return VR_FLOW_DR_NAT_CHANGE;
75 return VR_FLOW_DR_FLOW_LIMIT;
77 return VR_FLOW_DR_LINKLOCAL_SRC_NAT;
79 return VR_FLOW_DR_NO_MIRROR_ENTRY;
81 return VR_FLOW_DR_SAME_FLOW_RFLOW_KEY;
83 return VR_FLOW_DR_PORT_MAP_DROP;
85 return VR_FLOW_DR_NO_SRC_ROUTE_L2RPF;
87 return VR_FLOW_DR_FAT_FLOW_NAT_CONFLICT;
89 return VR_FLOW_DR_POLICY;
91 return VR_FLOW_DR_OUT_POLICY;
95 return VR_FLOW_DR_OUT_SG;
97 return VR_FLOW_DR_REVERSE_SG;
99 return VR_FLOW_DR_REVERSE_OUT_SG;
101 return VR_FLOW_DR_FW_POLICY;
103 return VR_FLOW_DR_OUT_FW_POLICY;
105 return VR_FLOW_DR_REVERSE_FW_POLICY;
107 return VR_FLOW_DR_REVERSE_OUT_FW_POLICY;
109 return VR_FLOW_DR_FWAAS_POLICY;
111 return VR_FLOW_DR_OUT_FWAAS_POLICY;
113 return VR_FLOW_DR_REVERSE_FWAAS_POLICY;
115 return VR_FLOW_DR_REVERSE_OUT_FWAAS_POLICY;
119 return VR_FLOW_DR_UNKNOWN;
130 Reset(flow, hash_id);
147 old_component_nh_idx_ = 0xFFFF;
148 old_first_mirror_index_ = 0xFFFF;
149 old_second_mirror_index_ = 0xFFFF;
151 old_drop_reason_ = 0;
157 ksync_response_info_.Reset();
160 underlay_gw_index = -1;
185 std::vector<int8_t> &data) {
187 uint32_t addr = ksync_obj_->ksync()->agent()->router_id().to_ulong();
190 data.push_back(((addr >> 24) & 0xFF));
191 data.push_back(((addr >> 16) & 0xFF));
192 data.push_back(((addr >> 8) & 0xFF));
193 data.push_back(((addr) & 0xFF));
198 action = fe->match_p().action_info.action;
201 action |= 0x40000000;
203 data.push_back((action >> 24) & 0xFF);
204 data.push_back((action >> 16) & 0xFF);
205 data.push_back((action >> 8) & 0xFF);
206 data.push_back((action) & 0xFF);
209 data.push_back(fe->data().source_vn_match.size());
210 data.insert(data.end(), fe->data().source_vn_match.begin(),
211 fe->data().source_vn_match.end());
213 data.push_back(fe->data().dest_vn_match.size());
214 data.insert(data.end(), fe->data().dest_vn_match.begin(),
215 fe->data().dest_vn_match.end());
222 uint64_t supper, dupper, slower, dlower;
225 IpToU64(sip, dip, &supper, &slower, &dupper, &dlower);
226 req->set_fr_flow_sip_l(slower);
227 req->set_fr_flow_sip_u(supper);
228 req->set_fr_flow_dip_l(dlower);
229 req->set_fr_flow_dip_u(dupper);
234 vr_flow_req &req = ksync_obj_->flow_req();
238 uint16_t drop_reason = VR_FLOW_DR_UNKNOWN;
244 if (gen_id_ != evict_gen_id_) {
247 hash_id_, evict_gen_id_);
251 req.set_fr_op(flow_op::FLOW_SET);
253 req.set_fr_index(hash_id_);
254 req.set_fr_gen_id(gen_id_);
255 const FlowKey *fe_key = &flow_entry_->key();
257 req.set_fr_flow_proto(fe_key->
protocol);
258 req.set_fr_flow_sport(htons(fe_key->
src_port));
259 req.set_fr_flow_dport(htons(fe_key->
dst_port));
260 req.set_fr_flow_nh_id(fe_key->
nh);
262 req.set_fr_family(AF_INET);
264 req.set_fr_family(AF_INET6);
265 req.set_fr_flow_vrf(flow_entry_->data().vrf);
269 if (op == sandesh_op::DEL) {
275 req.set_fr_flags1(0);
280 flags = VR_FLOW_FLAG_ACTIVE;
281 uint32_t fe_action = flow_entry_->match_p().action_info.action;
283 action = VR_FLOW_ACTION_FORWARD;
287 action = VR_FLOW_ACTION_DROP;
288 drop_reason =
GetDropReason(flow_entry_->data().drop_reason);
291 if (action == VR_FLOW_ACTION_FORWARD &&
293 action = VR_FLOW_ACTION_NAT;
296 if (action == VR_FLOW_ACTION_NAT &&
297 flow_entry_->reverse_flow_entry() == NULL) {
298 action = VR_FLOW_ACTION_DROP;
303 if (flow_entry_->GetHbsInterface() ==
305 flags1 |= VR_FLOW_FLAG1_HBS_RIGHT;
307 flags1 |= VR_FLOW_FLAG1_HBS_LEFT;
313 flags |= VR_FLOW_FLAG_MIRROR;
314 req.set_fr_mir_id(-1);
315 req.set_fr_sec_mir_id(-1);
316 if (flow_entry_->match_p().action_info.mirror_l.size() >
319 "Don't support more than two mirrors/analyzers per "
322 data().match_p.action_info.mirror_l.size()));
325 std::vector<MirrorActionSpec>::const_iterator it;
326 it = flow_entry_->match_p().action_info.mirror_l.begin();
329 uint16_t idx_1 = obj->
GetIdx((*it).analyzer_name);
330 req.set_fr_mir_id(idx_1);
331 FLOW_TRACE(ModuleInfo,
"Mirror index first: " +
334 if (it != flow_entry_->match_p().action_info.mirror_l.end()) {
335 uint16_t idx_2 = obj->
GetIdx((*it).analyzer_name);
336 if (idx_1 != idx_2) {
337 req.set_fr_sec_mir_id(idx_2);
338 FLOW_TRACE(ModuleInfo,
"Mirror index second: " +
342 "Both Mirror indexes are same, hence didn't set "
343 "the second mirror dest.");
346 req.set_fr_mir_vrf(flow_entry_->data().mirror_vrf);
347 req.set_fr_mir_sip(htonl(ksync_obj_->ksync()->agent()->
348 router_id().to_ulong()));
349 req.set_fr_mir_sport(htons(ksync_obj_->ksync()->agent()->
351 std::vector<int8_t> pcap_data;
352 SetPcapData(flow_entry_, pcap_data);
353 req.set_fr_pcap_meta_data(pcap_data);
356 if (flow_entry_->data().component_nh_idx !=
358 req.set_fr_ecmp_nh_index(flow_entry_->data().component_nh_idx);
360 req.set_fr_ecmp_nh_index(-1);
363 if (action == VR_FLOW_ACTION_NAT) {
367 if (flow_entry_->key().src_addr != nat_key->
dst_addr) {
368 flags |= VR_FLOW_FLAG_SNAT;
370 if (flow_entry_->key().dst_addr != nat_key->
src_addr) {
371 flags |= VR_FLOW_FLAG_DNAT;
374 if (flow_entry_->key().protocol == IPPROTO_TCP ||
375 flow_entry_->key().protocol == IPPROTO_UDP) {
376 if (flow_entry_->key().src_port != nat_key->
dst_port) {
377 flags |= VR_FLOW_FLAG_SPAT;
379 if (flow_entry_->key().dst_port != nat_key->
src_port) {
380 flags |= VR_FLOW_FLAG_DPAT;
386 flags |= VR_FLOW_FLAG_LINK_LOCAL;
391 flags |= VR_FLOW_BGP_SERVICE;
395 flags |= VR_FLOW_BGP_SERVICE;
398 flags |= VR_FLOW_FLAG_VRFT;
399 req.set_fr_flow_dvrf(flow_entry_->data().dest_vrf);
401 flags |= VR_FLOW_FLAG_VRFT;
402 req.set_fr_flow_dvrf(flow_entry_->data().dest_vrf);
406 flags |= VR_FLOW_FLAG_VRFT;
407 req.set_fr_flow_dvrf(flow_entry_->data().dest_vrf);
411 action = VR_FLOW_ACTION_HOLD;
415 req.set_fr_src_nh_index(src_nh_id_);
419 req.set_fr_src_nh_index(0);
424 flags |= VR_RFLOW_VALID;
428 req.set_fr_rflow_nh_id(rkey.
nh);
429 uint64_t supper, dupper, slower, dlower;
433 req.set_fr_rflow_sip_l(slower);
434 req.set_fr_rflow_sip_u(supper);
435 req.set_fr_rflow_dip_l(dlower);
436 req.set_fr_rflow_dip_u(dupper);
438 req.set_fr_rflow_sport(htons(rkey.
src_port));
439 req.set_fr_rflow_dport(htons(rkey.
dst_port));
443 if (flow_entry_->IsShortFlow()) {
444 action = VR_FLOW_ACTION_DROP;
447 req.set_fr_flags(flags);
448 req.set_fr_flags1(flags1);
449 req.set_fr_action(action);
450 req.set_fr_drop_reason(drop_reason);
451 req.set_fr_qos_id(qos_config_idx);
452 req.set_fr_ttl(flow_entry_->data().ttl);
453 req.set_fr_underlay_ecmp_index(underlay_gw_index);
457 token_ = proto->
GetToken(last_event_);
458 encode_len = req.WriteBinary((uint8_t *)buf, buf_len, &error);
463 bool changed =
false;
468 if (old_reverse_flow_id_ != rev_flow->
flow_handle()) {
475 if (flow_entry_->match_p().action_info.action != old_action_) {
476 old_action_ = flow_entry_->match_p().action_info.action;
480 if (flow_entry_->data().drop_reason != old_drop_reason_) {
481 old_drop_reason_ = flow_entry_->data().drop_reason;
484 if (flow_entry_->data().component_nh_idx != old_component_nh_idx_) {
485 old_component_nh_idx_ = flow_entry_->data().component_nh_idx;
489 if (vrouter_gen_id_ != gen_id_) {
490 vrouter_gen_id_ = gen_id_;
494 if (vrouter_hash_id_ != hash_id_) {
495 vrouter_hash_id_ = hash_id_;
501 std::vector<MirrorActionSpec>::const_iterator it;
502 it = flow_entry_->match_p().action_info.mirror_l.begin();
503 if (it != flow_entry_->match_p().action_info.mirror_l.end()) {
504 uint16_t idx = obj->
GetIdx((*it).analyzer_name);
505 if (!((*it).analyzer_name.empty()) &&
508 ksync_obj_->UpdateUnresolvedFlowEntry(flow_entry_);
509 }
else if (old_first_mirror_index_ != idx) {
510 old_first_mirror_index_ = idx;
514 if (it != flow_entry_->match_p().action_info.mirror_l.end()) {
515 idx = obj->
GetIdx((*it).analyzer_name);
516 if (!((*it).analyzer_name.empty()) &&
519 ksync_obj_->UpdateUnresolvedFlowEntry(flow_entry_);
520 }
else if (old_second_mirror_index_ != idx) {
521 old_second_mirror_index_ = idx;
538 if (enable_rpf_ != flow_entry_->data().enable_rpf) {
539 enable_rpf_ = flow_entry_->data().enable_rpf;
544 if (flow_entry_->data().rpf_nh.get()) {
545 nh_id = flow_entry_->data().rpf_nh.get()->id();
547 if (src_nh_id_ != nh_id) {
552 if (qos_config_idx != flow_entry_->data().qos_config_idx) {
553 qos_config_idx = flow_entry_->data().qos_config_idx;
556 if (transaction_id_ != flow_entry_->GetTransactionId()) {
557 transaction_id_ = flow_entry_->GetTransactionId();
560 if (underlay_gw_index != flow_entry_->data().underlay_gw_index_) {
561 underlay_gw_index = flow_entry_->data().underlay_gw_index_;
576 return Encode(sandesh_op::ADD, buf, buf_len);
580 return Encode(sandesh_op::ADD, buf, buf_len);
584 return Encode(sandesh_op::DEL, buf, buf_len);
588 std::ostringstream str;
589 const FlowKey *fe_key = &flow_entry_->key();
590 str <<
"Flow : " << hash_id_
591 <<
" with Source IP: " << fe_key->
src_addr.to_string()
592 <<
" Source port: " << fe_key->
src_port
593 <<
" Destination IP: " << fe_key->
dst_addr.to_string()
594 <<
" Destination port: " << fe_key->
dst_port
595 <<
" Protocol "<< (uint16_t)fe_key->
protocol;
616 if (err == ENOSPC || err == EBADF) {
617 KSYNC_ERROR(VRouterError,
"VRouter operation failed. Error <", err,
618 ":", VrouterError(err),
">. Object <",
ToString(),
619 ">. Operation <", AckOperationString(event),
620 ">. Message number :", seq_no);
627 return "Flow gen id Mismatch";
628 else if (error == ENOSPC)
629 return "Flow Table bucket full";
630 else if (error == EFAULT)
631 return "Flow Key Mismatch with same gen id";
638 unresolved_flow_list_.push_back(flow_entry);
648 if (timer_ == NULL) {
650 *(ksync_->agent()->event_manager())->io_service(),
651 "flow dep sync timer",
653 flow_table()->table_index());
655 timer_->
Start(kFlowDepSyncTimeout,
667 while (!unresolved_flow_list_.empty() && count < KFlowUnresolvedListYield) {
670 unresolved_flow_list_.pop_front();
678 if (!unresolved_flow_list_.empty())
684 KSyncObject(
"KSync FlowTable"), ksync_(ksync), free_list_(this),
689 KSyncObject(
"KSync FlowTable", max_index), ksync_(ksync), free_list_(this) {
722 uint32_t flow_handle) {
733 object_(object), max_count_(0), grow_pending_(false), total_alloc_(0),
734 total_free_(0), free_list_() {
761 for (uint32_t i = 0; i <
kGrowSize; i++) {
FlowTable * flow_table() const
void KSyncEventRequest(KSyncEntry *ksync_entry, KSyncEntry::KSyncEvent event, uint32_t flow_handle, uint8_t gen_id, int ksync_error, uint64_t evict_flow_bytes, uint64_t evict_flow_packets, int32_t evict_flow_oflow, uint32_t transcation_id)
FlowTableKSyncObject(KSync *ksync)
static const uint32_t kInvalidComponentNHIdx
void SetUnResolvedList(bool added)
static const uint32_t kTestInitCount
void set_evict_gen_id(uint8_t gen_id)
uint32_t GetTransactionId()
KSyncEntry * Alloc(const KSyncEntry *key, uint32_t index)
static void EncodeKSyncIp(vr_flow_req *req, const IpAddress &sip, const IpAddress &dip)
virtual KSyncEntry * UnresolvedReference()
KSyncFlowEntryFreeList free_list_
void IpToU64(const IpAddress &sip, const IpAddress &dip, uint64_t *sip_u, uint64_t *sip_l, uint64_t *dip_u, uint64_t *dip_l)
boost::asio::ip::address IpAddress
std::string ToString() const
static const uint32_t kInvalidIndex
#define KSYNC_ERROR(obj,...)
uint16_t table_index() const
FlowTableKSyncObject * object_
static const uint32_t kMaxThreshold
virtual void NetlinkAck(KSyncEntry *entry, KSyncEntry::KSyncEvent event)
void ChangeKey(KSyncEntry *entry, uint32_t arg)
uint16_t allocated_port()
void SetPcapData(FlowEntryPtr fe, std::vector< int8_t > &data)
void GenerateKSyncEvent(FlowTableKSyncEntry *entry, KSyncEntry::KSyncEvent event)
const FlowKey & key() const
static string ToString(PhysicalDevice::ManagementProtocol proto)
void UpdateKey(KSyncEntry *entry, uint32_t flow_handle)
uint32_t GetKey(KSyncEntry *entry)
virtual void ErrorHandler(int, uint32_t, KSyncEvent) const
static const uint8_t kInvalidIndex
static const uint32_t kRpfDiscardIndex
virtual ~FlowTableKSyncEntry()
bool is_flags_set(const FlowEntryFlags &flags) const
virtual ~KSyncFlowEntryFreeList()
static const std::string integerToString(const NumberType &num)
virtual ~FlowTableKSyncObject()
void Free(FlowTableKSyncEntry *flow)
MirrorKSyncObject * mirror_ksync_obj() const
void UpdateUnresolvedFlowEntry(FlowEntryPtr flowptr)
uint32_t get_transaction_id() const
void Free(KSyncEntry *key)
FlowTableKSyncEntry * Allocate(const KSyncEntry *key)
uint64_t evict_flow_packets_
void EnqueueUnResolvedFlowEntry(FlowEntry *flow)
static const uint32_t kMinThreshold
#define FLOW_TRACE(obj,...)
const FlowKSyncResponseInfo * ksync_response_info() const
virtual std::string VrouterError(uint32_t error) const
static Timer * CreateTimer(boost::asio::io_context &service, const std::string &name, int task_id=Timer::GetTimerTaskId(), int task_instance=Timer::GetTimerInstanceId(), bool delete_on_completion=false)
FlowProto * get_flow_proto() const
static uint16_t GetDropReason(uint16_t dr)
void NetlinkAck(KSyncEntry *entry, KSyncEntry::KSyncEvent event)
virtual std::string VrouterError(uint32_t error) const
uint32_t flow_handle() const
int AddMsg(char *buf, int buf_len)
bool IsLess(const KSyncEntry &rhs) const
static const uint8_t kMaxMirrorsPerFlow
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
static const uint32_t kInvalidFlowHandle
bool IsOnUnresolvedList()
FlowTableKSyncEntry(FlowTableKSyncObject *obj)
FlowEntry * reverse_flow_entry()
virtual uint32_t GetTableIndex() const
uint64_t evict_flow_bytes_
FlowEntryPtr flow_entry() const
int DeleteMsg(char *buf, int buf_len)
int32_t evict_flow_oflow_
KSyncFlowEntryFreeList(FlowTableKSyncObject *object)
int ChangeMsg(char *buf, int buf_len)
uint32_t GetIdx(std::string analyzer_name)
static const uint32_t kGrowSize
static const uint32_t kInitCount
void UpdateFlowHandle(FlowTableKSyncEntry *entry, uint32_t flow_handle)
int Encode(sandesh_op::type op, char *buf, int buf_len)
static bool DeleteTimer(Timer *Timer)
boost::intrusive_ptr< FlowEntry > FlowEntryPtr
void GrowFreeListRequest(FlowTable *table)
KSyncObject * GetObject() const
TokenPtr GetToken(FlowEvent::Event event)
FlowTableKSyncEntry * Find(FlowEntry *key)