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