Line data Source code
1 : /*
2 : * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
3 : */
4 : #include "mac_learning_db_client.h"
5 : #include "mac_learning_init.h"
6 : #include "mac_learning_proto.h"
7 : #include "mac_learning_proto_handler.h"
8 : #include "mac_learning.h"
9 : #include "mac_learning_mgmt.h"
10 : #include "mac_aging.h"
11 :
12 1 : MacLearningDBClient::MacLearningDBClient(Agent *agent) :
13 1 : agent_(agent), interface_listener_id_(), vrf_listener_id_(),
14 1 : vn_listener_id_(), hc_listener_id_() {
15 1 : }
16 :
17 1 : void MacLearningDBClient::Init() {
18 1 : interface_listener_id_ = agent_->interface_table()->Register
19 1 : (boost::bind(&MacLearningDBClient::InterfaceNotify, this, _1, _2));
20 1 : vrf_listener_id_ = agent_->vrf_table()->Register
21 1 : (boost::bind(&MacLearningDBClient::VrfNotify, this, _1, _2));
22 1 : vn_listener_id_ = agent_->vn_table()->Register
23 1 : (boost::bind(&MacLearningDBClient::VnNotify, this, _1, _2));
24 1 : hc_listener_id_ = agent_->health_check_table()->Register
25 1 : (boost::bind(&MacLearningDBClient::HealthCheckNotify, this, _1, _2));
26 1 : }
27 :
28 1 : void MacLearningDBClient::Shutdown() {
29 1 : agent_->interface_table()->Unregister(interface_listener_id_);
30 1 : agent_->vrf_table()->Unregister(vrf_listener_id_);
31 1 : agent_->vn_table()->Unregister(vn_listener_id_);
32 1 : agent_->health_check_table()->Unregister(hc_listener_id_);
33 1 : }
34 :
35 2 : MacLearningDBClient::~MacLearningDBClient() {
36 2 : }
37 :
38 86 : void MacLearningDBClient::InterfaceNotify(DBTablePartBase *part, DBEntryBase *e) {
39 86 : Interface *intf = static_cast<Interface *>(e);
40 86 : if (intf->type() != Interface::VM_INTERFACE) {
41 15 : return;
42 : }
43 :
44 : MacLearningIntfState *state = static_cast<MacLearningIntfState *>
45 71 : (e->GetState(part->parent(), interface_listener_id_));
46 :
47 71 : VmInterface *vm_port = static_cast<VmInterface *>(intf);
48 71 : if (intf->IsDeleted()) {
49 16 : if (state) {
50 16 : DeleteEvent(vm_port, state);
51 : }
52 16 : return;
53 : }
54 :
55 55 : bool changed = false;
56 55 : bool delete_mac = false;
57 55 : if (state == NULL) {
58 16 : state = new MacLearningIntfState();
59 16 : e->SetState(part->parent(), interface_listener_id_, state);
60 16 : state->l2_label_ = vm_port->l2_label();
61 16 : state->sg_l_ = vm_port->sg_list();
62 16 : state->learning_enabled_ = vm_port->learning_enabled();
63 16 : state->policy_enabled_ = vm_port->policy_enabled();
64 16 : state->l2_active_ = vm_port->IsL2Active();
65 16 : changed = true;
66 16 : e->SetState(part->parent(), interface_listener_id_, state);
67 : } else {
68 39 : if (state->deleted_ == true) {
69 0 : state->deleted_ = false;
70 0 : changed = true;
71 : }
72 :
73 39 : if (state->l2_label_ != vm_port->l2_label()) {
74 18 : state->l2_label_ = vm_port->l2_label();
75 18 : changed = true;
76 : }
77 :
78 39 : const VmInterface::SecurityGroupEntryList &new_sg_l = vm_port->sg_list();
79 39 : if (state->sg_l_.list_ != new_sg_l.list_) {
80 5 : state->sg_l_ = new_sg_l;
81 5 : changed = true;
82 : }
83 :
84 39 : if (state->learning_enabled_ != vm_port->learning_enabled()) {
85 0 : state->learning_enabled_ = vm_port->learning_enabled();
86 0 : if (state->learning_enabled_ == false) {
87 0 : delete_mac = true;
88 : }
89 : }
90 :
91 39 : if (state->policy_enabled_ != vm_port->policy_enabled()) {
92 15 : state->policy_enabled_ = vm_port->policy_enabled();
93 15 : changed = true;
94 : }
95 :
96 39 : if (state->l2_active_ != vm_port->IsL2Active()) {
97 15 : state->l2_active_ = vm_port->IsL2Active();
98 15 : if (state->l2_active_ == false) {
99 0 : delete_mac = true;
100 : }
101 : }
102 : }
103 :
104 55 : if (delete_mac) {
105 0 : DeleteAllMac(vm_port, state);
106 0 : return;
107 : }
108 :
109 55 : if (changed) {
110 41 : AddEvent(vm_port, state);
111 : }
112 : }
113 :
114 23 : void MacLearningDBClient::VnNotify(DBTablePartBase *part, DBEntryBase *e) {
115 23 : VnEntry *vn = static_cast<VnEntry *>(e);
116 :
117 : MacLearningVnState *state = static_cast<MacLearningVnState *>
118 23 : (e->GetState(part->parent(), vn_listener_id_));
119 :
120 23 : if (vn->IsDeleted()) {
121 7 : if (state) {
122 7 : DeleteEvent(vn, state);
123 : }
124 7 : return;
125 : }
126 :
127 16 : bool changed = false;
128 16 : bool delete_mac_ip = false;
129 16 : if (state == NULL) {
130 7 : state = new MacLearningVnState();
131 7 : e->SetState(part->parent(), vn_listener_id_, state);
132 7 : state->mac_ip_learning_enabled_ = vn->mac_ip_learning_enable();
133 7 : state->hc_uuid_ = vn->health_check_uuid();
134 7 : changed = true;
135 : } else {
136 9 : if (state->mac_ip_learning_enabled_ != vn->mac_ip_learning_enable()) {
137 0 : state->mac_ip_learning_enabled_ = vn->mac_ip_learning_enable();
138 0 : if (state->mac_ip_learning_enabled_ == false) {
139 0 : delete_mac_ip = true;
140 : }
141 : }
142 9 : if (state->hc_uuid_ != vn->health_check_uuid()) {
143 0 : state->hc_uuid_ = vn->health_check_uuid();
144 0 : changed = true;
145 : }
146 :
147 : }
148 :
149 16 : if (delete_mac_ip) {
150 0 : DeleteAllMac(vn, state);
151 0 : return;
152 : }
153 :
154 16 : if (changed) {
155 7 : AddEvent(vn, state);
156 : }
157 : }
158 :
159 0 : void MacLearningDBClient::HealthCheckNotify(DBTablePartBase *part, DBEntryBase *e) {
160 0 : HealthCheckService *hc_service = static_cast<HealthCheckService *>(e);
161 :
162 : MacLearningHealthCheckState *state = static_cast<MacLearningHealthCheckState *>
163 0 : (e->GetState(part->parent(), hc_listener_id_));
164 :
165 0 : if (hc_service->IsDeleted()) {
166 0 : if (state) {
167 0 : DeleteNoOpEvent(hc_service, state);
168 : }
169 0 : return;
170 : }
171 0 : bool param_changed = false;
172 0 : bool ip_list_changed = false;
173 0 : if (state == NULL) {
174 0 : state = new MacLearningHealthCheckState();
175 0 : e->SetState(part->parent(), hc_listener_id_, state);
176 0 : state->delay_ = hc_service->delay();
177 0 : state->delay_usecs_ = hc_service->delay_usecs();
178 0 : state->timeout_ = hc_service->timeout();
179 0 : state->timeout_usecs_ = hc_service->timeout_usecs();
180 0 : state->max_retries_ = hc_service->max_retries();
181 0 : state->is_hc_enable_all_target_ips =
182 0 : hc_service->IsHcEnableAllTargetIp();
183 0 : state->hc_target_ip_list_ = hc_service->GetTargetIpList();
184 0 : param_changed = true;
185 : } else {
186 0 : if (state->delay_ != hc_service->delay()) {
187 0 : state->delay_ = hc_service->delay();
188 0 : param_changed = true;
189 : }
190 0 : if (state->delay_usecs_ != hc_service->delay_usecs()) {
191 0 : state->delay_usecs_ = hc_service->delay_usecs();
192 0 : param_changed = true;
193 : }
194 0 : if (state->timeout_ != hc_service->timeout()) {
195 0 : state->timeout_ = hc_service->timeout();
196 0 : param_changed = true;
197 : }
198 0 : if (state->timeout_usecs_ != hc_service->timeout_usecs()) {
199 0 : state->timeout_usecs_ = hc_service->timeout_usecs();
200 0 : param_changed = true;
201 : }
202 0 : if (state->max_retries_ != hc_service->max_retries()) {
203 0 : state->max_retries_ = hc_service->max_retries();
204 0 : param_changed = true;
205 : }
206 0 : if (state->is_hc_enable_all_target_ips !=
207 0 : hc_service->IsHcEnableAllTargetIp()) {
208 0 : state->is_hc_enable_all_target_ips =
209 0 : hc_service->IsHcEnableAllTargetIp();
210 0 : ip_list_changed = true;
211 : }
212 0 : if (state->hc_target_ip_list_ != hc_service->GetTargetIpList()) {
213 0 : state->hc_target_ip_list_ = hc_service->GetTargetIpList();
214 0 : ip_list_changed = true;
215 : }
216 : }
217 0 : if (param_changed) {
218 0 : AddEvent(hc_service, state);
219 : }
220 0 : if (ip_list_changed) {
221 0 : std::set<boost::uuids::uuid> vn_uuid_list = hc_service->GetVnUuidList();
222 0 : std::set<boost::uuids::uuid>::iterator it = vn_uuid_list.begin();
223 0 : while(it != vn_uuid_list.end()) {
224 0 : VnEntry *vn = agent_->vn_table()->Find(*it);
225 0 : if (vn && !vn->IsDeleted()) {
226 : MacLearningVnState *state = static_cast<MacLearningVnState *>
227 0 : (vn->GetState(vn->get_table(), vn_listener_id_));
228 0 : if (state) {
229 0 : AddEvent(vn, state);
230 : }
231 : }
232 0 : it++;
233 : }
234 0 : }
235 : }
236 :
237 :
238 221 : void MacLearningDBClient::RouteNotify(MacLearningVrfState *vrf_state,
239 : Agent::RouteTableType type,
240 : DBTablePartBase *partition,
241 : DBEntryBase *e) {
242 221 : DBTableBase::ListenerId id = vrf_state->bridge_listener_id_;
243 : MacLearningRouteState *rt_state =
244 221 : static_cast<MacLearningRouteState *>(e->GetState(partition->parent(),
245 : vrf_state->bridge_listener_id_));
246 221 : AgentRoute *route = static_cast<AgentRoute *>(e);
247 :
248 221 : ReleaseToken(route);
249 :
250 221 : if (route->IsDeleted() && route->is_multicast() == false) {
251 50 : if (vrf_state && rt_state) {
252 50 : rt_state->gen_id_++;
253 50 : DeleteEvent(route, rt_state);
254 : }
255 50 : return;
256 : }
257 :
258 171 : if (vrf_state->deleted_) {
259 : // ignore route add/change for delete notified VRF.
260 0 : return;
261 : }
262 :
263 171 : if (route->is_multicast()) {
264 52 : return;
265 : }
266 :
267 119 : if (rt_state == NULL) {
268 50 : rt_state = new MacLearningRouteState();
269 50 : route->SetState(partition->parent(), id, rt_state);
270 50 : AddEvent(route, rt_state);
271 : } else {
272 69 : ChangeEvent(route, rt_state);
273 : }
274 : }
275 :
276 107 : void MacLearningDBClient::EvpnRouteNotify(MacLearningVrfState *vrf_state,
277 : Agent::RouteTableType type,
278 : DBTablePartBase *partition,
279 : DBEntryBase *e) {
280 107 : AgentRoute *route = static_cast<AgentRoute *>(e);
281 :
282 107 : if (route->IsDeleted()) {
283 100 : return;
284 : }
285 :
286 75 : if (vrf_state->deleted_) {
287 : // ignore route add/change for delete notified VRF.
288 0 : return;
289 : }
290 :
291 75 : if (route->is_multicast()) {
292 0 : return;
293 : }
294 :
295 75 : EvpnRouteEntry *entry = dynamic_cast<EvpnRouteEntry *>(route);
296 75 : if (!entry) {
297 0 : return;
298 : }
299 :
300 75 : if (!entry->IsType2()) {
301 0 : return;
302 : }
303 75 : if (route->FindLocalVmPortPath()) {
304 68 : return;
305 : }
306 :
307 7 : IpAddress ip_ = entry->prefix_address();
308 7 : MacAddress mac_ = entry->mac();
309 : MacLearningEntryRequestPtr ptr(new MacLearningEntryRequest(
310 : MacLearningEntryRequest::REMOTE_MAC_IP,
311 7 : entry->vrf_id(),
312 : ip_,
313 7 : mac_));
314 :
315 7 : agent_->mac_learning_proto()->
316 7 : GetMacIpLearningTable()->Enqueue(ptr);
317 :
318 7 : }
319 9 : void MacLearningDBClient::MacLearningVrfState::Register(MacLearningDBClient *client,
320 : VrfEntry *vrf) {
321 : // Register to the Bridge Unicast Table
322 : BridgeAgentRouteTable *bridge_table = static_cast<BridgeAgentRouteTable *>
323 9 : (vrf->GetBridgeRouteTable());
324 9 : bridge_listener_id_ =
325 9 : bridge_table->Register(boost::bind(&MacLearningDBClient::RouteNotify,
326 : client, this, Agent::BRIDGE, _1,
327 : _2));
328 : // Register to the EVPN Table
329 : EvpnAgentRouteTable *evpn_table = static_cast<EvpnAgentRouteTable *>
330 9 : (vrf->GetEvpnRouteTable());
331 9 : evpn_listener_id_ =
332 9 : evpn_table->Register(boost::bind(&MacLearningDBClient::EvpnRouteNotify,
333 : client, this, Agent::EVPN, _1,
334 : _2));
335 9 : }
336 :
337 9 : void MacLearningDBClient::MacLearningVrfState::Unregister(VrfEntry *vrf) {
338 : BridgeAgentRouteTable *bridge_table = static_cast<BridgeAgentRouteTable *>
339 9 : (vrf->GetBridgeRouteTable());
340 9 : bridge_table->Unregister(bridge_listener_id_);
341 : // Register to the EVPN Table
342 : EvpnAgentRouteTable *evpn_table = static_cast<EvpnAgentRouteTable *>
343 9 : (vrf->GetEvpnRouteTable());
344 9 : evpn_table->Unregister(evpn_listener_id_);
345 9 : }
346 :
347 83 : void MacLearningDBClient::VrfNotify(DBTablePartBase *part, DBEntryBase *e) {
348 83 : VrfEntry *vrf = static_cast<VrfEntry *>(e);
349 :
350 : MacLearningVrfState *state = static_cast<MacLearningVrfState *>
351 83 : (e->GetState(part->parent(), vrf_listener_id_));
352 :
353 83 : if (vrf->IsDeleted()) {
354 68 : if (state) {
355 9 : DeleteEvent(vrf, state);
356 : }
357 68 : return;
358 : }
359 :
360 15 : if (state == NULL) {
361 9 : state = new MacLearningVrfState();
362 9 : e->SetState(part->parent(), vrf_listener_id_, state);
363 9 : state->Register(this, vrf);
364 9 : state->isid_ = vrf->isid();
365 9 : AddEvent(vrf, state);
366 : }
367 :
368 15 : if (state->learning_enabled_ != vrf->learning_enabled()) {
369 1 : state->learning_enabled_ = vrf->learning_enabled();
370 1 : if (state->learning_enabled_ == false) {
371 1 : DeleteAllMac(vrf, state);
372 : }
373 : }
374 :
375 15 : if (state->isid_ != vrf->isid()) {
376 0 : state->isid_ = vrf->isid();
377 0 : DeleteAllMac(vrf, state);
378 : }
379 : }
380 :
381 50 : void MacLearningDBClient::FreeRouteState(const DBEntry *ce, uint32_t gen_id) {
382 50 : DBEntry *e = const_cast<DBEntry *>(ce);
383 50 : AgentRoute *rt = static_cast<AgentRoute *>(e);
384 50 : if (rt->IsDeleted() == false) {
385 0 : return;
386 : }
387 :
388 50 : VrfEntry *vrf = rt->vrf();
389 : MacLearningVrfState *vrf_state = static_cast<MacLearningVrfState *>
390 50 : (vrf->GetState(vrf->get_table(), vrf_listener_id_));
391 50 : if (vrf_state == NULL) {
392 0 : return;
393 : }
394 :
395 : MacLearningRouteState *state =
396 50 : static_cast<MacLearningRouteState *>(rt->GetState(rt->get_table(),
397 : vrf_state->bridge_listener_id_));
398 50 : if (state->gen_id_ != gen_id) {
399 0 : return;
400 : }
401 :
402 50 : rt->ClearState(rt->get_table(), vrf_state->bridge_listener_id_);
403 50 : delete state;
404 : }
405 :
406 9 : void MacLearningDBClient::EnqueueAgingTableDelete(const VrfEntry *vrf) {
407 9 : MacLearningProto *ml_proto = agent_->mac_learning_proto();
408 18 : for (uint32_t i = 0; i < ml_proto->size(); i++) {
409 : MacLearningEntryRequestPtr ptr(new MacLearningEntryRequest(
410 9 : MacLearningEntryRequest::DELETE_VRF, vrf->vrf_id()));
411 9 : ml_proto->Find(i)->aging_partition()->Enqueue(ptr);
412 9 : }
413 9 : }
414 :
415 82 : void MacLearningDBClient::FreeDBState(const DBEntry *entry, uint32_t gen_id) {
416 82 : if (dynamic_cast<const Interface *>(entry)) {
417 16 : DBTable *table = agent_->interface_table();
418 16 : Interface *intf = static_cast<Interface *>(table->Find(entry));
419 16 : DBState *state = intf->GetState(intf->get_table(),
420 : interface_listener_id_);
421 16 : intf->ClearState(intf->get_table(), interface_listener_id_);
422 16 : delete state;
423 16 : return;
424 : }
425 :
426 66 : if (dynamic_cast<const VrfEntry *>(entry)) {
427 : //Enqueue request to delete aging table pointers
428 9 : DBTable *table = agent_->vrf_table();
429 9 : VrfEntry *vrf = static_cast<VrfEntry *>(table->Find(entry));
430 :
431 9 : EnqueueAgingTableDelete(vrf);
432 :
433 9 : DBState *state = vrf->GetState(vrf->get_table(),
434 : vrf_listener_id_);
435 9 : MacLearningVrfState *vrf_state =
436 : static_cast<MacLearningVrfState *>(state);
437 9 : vrf->ClearState(vrf->get_table(), vrf_listener_id_);
438 9 : vrf_state->Unregister(vrf);
439 9 : delete state;
440 9 : return;
441 : }
442 :
443 57 : if (dynamic_cast<const AgentRoute *>(entry)) {
444 50 : FreeRouteState(entry, gen_id);
445 50 : return;
446 : }
447 7 : if (dynamic_cast<const VnEntry *>(entry)) {
448 7 : DBTable *table = agent_->vn_table();
449 7 : VnEntry *vn = static_cast<VnEntry *>(table->Find(entry));
450 7 : DBState *state = vn->GetState(vn->get_table(),
451 : vn_listener_id_);
452 7 : vn->ClearState(vn->get_table(), vn_listener_id_);
453 7 : delete state;
454 7 : return;
455 : }
456 0 : if (dynamic_cast<const HealthCheckService *>(entry)) {
457 0 : DBTable *table = agent_->health_check_table();
458 0 : HealthCheckService *hc = static_cast<HealthCheckService *>(table->Find(entry));
459 0 : DBState *state = hc->GetState(hc->get_table(),
460 : hc_listener_id_);
461 0 : hc->ClearState(hc->get_table(), hc_listener_id_);
462 0 : delete state;
463 0 : return;
464 : }
465 : }
466 :
467 107 : void MacLearningDBClient::AddEvent(const DBEntry *entry,
468 : MacLearningDBState *state) {
469 : MacLearningMgmtRequestPtr ptr(new MacLearningMgmtRequest(
470 107 : MacLearningMgmtRequest::ADD_DBENTRY, entry, state->gen_id_));
471 107 : agent_->mac_learning_module()->mac_learning_mgmt()->Enqueue(ptr);
472 107 : }
473 :
474 69 : void MacLearningDBClient::ChangeEvent(const DBEntry *entry,
475 : MacLearningDBState *state) {
476 : MacLearningMgmtRequestPtr ptr(new MacLearningMgmtRequest(
477 69 : MacLearningMgmtRequest::CHANGE_DBENTRY, entry, state->gen_id_));
478 69 : agent_->mac_learning_module()->mac_learning_mgmt()->Enqueue(ptr);
479 69 : }
480 :
481 82 : void MacLearningDBClient::DeleteEvent(const DBEntry *entry,
482 : MacLearningDBState *state) {
483 : MacLearningMgmtRequestPtr ptr(new MacLearningMgmtRequest(
484 : MacLearningMgmtRequest::DELETE_DBENTRY, entry,
485 82 : state->gen_id_));
486 82 : agent_->mac_learning_module()->mac_learning_mgmt()->Enqueue(ptr);
487 82 : }
488 : // this event does not trigger macip entry delete event, it marks
489 : // maclearningdbentry as deleted. this is needed for cases where
490 : // dependent entries are interested only add/update events.
491 0 : void MacLearningDBClient::DeleteNoOpEvent(const DBEntry *entry,
492 : MacLearningDBState *state) {
493 : MacLearningMgmtRequestPtr ptr(new MacLearningMgmtRequest(
494 : MacLearningMgmtRequest::DELETE_DBENTRY_NO_OP, entry,
495 0 : state->gen_id_));
496 0 : agent_->mac_learning_module()->mac_learning_mgmt()->Enqueue(ptr);
497 0 : }
498 1 : void MacLearningDBClient::DeleteAllMac(const DBEntry *entry, MacLearningDBState *state) {
499 : MacLearningMgmtRequestPtr ptr(new MacLearningMgmtRequest(
500 : MacLearningMgmtRequest::DELETE_ALL_MAC, entry,
501 1 : state->gen_id_));
502 1 : agent_->mac_learning_module()->mac_learning_mgmt()->Enqueue(ptr);
503 1 : }
504 :
505 221 : void MacLearningDBClient::ReleaseToken(const DBEntry *entry) {
506 : const BridgeRouteEntry *brt =
507 221 : dynamic_cast<const BridgeRouteEntry *>(entry);
508 :
509 : //Get the partition id for mac of interest
510 442 : uint32_t id = agent_->mac_learning_proto()->Hash(brt->vrf()->vrf_id(),
511 221 : brt->prefix_address());
512 : MacLearningPartition *partition =
513 221 : agent_->mac_learning_proto()->Find(id);
514 221 : assert(partition);
515 :
516 : //Release the token
517 221 : MacLearningKey key(brt->vrf()->vrf_id(), brt->prefix_address());
518 221 : partition->ReleaseToken(key);
519 221 : }
|