Line data Source code
1 : /* 2 : * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : #include <oper/vn.h> 5 : #include <oper/sg.h> 6 : #include <oper/vm.h> 7 : #include <oper/vrf.h> 8 : #include <oper/nexthop.h> 9 : #include <oper/interface_common.h> 10 : #include <oper/route_common.h> 11 : #include "mac_learning_proto.h" 12 : #include "mac_learning_proto_handler.h" 13 : #include "mac_learning_init.h" 14 : #include "mac_learning.h" 15 : #include "mac_aging.h" 16 : #include "mac_learning_mgmt.h" 17 : #include "vr_bridge.h" 18 : #include "vrouter/ksync/ksync_init.h" 19 : #include "vrouter/ksync/ksync_bridge_table.h" 20 : 21 0 : MacAgingEntry::MacAgingEntry(MacLearningEntryPtr ptr): 22 0 : mac_learning_entry_(ptr), packets_(0), deleted_(false) { 23 0 : last_modified_time_ = UTCTimestampUsec(); 24 0 : addition_time_ = UTCTimestampUsec(); 25 0 : } 26 : 27 0 : void MacAgingEntry::FillSandesh(SandeshMacEntry *smac) const { 28 : MacPbbLearningEntry *entry = 29 0 : dynamic_cast<MacPbbLearningEntry *>(mac_learning_entry_.get()); 30 0 : smac->set_vrf(mac_learning_entry_->vrf()->GetName()); 31 0 : smac->set_mac(entry->mac().ToString()); 32 0 : smac->set_index(entry->index()); 33 0 : smac->set_packets(packets_); 34 : std::string time_since_addition = 35 0 : duration_usecs_to_string(UTCTimestampUsec() - addition_time_); 36 0 : smac->set_time_since_add(time_since_addition); 37 : std::string last_stats_change = 38 0 : duration_usecs_to_string(UTCTimestampUsec() - last_modified_time_); 39 0 : smac->set_last_stats_change(last_stats_change); 40 0 : } 41 : 42 0 : MacAgingTable::MacAgingTable(Agent *agent, const VrfEntry *vrf) : 43 0 : agent_(agent), timeout_msec_(kDefaultAgingTimeout), vrf_(vrf) { 44 0 : } 45 : 46 0 : MacAgingTable::~MacAgingTable() { 47 0 : } 48 : 49 0 : void MacAgingTable::Add(MacLearningEntryPtr ptr) { 50 0 : MacAgingEntryTable::iterator it = aging_table_.find(ptr.get()); 51 0 : if (it != aging_table_.end()) { 52 0 : it->second->set_deleted(false); 53 0 : return; 54 : } 55 : 56 0 : MacAgingEntryPtr aging_entry_ptr(new MacAgingEntry(ptr)); 57 0 : aging_table_.insert(MacAgingPair(ptr.get(), aging_entry_ptr)); 58 0 : Trace("Adding MAC entry", aging_entry_ptr.get()); 59 0 : } 60 : 61 0 : void MacAgingTable::Delete(MacLearningEntryPtr ptr) { 62 0 : MacAgingEntryTable::iterator it = aging_table_.find(ptr.get()); 63 0 : if (it != aging_table_.end()) { 64 0 : Trace("Deleting MAC entry", it->second.get()); 65 0 : aging_table_.erase(it); 66 : } 67 0 : } 68 : 69 0 : void MacAgingTable::ReadStats(MacAgingEntry *ptr) { 70 : MacPbbLearningEntry *entry = 71 0 : dynamic_cast<MacPbbLearningEntry *>(ptr->mac_learning_entry().get()); 72 0 : uint32_t index = entry->index(); 73 0 : vr_bridge_entry *vr_entry = agent_->ksync()->ksync_bridge_memory()-> 74 0 : GetBridgeEntry(index); 75 0 : if (vr_entry == NULL) { 76 0 : ptr->set_packets(0); 77 : } else { 78 0 : ptr->set_packets(vr_entry->be_packets); 79 : } 80 0 : } 81 : 82 : 83 0 : bool MacAgingTable::ShouldBeAged(MacAgingEntry *ptr, 84 : uint64_t curr_time) { 85 0 : uint64_t packets = ptr->packets(); 86 : 87 0 : ReadStats(ptr); 88 : 89 0 : if (packets == ptr->packets()) { 90 0 : if (curr_time - ptr->last_modified_time() > timeout_in_usecs()) { 91 0 : return true; 92 : } 93 0 : return false; 94 : } 95 : 96 0 : ptr->set_last_modified_time(curr_time); 97 0 : return false; 98 : } 99 : 100 0 : void MacAgingTable::Trace(const std::string &str, MacAgingEntry *ptr) { 101 0 : std::string vrf = ""; 102 0 : if (ptr->mac_learning_entry()->vrf() != NULL) { 103 0 : vrf = ptr->mac_learning_entry()->vrf()->GetName(); 104 : } 105 : MacPbbLearningEntry *entry = 106 0 : dynamic_cast<MacPbbLearningEntry *>(ptr->mac_learning_entry().get()); 107 0 : MAC_AGING_TRACE(MacLearningTraceBuf, vrf, 108 : entry->mac().ToString(), 109 : entry->index(), 110 : ptr->packets(), str); 111 0 : } 112 : 113 0 : void MacAgingTable::SendDeleteMsg(MacAgingEntry *ptr) { 114 0 : Trace("Aging", ptr); 115 0 : ptr->set_deleted(true); 116 : MacLearningEntryRequestPtr req(new MacLearningEntryRequest( 117 0 : MacLearningEntryRequest::DELETE_MAC, ptr->mac_learning_entry())); 118 0 : ptr->mac_learning_entry()->EnqueueToTable(req); 119 0 : } 120 : 121 : uint32_t 122 0 : MacAgingTable::CalculateEntriesPerIteration(uint32_t aging_table_entry_count) { 123 0 : uint32_t entry_count = aging_table_entry_count; 124 : 125 0 : if (vrf_) { 126 0 : timeout_msec_ = vrf_->mac_aging_time() * 1000; 127 : } 128 : 129 0 : if (timeout_msec_ == 0) { 130 0 : return 0; 131 : } 132 : 133 : //We want to scan all the entries 2 times before aging timeout 134 0 : uint32_t table_scan_time = timeout_msec_ / 10; 135 : 136 0 : uint32_t no_of_iteration = table_scan_time / 137 : MacAgingPartition::kMinIterationTimeout; 138 : 139 0 : if (no_of_iteration == 0) { 140 0 : no_of_iteration = 1; 141 : } 142 : 143 0 : uint32_t entry_count_per_iteration = entry_count / no_of_iteration; 144 : 145 0 : if (entry_count_per_iteration < kMinEntriesPerScan) { 146 0 : entry_count_per_iteration = kMinEntriesPerScan; 147 : } 148 0 : return entry_count_per_iteration; 149 : } 150 : 151 0 : bool MacAgingTable::Run() { 152 0 : uint64_t curr_time = UTCTimestampUsec(); 153 : 154 0 : MacAgingEntryTable::const_iterator it = aging_table_.upper_bound(last_key_); 155 0 : if (it == aging_table_.end()) { 156 0 : it = aging_table_.begin(); 157 : } 158 : 159 0 : uint32_t i = 0; 160 0 : uint32_t entries = CalculateEntriesPerIteration(aging_table_.size()); 161 0 : while (it != aging_table_.end() && i < entries) { 162 0 : if (it->second->deleted() == false && 163 0 : ShouldBeAged(it->second.get(), curr_time)) { 164 0 : SendDeleteMsg(it->second.get()); 165 : } 166 0 : last_key_ = it->first; 167 0 : it++; 168 0 : i++; 169 : } 170 : 171 0 : if (aging_table_.size() == 0) { 172 0 : return false; 173 : } 174 : 175 0 : return true; 176 : } 177 : 178 3 : MacAgingPartition::MacAgingPartition(Agent *agent, uint32_t partition_id) : 179 3 : agent_(agent), partition_id_(partition_id), 180 3 : request_queue_(agent_->task_scheduler()->GetTaskId(kTaskMacAging), 181 : partition_id, 182 : boost::bind(&MacAgingPartition::RequestHandler, 183 : this, _1)), 184 3 : timer_(TimerManager::CreateTimer(*(agent->event_manager()->io_service()), 185 : "MacAgingTimer", 186 : agent->task_scheduler()-> 187 6 : GetTaskId(kTaskMacAging), partition_id)) { 188 3 : } 189 : 190 6 : MacAgingPartition::~MacAgingPartition() { 191 3 : TimerManager::DeleteTimer(timer_); 192 6 : } 193 : 194 12 : void MacAgingPartition::Enqueue(MacLearningEntryRequestPtr req) { 195 12 : request_queue_.Enqueue(req); 196 12 : } 197 : 198 0 : void MacAgingPartition::Add(MacLearningEntryPtr mle) { 199 0 : uint32_t vrf_id = mle->vrf_id(); 200 : 201 0 : if (aging_table_map_[vrf_id] == NULL) { 202 0 : const VrfEntry *vrf = agent_->vrf_table()->FindVrfFromId(vrf_id); 203 0 : assert(vrf->IsActive() == true); 204 0 : MacAgingTablePtr aging_table(new MacAgingTable(agent_, vrf)); 205 0 : aging_table_map_[vrf_id] = aging_table; 206 0 : } 207 : 208 0 : aging_table_map_[vrf_id]->Add(mle); 209 : 210 0 : if (timer_->running() == false) { 211 0 : timer_->Start(kMinIterationTimeout, 212 : boost::bind(&MacAgingPartition::Run, this)); 213 : } 214 0 : } 215 : 216 0 : void MacAgingPartition::Delete(MacLearningEntryPtr mle) { 217 0 : uint32_t vrf_id = mle->vrf_id(); 218 0 : if (aging_table_map_[vrf_id] != NULL) { 219 0 : aging_table_map_[vrf_id]->Delete(mle); 220 : } 221 0 : } 222 : 223 0 : bool MacAgingPartition::Run() { 224 0 : bool ret = false; 225 0 : MacAgingTableMap::iterator it = aging_table_map_.begin(); 226 0 : for (;it != aging_table_map_.end(); it++) { 227 0 : if (it->second.get() && it->second->Run()) { 228 0 : ret = true; 229 : } 230 : } 231 : 232 0 : return ret; 233 : } 234 : 235 12 : void MacAgingPartition::DeleteVrf(uint32_t id) { 236 12 : aging_table_map_[id].reset(); 237 12 : } 238 : 239 12 : bool MacAgingPartition::RequestHandler(MacLearningEntryRequestPtr req) { 240 12 : switch(req->event()) { 241 0 : case MacLearningEntryRequest::ADD_MAC: 242 0 : Add(req->mac_learning_entry()); 243 0 : break; 244 : 245 0 : case MacLearningEntryRequest::DELETE_MAC: 246 0 : Delete(req->mac_learning_entry()); 247 0 : break; 248 : 249 12 : case MacLearningEntryRequest::DELETE_VRF: 250 12 : DeleteVrf(req->vrf_id()); 251 12 : break; 252 : 253 0 : default: 254 0 : assert(0); 255 : } 256 12 : return true; 257 : }