Line data Source code
1 : /*
2 : * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
3 : */
4 : #include <init/agent_param.h>
5 : #include <oper/vn.h>
6 : #include <oper/sg.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_learning_mgmt.h"
16 : #include "mac_aging.h"
17 : #include "vr_bridge.h"
18 :
19 :
20 0 : MacPbbLearningEntry::MacPbbLearningEntry(MacLearningPartition *table, uint32_t vrf_id,
21 : const MacAddress &mac,
22 0 : uint32_t index):
23 0 : MacLearningEntry(vrf_id),mac_learning_table_(table), key_(vrf_id, mac), index_(index) {
24 : vrf_ = table->agent()->vrf_table()->
25 0 : FindVrfFromIdIncludingDeletedVrf(key_.vrf_id_);
26 0 : }
27 :
28 0 : void MacPbbLearningEntry::Delete() {
29 0 : deleted_ = true;
30 0 : AddToken(mac_learning_table_->agent()->mac_learning_proto()->
31 0 : GetToken(MacLearningEntryRequest::DELETE_MAC));
32 :
33 0 : mac_learning_table_->agent()->fabric_evpn_table()->
34 0 : DeleteReq(mac_learning_table_->agent()->mac_learning_peer(),
35 0 : vrf()->GetName(), mac(), Ip4Address(0), 32, 0, NULL);
36 0 : }
37 :
38 0 : void MacPbbLearningEntry::AddWithToken() {
39 0 : if (Add()) {
40 0 : AddToken(mac_learning_table_->agent()->mac_learning_proto()->
41 0 : GetToken(MacLearningEntryRequest::ADD_MAC));
42 : }
43 0 : }
44 :
45 0 : void MacPbbLearningEntry::Resync() {
46 0 : if (Add()) {
47 0 : AddToken(mac_learning_table_->agent()->mac_learning_proto()->
48 0 : GetToken(MacLearningEntryRequest::RESYNC_MAC));
49 : }
50 0 : }
51 :
52 0 : void MacPbbLearningEntry::EnqueueToTable(MacLearningEntryRequestPtr req) {
53 0 : mac_learning_table_->Enqueue(req);
54 0 : }
55 0 : MacLearningEntryLocal::MacLearningEntryLocal(MacLearningPartition *table,
56 : uint32_t vrf_id,
57 : const MacAddress &mac,
58 : uint32_t index,
59 0 : InterfaceConstRef intf):
60 0 : MacPbbLearningEntry(table, vrf_id, mac, index), intf_(intf) {
61 0 : }
62 :
63 0 : bool MacLearningEntryLocal::Add() {
64 0 : const VmInterface *vm_intf = dynamic_cast<const VmInterface *>(intf_.get());
65 0 : assert(vm_intf);
66 :
67 0 : if (vrf()->IsActive() == false) {
68 0 : return false;
69 : }
70 :
71 0 : if (vm_intf->vn() == NULL) {
72 0 : return false;
73 : }
74 :
75 0 : if (vm_intf->vn() == NULL) {
76 0 : return false;
77 : }
78 :
79 0 : SecurityGroupList sg_list;
80 0 : vm_intf->CopySgIdList(&sg_list);
81 :
82 0 : TagList tag_list;
83 0 : vm_intf->CopyTagIdList(&tag_list);
84 :
85 0 : mac_learning_table_->agent()->fabric_evpn_table()->
86 0 : AddLocalVmRouteReq(mac_learning_table_->agent()->mac_learning_peer(),
87 : vrf()->GetName(),
88 0 : mac(), vm_intf, Ip4Address(0),
89 : vm_intf->l2_label(),
90 : vm_intf->vn()->GetName(), sg_list, tag_list,
91 0 : PathPreference(), 0,
92 0 : vm_intf->etree_leaf());
93 0 : return true;
94 0 : }
95 :
96 0 : MacLearningEntryRemote::MacLearningEntryRemote(MacLearningPartition *table,
97 : uint32_t vrf_id,
98 : const MacAddress &mac,
99 : uint32_t index,
100 0 : IpAddress remote_ip):
101 0 : MacPbbLearningEntry(table, vrf_id, mac, index), remote_ip_(remote_ip) {
102 0 : }
103 :
104 0 : bool MacLearningEntryRemote::Add() {
105 0 : return true;
106 : }
107 :
108 0 : MacLearningEntryPBB::MacLearningEntryPBB(MacLearningPartition *table,
109 : uint32_t vrf_id,
110 : const MacAddress &mac,
111 : uint32_t index,
112 0 : const MacAddress &bmac) :
113 0 : MacPbbLearningEntry(table, vrf_id, mac, index), bmac_(bmac) {
114 0 : }
115 :
116 0 : bool MacLearningEntryPBB::Add() {
117 0 : assert(vrf_);
118 0 : uint32_t isid = vrf_->isid();
119 0 : std::string bmac_vrf_name = vrf_->bmac_vrf_name();
120 0 : PBBRoute *data = new PBBRoute(VrfKey(bmac_vrf_name), bmac_, isid,
121 0 : VnListType(),
122 0 : SecurityGroupList(), TagList());
123 0 : EvpnAgentRouteTable::AddRemoteVmRouteReq(mac_learning_table_->agent()->
124 : mac_learning_peer(),
125 : vrf()->GetName(),
126 0 : mac(), Ip4Address(0), 32, 0, data);
127 0 : return true;
128 0 : }
129 :
130 9 : MacLearningRequestQueue::MacLearningRequestQueue(MacLearningPartition *partition,
131 9 : TokenPool *pool):
132 9 : partition_(partition), pool_(pool),
133 18 : queue_(partition_->agent()->task_scheduler()->GetTaskId(kTaskMacLearning),
134 9 : partition->id(),
135 9 : boost::bind(&MacLearningRequestQueue::HandleEvent, this, _1)) {
136 9 : queue_.SetStartRunnerFunc(boost::bind(&MacLearningRequestQueue::TokenCheck,
137 : this));
138 9 : }
139 :
140 94 : bool MacLearningRequestQueue::TokenCheck() {
141 94 : if (pool_) {
142 94 : return pool_->TokenCheck();
143 : }
144 :
145 0 : return true;
146 : }
147 :
148 87 : bool MacLearningRequestQueue::HandleEvent(MacLearningEntryRequestPtr ptr) {
149 87 : return partition_->RequestHandler(ptr);
150 : }
151 :
152 3 : MacLearningPartition::MacLearningPartition(Agent *agent,
153 : MacLearningProto *proto,
154 3 : uint32_t id):
155 3 : agent_(agent), id_(id),
156 3 : add_request_queue_(this, proto->add_tokens()),
157 3 : change_request_queue_(this, proto->change_tokens()),
158 6 : delete_request_queue_(this, proto->delete_tokens()) {
159 3 : aging_partition_.reset(new MacAgingPartition(agent, id));
160 3 : }
161 :
162 6 : MacLearningPartition::~MacLearningPartition() {
163 3 : assert(mac_learning_table_.size() == 0);
164 6 : }
165 :
166 0 : void MacLearningPartition::MayBeStartRunner(TokenPool *pool) {
167 0 : if (agent_->mac_learning_proto()->add_tokens() == pool) {
168 0 : add_request_queue_.MayBeStartRunner();
169 0 : } else if (agent_->mac_learning_proto()->change_tokens() == pool) {
170 0 : change_request_queue_.MayBeStartRunner();
171 : } else {
172 0 : delete_request_queue_.MayBeStartRunner();
173 : }
174 0 : }
175 :
176 87 : bool MacLearningPartition::RequestHandler(MacLearningEntryRequestPtr ptr) {
177 87 : switch(ptr->event()) {
178 0 : case MacLearningEntryRequest::VROUTER_MSG:
179 0 : agent()->mac_learning_proto()->ProcessProto(ptr->pkt_info());
180 0 : break;
181 :
182 0 : case MacLearningEntryRequest::ADD_MAC:
183 0 : Add(ptr->mac_learning_entry());
184 0 : break;
185 :
186 0 : case MacLearningEntryRequest::RESYNC_MAC:
187 0 : Resync(ptr->mac_learning_entry());
188 0 : break;
189 :
190 0 : case MacLearningEntryRequest::DELETE_MAC:
191 0 : Delete(ptr->mac_learning_entry());
192 0 : break;
193 :
194 87 : case MacLearningEntryRequest::FREE_DB_ENTRY:
195 : agent()->mac_learning_module()->
196 87 : mac_learning_db_client()->FreeDBState(ptr->db_entry(),
197 : ptr->gen_id());
198 87 : break;
199 :
200 0 : default:
201 0 : assert(0);
202 : }
203 87 : return true;
204 : }
205 :
206 0 : void MacLearningPartition::EnqueueMgmtReq(MacLearningEntryPtr ptr, bool add) {
207 0 : MacLearningMgmtRequest::Event e = MacLearningMgmtRequest::ADD_MAC;
208 0 : if (add == false) {
209 0 : e = MacLearningMgmtRequest::DELETE_MAC;
210 : }
211 0 : MacLearningMgmtRequestPtr req(new MacLearningMgmtRequest(e, ptr));
212 0 : agent()->mac_learning_module()->mac_learning_mgmt()->Enqueue(req);
213 0 : }
214 :
215 0 : void MacLearningPartition::Add(MacLearningEntryPtr ptr) {
216 0 : MacPbbLearningEntry *entry = dynamic_cast<MacPbbLearningEntry *>(ptr.get());
217 0 : if (!entry) {
218 0 : return;
219 : }
220 0 : MacLearningKey key(ptr->vrf_id(), entry->mac());
221 :
222 : std::pair<MacLearningEntryTable::iterator, bool> it =
223 0 : mac_learning_table_.insert(MacLearningEntryPair(key, ptr));
224 0 : if (it.second == false) {
225 : //Entry already present, clear the entry and delete it from
226 : //aging tree
227 0 : ptr->CopyToken(it.first->second.get());
228 0 : if (it.first->second->deleted() == false) {
229 : MacLearningEntryRequestPtr aging_req(new MacLearningEntryRequest(
230 0 : MacLearningEntryRequest::DELETE_MAC, it.first->second));
231 0 : aging_partition_->Enqueue(aging_req);
232 0 : }
233 0 : mac_learning_table_[key] = ptr;
234 : }
235 :
236 0 : ptr->AddWithToken();
237 0 : EnqueueMgmtReq(ptr, true);
238 : MacLearningEntryRequestPtr aging_req(new MacLearningEntryRequest(
239 0 : MacLearningEntryRequest::ADD_MAC, ptr));
240 0 : aging_partition_->Enqueue(aging_req);
241 0 : }
242 :
243 0 : void MacLearningPartition::Delete(const MacLearningEntryPtr ptr) {
244 0 : if (ptr->deleted() == true) {
245 0 : return;
246 : }
247 0 : MacPbbLearningEntry *entry = dynamic_cast<MacPbbLearningEntry *>(ptr.get());
248 0 : if (!entry) {
249 0 : return;
250 : }
251 0 : MacLearningKey key(ptr->vrf_id(), entry->mac());
252 0 : if (mac_learning_table_.find(key) == mac_learning_table_.end()) {
253 0 : return;
254 : }
255 :
256 0 : ptr->Delete();
257 : MacLearningEntryRequestPtr aging_req(new MacLearningEntryRequest(
258 : MacLearningEntryRequest::DELETE_MAC,
259 0 : ptr));
260 0 : aging_partition_->Enqueue(aging_req);
261 0 : EnqueueMgmtReq(ptr, false);
262 0 : }
263 :
264 0 : void MacLearningPartition::Resync(MacLearningEntryPtr ptr) {
265 0 : MacPbbLearningEntry *entry = dynamic_cast<MacPbbLearningEntry *>(ptr.get());
266 0 : if (!entry) {
267 0 : return;
268 : }
269 0 : MacLearningKey key(ptr->vrf_id(), entry->mac());
270 0 : if (mac_learning_table_.find(key) == mac_learning_table_.end()) {
271 0 : return;
272 : }
273 :
274 0 : ptr->Resync();
275 : }
276 :
277 87 : void MacLearningPartition::Enqueue(MacLearningEntryRequestPtr req) {
278 87 : switch(req->event()) {
279 87 : case MacLearningEntryRequest::VROUTER_MSG:
280 : case MacLearningEntryRequest::ADD_MAC:
281 : case MacLearningEntryRequest::FREE_DB_ENTRY:
282 : case MacLearningEntryRequest::DELETE_VRF:
283 87 : add_request_queue_.Enqueue(req);
284 87 : break;
285 :
286 0 : case MacLearningEntryRequest::RESYNC_MAC:
287 0 : change_request_queue_.Enqueue(req);
288 0 : break;
289 :
290 0 : case MacLearningEntryRequest::DELETE_MAC:
291 0 : delete_request_queue_.Enqueue(req);
292 0 : break;
293 :
294 0 : default:
295 0 : assert(0);
296 : }
297 87 : return;
298 : }
299 :
300 : MacLearningEntry*
301 237 : MacLearningPartition::Find(const MacLearningKey &key) {
302 237 : MacLearningEntryTable::iterator it = mac_learning_table_.find(key);
303 237 : if (it == mac_learning_table_.end()) {
304 237 : return NULL;
305 : }
306 0 : return it->second.get();
307 : }
308 :
309 : MacLearningEntryPtr
310 0 : MacLearningPartition::TestGet(const MacLearningKey &key) {
311 0 : MacLearningEntryTable::iterator it = mac_learning_table_.find(key);
312 0 : return it->second;
313 : }
314 :
315 237 : void MacLearningPartition::ReleaseToken(const MacLearningKey &key) {
316 237 : MacLearningEntry *mac_entry = Find(key);
317 237 : if (mac_entry) {
318 0 : mac_entry->ReleaseToken();
319 0 : if (mac_entry->deleted()) {
320 0 : mac_learning_table_.erase(key);
321 : }
322 : }
323 237 : }
324 :
325 0 : MacLearningSandeshResp::MacLearningSandeshResp(Agent *agent,
326 : MacEntryResp *resp,
327 : std::string resp_ctx,
328 : std::string key,
329 0 : const MacAddress &mac) :
330 : Task((TaskScheduler::GetInstance()->
331 : GetTaskId("Agent::MacLearningSandeshTask")), 0),
332 0 : agent_(agent), resp_(resp), resp_data_(resp_ctx), partition_id_(0),
333 0 : vrf_id_(0), mac_(MacAddress::ZeroMac()), exact_match_(false),
334 0 : user_given_mac_(mac) {
335 0 : if (key != agent_->NullString()) {
336 0 : SetMacKey(key);
337 : }
338 0 : }
339 :
340 0 : MacLearningSandeshResp::~MacLearningSandeshResp() {
341 0 : }
342 :
343 0 : bool MacLearningSandeshResp::SetMacKey(string key) {
344 0 : const char ch = kDelimiter;
345 0 : size_t n = std::count(key.begin(), key.end(), ch);
346 0 : if (n != 3) {
347 0 : return false;
348 : }
349 :
350 0 : std::stringstream ss(key);
351 0 : string item;
352 :
353 0 : if (getline(ss, item, ch)) {
354 0 : std::istringstream(item) >> partition_id_;
355 : }
356 0 : if (getline(ss, item, ch)) {
357 0 : std::istringstream(item) >> vrf_id_;
358 : }
359 0 : if (getline(ss, item, ch)) {
360 0 : mac_ = MacAddress::FromString(item);
361 : }
362 0 : if (getline(ss, item, ch)) {
363 0 : std::istringstream(item) >> exact_match_;
364 : }
365 0 : return true;
366 0 : }
367 :
368 : string
369 0 : MacLearningSandeshResp::GetMacKey() {
370 0 : std::stringstream ss;
371 0 : ss << partition_id_ << kDelimiter;
372 0 : ss << vrf_id_ << kDelimiter;
373 0 : ss << mac_.ToString();
374 0 : ss << kDelimiter << exact_match_;
375 0 : return ss.str();
376 0 : }
377 :
378 : const MacLearningPartition*
379 0 : MacLearningSandeshResp::GetPartition() {
380 0 : if (partition_id_ >= agent_->params()->mac_learning_thread_count()) {
381 0 : return NULL;
382 : }
383 :
384 0 : MacLearningPartition *mp = agent_->mac_learning_proto()->
385 0 : Find(partition_id_);
386 0 : return mp;
387 : }
388 :
389 : bool
390 0 : MacLearningSandeshResp::Run() {
391 : std::vector<SandeshMacEntry>& list =
392 0 : const_cast<std::vector<SandeshMacEntry>&>(resp_->get_mac_entry_list());
393 0 : uint32_t entries_count = 0;
394 :
395 0 : while (entries_count < kMaxResponse) {
396 0 : const MacLearningPartition *mp = GetPartition();
397 0 : if (mp == NULL) {
398 0 : break;
399 : }
400 :
401 0 : MacLearningKey key(vrf_id_, mac_);
402 0 : MacLearningPartition::MacLearningEntryTable::const_iterator it;
403 0 : if (user_given_mac_ != MacAddress::ZeroMac()) {
404 0 : it = mp->mac_learning_table_.find(key);
405 : } else {
406 0 : it = mp->mac_learning_table_.upper_bound(key);
407 : }
408 :
409 0 : while (entries_count < kMaxResponse) {
410 0 : if (exact_match_ && it->first.vrf_id_ != vrf_id_) {
411 0 : break;
412 : } else {
413 0 : vrf_id_ = it->first.vrf_id_;
414 : }
415 :
416 0 : if (it == mp->mac_learning_table_.end()) {
417 0 : break;
418 : }
419 :
420 : const MacAgingTable *at =
421 0 : mp->aging_partition()->Find(it->first.vrf_id_);
422 : //Find the aging entry
423 0 : const MacAgingEntry *aging_entry = NULL;
424 0 : if (at) {
425 0 : aging_entry = at->Find(it->second.get());
426 : }
427 0 : if (aging_entry) {
428 0 : SandeshMacEntry data;
429 0 : data.set_partition(partition_id_);
430 0 : aging_entry->FillSandesh(&data);
431 0 : list.push_back(data);
432 0 : }
433 :
434 0 : entries_count++;
435 0 : if (user_given_mac_ != MacAddress::ZeroMac()) {
436 0 : break;
437 : }
438 0 : mac_ = it->first.mac_;
439 0 : it++;
440 : }
441 :
442 0 : if (entries_count >= kMaxResponse) {
443 0 : break;
444 : }
445 :
446 0 : if (exact_match_ == false) {
447 0 : vrf_id_++;
448 : }
449 :
450 0 : if (it == mp->mac_learning_table_.end()) {
451 0 : partition_id_++;
452 0 : if (exact_match_ == false) {
453 0 : vrf_id_ = 0;
454 : }
455 : }
456 :
457 0 : if (user_given_mac_ != MacAddress::ZeroMac()) {
458 : //If entry is found in current partition
459 : //move on to next partition
460 0 : if (it != mp->mac_learning_table_.end()) {
461 0 : partition_id_++;
462 : }
463 0 : mac_ = user_given_mac_;
464 : } else {
465 0 : mac_ = MacAddress::ZeroMac();
466 : }
467 : }
468 :
469 0 : if (partition_id_ < agent_->params()->mac_learning_thread_count()) {
470 0 : resp_->set_mac_key(GetMacKey());
471 : }
472 :
473 0 : SendResponse(resp_);
474 0 : return true;
475 : }
476 :
477 0 : void MacLearningSandeshResp::SendResponse(SandeshResponse *resp) {
478 0 : resp->set_context(resp_data_);
479 0 : resp->set_more(false);
480 0 : resp->Response();
481 0 : }
482 :
483 0 : void FetchMacEntry::HandleRequest() const {
484 0 : Agent *agent = Agent::GetInstance();
485 :
486 0 : std::ostringstream str;
487 0 : str << "0" << MacLearningSandeshResp::kDelimiter << get_vrf_id() <<
488 0 : MacLearningSandeshResp::kDelimiter << get_mac();
489 :
490 0 : bool exact_match = false;
491 0 : if (get_vrf_id() != 0 || get_mac() != agent->NullString()) {
492 0 : exact_match = true;
493 : }
494 0 : str << MacLearningSandeshResp::kDelimiter << exact_match;
495 :
496 0 : MacAddress mac = MacAddress::FromString(get_mac());
497 :
498 0 : MacEntryResp *resp = new MacEntryResp();
499 : MacLearningSandeshResp *task = new MacLearningSandeshResp(agent, resp,
500 0 : context(),
501 0 : str.str(), mac);
502 0 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
503 0 : scheduler->Enqueue(task);
504 0 : }
505 :
506 0 : void NextMacEntrySet::HandleRequest() const {
507 0 : Agent *agent = Agent::GetInstance();
508 :
509 0 : MacEntryResp *resp = new MacEntryResp();
510 : MacLearningSandeshResp *task = new MacLearningSandeshResp(agent, resp,
511 0 : context(),
512 0 : get_mac_entry_key(),
513 0 : MacAddress::ZeroMac());
514 0 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
515 0 : scheduler->Enqueue(task);
516 0 : }
|