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