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