Line data Source code
1 : /*
2 : * Copyright (c) Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <cmn/agent_cmn.h>
7 : #include <base/task_annotations.h>
8 : #include <oper/vrf.h>
9 : #include <oper/vn.h>
10 : #include <oper/nexthop.h>
11 : #include <oper/vxlan.h>
12 : #include <oper/mirror_table.h>
13 : #include <oper/agent_sandesh.h>
14 : #include <oper/mpls.h>
15 :
16 : using namespace std;
17 :
18 564 : VxLanId::~VxLanId() {
19 282 : if (vxlan_id_ == VxLanTable::kInvalidvxlan_id) {
20 0 : return;
21 : }
22 564 : }
23 :
24 0 : DBEntryBase::KeyPtr VxLanId::GetDBRequestKey() const {
25 0 : VxLanIdKey *key = new VxLanIdKey(vxlan_id_);
26 0 : return DBEntryBase::KeyPtr(key);
27 : }
28 :
29 0 : void VxLanId::SetKey(const DBRequestKey *k) {
30 0 : const VxLanIdKey *key = static_cast<const VxLanIdKey *>(k);
31 0 : vxlan_id_ = key->vxlan_id();
32 0 : }
33 :
34 2 : void VxLanTable::Initialize() {
35 2 : Register();
36 2 : }
37 :
38 2 : void VxLanTable::Register() {
39 2 : interface_listener_id_ = agent()->interface_table()->Register(
40 : boost::bind(&VxLanTable::VmInterfaceNotify, this, _1, _2));
41 :
42 2 : }
43 :
44 2 : void VxLanTable::Shutdown() {
45 2 : agent()->interface_table()->Unregister(interface_listener_id_);
46 2 : }
47 :
48 1421 : void VxLanTable::VmInterfaceNotify(DBTablePartBase *partition, DBEntryBase *e) {
49 1421 : const Interface *intf = static_cast<const Interface *>(e);
50 : const VmInterface *vm_itf;
51 1421 : bool composite_nh_modified = false;
52 1421 : if (intf->type() != Interface::VM_INTERFACE) {
53 21 : return;
54 : }
55 :
56 1400 : vm_itf = static_cast<const VmInterface *>(intf);
57 :
58 1400 : if (vm_itf->vn() == NULL) {
59 416 : return;
60 : }
61 :
62 984 : const VnEntry *vn = vm_itf->vn();
63 984 : if (!vn->mirror_destination()) {
64 984 : return;
65 : }
66 :
67 0 : ComponentNHKeyPtr nh_key(new ComponentNHKey(vm_itf->label(),vm_itf->GetUuid(),
68 : InterfaceNHFlags::BRIDGE,
69 0 : vm_itf->vm_mac()));
70 : // if the interface deleted remove the entry from map
71 : // else add it to composite NH list
72 0 : if (intf->IsDeleted() || ((vm_itf->l2_active() == false) &&
73 0 : (vm_itf->ipv4_active() == false) &&
74 0 : (vm_itf->ipv6_active() == false))) {
75 0 : composite_nh_modified = DeleteCompositeNH(vm_itf->vxlan_id(), nh_key);
76 : } else {
77 0 : composite_nh_modified = AddCompositeNH(vm_itf->vxlan_id(), nh_key);
78 : // In case an older NH exists for the same interface, which was added based on
79 : // a different vmi->label(), we need to delete that before adding the new one,
80 : // otherwise there traffic will be duplicated on the output interface, since
81 : // both the older and newer NH (policy disabled/enabled) point to the same
82 : // output interface
83 0 : if (composite_nh_modified && vm_itf->label_op() != MplsTable::kInvalidLabel) {
84 : ComponentNHKeyPtr nh_key_op(
85 0 : new ComponentNHKey(vm_itf->label_op(),vm_itf->GetUuid(),
86 : InterfaceNHFlags::BRIDGE,
87 0 : vm_itf->vm_mac()));
88 0 : DeleteCompositeNH(vm_itf->vxlan_id(), nh_key_op);
89 0 : }
90 : }
91 :
92 0 : if (composite_nh_modified) {
93 0 : Create(vm_itf->vxlan_id(), vm_itf->vrf()->GetName(),
94 0 : vn->flood_unknown_unicast(), vn->mirror_destination(),
95 0 : vm_itf->learning_enabled(), !vn->vxlan_routing_vn());
96 : }
97 0 : return;
98 0 : }
99 :
100 0 : bool VxLanTable::DeleteCompositeNH(uint32_t vxlan_id,
101 : ComponentNHKeyPtr nh_key) {
102 0 : VxlanCompositeNHList::iterator it = vxlan_composite_nh_map_.find(vxlan_id);
103 0 : if (it != vxlan_composite_nh_map_.end()) {
104 0 : ComponentNHKeyList::iterator list_it = it->second.begin();
105 0 : for (; list_it != it->second.end(); list_it++) {
106 0 : if (*list_it == NULL) {
107 0 : continue;
108 : }
109 0 : if (**list_it == *nh_key) {
110 : // release the ComponentNHKeyPtr
111 0 : (*list_it).reset();
112 0 : it->second.erase(list_it);
113 0 : return true;
114 : }
115 : }
116 0 : return false;
117 : }
118 0 : return false;
119 : }
120 :
121 0 : bool VxLanTable::AddCompositeNH(uint32_t vxlan_id, ComponentNHKeyPtr nh_key) {
122 0 : VxlanCompositeNHList::iterator it = vxlan_composite_nh_map_.find(vxlan_id);
123 0 : if (it != vxlan_composite_nh_map_.end()) {
124 0 : ComponentNHKeyList::const_iterator list_it = it->second.begin();
125 0 : for (; list_it != it->second.end(); list_it++) {
126 0 : if (*list_it == NULL) {
127 0 : continue;
128 : }
129 0 : if (**list_it == *nh_key) {
130 : // already there no modification
131 0 : return false;
132 : }
133 : }
134 0 : it->second.push_back(nh_key);
135 0 : return true;
136 : }
137 0 : ComponentNHKeyList list;
138 0 : list.push_back(nh_key);
139 0 : vxlan_composite_nh_map_.insert(VxlanCompositeNHEntry(vxlan_id, list));
140 0 : return true;
141 0 : }
142 :
143 :
144 215 : std::unique_ptr<DBEntry> VxLanTable::AllocEntry(const DBRequestKey *k) const {
145 215 : const VxLanIdKey *key = static_cast<const VxLanIdKey *>(k);
146 215 : VxLanId *vxlan_id = new VxLanId(key->vxlan_id());
147 215 : return std::unique_ptr<DBEntry>(static_cast<DBEntry *>(vxlan_id));
148 : }
149 :
150 134 : void VxLanTable::Process(DBRequest &req) {
151 134 : agent()->ConcurrencyCheck();
152 : DBTablePartition *tpart =
153 134 : static_cast<DBTablePartition *>(GetTablePartition(req.key.get()));
154 134 : Input(tpart, NULL, &req);
155 134 : }
156 :
157 67 : DBEntry *VxLanTable::Add(const DBRequest *req) {
158 67 : VxLanIdKey *key = static_cast<VxLanIdKey *>(req->key.get());
159 67 : VxLanId *vxlan_id = new VxLanId(key->vxlan_id());
160 :
161 67 : ChangeHandler(vxlan_id, req);
162 67 : vxlan_id->SendObjectLog(this, AgentLogEvent::ADD);
163 67 : return vxlan_id;
164 : }
165 :
166 0 : bool VxLanTable::OnChange(DBEntry *entry, const DBRequest *req) {
167 : bool ret;
168 0 : VxLanId *vxlan_id = static_cast<VxLanId *>(entry);
169 0 : ret = ChangeHandler(vxlan_id, req);
170 0 : vxlan_id->SendObjectLog(this, AgentLogEvent::CHANGE);
171 0 : return ret;
172 : }
173 :
174 : // No Change expected for vxlan_id vxlan_id
175 67 : bool VxLanTable::ChangeHandler(VxLanId *vxlan_id, const DBRequest *req) {
176 67 : bool ret = false;
177 67 : VxLanIdData *data = static_cast<VxLanIdData *>(req->data.get());
178 :
179 67 : Agent::GetInstance()->nexthop_table()->Process(data->nh_req());
180 : NextHop *nh;
181 : // if VN is enabled with mirror destination point the vxlan nh
182 : // to CompositeNH
183 67 : if (data->mirror_destination()) {
184 : VxlanCompositeNHList::iterator it =
185 0 : vxlan_composite_nh_map_.find(vxlan_id->vxlan_id());
186 0 : if (it != vxlan_composite_nh_map_.end()) {
187 0 : CompositeNHKey nh_key(Composite::L2INTERFACE, false, it->second,
188 0 : data->vrf_name());
189 0 : nh = static_cast<NextHop *>
190 0 : (Agent::GetInstance()->nexthop_table()->FindActiveEntry(&nh_key));
191 0 : } else {
192 : // vm interface notification arraived at so create dummy CompositeNH
193 0 : ComponentNHKeyPtr nh_ptr;
194 0 : nh_ptr.reset();
195 0 : ComponentNHKeyList list;
196 0 : list.push_back(nh_ptr);
197 : CompositeNHKey nh_key(Composite::L2INTERFACE, false, list,
198 0 : data->vrf_name());
199 0 : nh = static_cast<NextHop *>
200 0 : (agent()->nexthop_table()->FindActiveEntry(&nh_key));
201 0 : }
202 : } else {
203 67 : VrfNHKey nh_key(data->vrf_name(), false, data->bridge());
204 67 : nh = static_cast<NextHop *>
205 67 : (Agent::GetInstance()->nexthop_table()->FindActiveEntry(&nh_key));
206 67 : }
207 :
208 67 : if (vxlan_id->nh_ != nh) {
209 67 : vxlan_id->nh_ = nh;
210 67 : ret = true;
211 : }
212 :
213 67 : return ret;
214 : }
215 :
216 67 : bool VxLanTable::Delete(DBEntry *entry, const DBRequest *req) {
217 67 : VxLanId *vxlan_id = static_cast<VxLanId *>(entry);
218 67 : vxlan_id->SendObjectLog(this, AgentLogEvent::DEL);
219 67 : return true;
220 : }
221 :
222 72 : VxLanId *VxLanTable::Find(uint32_t vxlan_id) {
223 72 : VxLanIdKey key(vxlan_id);
224 144 : return static_cast<VxLanId *>(FindActiveEntry(&key));
225 72 : }
226 :
227 9 : VxLanId *VxLanTable::FindNoLock(uint32_t vxlan_id) {
228 9 : VxLanIdKey key(vxlan_id);
229 18 : return static_cast<VxLanId *>(FindActiveEntryNoLock(&key));
230 9 : }
231 :
232 67 : void VxLanTable::OnZeroRefcount(AgentDBEntry *e) {
233 67 : const VxLanId *vxlan_id = static_cast<const VxLanId *>(e);
234 67 : Delete(vxlan_id->vxlan_id());
235 67 : }
236 :
237 : // Follows semantics defined for the ConfigTree in vxlan.h
238 : // Return values:
239 : // - vxlan dbentry if "vn" is "active"
240 : // - NULL if "vn" is "inactive"
241 67 : VxLanId *VxLanTable::Locate(uint32_t vxlan_id, const boost::uuids::uuid &vn,
242 : const std::string &vrf, bool flood_unknown_unicast,
243 : bool mirror_destination, bool learning_enabled,
244 : bool bridge) {
245 : // Treat a request without VRF as delete of config entry
246 67 : if (vrf.empty()) {
247 0 : Delete(vxlan_id, vn);
248 0 : return NULL;
249 : }
250 :
251 : // If there are no config-entries persent for the vxlan,
252 : // - Add the config-entry and make it active
253 : // - Create VxLan entry
254 67 : ConfigTree::iterator it = config_tree_.lower_bound(
255 67 : ConfigKey(vxlan_id, boost::uuids::nil_uuid()));
256 :
257 67 : if (it == config_tree_.end() || it->first.vxlan_id_ != vxlan_id) {
258 67 : config_tree_.insert(make_pair(ConfigKey(vxlan_id, vn),
259 134 : ConfigEntry(vrf, flood_unknown_unicast,
260 : true, mirror_destination,
261 : bridge)));
262 67 : Create(vxlan_id, vrf, flood_unknown_unicast, mirror_destination,
263 : learning_enabled, bridge);
264 67 : return Find(vxlan_id);
265 : }
266 :
267 : // Handle change to existing config-entry
268 0 : it = config_tree_.find(ConfigKey(vxlan_id, vn));
269 0 : if (it != config_tree_.end()) {
270 0 : it->second.vrf_ = vrf;
271 0 : it->second.flood_unknown_unicast_ = flood_unknown_unicast;
272 0 : it->second.mirror_destination_ = mirror_destination;
273 0 : it->second.learning_enabled_ = learning_enabled;
274 0 : it->second.bridge_ = bridge;
275 :
276 : // If entry is active, update vxlan dbentry with new information
277 0 : if (it->second.active_) {
278 0 : Create(vxlan_id, vrf, flood_unknown_unicast, mirror_destination,
279 : learning_enabled, bridge);
280 0 : return Find(vxlan_id);
281 : }
282 : // If entry inactive, return NULL
283 0 : return NULL;
284 : }
285 :
286 : // Entry not present, add it to config-tree
287 0 : config_tree_.insert(make_pair(ConfigKey(vxlan_id, vn),
288 0 : ConfigEntry(vrf, flood_unknown_unicast,
289 : false, mirror_destination,
290 : bridge)));
291 : // Return NULL since the VN is active
292 0 : return NULL;
293 : }
294 :
295 67 : VxLanId *VxLanTable::Delete(uint32_t vxlan_id, const boost::uuids::uuid &vn) {
296 67 : ConfigTree::iterator it = config_tree_.find(ConfigKey(vxlan_id, vn));
297 : // Entry not found
298 67 : if (it == config_tree_.end()) {
299 0 : return NULL;
300 : }
301 :
302 : // If the entry is active and getting deleted, make new "active" entry
303 67 : bool active = it->second.active_;
304 67 : config_tree_.erase(it);
305 67 : if (active == false)
306 0 : return NULL;
307 :
308 : // Make first entry as active
309 67 : it = config_tree_.lower_bound(
310 67 : ConfigKey(vxlan_id, boost::uuids::nil_uuid()));
311 :
312 67 : if (it == config_tree_.end() || it->first.vxlan_id_ != vxlan_id)
313 67 : return NULL;
314 :
315 0 : it->second.active_ = true;
316 0 : Create(vxlan_id, it->second.vrf_, it->second.flood_unknown_unicast_,
317 0 : it->second.mirror_destination_, it->second.learning_enabled_,
318 0 : it->second.bridge_);
319 0 : agent()->vn_table()->ResyncReq(it->first.vn_);
320 0 : return NULL;
321 : }
322 :
323 2 : DBTableBase *VxLanTable::CreateTable(DB *db, const std::string &name) {
324 2 : VxLanTable *table = new VxLanTable(db, name);
325 2 : table->Init();
326 2 : return table;
327 : }
328 :
329 67 : void VxLanTable::Create(uint32_t vxlan_id, const string &vrf_name,
330 : bool flood_unknown_unicast, bool mirror_destination,
331 : bool learning_enable, bool bridge) {
332 67 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
333 67 : if (mirror_destination) {
334 : VxlanCompositeNHList::iterator it =
335 0 : vxlan_composite_nh_map_.find(vxlan_id);
336 0 : if (it != vxlan_composite_nh_map_.end()) {
337 0 : nh_req.key.reset(new CompositeNHKey(Composite::L2INTERFACE, false,
338 0 : it->second, vrf_name));
339 : } else {
340 0 : ComponentNHKeyPtr nh_ptr;
341 0 : nh_ptr.reset();
342 0 : ComponentNHKeyList list;
343 0 : list.push_back(nh_ptr);
344 0 : nh_req.key.reset(new CompositeNHKey(Composite::L2INTERFACE, false,
345 0 : list, vrf_name));
346 0 : }
347 0 : nh_req.data.reset(new CompositeNHData());
348 : } else {
349 67 : nh_req.key.reset(new VrfNHKey(vrf_name, false, bridge));
350 67 : nh_req.data.reset(new VrfNHData(flood_unknown_unicast, learning_enable,
351 67 : false));
352 : }
353 67 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
354 67 : req.key.reset(new VxLanIdKey(vxlan_id));
355 67 : req.data.reset(new VxLanIdData(vrf_name, nh_req, mirror_destination,
356 67 : bridge));
357 67 : Process(req);
358 134 : return;
359 67 : }
360 :
361 67 : void VxLanTable::Delete(uint32_t vxlan_id) {
362 67 : DBRequest req(DBRequest::DB_ENTRY_DELETE);
363 67 : req.key.reset(new VxLanIdKey(vxlan_id));
364 67 : req.data.reset(NULL);
365 67 : VxlanCompositeNHList::iterator it = vxlan_composite_nh_map_.find(vxlan_id);
366 67 : if (it != vxlan_composite_nh_map_.end()) {
367 0 : vxlan_composite_nh_map_.erase(it);
368 : }
369 67 : Process(req);
370 67 : }
371 :
372 0 : bool VxLanId::DBEntrySandesh(Sandesh *sresp, std::string &name) const {
373 0 : VxLanResp *resp = static_cast<VxLanResp *>(sresp);
374 :
375 0 : VxLanSandeshData data;
376 0 : data.set_vxlan_id(vxlan_id_);
377 0 : nh_->SetNHSandeshData(data.nh);
378 : std::vector<VxLanSandeshData> &list =
379 0 : const_cast<std::vector<VxLanSandeshData>&>(resp->get_vxlan_list());
380 0 : list.push_back(data);
381 :
382 0 : return true;
383 0 : }
384 :
385 134 : void VxLanId::SendObjectLog(const AgentDBTable *table,
386 : AgentLogEvent::type event) const {
387 134 : VxLanObjectLogInfo info;
388 134 : string str, nh_type;
389 :
390 134 : info.set_vxlan_id((int)vxlan_id_);
391 134 : switch (event) {
392 67 : case AgentLogEvent::ADD:
393 67 : str.assign("Addition ");
394 67 : break;
395 67 : case AgentLogEvent::DEL:
396 67 : str.assign("Deletion ");
397 67 : info.set_event(str);
398 67 : OPER_TRACE_ENTRY(VxLan, table, info);
399 67 : return;
400 0 : case AgentLogEvent::CHANGE:
401 0 : str.assign("Modification ");
402 0 : break;
403 0 : default:
404 0 : str.assign("Unknown");
405 0 : break;
406 : }
407 67 : info.set_event(str);
408 67 : const NextHop *nh = nexthop();
409 67 : if (nh != NULL) {
410 : //const VrfNH *vrf_nh;
411 67 : switch(nh->GetType()) {
412 67 : case NextHop::VRF: {
413 67 : nh_type.assign("VRF");
414 67 : const VrfNH *vrf_nh = static_cast<const VrfNH *>(nh);
415 67 : info.set_vrf_name(vrf_nh->GetVrf()->GetName());
416 67 : break;
417 : }
418 0 : default:
419 0 : nh_type.assign("unknown");
420 0 : break;
421 : }
422 : }
423 67 : info.set_nh_type(nh_type);
424 67 : OPER_TRACE_ENTRY(VxLan, table, info);
425 268 : }
426 :
427 0 : void VxLanReq::HandleRequest() const {
428 0 : AgentSandeshPtr sand(new AgentVxLanSandesh(context(), get_vxlan_id()));
429 0 : sand->DoSandesh(sand);
430 0 : }
431 :
432 0 : AgentSandeshPtr VxLanTable::GetAgentSandesh(const AgentSandeshArguments *args,
433 : const std::string &context) {
434 : return AgentSandeshPtr(new AgentVxLanSandesh(context,
435 0 : args->GetString("vxlan_id")));
436 : }
437 :
438 : /////////////////////////////////////////////////////////////////////////////
439 : // Sandesh routines to dump config tree
440 : /////////////////////////////////////////////////////////////////////////////
441 : class VxLanConfigSandeshTask : public Task {
442 : public:
443 0 : VxLanConfigSandeshTask(Agent *agent, uint32_t vxlan_id, const string &vn,
444 0 : const string &active, const string &context) :
445 : Task(agent->task_scheduler()->GetTaskId(AGENT_SANDESH_TASKNAME), 0),
446 0 : agent_(agent), vxlan_id_(vxlan_id), vn_(vn), active_(active),
447 0 : context_(context) { }
448 0 : ~VxLanConfigSandeshTask() { }
449 : virtual bool Run();
450 0 : std::string Description() const { return "VxLanConfigSandeshTask"; }
451 :
452 : private:
453 : Agent *agent_;
454 : uint32_t vxlan_id_;
455 : string vn_;
456 : string active_;
457 : string context_;
458 : DISALLOW_COPY_AND_ASSIGN(VxLanConfigSandeshTask);
459 : };
460 :
461 0 : bool VxLanConfigSandeshTask::Run() {
462 0 : VxLanConfigResp *resp = new VxLanConfigResp();
463 : vector<VxLanConfigEntry> &list =
464 0 : const_cast<vector<VxLanConfigEntry>&>(resp->get_vxlan_config_entries());
465 :
466 0 : boost::uuids::uuid u = boost::uuids::nil_uuid();
467 0 : if (vn_.empty() == false) {
468 0 : u = StringToUuid(vn_);
469 : }
470 :
471 0 : const VxLanTable::ConfigTree &tree = agent_->vxlan_table()->config_tree();
472 0 : VxLanTable::ConfigTree::const_iterator it = tree.begin();
473 0 : while (it != tree.end()) {
474 0 : VxLanConfigEntry entry;
475 0 : if (vxlan_id_ != 0) {
476 0 : if (vxlan_id_ != it->first.vxlan_id_) {
477 0 : it++;
478 0 : continue;
479 : }
480 : }
481 :
482 0 : if (u != boost::uuids::nil_uuid() && u != it->first.vn_) {
483 0 : it++;
484 0 : continue;
485 : }
486 :
487 0 : if (active_.empty() == false) {
488 0 : if ((active_ == "true" || active_ == "yes" || active_ == "active")
489 0 : && (it->second.active_ != true)) {
490 0 : it++;
491 0 : continue;
492 : }
493 :
494 0 : if ((active_ == "false" || active_ == "no" || active_ == "inactive")
495 0 : && (it->second.active_ != false)) {
496 0 : it++;
497 0 : continue;
498 : }
499 : }
500 :
501 0 : entry.set_vxlan_id(it->first.vxlan_id_);
502 0 : entry.set_vn_uuid(UuidToString(it->first.vn_));
503 0 : entry.set_vrf(it->second.vrf_);
504 0 : entry.set_flood_unknown_unicast(it->second.flood_unknown_unicast_);
505 0 : entry.set_active(it->second.active_);
506 0 : list.push_back(entry);
507 0 : it++;
508 0 : }
509 0 : resp->set_context(context_);
510 0 : resp->set_more(false);
511 0 : resp->Response();
512 0 : return true;
513 : }
514 :
515 0 : void VxLanConfigReq::HandleRequest() const {
516 0 : Agent *agent = Agent::GetInstance();
517 : VxLanConfigSandeshTask *task =
518 0 : new VxLanConfigSandeshTask(agent, get_vxlan_id(), get_vn(),
519 0 : get_active(), context());
520 0 : agent->task_scheduler()->Enqueue(task);
521 0 : }
|