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 33 : void MacLearningDBClient::InterfaceNotify(DBTablePartBase *part, DBEntryBase *e) {
39 33 : Interface *intf = static_cast<Interface *>(e);
40 33 : if (intf->type() != Interface::VM_INTERFACE) {
41 4 : return;
42 : }
43 :
44 : MacLearningIntfState *state = static_cast<MacLearningIntfState *>
45 29 : (e->GetState(part->parent(), interface_listener_id_));
46 :
47 29 : VmInterface *vm_port = static_cast<VmInterface *>(intf);
48 29 : if (intf->IsDeleted()) {
49 5 : if (state) {
50 5 : DeleteEvent(vm_port, state);
51 : }
52 5 : return;
53 : }
54 :
55 24 : bool changed = false;
56 24 : bool delete_mac = false;
57 24 : if (state == NULL) {
58 5 : state = new MacLearningIntfState();
59 5 : e->SetState(part->parent(), interface_listener_id_, state);
60 5 : state->l2_label_ = vm_port->l2_label();
61 5 : state->sg_l_ = vm_port->sg_list();
62 5 : state->learning_enabled_ = vm_port->learning_enabled();
63 5 : state->policy_enabled_ = vm_port->policy_enabled();
64 5 : state->l2_active_ = vm_port->IsL2Active();
65 5 : changed = true;
66 5 : e->SetState(part->parent(), interface_listener_id_, state);
67 : } else {
68 19 : if (state->deleted_ == true) {
69 0 : state->deleted_ = false;
70 0 : changed = true;
71 : }
72 :
73 19 : if (state->l2_label_ != vm_port->l2_label()) {
74 8 : state->l2_label_ = vm_port->l2_label();
75 8 : changed = true;
76 : }
77 :
78 19 : const VmInterface::SecurityGroupEntryList &new_sg_l = vm_port->sg_list();
79 19 : if (state->sg_l_.list_ != new_sg_l.list_) {
80 0 : state->sg_l_ = new_sg_l;
81 0 : changed = true;
82 : }
83 :
84 19 : 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 19 : if (state->policy_enabled_ != vm_port->policy_enabled()) {
92 4 : state->policy_enabled_ = vm_port->policy_enabled();
93 4 : changed = true;
94 : }
95 :
96 19 : if (state->l2_active_ != vm_port->IsL2Active()) {
97 4 : state->l2_active_ = vm_port->IsL2Active();
98 4 : if (state->l2_active_ == false) {
99 0 : delete_mac = true;
100 : }
101 : }
102 : }
103 :
104 24 : if (delete_mac) {
105 0 : DeleteAllMac(vm_port, state);
106 0 : return;
107 : }
108 :
109 24 : if (changed) {
110 13 : AddEvent(vm_port, state);
111 : }
112 : }
113 :
114 10 : void MacLearningDBClient::VnNotify(DBTablePartBase *part, DBEntryBase *e) {
115 10 : VnEntry *vn = static_cast<VnEntry *>(e);
116 :
117 : MacLearningVnState *state = static_cast<MacLearningVnState *>
118 10 : (e->GetState(part->parent(), vn_listener_id_));
119 :
120 10 : if (vn->IsDeleted()) {
121 2 : if (state) {
122 2 : DeleteEvent(vn, state);
123 : }
124 2 : return;
125 : }
126 :
127 8 : bool changed = false;
128 8 : bool delete_mac_ip = false;
129 8 : if (state == NULL) {
130 2 : state = new MacLearningVnState();
131 2 : e->SetState(part->parent(), vn_listener_id_, state);
132 2 : state->mac_ip_learning_enabled_ = vn->mac_ip_learning_enable();
133 2 : state->hc_uuid_ = vn->health_check_uuid();
134 2 : changed = true;
135 : } else {
136 6 : 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 6 : 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 8 : if (delete_mac_ip) {
150 0 : DeleteAllMac(vn, state);
151 0 : return;
152 : }
153 :
154 8 : if (changed) {
155 2 : 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 66 : void MacLearningDBClient::RouteNotify(MacLearningVrfState *vrf_state,
239 : Agent::RouteTableType type,
240 : DBTablePartBase *partition,
241 : DBEntryBase *e) {
242 66 : DBTableBase::ListenerId id = vrf_state->bridge_listener_id_;
243 : MacLearningRouteState *rt_state =
244 66 : static_cast<MacLearningRouteState *>(e->GetState(partition->parent(),
245 : vrf_state->bridge_listener_id_));
246 66 : AgentRoute *route = static_cast<AgentRoute *>(e);
247 :
248 66 : ReleaseToken(route);
249 :
250 66 : if (route->IsDeleted() && route->is_multicast() == false) {
251 16 : if (vrf_state && rt_state) {
252 16 : rt_state->gen_id_++;
253 16 : DeleteEvent(route, rt_state);
254 : }
255 16 : return;
256 : }
257 :
258 50 : if (vrf_state->deleted_) {
259 : // ignore route add/change for delete notified VRF.
260 0 : return;
261 : }
262 :
263 50 : if (route->is_multicast()) {
264 19 : return;
265 : }
266 :
267 31 : if (rt_state == NULL) {
268 16 : rt_state = new MacLearningRouteState();
269 16 : route->SetState(partition->parent(), id, rt_state);
270 16 : AddEvent(route, rt_state);
271 : } else {
272 15 : ChangeEvent(route, rt_state);
273 : }
274 : }
275 :
276 33 : void MacLearningDBClient::EvpnRouteNotify(MacLearningVrfState *vrf_state,
277 : Agent::RouteTableType type,
278 : DBTablePartBase *partition,
279 : DBEntryBase *e) {
280 33 : AgentRoute *route = static_cast<AgentRoute *>(e);
281 :
282 33 : if (route->IsDeleted()) {
283 33 : return;
284 : }
285 :
286 24 : if (vrf_state->deleted_) {
287 : // ignore route add/change for delete notified VRF.
288 0 : return;
289 : }
290 :
291 24 : if (route->is_multicast()) {
292 0 : return;
293 : }
294 :
295 24 : EvpnRouteEntry *entry = dynamic_cast<EvpnRouteEntry *>(route);
296 24 : if (!entry) {
297 0 : return;
298 : }
299 :
300 24 : if (!entry->IsType2()) {
301 0 : return;
302 : }
303 24 : if (route->FindLocalVmPortPath()) {
304 24 : return;
305 : }
306 :
307 0 : IpAddress ip_ = entry->prefix_address();
308 0 : MacAddress mac_ = entry->mac();
309 : MacLearningEntryRequestPtr ptr(new MacLearningEntryRequest(
310 : MacLearningEntryRequest::REMOTE_MAC_IP,
311 0 : entry->vrf_id(),
312 : ip_,
313 0 : mac_));
314 :
315 0 : agent_->mac_learning_proto()->
316 0 : GetMacIpLearningTable()->Enqueue(ptr);
317 :
318 0 : }
319 4 : void MacLearningDBClient::MacLearningVrfState::Register(MacLearningDBClient *client,
320 : VrfEntry *vrf) {
321 : // Register to the Bridge Unicast Table
322 : BridgeAgentRouteTable *bridge_table = static_cast<BridgeAgentRouteTable *>
323 4 : (vrf->GetBridgeRouteTable());
324 4 : bridge_listener_id_ =
325 4 : 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 4 : (vrf->GetEvpnRouteTable());
331 4 : evpn_listener_id_ =
332 4 : evpn_table->Register(boost::bind(&MacLearningDBClient::EvpnRouteNotify,
333 : client, this, Agent::EVPN, _1,
334 : _2));
335 4 : }
336 :
337 4 : void MacLearningDBClient::MacLearningVrfState::Unregister(VrfEntry *vrf) {
338 : BridgeAgentRouteTable *bridge_table = static_cast<BridgeAgentRouteTable *>
339 4 : (vrf->GetBridgeRouteTable());
340 4 : bridge_table->Unregister(bridge_listener_id_);
341 : // Register to the EVPN Table
342 : EvpnAgentRouteTable *evpn_table = static_cast<EvpnAgentRouteTable *>
343 4 : (vrf->GetEvpnRouteTable());
344 4 : evpn_table->Unregister(evpn_listener_id_);
345 4 : }
346 :
347 37 : void MacLearningDBClient::VrfNotify(DBTablePartBase *part, DBEntryBase *e) {
348 37 : VrfEntry *vrf = static_cast<VrfEntry *>(e);
349 :
350 : MacLearningVrfState *state = static_cast<MacLearningVrfState *>
351 37 : (e->GetState(part->parent(), vrf_listener_id_));
352 :
353 37 : if (vrf->IsDeleted()) {
354 31 : if (state) {
355 4 : DeleteEvent(vrf, state);
356 : }
357 31 : return;
358 : }
359 :
360 6 : if (state == NULL) {
361 4 : state = new MacLearningVrfState();
362 4 : e->SetState(part->parent(), vrf_listener_id_, state);
363 4 : state->Register(this, vrf);
364 4 : state->isid_ = vrf->isid();
365 4 : AddEvent(vrf, state);
366 : }
367 :
368 6 : if (state->learning_enabled_ != vrf->learning_enabled()) {
369 4 : state->learning_enabled_ = vrf->learning_enabled();
370 4 : if (state->learning_enabled_ == false) {
371 4 : DeleteAllMac(vrf, state);
372 : }
373 : }
374 :
375 6 : if (state->isid_ != vrf->isid()) {
376 0 : state->isid_ = vrf->isid();
377 0 : DeleteAllMac(vrf, state);
378 : }
379 : }
380 :
381 16 : void MacLearningDBClient::FreeRouteState(const DBEntry *ce, uint32_t gen_id) {
382 16 : DBEntry *e = const_cast<DBEntry *>(ce);
383 16 : AgentRoute *rt = static_cast<AgentRoute *>(e);
384 16 : if (rt->IsDeleted() == false) {
385 0 : return;
386 : }
387 :
388 16 : VrfEntry *vrf = rt->vrf();
389 : MacLearningVrfState *vrf_state = static_cast<MacLearningVrfState *>
390 16 : (vrf->GetState(vrf->get_table(), vrf_listener_id_));
391 16 : if (vrf_state == NULL) {
392 0 : return;
393 : }
394 :
395 : MacLearningRouteState *state =
396 16 : static_cast<MacLearningRouteState *>(rt->GetState(rt->get_table(),
397 : vrf_state->bridge_listener_id_));
398 16 : if (state->gen_id_ != gen_id) {
399 0 : return;
400 : }
401 :
402 16 : rt->ClearState(rt->get_table(), vrf_state->bridge_listener_id_);
403 16 : delete state;
404 : }
405 :
406 4 : void MacLearningDBClient::EnqueueAgingTableDelete(const VrfEntry *vrf) {
407 4 : MacLearningProto *ml_proto = agent_->mac_learning_proto();
408 8 : for (uint32_t i = 0; i < ml_proto->size(); i++) {
409 : MacLearningEntryRequestPtr ptr(new MacLearningEntryRequest(
410 4 : MacLearningEntryRequest::DELETE_VRF, vrf->vrf_id()));
411 4 : ml_proto->Find(i)->aging_partition()->Enqueue(ptr);
412 4 : }
413 4 : }
414 :
415 27 : void MacLearningDBClient::FreeDBState(const DBEntry *entry, uint32_t gen_id) {
416 27 : if (dynamic_cast<const Interface *>(entry)) {
417 5 : DBTable *table = agent_->interface_table();
418 5 : Interface *intf = static_cast<Interface *>(table->Find(entry));
419 5 : DBState *state = intf->GetState(intf->get_table(),
420 : interface_listener_id_);
421 5 : intf->ClearState(intf->get_table(), interface_listener_id_);
422 5 : delete state;
423 5 : return;
424 : }
425 :
426 22 : if (dynamic_cast<const VrfEntry *>(entry)) {
427 : //Enqueue request to delete aging table pointers
428 4 : DBTable *table = agent_->vrf_table();
429 4 : VrfEntry *vrf = static_cast<VrfEntry *>(table->Find(entry));
430 :
431 4 : EnqueueAgingTableDelete(vrf);
432 :
433 4 : DBState *state = vrf->GetState(vrf->get_table(),
434 : vrf_listener_id_);
435 4 : MacLearningVrfState *vrf_state =
436 : static_cast<MacLearningVrfState *>(state);
437 4 : vrf->ClearState(vrf->get_table(), vrf_listener_id_);
438 4 : vrf_state->Unregister(vrf);
439 4 : delete state;
440 4 : return;
441 : }
442 :
443 18 : if (dynamic_cast<const AgentRoute *>(entry)) {
444 16 : FreeRouteState(entry, gen_id);
445 16 : return;
446 : }
447 2 : if (dynamic_cast<const VnEntry *>(entry)) {
448 2 : DBTable *table = agent_->vn_table();
449 2 : VnEntry *vn = static_cast<VnEntry *>(table->Find(entry));
450 2 : DBState *state = vn->GetState(vn->get_table(),
451 : vn_listener_id_);
452 2 : vn->ClearState(vn->get_table(), vn_listener_id_);
453 2 : delete state;
454 2 : 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 35 : void MacLearningDBClient::AddEvent(const DBEntry *entry,
468 : MacLearningDBState *state) {
469 : MacLearningMgmtRequestPtr ptr(new MacLearningMgmtRequest(
470 35 : MacLearningMgmtRequest::ADD_DBENTRY, entry, state->gen_id_));
471 35 : agent_->mac_learning_module()->mac_learning_mgmt()->Enqueue(ptr);
472 35 : }
473 :
474 15 : void MacLearningDBClient::ChangeEvent(const DBEntry *entry,
475 : MacLearningDBState *state) {
476 : MacLearningMgmtRequestPtr ptr(new MacLearningMgmtRequest(
477 15 : MacLearningMgmtRequest::CHANGE_DBENTRY, entry, state->gen_id_));
478 15 : agent_->mac_learning_module()->mac_learning_mgmt()->Enqueue(ptr);
479 15 : }
480 :
481 27 : void MacLearningDBClient::DeleteEvent(const DBEntry *entry,
482 : MacLearningDBState *state) {
483 : MacLearningMgmtRequestPtr ptr(new MacLearningMgmtRequest(
484 : MacLearningMgmtRequest::DELETE_DBENTRY, entry,
485 27 : state->gen_id_));
486 27 : agent_->mac_learning_module()->mac_learning_mgmt()->Enqueue(ptr);
487 27 : }
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 4 : void MacLearningDBClient::DeleteAllMac(const DBEntry *entry, MacLearningDBState *state) {
499 : MacLearningMgmtRequestPtr ptr(new MacLearningMgmtRequest(
500 : MacLearningMgmtRequest::DELETE_ALL_MAC, entry,
501 4 : state->gen_id_));
502 4 : agent_->mac_learning_module()->mac_learning_mgmt()->Enqueue(ptr);
503 4 : }
504 :
505 66 : void MacLearningDBClient::ReleaseToken(const DBEntry *entry) {
506 : const BridgeRouteEntry *brt =
507 66 : dynamic_cast<const BridgeRouteEntry *>(entry);
508 :
509 : //Get the partition id for mac of interest
510 132 : uint32_t id = agent_->mac_learning_proto()->Hash(brt->vrf()->vrf_id(),
511 66 : brt->prefix_address());
512 : MacLearningPartition *partition =
513 66 : agent_->mac_learning_proto()->Find(id);
514 66 : assert(partition);
515 :
516 : //Release the token
517 66 : MacLearningKey key(brt->vrf()->vrf_id(), brt->prefix_address());
518 66 : partition->ReleaseToken(key);
519 66 : }
|