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