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