Line data Source code
1 : /*
2 : * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <boost/uuid/uuid_io.hpp>
7 : #include <vnc_cfg_types.h>
8 : #include <base/util.h>
9 :
10 : #include <ifmap/ifmap_node.h>
11 : #include <cmn/agent_cmn.h>
12 : #include <cfg/cfg_init.h>
13 : #include <oper/agent_sandesh.h>
14 : #include <oper/operdb_init.h>
15 : #include <oper/config_manager.h>
16 : #include <oper/ifmap_dependency_manager.h>
17 :
18 : #include <oper/physical_device.h>
19 : #include <oper/physical_device_vn.h>
20 : #include <oper/tunnel_nh.h>
21 :
22 : #include <vector>
23 : #include <string>
24 : #include <strings.h>
25 : #include <multicast_types.h>
26 :
27 : using std::string;
28 : using boost::assign::map_list_of;
29 : using boost::assign::list_of;
30 :
31 : /////////////////////////////////////////////////////////////////////////////
32 : // PhysicalDevice routines
33 : /////////////////////////////////////////////////////////////////////////////
34 6 : static string ToString(PhysicalDevice::ManagementProtocol proto) {
35 6 : switch (proto) {
36 0 : case PhysicalDevice::OVS:
37 0 : return "OVS";
38 : break;
39 :
40 6 : default:
41 6 : break;
42 : }
43 :
44 6 : return "INVALID";
45 : }
46 :
47 4 : static PhysicalDevice::ManagementProtocol FromString(const string &proto) {
48 4 : if (strcasecmp(proto.c_str(), "ovs"))
49 0 : return PhysicalDevice::OVS;
50 :
51 4 : return PhysicalDevice::INVALID;
52 : }
53 :
54 42 : bool PhysicalDevice::IsLess(const DBEntry &rhs) const {
55 42 : const PhysicalDevice &a =
56 : static_cast<const PhysicalDevice &>(rhs);
57 42 : return (uuid_ < a.uuid_);
58 : }
59 :
60 0 : string PhysicalDevice::ToString() const {
61 0 : return UuidToString(uuid_);
62 : }
63 :
64 0 : DBEntryBase::KeyPtr PhysicalDevice::GetDBRequestKey() const {
65 0 : PhysicalDeviceKey *key = new PhysicalDeviceKey(uuid_);
66 0 : return DBEntryBase::KeyPtr(key);
67 : }
68 :
69 0 : void PhysicalDevice::SetKey(const DBRequestKey *key) {
70 0 : const PhysicalDeviceKey *k = static_cast<const PhysicalDeviceKey *>(key);
71 0 : uuid_ = k->uuid_;
72 0 : }
73 :
74 4 : bool PhysicalDevice::Copy(PhysicalDeviceTable *table,
75 : const PhysicalDeviceData *data) {
76 4 : bool ret = false;
77 4 : bool ip_updated = false;
78 4 : IpAddress old_ip;
79 :
80 4 : if (fq_name_ != data->fq_name_) {
81 1 : fq_name_ = data->fq_name_;
82 1 : ret = true;
83 : }
84 :
85 4 : if (name_ != data->name_) {
86 1 : name_ = data->name_;
87 1 : ret = true;
88 : }
89 :
90 4 : if (vendor_ != data->vendor_) {
91 0 : vendor_ = data->vendor_;
92 0 : ret = true;
93 : }
94 :
95 4 : if (ip_ != data->ip_) {
96 1 : old_ip = ip_;
97 1 : ip_updated = true;
98 1 : ip_ = data->ip_;
99 1 : ret = true;
100 : }
101 :
102 4 : if (management_ip_ != data->management_ip_) {
103 0 : management_ip_ = data->management_ip_;
104 0 : ret = true;
105 : }
106 :
107 4 : if (management_ip_ != data->management_ip_) {
108 0 : management_ip_ = data->management_ip_;
109 0 : ret = true;
110 : }
111 :
112 4 : ManagementProtocol proto = FromString(data->protocol_);
113 4 : if (protocol_ != proto) {
114 0 : protocol_ = proto;
115 0 : ret = true;
116 : }
117 :
118 4 : if (ip_updated) {
119 1 : table->UpdateIpToDevMap(old_ip, ip_, this);
120 : }
121 :
122 4 : return ret;
123 : }
124 :
125 : /////////////////////////////////////////////////////////////////////////////
126 : // PhysicalDeviceTable routines
127 : /////////////////////////////////////////////////////////////////////////////
128 24 : std::unique_ptr<DBEntry> PhysicalDeviceTable::AllocEntry(const DBRequestKey *k)
129 : const {
130 24 : const PhysicalDeviceKey *key = static_cast<const PhysicalDeviceKey *>(k);
131 24 : PhysicalDevice *dev = new PhysicalDevice(key->uuid_);
132 24 : return std::unique_ptr<DBEntry>(static_cast<DBEntry *>(dev));
133 : }
134 :
135 1 : DBEntry *PhysicalDeviceTable::OperDBAdd(const DBRequest *req) {
136 1 : PhysicalDeviceKey *key = static_cast<PhysicalDeviceKey *>(req->key.get());
137 : PhysicalDeviceData *data = static_cast<PhysicalDeviceData *>
138 1 : (req->data.get());
139 1 : PhysicalDevice *dev = new PhysicalDevice(key->uuid_);
140 1 : dev->Copy(this, data);
141 1 : dev->SendObjectLog(AgentLogEvent::ADD);
142 1 : return dev;
143 : }
144 :
145 3 : bool PhysicalDeviceTable::OperDBOnChange(DBEntry *entry, const DBRequest *req) {
146 3 : PhysicalDevice *dev = static_cast<PhysicalDevice *>(entry);
147 3 : PhysicalDeviceData *data = dynamic_cast<PhysicalDeviceData *>
148 3 : (req->data.get());
149 3 : assert(data);
150 3 : bool ret = dev->Copy(this, data);
151 3 : dev->SendObjectLog(AgentLogEvent::CHANGE);
152 3 : return ret;
153 : }
154 :
155 0 : bool PhysicalDeviceTable::OperDBResync(DBEntry *entry, const DBRequest *req) {
156 0 : PhysicalDevice *dev = static_cast<PhysicalDevice *>(entry);
157 : PhysicalDeviceTsnManagedData *data =
158 0 : dynamic_cast<PhysicalDeviceTsnManagedData *>(req->data.get());
159 0 : assert(data);
160 0 : if (dev->master() != data->master_) {
161 0 : dev->set_master(data->master_);
162 0 : return true;
163 : }
164 0 : return false;
165 : }
166 :
167 2 : bool PhysicalDeviceTable::OperDBDelete(DBEntry *entry, const DBRequest *req) {
168 2 : PhysicalDevice *dev = static_cast<PhysicalDevice *>(entry);
169 2 : DeleteIpToDevEntry(dev->ip());
170 2 : dev->SendObjectLog(AgentLogEvent::DEL);
171 2 : return true;
172 : }
173 :
174 18 : PhysicalDevice *PhysicalDeviceTable::Find(const boost::uuids::uuid &u) {
175 18 : PhysicalDeviceKey key(u);
176 36 : return static_cast<PhysicalDevice *>(FindActiveEntry(&key));
177 18 : }
178 :
179 2 : DBTableBase *PhysicalDeviceTable::CreateTable(DB *db, const std::string &name) {
180 2 : PhysicalDeviceTable *table = new PhysicalDeviceTable(db, name);
181 2 : table->Init();
182 2 : return table;
183 : }
184 :
185 : /////////////////////////////////////////////////////////////////////////////
186 : // Config handling
187 : /////////////////////////////////////////////////////////////////////////////
188 2 : void PhysicalDeviceTable::RegisterDBClients(IFMapDependencyManager *dep) {
189 2 : }
190 :
191 11 : static PhysicalDeviceKey *BuildKey(const autogen::PhysicalRouter
192 : *router, const boost::uuids::uuid &u) {
193 11 : return new PhysicalDeviceKey(u);
194 : }
195 :
196 4 : static PhysicalDeviceData *BuildData(Agent *agent, IFMapNode *node,
197 : const autogen::PhysicalRouter *router) {
198 4 : boost::system::error_code ec;
199 4 : IpAddress ip = IpAddress();
200 4 : IpAddress mip = IpAddress();
201 4 : ip = IpAddress::from_string(router->dataplane_ip(), ec);
202 4 : mip = IpAddress::from_string(router->management_ip(), ec);
203 4 : return new PhysicalDeviceData(agent, node->name(), router->display_name(),
204 4 : router->vendor_name(), ip, mip, "OVS", node);
205 : }
206 :
207 7 : bool PhysicalDeviceTable::IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u) {
208 : autogen::PhysicalRouter *router = static_cast <autogen::PhysicalRouter *>
209 7 : (node->GetObject());
210 7 : autogen::IdPermsType id_perms = router->id_perms();
211 7 : CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u);
212 7 : return true;
213 7 : }
214 :
215 4 : bool PhysicalDeviceTable::ProcessConfig(IFMapNode *node, DBRequest &req,
216 : const boost::uuids::uuid &u) {
217 : autogen::PhysicalRouter *router = static_cast <autogen::PhysicalRouter *>
218 4 : (node->GetObject());
219 4 : assert(router);
220 :
221 4 : req.key.reset(BuildKey(router, u));
222 4 : if (node->IsDeleted()) {
223 0 : req.oper = DBRequest::DB_ENTRY_DELETE;
224 0 : return true;
225 : }
226 :
227 4 : req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
228 4 : req.data.reset(BuildData(agent(), node, router));
229 4 : Enqueue(&req);
230 :
231 4 : return false;
232 : }
233 :
234 7 : bool PhysicalDeviceTable::IFNodeToReq(IFMapNode *node, DBRequest &req,
235 : const boost::uuids::uuid &u) {
236 : autogen::PhysicalRouter *router = static_cast <autogen::PhysicalRouter *>
237 7 : (node->GetObject());
238 7 : assert(router);
239 :
240 7 : assert(!u.is_nil());
241 :
242 7 : req.key.reset(BuildKey(router, u));
243 7 : if ((req.oper == DBRequest::DB_ENTRY_DELETE) || node->IsDeleted()) {
244 2 : req.oper = DBRequest::DB_ENTRY_DELETE;
245 2 : return true;
246 : }
247 :
248 5 : agent()->config_manager()->AddPhysicalDeviceNode(node);
249 5 : return false;
250 : }
251 :
252 : /////////////////////////////////////////////////////////////////////////////
253 : // Sandesh routines
254 : /////////////////////////////////////////////////////////////////////////////
255 : class DeviceSandesh : public AgentSandesh {
256 : public:
257 0 : DeviceSandesh(std::string context, const std::string &name)
258 0 : : AgentSandesh(context, name) {}
259 :
260 : private:
261 0 : DBTable *AgentGetTable() {
262 : return static_cast<DBTable *>
263 0 : (Agent::GetInstance()->physical_device_table());
264 : }
265 0 : void Alloc() {
266 0 : resp_ = new SandeshDeviceListResp();
267 0 : }
268 : };
269 :
270 0 : static void SetDeviceSandeshData(const PhysicalDevice *entry,
271 : SandeshDevice *data) {
272 0 : data->set_uuid(UuidToString(entry->uuid()));
273 0 : data->set_fq_name(entry->fq_name());
274 0 : data->set_name(entry->name());
275 0 : data->set_vendor(entry->vendor());
276 0 : data->set_ip_address(entry->ip().to_string());
277 0 : data->set_management_protocol(ToString(entry->protocol()));
278 0 : data->set_master(entry->master());
279 0 : }
280 :
281 0 : bool PhysicalDevice::DBEntrySandesh(Sandesh *resp, std::string &name)
282 : const {
283 0 : SandeshDeviceListResp *dev_resp =
284 : static_cast<SandeshDeviceListResp *> (resp);
285 :
286 0 : std::string str_uuid = UuidToString(uuid_);
287 0 : if (name.empty() || name_.find(name) != string::npos) {
288 0 : SandeshDevice data;
289 0 : SetDeviceSandeshData(this, &data);
290 : std::vector<SandeshDevice> &list =
291 : const_cast<std::vector<SandeshDevice>&>
292 0 : (dev_resp->get_device_list());
293 0 : list.push_back(data);
294 0 : return true;
295 0 : }
296 :
297 0 : return false;
298 0 : }
299 :
300 0 : void SandeshDeviceReq::HandleRequest() const {
301 0 : AgentSandeshPtr sand(new DeviceSandesh(context(), get_name()));
302 0 : sand->DoSandesh(sand);
303 0 : }
304 :
305 0 : AgentSandeshPtr PhysicalDeviceTable::GetAgentSandesh
306 : (const AgentSandeshArguments *args, const std::string &context) {
307 0 : return AgentSandeshPtr(new DeviceSandesh(context, args->GetString("name")));
308 : }
309 :
310 6 : void PhysicalDevice::SendObjectLog(AgentLogEvent::type event) const {
311 6 : DeviceObjectLogInfo info;
312 :
313 6 : string str;
314 6 : switch (event) {
315 1 : case AgentLogEvent::ADD:
316 1 : str.assign("Addition ");
317 1 : break;
318 2 : case AgentLogEvent::DEL:
319 2 : str.assign("Deletion ");
320 2 : break;
321 3 : case AgentLogEvent::CHANGE:
322 3 : str.assign("Modification ");
323 3 : break;
324 0 : default:
325 0 : str.assign("INVALID");
326 0 : break;
327 : }
328 6 : info.set_event(str);
329 :
330 6 : info.set_uuid(UuidToString(uuid_));
331 6 : info.set_fq_name(fq_name_);
332 6 : info.set_name(name_);
333 6 : info.set_vendor(vendor_);
334 6 : info.set_ip_address(ip_.to_string());
335 6 : info.set_management_protocol(::ToString(protocol_));
336 6 : info.set_ref_count(GetRefCount());
337 6 : DEVICE_OBJECT_LOG_LOG("Device", SandeshLevel::SYS_INFO, info);
338 6 : }
339 :
340 1 : void PhysicalDeviceTable::UpdateIpToDevMap(IpAddress old_ip, IpAddress new_ip,
341 : PhysicalDevice *p) {
342 1 : DeleteIpToDevEntry(old_ip);
343 1 : if (!new_ip.is_unspecified()) {
344 1 : IpToDeviceMap::iterator it = ip_tree_.find(new_ip);
345 1 : if (it == ip_tree_.end()) {
346 1 : ip_tree_.insert(IpToDevicePair(new_ip, p));
347 : }
348 : }
349 1 : }
350 :
351 3 : void PhysicalDeviceTable::DeleteIpToDevEntry(IpAddress ip) {
352 3 : if (!ip.is_unspecified()) {
353 2 : IpToDeviceMap::iterator it = ip_tree_.find(ip);
354 2 : if (it != ip_tree_.end()) {
355 1 : ip_tree_.erase(it);
356 : }
357 : }
358 3 : }
359 :
360 0 : PhysicalDevice *PhysicalDeviceTable::IpToPhysicalDevice(IpAddress ip) {
361 0 : if (!ip.is_unspecified()) {
362 0 : IpToDeviceMap::iterator it = ip_tree_.find(ip);
363 0 : if (it != ip_tree_.end()) {
364 0 : return it->second;
365 : }
366 : }
367 0 : return NULL;
368 : }
369 :
370 : // Mastership changed for device, enqueue RESYNC to update master_ field if
371 : // physical-device already present
372 0 : void PhysicalDeviceTable::EnqueueDeviceChange(const boost::uuids::uuid &u,
373 : bool master) {
374 0 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
375 0 : req.key.reset(new PhysicalDeviceKey(u, AgentKey::RESYNC));
376 :
377 0 : req.data.reset(new PhysicalDeviceTsnManagedData(agent(), master));
378 0 : Enqueue(&req);
379 0 : }
380 :
381 0 : void PhysicalDeviceTable::AddDeviceToVrfEntry(const boost::uuids::uuid &u,
382 : const std::string &vrf) {
383 0 : DeviceVrfMap::iterator it = device2vrf_map_.find(u);
384 0 : if (it == device2vrf_map_.end()) {
385 0 : VrfSet vrf_set;
386 0 : vrf_set.insert(vrf);
387 0 : device2vrf_map_.insert(DeviceVrfPair(u, vrf_set));
388 0 : return;
389 0 : }
390 0 : VrfSet &vrf_set = it->second;
391 0 : VrfSet::iterator vit = vrf_set.find(vrf);
392 0 : if (vit == vrf_set.end()) {
393 0 : vrf_set.insert(vrf);
394 : }
395 : }
396 :
397 : /* Removes VRF from the vrf_list to which the device points. If the device does
398 : * not point to any more VRFs, then the device entry itself is removed. If the
399 : * device entry itself is removed or if the device is absent in the list, it
400 : * returns true. */
401 0 : bool PhysicalDeviceTable::RemoveDeviceToVrfEntry(const boost::uuids::uuid &u,
402 : const std::string &vrf) {
403 0 : DeviceVrfMap::iterator it = device2vrf_map_.find(u);
404 0 : if (it == device2vrf_map_.end()) {
405 0 : return true;
406 : }
407 0 : VrfSet &vrf_set = it->second;
408 0 : VrfSet::iterator vit = vrf_set.find(vrf);
409 0 : if (vit == vrf_set.end()) {
410 0 : return false;
411 : }
412 : /* If the VRF to be removed is the only vrf to which the device points,
413 : * then remove the device itself */
414 0 : if (vrf_set.size() == 1) {
415 0 : device2vrf_map_.erase(it);
416 0 : return true;
417 : }
418 0 : vrf_set.erase(vit);
419 0 : return false;
420 : }
421 :
422 0 : void PhysicalDeviceTable::ResetDeviceMastership(const boost::uuids::uuid &u,
423 : const std::string &vrf) {
424 0 : if (!RemoveDeviceToVrfEntry(u, vrf)) {
425 : /* If the device is pointing to any other vrfs apart from the
426 : * one passed to this API, then we still need to have
427 : * mastership as true for that device */
428 0 : return;
429 : }
430 0 : PhysicalDeviceSet::iterator dit = managed_pd_set_.find(u);
431 0 : if (dit != managed_pd_set_.end()) {
432 : /* Update mastership as false for the device */
433 0 : EnqueueDeviceChange(u, false);
434 0 : managed_pd_set_.erase(dit);
435 : }
436 : }
437 :
438 0 : void PhysicalDeviceTable::UpdateDeviceMastership(const std::string &vrf,
439 : ComponentNHList clist,
440 : bool del) {
441 0 : PhysicalDeviceSet new_set;
442 :
443 0 : if (del) {
444 0 : VrfDevicesMap::iterator it = vrf2devices_map_.find(vrf);
445 0 : if (it == vrf2devices_map_.end()) {
446 0 : return;
447 : }
448 0 : PhysicalDeviceSet dev_set = it->second;
449 0 : PhysicalDeviceSet::iterator pit = dev_set.begin();
450 0 : while (pit != dev_set.end()) {
451 0 : ResetDeviceMastership(*pit, vrf);
452 0 : ++pit;
453 : }
454 0 : vrf2devices_map_.erase(it);
455 0 : return;
456 0 : }
457 :
458 0 : ComponentNHList::const_iterator comp_nh_it = clist.begin();
459 0 : for(;comp_nh_it != clist.end(); comp_nh_it++) {
460 0 : if ((*comp_nh_it) == NULL) {
461 0 : continue;
462 : }
463 :
464 0 : if ((*comp_nh_it)->nh()->GetType() != NextHop::TUNNEL) {
465 0 : continue;
466 : }
467 : const TunnelNH *tnh = static_cast<const TunnelNH *>
468 0 : ((*comp_nh_it)->nh());
469 :
470 0 : PhysicalDevice *dev = IpToPhysicalDevice(*(tnh->GetDip()));
471 0 : if (dev == NULL) {
472 0 : continue;
473 : }
474 0 : AddDeviceToVrfEntry(dev->uuid(), vrf);
475 : /* Enqueue the change as true only if it was not earlier enqueued.
476 : * List of previously enqueued devices (with master as true) is
477 : * present in managed_pd_set_ */
478 0 : PhysicalDeviceSet::iterator pit = managed_pd_set_.find(dev->uuid());
479 0 : if (pit == managed_pd_set_.end()) {
480 0 : EnqueueDeviceChange(dev->uuid(), true);
481 0 : managed_pd_set_.insert(dev->uuid());
482 : }
483 0 : new_set.insert(dev->uuid());
484 : }
485 :
486 : /* Iterate through the old per vrf physical device list. If any of them are
487 : * not present in new list, enqueue change on those devices with master
488 : * as false */
489 0 : VrfDevicesMap::iterator it = vrf2devices_map_.find(vrf);
490 0 : if (it == vrf2devices_map_.end()) {
491 0 : vrf2devices_map_.insert(VrfDevicesPair(vrf, new_set));
492 0 : return;
493 : }
494 0 : PhysicalDeviceSet dev_set = it->second;
495 0 : PhysicalDeviceSet::iterator pit = dev_set.begin();
496 0 : while (pit != dev_set.end()) {
497 0 : const boost::uuids::uuid &u = *pit;
498 0 : ++pit;
499 0 : PhysicalDeviceSet::iterator dit = new_set.find(u);
500 0 : if (dit == new_set.end()) {
501 : /* This means that physical-device 'u' is removed from vrf passed
502 : * to this API. Reset the mastership only if the physical-device
503 : * is not present for any other VRFs */
504 0 : ResetDeviceMastership(u, vrf);
505 : }
506 : }
507 : //Update the devices_set for the vrf with new_set
508 0 : it->second = new_set;
509 0 : }
510 :
511 0 : void MasterPhysicalDevicesReq::HandleRequest() const {
512 0 : MasterPhysicalDevicesResp *resp = new MasterPhysicalDevicesResp();
513 0 : resp->set_context(context());
514 :
515 0 : Agent *agent = Agent::GetInstance();
516 0 : PhysicalDeviceTable *obj = agent->physical_device_table();
517 : const PhysicalDeviceTable::PhysicalDeviceSet &dev_list =
518 0 : obj->managed_pd_set();
519 : PhysicalDeviceTable::PhysicalDeviceSet::const_iterator it =
520 0 : dev_list.begin();
521 0 : std::vector<PDeviceData> list;
522 0 : while (it != dev_list.end()) {
523 0 : PDeviceData data;
524 0 : data.set_uuid(to_string(*it));
525 0 : list.push_back(data);
526 0 : ++it;
527 0 : }
528 0 : resp->set_dev_list(list);
529 0 : resp->set_more(false);
530 0 : resp->Response();
531 0 : }
|