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