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