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