From 73aa1755362700a45ec455bf914f22132389df85 Mon Sep 17 00:00:00 2001 From: jayaramsatya Date: Wed, 6 Jul 2016 15:29:07 +0530 Subject: [PATCH] Mirroring function will be enhanced with the following options: 1. Knob to control addition of Juniper header This nob is to control the mirror packet with or without Juniper header 2. Knob to control if the Nexthop used is dynamic or static. if this nob is by default enabled for dynamic if static is choosen then config needs to be updated with Vtep VNI details Config points to Dynamic without Juniper header ------------------------------------------------ config provides mirror_vrf if the Vrfentry is present based on remote vm mac bridge entry lookup is done and if it is present the active nexthop & label pointed will be attached to mirror entry Vrfentry is not present oper entry will be created that downloads the control-node route information if the active next hop is preset attach it to mirror entry otherwise point to Discard entry. Config points to Static without Juniper header ---------------------------------------------- Config provides Vtep destination IP & VNI details if the active nexthop points to TunnelNH of type vxlan, attach it to Mirror entry otherwise create new tunnel NH with vtep dst ip of type VXLAN and attach it to mirror entry. Change-Id: Ib6c4af21b5807f9bf57b83728fcd4ea4106add57 Partial-Bug: #1592049 --- src/vnsw/agent/cfg/cfg_mirror.cc | 78 ++++- src/vnsw/agent/filter/acl.cc | 44 ++- src/vnsw/agent/filter/acl_entry_spec.h | 10 + src/vnsw/agent/oper/agent.sandesh | 10 + src/vnsw/agent/oper/mirror_table.cc | 247 +++++++++++++++- src/vnsw/agent/oper/mirror_table.h | 56 +++- src/vnsw/agent/oper/vm_interface.cc | 31 +- src/vnsw/agent/oper/vrf.h | 1 + src/vnsw/agent/test/test_mirror.cc | 293 ++++++++++++++++++- src/vnsw/agent/vrouter/ksync/mirror_ksync.cc | 8 +- src/vnsw/agent/vrouter/ksync/mirror_ksync.h | 2 + 11 files changed, 746 insertions(+), 34 deletions(-) diff --git a/src/vnsw/agent/cfg/cfg_mirror.cc b/src/vnsw/agent/cfg/cfg_mirror.cc index fc3b51dd4c1..ac9c0d99c2f 100644 --- a/src/vnsw/agent/cfg/cfg_mirror.cc +++ b/src/vnsw/agent/cfg/cfg_mirror.cc @@ -98,12 +98,36 @@ const char *MirrorCfgTable::Add(const MirrorCreateReq &cfg) { return "Invalid mirror destination port "; } - IpAddress sip = agent_cfg_->agent()->GetMirrorSourceIp(dest_ip); - - MirrorTable::AddMirrorEntry(entry->key.handle, - entry->data.mirror_vrf, sip, - agent_cfg_->agent()->mirror_port(), - dest_ip, entry->data.udp_port); + IpAddress sip = agent_cfg_->agent()->GetMirrorSourceIp(dest_ip); + MirrorEntryData::MirrorEntryFlags mirror_flag = + MirrorTable::DecodeMirrorFlag(cfg.get_nhmode(), + cfg.get_juniperheader()); + if (mirror_flag == MirrorEntryData::DynamicNH_With_JuniperHdr) { + MirrorTable::AddMirrorEntry(entry->key.handle, + entry->data.mirror_vrf, sip, + agent_cfg_->agent()->mirror_port(), + dest_ip, entry->data.udp_port); + } else if (mirror_flag == MirrorEntryData::DynamicNH_Without_JuniperHdr) { + MacAddress mac = MacAddress::FromString(cfg.get_analyzer_vm_mac()); + MirrorTable::AddMirrorEntry(entry->key.handle,entry->data.mirror_vrf, + sip, agent_cfg_->agent()->mirror_port(), + dest_ip, entry->data.udp_port, 0, + mirror_flag, mac); + } else if (mirror_flag == MirrorEntryData::StaticNH_Without_JuniperHdr) { + + IpAddress dst_ip = IpAddress::from_string(cfg.get_vtep_dst_ip(), ec); + if (ec.value() != 0) { + delete entry; + return "Invalid mirror destination address "; + } + MirrorTable::AddMirrorEntry(entry->key.handle, entry->data.mirror_vrf, + sip, agent_cfg_->agent()->mirror_port(), + dst_ip, entry->data.udp_port, + cfg.get_vni(), mirror_flag, + MacAddress::ZeroMac()); + } else { + return "Mode not supported"; + } // Update ACL VnAclMap::iterator va_it; @@ -432,12 +456,42 @@ const char *IntfMirrorCfgTable::Add(const IntfMirrorCreateReq &intf_mirror) { entry->data.mirror_dest.time_period = intf_mirror.get_time_period(); entry->data.mirror_dest.mirror_vrf = intf_mirror.get_mirror_vrf(); - MirrorTable::AddMirrorEntry(entry->key.handle, - entry->data.mirror_dest.mirror_vrf, - entry->data.mirror_dest.sip, - entry->data.mirror_dest.sport, - entry->data.mirror_dest.dip, - entry->data.mirror_dest.dport); + MirrorEntryData::MirrorEntryFlags mirror_flag = + MirrorTable::DecodeMirrorFlag (intf_mirror.get_nhmode(), + intf_mirror.get_juniperheader()); + if (mirror_flag == MirrorEntryData::DynamicNH_With_JuniperHdr) { + MirrorTable::AddMirrorEntry(entry->key.handle, + entry->data.mirror_dest.mirror_vrf, + entry->data.mirror_dest.sip, + entry->data.mirror_dest.sport, + entry->data.mirror_dest.dip, + entry->data.mirror_dest.dport); + } else if (mirror_flag == MirrorEntryData::DynamicNH_Without_JuniperHdr) { + MacAddress mac = MacAddress::FromString(intf_mirror.get_analyzer_vm_mac()); + MirrorTable::AddMirrorEntry(entry->key.handle, + entry->data.mirror_dest.mirror_vrf, + entry->data.mirror_dest.sip, + entry->data.mirror_dest.sport, + entry->data.mirror_dest.dip, + entry->data.mirror_dest.dport, 0, + mirror_flag, mac); + } else if (mirror_flag == MirrorEntryData::StaticNH_Without_JuniperHdr) { + IpAddress dst_ip = IpAddress::from_string(intf_mirror.get_vtep_dst_ip(), ec); + if (ec.value() != 0) { + delete entry; + return "Invalid mirror destination address "; + } + MirrorTable::AddMirrorEntry(entry->key.handle, + entry->data.mirror_dest.mirror_vrf, + entry->data.mirror_dest.sip, + entry->data.mirror_dest.sport, + dst_ip, entry->data.mirror_dest.dport, + intf_mirror.get_vni(), mirror_flag, + MacAddress::ZeroMac()); + } else { + return "not supported"; + } + intf_mc_tree_.insert(std::pair(key, entry)); VmInterfaceKey *intf_key = new VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, diff --git a/src/vnsw/agent/filter/acl.cc b/src/vnsw/agent/filter/acl.cc index 709db1d6eb2..26a76381ad2 100644 --- a/src/vnsw/agent/filter/acl.cc +++ b/src/vnsw/agent/filter/acl.cc @@ -944,9 +944,28 @@ void AclEntrySpec::AddMirrorEntry(Agent *agent) const { } IpAddress sip = agent->GetMirrorSourceIp(action.ma.ip); - agent->mirror_table()->AddMirrorEntry(action.ma.analyzer_name, - action.ma.vrf_name, sip, agent->mirror_port(), action.ma.ip, - action.ma.port); + MirrorEntryData::MirrorEntryFlags mirror_flag = + MirrorTable::DecodeMirrorFlag(action.ma.nh_mode, + action.ma.juniper_header); + if (mirror_flag == MirrorEntryData::DynamicNH_With_JuniperHdr) { + agent->mirror_table()->AddMirrorEntry(action.ma.analyzer_name, + action.ma.vrf_name, sip, agent->mirror_port(), action.ma.ip, + action.ma.port); + } else if (mirror_flag == MirrorEntryData::DynamicNH_Without_JuniperHdr) { + // remote_vm_analyzer mac provided from the config + agent->mirror_table()->AddMirrorEntry(action.ma.analyzer_name, + action.ma.vrf_name, sip, agent->mirror_port(), action.ma.ip, + action.ma.port, 0, mirror_flag, action.ma.mac); + } else if (mirror_flag == MirrorEntryData::StaticNH_Without_JuniperHdr) { + // Vtep dst ip & Vni will be provided from the config + agent->mirror_table()->AddMirrorEntry(action.ma.analyzer_name, + action.ma.vrf_name, sip, agent->mirror_port(), + action.ma.staticnhdata.vtep_dst_ip, action.ma.port, + action.ma.staticnhdata.vni, mirror_flag, + action.ma.staticnhdata.vtep_dst_mac); + } else { + LOG(ERROR, "Mirror nh mode not supported"); + } } } @@ -979,6 +998,25 @@ void AclEntrySpec::PopulateAction(const AclTable *acl_table, maction.ma.analyzer_name = action_list.mirror_to.analyzer_name; maction.ma.ip = IpAddress::from_string(action_list.mirror_to.analyzer_ip_address, ec); + maction.ma.juniper_header = action_list.mirror_to.juniper_header; + maction.ma.nh_mode = action_list.mirror_to.nh_mode; + MirrorEntryData::MirrorEntryFlags mirror_flag = + MirrorTable::DecodeMirrorFlag (maction.ma.nh_mode, + maction.ma.juniper_header); + if (mirror_flag == MirrorEntryData::StaticNH_Without_JuniperHdr) { + maction.ma.staticnhdata.vtep_dst_ip = + IpAddress::from_string( + action_list.mirror_to.static_nh_header.vtep_dst_ip_address, ec); + maction.ma.staticnhdata.vtep_dst_mac = + MacAddress::FromString(action_list.mirror_to.static_nh_header.vtep_dst_mac_address); + maction.ma.staticnhdata.vni = + action_list.mirror_to.static_nh_header.vni; + } else if(mirror_flag == MirrorEntryData::DynamicNH_Without_JuniperHdr) { + maction.ma.vrf_name = action_list.mirror_to.routing_instance; + maction.ma.mac = + MacAddress::FromString(action_list.mirror_to.analyzer_mac_address); + } + if (ec.value() == 0) { if (action_list.mirror_to.udp_port) { maction.ma.port = action_list.mirror_to.udp_port; diff --git a/src/vnsw/agent/filter/acl_entry_spec.h b/src/vnsw/agent/filter/acl_entry_spec.h index 93bf67607ff..59d7ea0dd3a 100644 --- a/src/vnsw/agent/filter/acl_entry_spec.h +++ b/src/vnsw/agent/filter/acl_entry_spec.h @@ -22,12 +22,22 @@ struct RangeSpec { uint16_t max; }; +struct StaticMirrorNhData { + IpAddress vtep_dst_ip; + uint32_t vni; + MacAddress vtep_dst_mac; +}; + struct MirrorActionSpec { std::string analyzer_name; std::string vrf_name; IpAddress ip; + MacAddress mac; uint16_t port; std::string encap; + bool juniper_header; + std::string nh_mode; + StaticMirrorNhData staticnhdata; bool operator == (const MirrorActionSpec &rhs) const { return analyzer_name == rhs.analyzer_name; } diff --git a/src/vnsw/agent/oper/agent.sandesh b/src/vnsw/agent/oper/agent.sandesh index 0da8c709d84..befe22b7933 100644 --- a/src/vnsw/agent/oper/agent.sandesh +++ b/src/vnsw/agent/oper/agent.sandesh @@ -1073,6 +1073,11 @@ request sandesh MirrorCreateReq { // Time period for mirroring in seconds 16: i32 time_period; 17: string mirror_vrf; + 18: optional string nhmode; // dynamic or static NH + 19: optional bool juniperheader; + 20: optional string analyzer_vm_mac; // analyzer mac + 21: optional string vtep_dst_ip; + 22: optional i32 vni; } /** @@ -1249,6 +1254,11 @@ request sandesh IntfMirrorCreateReq { 5: optional i32 udp_port; 6: optional i32 time_period; 7: optional string mirror_vrf; + 8: optional string nhmode; // dynamic or static NH + 9: optional bool juniperheader; + 10: optional string analyzer_vm_mac; // analyzer mac + 11: optional string vtep_dst_ip; + 12: optional i32 vni; } /** diff --git a/src/vnsw/agent/oper/mirror_table.cc b/src/vnsw/agent/oper/mirror_table.cc index 9f276527147..135a6389c97 100644 --- a/src/vnsw/agent/oper/mirror_table.cc +++ b/src/vnsw/agent/oper/mirror_table.cc @@ -19,7 +19,6 @@ using namespace std; using namespace boost::asio; - MirrorTable *MirrorTable::mirror_table_; MirrorTable::~MirrorTable() { @@ -58,16 +57,96 @@ DBEntry *MirrorTable::Add(const DBRequest *req) { return mirror_entry; } +bool MirrorTable::OnChange(MirrorEntry *mirror_entry) { + bool ret = false; + NextHop *nh; + bool valid_nh = false; + if (mirror_entry->mirror_flags_ == + MirrorEntryData::DynamicNH_Without_JuniperHdr) { + VrfEntry *vrf = agent()->vrf_table()->FindVrfFromName(mirror_entry->vrf_name_); + // mirror vrf should have been created + if(vrf != NULL) { + BridgeRouteKey key(agent()->evpn_peer(), mirror_entry->vrf_name_, + mirror_entry->mac_); + BridgeRouteEntry *rt = static_cast + (static_cast + (vrf->GetBridgeRouteTable())->FindActiveEntry(&key)); + + // if route entry is preset assign the active nexthop to mirror entry + // if route entry & active apath is not preset create discard nh + // and add it unresolved entry + if (rt != NULL) { + const AgentPath *path = rt->GetActivePath(); + nh = path->nexthop(); + if (nh != NULL) { + mirror_entry->vni_ = rt->GetActiveLabel(); + AddResolvedVrfMirrorEntry(mirror_entry); + valid_nh = true; + } + } + } + } else { //StaticNH Without Juniper Hdr + InetUnicastRouteEntry *rt = + agent()->fabric_inet4_unicast_table()->FindLPM(mirror_entry->dip_); + //if route entry is preset add the active next hop else add discard nh + if (rt != NULL) { + DBRequest nh_req; + nh_req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + TunnelNHKey *nh_key = + new TunnelNHKey(agent()->fabric_vrf_name(), + mirror_entry->sip_.to_v4(), + mirror_entry->dip_.to_v4(), + false, TunnelType::VXLAN); + nh_req.key.reset(nh_key); + nh_req.data.reset(NULL); + agent()->nexthop_table()->Process(nh_req); + nh = static_cast + (agent()->nexthop_table()->FindActiveEntry(nh_key)); + if (nh != NULL) { + valid_nh = true; + AddResolvedVrfMirrorEntry(mirror_entry); + } + } + } + + // if there is no Valid nh point it to discard nh + if (!valid_nh) { + DiscardNH key; + nh = static_cast + (agent()->nexthop_table()->FindActiveEntry(&key)); + AddUnresolved(mirror_entry); + } + + if (mirror_entry->nh_ != nh) { + ret = true; + mirror_entry->nh_ = nh; + } + return ret; +} + bool MirrorTable::OnChange(DBEntry *entry, const DBRequest *req) { - bool ret = false; + bool ret = false; MirrorEntry *mirror_entry = static_cast(entry); MirrorEntryData *data = static_cast(req->data.get()); - - mirror_entry->vrf_name_ = data->vrf_name_; + if (mirror_entry->vrf_name_ != data->vrf_name_ || + mirror_entry->mirror_flags_ != data->mirror_flags_) { + DeleteMirrorVrf(mirror_entry); + mirror_entry->vrf_name_ = data->vrf_name_; + } mirror_entry->sip_ = data->sip_; mirror_entry->sport_ = data->sport_; mirror_entry->dip_ = data->dip_; mirror_entry->dport_ = data->dport_; + mirror_entry->mirror_flags_ = data->mirror_flags_; + mirror_entry->vni_ = data->vni_; + mirror_entry->mac_ = data->mac_; + mirror_entry->createdvrf_ = data->createdvrf_; + if (mirror_entry->mirror_flags_ == MirrorEntryData::DynamicNH_Without_JuniperHdr || + mirror_entry->mirror_flags_ == MirrorEntryData::StaticNH_Without_JuniperHdr) + { + ret = OnChange(mirror_entry); + return ret; + } DBRequest nh_req; nh_req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; @@ -115,9 +194,26 @@ bool MirrorTable::Delete(DBEntry *entry, const DBRequest *request) { MirrorEntry *mirror_entry = static_cast(entry); RemoveUnresolved(mirror_entry); DeleteResolvedVrfMirrorEntry(mirror_entry); + DeleteMirrorVrf(mirror_entry); return true; } +void MirrorTable::DeleteMirrorVrf(MirrorEntry *entry) { + if (entry->mirror_flags_ == MirrorEntryData::DynamicNH_Without_JuniperHdr){ + RemoveUnresolved(entry); + DeleteResolvedVrfMirrorEntry(entry); + VrfEntry *vrf = + agent()->vrf_table()->FindVrfFromName(entry->vrf_name_); + if (vrf) { + bool confvrf = vrf->flags() & VrfData::ConfigVrf; + bool gwvrf = vrf->flags() & VrfData::GwVrf; + if (entry->createdvrf_ && !confvrf && !gwvrf) + agent()->vrf_table()->DeleteVrfReq(entry->vrf_name_, + VrfData::MirrorVrf); + } + } +} + void MirrorTable::Add(VrfMirrorEntryList &vrf_entry_map, MirrorEntry *entry) { VrfMirrorEntryList::iterator it = vrf_entry_map.find(entry->vrf_name_); @@ -171,7 +267,9 @@ void MirrorTable::ResyncMirrorEntry(VrfMirrorEntryList &list, *((*list_it)->GetSip()), (*list_it)->GetSPort(), *((*list_it)->GetDip()), - (*list_it)->GetDPort()); + (*list_it)->GetDPort(), (*list_it)->GetMirrorFlag(), + (*list_it)->GetVni(), *((*list_it)->GetMac()), + (*list_it)->GetCreatedVrf()); req.key.reset(key); req.data.reset(data); Enqueue(&req); @@ -203,6 +301,41 @@ void MirrorTable::ResyncUnresolvedMirrorEntry(const VrfEntry *vrf) { ResyncMirrorEntry(unresolved_entry_list_, vrf); } + +void MirrorTable::AddMirrorEntry(const std::string &analyzer_name, + const std::string &vrf_name, + const IpAddress &sip, uint16_t sport, + const IpAddress &dip, uint16_t dport, + uint32_t vni, uint8_t mirror_flag, + const MacAddress &mac) { + Agent *agent = Agent::GetInstance(); + bool createdvrf = false; + DBRequest req; + + if (dip.is_v6() && vrf_name == mirror_table_->agent()->fabric_vrf_name()) { + LOG(ERROR, "Ipv6 as destination not supported on Fabric VRF: " << + dip.to_string()); + return; + } + // if Mirror VRF is not preset create the vrf. + // creatation of VRF ensures all the routes will be dowloaded from control node. + if (mirror_flag == MirrorEntryData::DynamicNH_Without_JuniperHdr) { + VrfEntry *vrf = agent->vrf_table()->FindVrfFromName(vrf_name); + if (vrf == NULL) { + agent->vrf_table()->CreateVrfReq(vrf_name, VrfData::MirrorVrf); + createdvrf = true; + } + } + MirrorEntryKey *key = new MirrorEntryKey(analyzer_name); + MirrorEntryData *data = new MirrorEntryData(vrf_name, sip, sport, dip, + dport, mirror_flag, vni, mac, + createdvrf); + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + req.key.reset(key); + req.data.reset(data); + mirror_table_->Enqueue(&req); +} + void MirrorTable::AddMirrorEntry(const std::string &analyzer_name, const std::string &vrf_name, const IpAddress &sip, uint16_t sport, @@ -226,7 +359,8 @@ void MirrorTable::AddMirrorEntry(const std::string &analyzer_name, req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; MirrorEntryKey *key = new MirrorEntryKey(analyzer_name); MirrorEntryData *data = new MirrorEntryData(vrf_name, sip, - sport, dip, dport); + sport, dip, dport, 1, 0 , + MacAddress::ZeroMac(), false); req.key.reset(key); req.data.reset(data); mirror_table_->Enqueue(&req); @@ -263,16 +397,101 @@ void MirrorTable::VrfListenerInit() { } void MirrorTable::VrfNotify(DBTablePartBase *base, DBEntryBase *entry) { - const VrfEntry *vrf = static_cast(entry); + VrfEntry *vrf = static_cast(entry); + MirrorVrfState *state = static_cast + (vrf->GetState(base->parent(), vrf_listener_id_)); if (vrf->IsDeleted()) { + if (state) { + UnRegisterBridgeRouteTableListener(vrf, state); + vrf->ClearState(base->parent(), vrf_listener_id_); + delete state; + } //VRF is getting deleted remove all the mirror nexthop ResyncResolvedMirrorEntry(vrf); return; } + // This will be for dynamic witout juniper header, to resolve the + // bridge entry lookup + bool miror_vrf = UnresolvedMirrorVrf(vrf, unresolved_entry_list_); + if (state == NULL && miror_vrf) { + state = new MirrorVrfState(); + state->seen_ = true; + vrf->SetState(base->parent(), vrf_listener_id_, state); + if (state->bridge_rt_table_listener_id_ == DBTableBase::kInvalidId) { + BridgeAgentRouteTable *bridge_table = + static_cast + (vrf->GetBridgeRouteTable()); + state->bridge_rt_table_listener_id_ = + bridge_table->Register(boost::bind(&MirrorTable::BridgeRouteTableNotify, + this, _1, _2)); + } + } ResyncUnresolvedMirrorEntry(vrf); } +bool MirrorTable::UnresolvedMirrorVrf(const VrfEntry *vrf, + VrfMirrorEntryList &list){ + VrfMirrorEntryList::iterator it = list.find(vrf->GetName()); + if (it == list.end()) { + return false; + } + // Need to check if there are any entries with DynamicNH_Without_JuniperHdr + MirrorEntryList::iterator list_it = it->second.begin(); + for(;list_it != it->second.end(); list_it++) { + if ((*list_it)->GetMirrorFlag() == + MirrorEntryData::DynamicNH_Without_JuniperHdr) { + return true; + } + } + return false; +} +// if the Unresolved remote mac is present it will return the entry +MirrorEntry* +MirrorTable::UnresolvedMirrorEntry(VrfEntry *vrf, const MacAddress & mac, + VrfMirrorEntryList &list) { + VrfMirrorEntryList::iterator it = list.find(vrf->GetName()); + if (it == list.end()) { + return NULL; + } + MirrorEntryList::iterator list_it = it->second.begin(); + for(;list_it != it->second.end(); list_it++) { + const MacAddress &remote_vm_mac = *((*list_it)->GetMac()); + if (remote_vm_mac == mac) { + return (*list_it); + } + } + return NULL; +} + + +void MirrorTable::BridgeRouteTableNotify(DBTablePartBase *partition, + DBEntryBase *entry) { + const BridgeRouteEntry *bridge_rt = static_cast(entry); + if (bridge_rt->IsDeleted()) { + ResyncResolvedMirrorEntry(bridge_rt->vrf()); + } else { + MirrorEntry *mirror_entry = UnresolvedMirrorEntry(bridge_rt->vrf(), + bridge_rt->mac(), + unresolved_entry_list_); + if (mirror_entry && + mirror_entry->mirror_flags_ == + MirrorEntryData::DynamicNH_Without_JuniperHdr) { + ResyncUnresolvedMirrorEntry(bridge_rt->vrf()); + } + } +} + +void MirrorTable::UnRegisterBridgeRouteTableListener(const VrfEntry *vrf, + MirrorVrfState *state) { + if (state->bridge_rt_table_listener_id_ == DBTableBase::kInvalidId) + return; + BridgeAgentRouteTable *bridge_table = static_cast + (vrf->GetBridgeRouteTable()); + bridge_table->Unregister(state->bridge_rt_table_listener_id_); + state->bridge_rt_table_listener_id_ = DBTableBase::kInvalidId; +} + void MirrorTable::ReadHandler(const boost::system::error_code &ec, size_t bytes_transferred) { @@ -369,3 +588,17 @@ AgentSandeshPtr MirrorTable::GetAgentSandesh(const AgentSandeshArguments *args, return AgentSandeshPtr(new AgentMirrorSandesh(context, args->GetString("analyzer_name"))); } + +MirrorEntryData::MirrorEntryFlags +MirrorTable::DecodeMirrorFlag (const std::string &nh_mode, bool juniper_header) { + std::string str = "static"; + if (juniper_header) { + if (boost::iequals(nh_mode, str)) + return MirrorEntryData::StaticNH_With_JuniperHdr; + return MirrorEntryData::DynamicNH_With_JuniperHdr; + } else { + if (boost::iequals(nh_mode, str)) + return MirrorEntryData::StaticNH_Without_JuniperHdr; + return MirrorEntryData::DynamicNH_Without_JuniperHdr; + } +} diff --git a/src/vnsw/agent/oper/mirror_table.h b/src/vnsw/agent/oper/mirror_table.h index 3860e788041..9b0dd539b30 100644 --- a/src/vnsw/agent/oper/mirror_table.h +++ b/src/vnsw/agent/oper/mirror_table.h @@ -17,22 +17,38 @@ struct MirrorEntryKey : public AgentKey { }; struct MirrorEntryData : public AgentData { + enum MirrorEntryFlags { + DynamicNH_With_JuniperHdr = 1, + DynamicNH_Without_JuniperHdr = 2, + StaticNH_With_JuniperHdr = 3, + StaticNH_Without_JuniperHdr = 4 + + }; + MirrorEntryData(const std::string vrf_name, const IpAddress &sip, const uint16_t sport, const IpAddress &dip, - const uint16_t dport): vrf_name_(vrf_name), - sip_(sip), sport_(sport), dip_(dip), dport_(dport) { }; + const uint16_t dport, uint8_t mirror_flags, + uint32_t vni, const MacAddress &mac, bool createdvrf): + vrf_name_(vrf_name), sip_(sip), sport_(sport), dip_(dip), + dport_(dport), mirror_flags_(mirror_flags), vni_(vni), + mac_(mac), createdvrf_(createdvrf){ }; + std::string vrf_name_; IpAddress sip_; uint16_t sport_; IpAddress dip_; uint16_t dport_; + uint8_t mirror_flags_; + uint32_t vni_; + MacAddress mac_; // can be type of vtep mac or analyzer-mac based on type NH + bool createdvrf_; }; class MirrorEntry : AgentRefCount, public AgentDBEntry { public: MirrorEntry(std::string analyzer_name) : analyzer_name_(analyzer_name), vrf_(NULL, this), nh_(NULL), - vrf_name_("") { }; + vrf_name_(""), createdvrf_(false) { }; virtual ~MirrorEntry() { }; virtual bool IsLess(const DBEntry &rhs) const; @@ -57,7 +73,10 @@ class MirrorEntry : AgentRefCount, public AgentDBEntry { uint16_t GetDPort() const {return dport_;} const NextHop *GetNH() const {return nh_.get();} const std::string vrf_name() const {return vrf_name_;} - + uint32_t GetVni() const {return vni_;} + uint8_t GetMirrorFlag() const {return mirror_flags_;} + const MacAddress *GetMac() const { return &mac_;} + bool GetCreatedVrf() const {return createdvrf_;} private: std::string analyzer_name_; VrfEntryRef vrf_; @@ -67,6 +86,12 @@ class MirrorEntry : AgentRefCount, public AgentDBEntry { uint16_t dport_; NextHopRef nh_; std::string vrf_name_; + uint8_t mirror_flags_; + uint32_t vni_; + MacAddress mac_; // can be type of vtep mac or analyzer-mac based on type NH + // this vrf will be created if this mirror vrf is not known to compute node + // add it subscribes for the route information to get down loaded + bool createdvrf_; friend class MirrorTable; }; @@ -99,6 +124,12 @@ class MirrorTable : public AgentDBTable { const std::string &vrf_name, const IpAddress &sip, uint16_t sport, const IpAddress &dip, uint16_t dport); + static void AddMirrorEntry(const std::string &analyzer_name, + const std::string &vrf_name, + const IpAddress &sip, uint16_t sport, + const IpAddress &dip, uint16_t dport, + uint32_t vni, uint8_t mirror_flag, + const MacAddress &mac); static void DelMirrorEntry(const std::string &analyzer_name); virtual void OnZeroRefcount(AgentDBEntry *e); static DBTableBase *CreateTable(DB *db, const std::string &name); @@ -118,7 +149,22 @@ class MirrorTable : public AgentDBTable { void VrfNotify(DBTablePartBase *root, DBEntryBase *entry); void Shutdown(); void Initialize(); - + bool OnChange(MirrorEntry *mirror_entry); + struct MirrorVrfState : DBState { + MirrorVrfState() : DBState(), seen_(false), + bridge_rt_table_listener_id_(DBTableBase::kInvalidId) {} + bool seen_; + DBTableBase::ListenerId bridge_rt_table_listener_id_; + }; + void BridgeRouteTableNotify(DBTablePartBase *partition, DBEntryBase *e); + void UnRegisterBridgeRouteTableListener(const VrfEntry *entry, + MirrorVrfState *state); + bool UnresolvedMirrorVrf(const VrfEntry *vrf, VrfMirrorEntryList &list); + MirrorEntry* UnresolvedMirrorEntry(VrfEntry *vrf, const MacAddress & mac, + VrfMirrorEntryList &list); + static MirrorEntryData::MirrorEntryFlags + DecodeMirrorFlag (const std::string &nh_mode, bool juniper_header); + void DeleteMirrorVrf(MirrorEntry *entry); private: std::auto_ptr udp_sock_; static MirrorTable *mirror_table_; diff --git a/src/vnsw/agent/oper/vm_interface.cc b/src/vnsw/agent/oper/vm_interface.cc index 515e3793d98..6a950b3fd10 100644 --- a/src/vnsw/agent/oper/vm_interface.cc +++ b/src/vnsw/agent/oper/vm_interface.cc @@ -696,12 +696,35 @@ static void ReadAnalyzerNameAndCreate(Agent *agent, } else { dport = ContrailPorts::AnalyzerUdpPort(); } + MirrorEntryData::MirrorEntryFlags mirror_flag = + MirrorTable::DecodeMirrorFlag(mirror_to.nh_mode, + mirror_to.juniper_header); // not using the vrf coming in; by setting this to empty, -1 will be // configured so that current VRF will be used (for leaked routes). - agent->mirror_table()->AddMirrorEntry - (mirror_to.analyzer_name, std::string(), - agent->GetMirrorSourceIp(dip), - agent->mirror_port(), dip, dport); + if (mirror_flag == MirrorEntryData::DynamicNH_With_JuniperHdr) { + agent->mirror_table()->AddMirrorEntry + (mirror_to.analyzer_name, std::string(), + agent->GetMirrorSourceIp(dip), + agent->mirror_port(), dip, dport); + } else if (mirror_flag == MirrorEntryData::DynamicNH_Without_JuniperHdr) { + agent->mirror_table()->AddMirrorEntry(mirror_to.analyzer_name, + mirror_to.routing_instance, agent->GetMirrorSourceIp(dip), + agent->mirror_port(), dip, dport, 0, mirror_flag, + MacAddress::FromString(mirror_to.analyzer_mac_address)); + } else if (mirror_flag == MirrorEntryData::StaticNH_Without_JuniperHdr) { + IpAddress vtep_dip = + IpAddress::from_string(mirror_to.static_nh_header.vtep_dst_ip_address, ec); + if (ec.value() != 0) { + return; + } + agent->mirror_table()->AddMirrorEntry(mirror_to.analyzer_name, + mirror_to.routing_instance, agent->GetMirrorSourceIp(dip), + agent->mirror_port(), vtep_dip, dport, + mirror_to.static_nh_header.vni, mirror_flag, + MacAddress::FromString(mirror_to.static_nh_header.vtep_dst_mac_address)); + } else { + LOG(ERROR, "Mirror nh mode not supported"); + } data.analyzer_name_ = mirror_to.analyzer_name; string traffic_direction = cfg->properties().interface_mirror.traffic_direction; diff --git a/src/vnsw/agent/oper/vrf.h b/src/vnsw/agent/oper/vrf.h index edcf80b16ce..84ae171f27c 100644 --- a/src/vnsw/agent/oper/vrf.h +++ b/src/vnsw/agent/oper/vrf.h @@ -41,6 +41,7 @@ struct VrfData : public AgentOperDBData { enum VrfEntryFlags { ConfigVrf = 1 << 0, // vrf is received from config GwVrf = 1 << 1, // GW configured for this VRF + MirrorVrf = 1 << 2, // internally Created VRF }; VrfData(Agent *agent, IFMapNode *node, uint32_t flags, diff --git a/src/vnsw/agent/test/test_mirror.cc b/src/vnsw/agent/test/test_mirror.cc index 07800fdab1f..ef39329b63a 100644 --- a/src/vnsw/agent/test/test_mirror.cc +++ b/src/vnsw/agent/test/test_mirror.cc @@ -57,7 +57,7 @@ class MirrorTableTest : public ::testing::Test { } virtual void TearDown() { - WAIT_FOR(1000, 1000, agent_->nexthop_table()->Size() == nh_count_); + WAIT_FOR(1002, 1000, agent_->nexthop_table()->Size() == nh_count_); WAIT_FOR(1000, 1000, agent_->vrf_table()->Size() == 1); } @@ -433,6 +433,297 @@ TEST_F(MirrorTableTest, MirrorEntryAddDel_6) { client->WaitForIdle(); } +//This test is to verify the Dynamic without Juniper header config +//Add Mirror Entry and check it is attached to the existing +//Tunnel NH created by BridgeTunnelRouteAdd +// Check that Static NH changed to MirrorNH after moving the nh mode +TEST_F(MirrorTableTest, StaticMirrorEntryAdd_6) { + Ip4Address vhost_ip(agent_->router_id()); + Ip4Address remote_server = Ip4Address::from_string("1.1.1.1"); + Ip4Address remote_vm_ip4_2 = Ip4Address::from_string("2.2.2.11"); + //Add mirror entry pointing to same vhost IP + std::string ana = analyzer + "r"; + std::string remote_vm_mac_str_; + MacAddress remote_vm_mac = MacAddress::FromString("00:00:01:01:01:11"); + TunnelType::TypeBmap bmap; + bmap = 1 << TunnelType::VXLAN; + AddVrf("vrf3"); + client->WaitForIdle(); + BridgeTunnelRouteAdd(agent_->local_peer(), "vrf3", bmap, remote_server, + 1, remote_vm_mac, remote_vm_ip4_2, 32); + client->WaitForIdle(); + MirrorTable::AddMirrorEntry(ana, "vrf3", vhost_ip, 0x1, remote_server, + 0x2, 0 , 2, remote_vm_mac); + client->WaitForIdle(); + + MirrorEntryKey key(ana); + const MirrorEntry *mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry != NULL); + const NextHop *mirr_nh = mirr_entry->GetNH(); + EXPECT_TRUE(mirr_nh->GetType() == NextHop::TUNNEL); + + EvpnAgentRouteTable::DeleteReq(agent_->local_peer(), "vrf3", remote_vm_mac, + remote_vm_ip4_2, 0, NULL); + MirrorTable::AddMirrorEntry(ana, "vrf3", + vhost_ip, 0x1, remote_server, 0x2); + client->WaitForIdle(); + + mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry != NULL); + mirr_nh = static_cast(mirr_entry->GetNH()); + mirr_nh = mirr_entry->GetNH(); + EXPECT_TRUE(mirr_nh->GetType() == NextHop::MIRROR); + DelVrf("vrf3"); + client->WaitForIdle(); + mirr_nh = mirr_entry->GetNH(); + EXPECT_TRUE(mirr_nh->GetType() == NextHop::DISCARD); + + MirrorTable::DelMirrorEntry(ana); + client->WaitForIdle(); + mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry == NULL); + client->WaitForIdle(); +} + +//This test is to verify the Dynamic without Juniper header config +//Add Mirror Entry without mirror VRF so that Mirror entry will create the +//vrf and attach to the Tunnel NH created by BridgeTunnelRouteAdd +// Change the VRF and check NH refrence is released +TEST_F(MirrorTableTest, StaticMirrorEntryAdd_7) { + Ip4Address vhost_ip(agent_->router_id()); + Ip4Address remote_server = Ip4Address::from_string("1.1.1.1"); + Ip4Address remote_vm_ip4_2 = Ip4Address::from_string("2.2.2.11"); + //Add mirror entry pointing to same vhost IP + std::string ana = analyzer + "r"; + MacAddress remote_vm_mac = MacAddress::FromString("00:00:01:01:01:11"); + TunnelType::TypeBmap bmap; + bmap = 1 << TunnelType::VXLAN; + client->WaitForIdle(); + + MirrorTable::AddMirrorEntry(ana, "vrf3", vhost_ip, 0x1, remote_server, + 0x2, 0 , 2, remote_vm_mac); + + BridgeTunnelRouteAdd(agent_->local_peer(), "vrf3", bmap, remote_server, + 1, remote_vm_mac, remote_vm_ip4_2, 32); + client->WaitForIdle(); + + MirrorEntryKey key(ana); + const MirrorEntry *mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry != NULL); + const NextHop *mirr_nh = mirr_entry->GetNH(); + EXPECT_TRUE(mirr_nh->GetType() == NextHop::TUNNEL); + + EvpnAgentRouteTable::DeleteReq(agent_->local_peer(), "vrf3", remote_vm_mac, + remote_vm_ip4_2, 0, NULL); + client->WaitForIdle(); + + MirrorTable::AddMirrorEntry(ana, "vrf4", vhost_ip, 0x1, remote_server, + 0x2, 0 , 2, remote_vm_mac); + BridgeTunnelRouteAdd(agent_->local_peer(), "vrf4", bmap, remote_server, + 1, remote_vm_mac, remote_vm_ip4_2, 32); + + client->WaitForIdle(); + mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry != NULL); + mirr_nh = mirr_entry->GetNH(); + EXPECT_TRUE(mirr_nh->GetType() == NextHop::TUNNEL); + EvpnAgentRouteTable::DeleteReq(agent_->local_peer(), "vrf4", remote_vm_mac, + remote_vm_ip4_2, 0, NULL); + client->WaitForIdle(); + MirrorTable::DelMirrorEntry(ana); + client->WaitForIdle(); + mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry == NULL); + client->WaitForIdle(); +} + +static void CreateTunnelNH(const string &vrf_name, const Ip4Address &sip, + const Ip4Address &dip, bool policy, + TunnelType::TypeBmap bmap){ + DBRequest req; + TunnelNHData *data = new TunnelNHData(); + + NextHopKey *key = new TunnelNHKey(vrf_name, sip, dip, policy, + TunnelType::ComputeType(bmap)); + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + req.key.reset(key); + req.data.reset(data); + Agent::GetInstance()->nexthop_table()->Enqueue(&req); +} + +static void DeleteTunnelNH(const string &vrf_name, const Ip4Address &sip, + const Ip4Address &dip, bool policy, + TunnelType::TypeBmap bmap){ + DBRequest req; + TunnelNHData *data = new TunnelNHData(); + + NextHopKey *key = new TunnelNHKey(vrf_name, sip, dip, policy, + TunnelType::ComputeType(bmap)); + req.oper = DBRequest::DB_ENTRY_DELETE; + req.key.reset(key); + req.data.reset(data); + Agent::GetInstance()->nexthop_table()->Enqueue(&req); +} + +void AddResolveRoute(const Ip4Address &server_ip, uint32_t plen) { + Agent* agent = Agent::GetInstance(); + InetInterfaceKey vhost_key(agent->vhost_interface()->name()); + agent->fabric_inet4_unicast_table()->AddResolveRoute( + agent->local_peer(), + agent->fabric_vrf_name(), server_ip, plen, vhost_key, + 0, false, "", SecurityGroupList()); + client->WaitForIdle(); +} + +void DeleteRoute(const Peer *peer, const std::string &vrf_name, + const Ip4Address &addr, uint32_t plen) { + Agent::GetInstance()->fabric_inet4_unicast_table()->DeleteReq(peer, vrf_name, + addr, plen, NULL); + client->WaitForIdle(); + client->WaitForIdle(); +} + +//This test is to verify the Static without Juniper header config +//create a route & add tunnelnh through test +//check that Mirror entry attached to vxlan tunnel nh +TEST_F(MirrorTableTest, StaticMirrorEntryAdd_8) { + Ip4Address vhost_ip(agent_->router_id()); + //Add mirror entry pointing to same vhost IP + Ip4Address remote_server = Ip4Address::from_string("8.8.8.8"); + MacAddress remote_vm_mac = MacAddress::FromString("00:00:08:08:08:08"); + std::string ana = analyzer + "r"; + TunnelType::TypeBmap bmap; + bmap = 1 << TunnelType::VXLAN; + AddResolveRoute(remote_server, 32); + client->WaitForIdle(); + AddArp("8.8.8.8", "00:00:08:08:08:08", agent_->fabric_interface_name().c_str()); + client->WaitForIdle(); + CreateTunnelNH(agent_->fabric_vrf_name(), vhost_ip, remote_server, false, bmap); + client->WaitForIdle(); + + MirrorTable::AddMirrorEntry(ana, "vrf3", vhost_ip, 0x1, remote_server, + 0x2, 0 , 4, remote_vm_mac); + client->WaitForIdle(); + + MirrorEntryKey key(ana); + const MirrorEntry *mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry != NULL); + const NextHop *mirr_nh = mirr_entry->GetNH(); + EXPECT_TRUE(mirr_nh->GetType() == NextHop::TUNNEL); + + client->WaitForIdle(); + DeleteTunnelNH(agent_->fabric_vrf_name(), vhost_ip, remote_server, false, bmap); + client->WaitForIdle(); + DelArp("8.8.8.8", "00:00:08:08:08:08", agent_->fabric_interface_name().c_str()); + client->WaitForIdle(); + DeleteRoute(agent_->local_peer(), agent_->fabric_vrf_name(), remote_server, + 32); + client->WaitForIdle(); + MirrorTable::DelMirrorEntry(ana); + client->WaitForIdle(); + + mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry == NULL); + client->WaitForIdle(); +} +//This test is to verify the Static without Juniper header config +//create a route in resolved state and check that Mirror entry creates tunnel nh +//and attaches to it. +TEST_F(MirrorTableTest, StaticMirrorEntryAdd_9) { + Ip4Address vhost_ip(agent_->router_id()); + //Add mirror entry pointing to same vhost IP + Ip4Address remote_server = Ip4Address::from_string("8.8.8.8"); + MacAddress remote_vm_mac = MacAddress::FromString("00:00:08:08:08:08"); + std::string ana = analyzer + "r"; + AddResolveRoute(remote_server, 16); + + client->WaitForIdle(); + + MirrorTable::AddMirrorEntry(ana, "vrf3", vhost_ip, 0x1, remote_server, + 0x2, 2 , 4, remote_vm_mac); + client->WaitForIdle(); + AddArp("8.8.8.8", "00:00:08:08:08:08", agent_->fabric_interface_name().c_str()); + client->WaitForIdle(); + MirrorEntryKey key(ana); + const MirrorEntry *mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry != NULL); + const NextHop *mirr_nh = mirr_entry->GetNH(); + EXPECT_TRUE(mirr_nh->GetType() == NextHop::TUNNEL); + + DelArp("8.8.8.8", "00:00:08:08:08:08", agent_->fabric_interface_name().c_str()); + client->WaitForIdle(); + DeleteRoute(agent_->local_peer(), agent_->fabric_vrf_name(), remote_server, + 16); + DeleteRoute(agent_->local_peer(), agent_->fabric_vrf_name(), remote_server, + 32); + client->WaitForIdle(); + MirrorTable::DelMirrorEntry(ana); + client->WaitForIdle(); + + mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry == NULL); + client->WaitForIdle(); +} +// This test case is to move the mode from dynamic without juniper hdr +// to dynamic with juniper header after moving see that internally created +// VRF is deleted and check that MirrorNH points to discard NH +TEST_F(MirrorTableTest, StaticMirrorEntryAdd_10) { + Ip4Address vhost_ip(agent_->router_id()); + Ip4Address remote_server = Ip4Address::from_string("1.1.1.1"); + Ip4Address remote_vm_ip4_2 = Ip4Address::from_string("2.2.2.11"); + //Add mirror entry pointing to same vhost IP + std::string ana = analyzer + "r"; + MacAddress remote_vm_mac = MacAddress::FromString("00:00:01:01:01:11"); + TunnelType::TypeBmap bmap; + bmap = 1 << TunnelType::VXLAN; + client->WaitForIdle(); + + MirrorTable::AddMirrorEntry(ana, "vrf3", vhost_ip, 0x1, remote_server, + 0x2, 0 , 2, remote_vm_mac); + + BridgeTunnelRouteAdd(agent_->local_peer(), "vrf3", bmap, remote_server, + 1, remote_vm_mac, remote_vm_ip4_2, 32); + client->WaitForIdle(); + + MirrorEntryKey key(ana); + const MirrorEntry *mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry != NULL); + const NextHop *mirr_nh = mirr_entry->GetNH(); + EXPECT_TRUE(mirr_nh->GetType() == NextHop::TUNNEL); + + EvpnAgentRouteTable::DeleteReq(agent_->local_peer(), "vrf3", remote_vm_mac, + remote_vm_ip4_2, 0, NULL); + client->WaitForIdle(); + MirrorTable::AddMirrorEntry(ana, "vrf3", + vhost_ip, 0x1, remote_server, 0x2); + client->WaitForIdle(); + + mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry != NULL); + mirr_nh = static_cast(mirr_entry->GetNH()); + mirr_nh = mirr_entry->GetNH(); + EXPECT_TRUE(mirr_nh->GetType() == NextHop::DISCARD); + client->WaitForIdle(); + MirrorTable::DelMirrorEntry(ana); + client->WaitForIdle(); + mirr_entry = static_cast + (agent_->mirror_table()->FindActiveEntry(&key)); + EXPECT_TRUE(mirr_entry == NULL); + client->WaitForIdle(); +} + int main(int argc, char *argv[]) { GETUSERARGS(); diff --git a/src/vnsw/agent/vrouter/ksync/mirror_ksync.cc b/src/vnsw/agent/vrouter/ksync/mirror_ksync.cc index 71aa8519ab5..b0b340436df 100644 --- a/src/vnsw/agent/vrouter/ksync/mirror_ksync.cc +++ b/src/vnsw/agent/vrouter/ksync/mirror_ksync.cc @@ -13,7 +13,8 @@ MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj, uint32_t index) : KSyncNetlinkDBEntry(index), ksync_obj_(obj), vrf_id_(entry->vrf_id_), sip_(entry->sip_), sport_(entry->sport_), dip_(entry->dip_), - dport_(entry->dport_), analyzer_name_(entry->analyzer_name_) { + dport_(entry->dport_), analyzer_name_(entry->analyzer_name_), + mirror_flag_(entry->mirror_flag_), vni_(entry->vni_) { } MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj, @@ -29,7 +30,8 @@ MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj, vrf_id_(mirror_entry->vrf_id()), sip_(*mirror_entry->GetSip()), sport_(mirror_entry->GetSPort()), dip_(*mirror_entry->GetDip()), dport_(mirror_entry->GetDPort()), nh_(NULL), - analyzer_name_(mirror_entry->GetAnalyzerName()) { + analyzer_name_(mirror_entry->GetAnalyzerName()), + mirror_flag_(mirror_entry->GetMirrorFlag()), vni_(mirror_entry->GetVni()) { } MirrorKSyncEntry::MirrorKSyncEntry(MirrorKSyncObject *obj, @@ -90,6 +92,8 @@ int MirrorKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) { encoder.set_mirr_index(GetIndex()); encoder.set_mirr_rid(0); encoder.set_mirr_nhid(nh_entry->nh_id()); + encoder.set_mirr_vni(vni_); + encoder.set_mirr_flags(mirror_flag_); int error = 0; encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error); assert(error == 0); diff --git a/src/vnsw/agent/vrouter/ksync/mirror_ksync.h b/src/vnsw/agent/vrouter/ksync/mirror_ksync.h index 0c2f458163b..8fa0d977ecf 100644 --- a/src/vnsw/agent/vrouter/ksync/mirror_ksync.h +++ b/src/vnsw/agent/vrouter/ksync/mirror_ksync.h @@ -47,6 +47,8 @@ class MirrorKSyncEntry : public KSyncNetlinkDBEntry { uint16_t dport_; KSyncEntryPtr nh_; std::string analyzer_name_; + uint8_t mirror_flag_; + uint32_t vni_; DISALLOW_COPY_AND_ASSIGN(MirrorKSyncEntry); };