Line data Source code
1 : /*
2 : * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <sstream>
6 : #include "service_instance.h"
7 :
8 : #include "ifmap/ifmap_node.h"
9 : #include "schema/vnc_cfg_types.h"
10 :
11 : #include "oper/ifmap_dependency_manager.h"
12 : #include "oper/operdb_init.h"
13 : #include <cfg/cfg_init.h>
14 : #include <cmn/agent.h>
15 : #include <init/agent_param.h>
16 : #include <oper/agent_sandesh.h>
17 : #include <oper/agent_types.h>
18 : #include "oper/instance_manager.h"
19 :
20 : using boost::uuids::uuid;
21 :
22 : /*
23 : * ServiceInstanceTable create requests contain the IFMapNode that this
24 : * entry corresponds to.
25 : */
26 : class ServiceInstanceCreate : public AgentData {
27 : public:
28 0 : ServiceInstanceCreate(IFMapNode *node) :
29 0 : node_(node) {
30 0 : }
31 0 : IFMapNode *node() { return node_; }
32 :
33 : private:
34 : IFMapNode *node_;
35 : };
36 :
37 : class ServiceInstanceTypesMapping {
38 : public:
39 : static const std::string kOtherType;
40 : static int StrServiceTypeToInt(const std::string &type);
41 : static const std::string &IntServiceTypeToStr(
42 : const ServiceInstance::ServiceType &type);
43 : static int StrVirtualizationTypeToInt(const std::string &type);
44 : static const std::string &IntVirtualizationTypeToStr(
45 : const ServiceInstance::VirtualizationType &type);
46 : static int StrVRouterInstanceTypeToInt(const std::string &type);
47 : static const std::string &IntVRouterInstanceTypeToStr(
48 : const ServiceInstance::VRouterInstanceType &type);
49 :
50 : private:
51 : typedef std::map<std::string, int> StrTypeToIntMap;
52 : typedef std::pair<std::string, int> StrTypeToIntPair;
53 : static StrTypeToIntMap service_type_map_;
54 : static StrTypeToIntMap virtualization_type_map_;
55 : static StrTypeToIntMap vrouter_instance_type_map_;
56 :
57 1 : static StrTypeToIntMap InitServiceTypeMap() {
58 1 : StrTypeToIntMap types;
59 1 : types.insert(StrTypeToIntPair("source-nat", ServiceInstance::SourceNAT));
60 1 : types.insert(StrTypeToIntPair("loadbalancer", ServiceInstance::LoadBalancer));
61 :
62 1 : return types;
63 0 : };
64 :
65 1 : static StrTypeToIntMap InitVirtualizationTypeMap() {
66 1 : StrTypeToIntMap types;
67 1 : types.insert(StrTypeToIntPair("virtual-machine", ServiceInstance::VirtualMachine));
68 1 : types.insert(StrTypeToIntPair("network-namespace", ServiceInstance::NetworkNamespace));
69 1 : types.insert(StrTypeToIntPair("vrouter-instance", ServiceInstance::VRouterInstance));
70 :
71 1 : return types;
72 0 : };
73 :
74 1 : static StrTypeToIntMap InitVRouterInstanceTypeMap() {
75 1 : StrTypeToIntMap types;
76 1 : types.insert(StrTypeToIntPair("libvirt-qemu", ServiceInstance::KVM));
77 1 : types.insert(StrTypeToIntPair("docker", ServiceInstance::Docker));
78 1 : return types;
79 0 : };
80 : };
81 :
82 0 : static uuid IdPermsGetUuid(const autogen::IdPermsType &id) {
83 : uuid uuid;
84 0 : CfgUuidSet(id.uuid.uuid_mslong, id.uuid.uuid_lslong, uuid);
85 0 : return uuid;
86 : }
87 :
88 0 : static bool IsNodeType(IFMapNode *node, const char *node_typename) {
89 0 : return (strcmp(node->table()->Typename(), node_typename) == 0);
90 : }
91 :
92 : /*
93 : * Walks through the graph starting from the service instance in order to
94 : * find the Virtual Machine associated. Set the vm_id of the ServiceInstanceData
95 : * object and return the VM node.
96 : */
97 0 : static IFMapNode *FindAndSetVirtualMachine(
98 : DBGraph *graph, IFMapNode *si_node,
99 : ServiceInstance::Properties *properties) {
100 :
101 0 : for (DBGraphVertex::adjacency_iterator iter = si_node->begin(graph);
102 0 : iter != si_node->end(graph); ++iter) {
103 0 : IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
104 0 : if (IsNodeType(adj, "virtual-machine")) {
105 : autogen::VirtualMachine *vm =
106 0 : static_cast<autogen::VirtualMachine *>(adj->GetObject());
107 0 : properties->instance_id = IdPermsGetUuid(vm->id_perms());
108 0 : return adj;
109 : }
110 : }
111 0 : return NULL;
112 : }
113 :
114 0 : static IFMapNode *FindNetworkIpam(DBGraph *graph, IFMapNode *vn_ipam_node) {
115 0 : for (DBGraphVertex::adjacency_iterator iter = vn_ipam_node->begin(graph);
116 0 : iter != vn_ipam_node->end(graph); ++iter) {
117 0 : IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
118 :
119 0 : if (IsNodeType(adj, "network-ipam")) {
120 0 : return adj;
121 : }
122 : }
123 0 : return NULL;
124 : }
125 :
126 0 : static IFMapNode *FindNetwork(DBGraph *graph, IFMapNode *vmi_node) {
127 : /*
128 : * Lookup for VirtualNetwork nodes
129 : */
130 0 : for (DBGraphVertex::adjacency_iterator iter = vmi_node->begin(graph);
131 0 : iter != vmi_node->end(graph); ++iter) {
132 0 : IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
133 0 : if (IsNodeType(adj, "virtual-network")) {
134 0 : return adj;
135 : }
136 : }
137 0 : return NULL;
138 : }
139 :
140 :
141 0 : static std::string FindInterfaceIp(DBGraph *graph, IFMapNode *vmi_node) {
142 0 : for (DBGraphVertex::adjacency_iterator iter = vmi_node->begin(graph);
143 0 : iter != vmi_node->end(graph); ++iter) {
144 0 : IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
145 0 : if (IsNodeType(adj, "instance-ip")) {
146 : autogen::InstanceIp *ip =
147 0 : static_cast<autogen::InstanceIp *>(adj->GetObject());
148 0 : return ip->address();
149 : }
150 : }
151 0 : return std::string();
152 : }
153 :
154 0 : static bool SubNetContainsIpv4(const autogen::IpamSubnetType &subnet,
155 : const std::string &ip) {
156 : typedef boost::asio::ip::address_v4 Ipv4Address;
157 0 : std::string prefix = subnet.subnet.ip_prefix;
158 0 : int prefix_len = subnet.subnet.ip_prefix_len;
159 :
160 0 : boost::system::error_code ec;
161 0 : Ipv4Address ipv4 = Ipv4Address::from_string(ip, ec);
162 0 : Ipv4Address ipv4_prefix = Ipv4Address::from_string(prefix, ec);
163 0 : unsigned long mask = (0xFFFFFFFF << (32 - prefix_len)) & 0xFFFFFFFF;
164 :
165 0 : if ((ipv4.to_ulong() & mask) == (ipv4_prefix.to_ulong() & mask)) {
166 0 : return true;
167 : }
168 0 : return false;
169 0 : }
170 :
171 0 : static void FindAndSetInterfaces(
172 : DBGraph *graph, IFMapNode *vm_node,
173 : autogen::ServiceInstance *svc_instance,
174 : ServiceInstance::Properties *properties) {
175 :
176 : /*
177 : * The outside virtual-network is always specified (by the
178 : * process that creates the service-instance).
179 : * The inside virtual-network is optional for loadbalancer.
180 : * For VRouter instance there can be up to 3 interfaces.
181 : * TODO: support more than 3 interfaces for VRouter instances.
182 : * Lookup for VMI nodes
183 : */
184 0 : properties->interface_count = 0;
185 0 : for (DBGraphVertex::adjacency_iterator iter = vm_node->begin(graph);
186 0 : iter != vm_node->end(graph); ++iter) {
187 0 : IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
188 0 : if (!IsNodeType(adj, "virtual-machine-interface")) {
189 0 : continue;
190 : }
191 : autogen::VirtualMachineInterface *vmi =
192 : static_cast<autogen::VirtualMachineInterface *>(
193 0 : adj->GetObject());
194 :
195 : const autogen::VirtualMachineInterfacePropertiesType &vmi_props =
196 0 : vmi->properties();
197 :
198 0 : IFMapNode *vn_node = FindNetwork(graph, adj);
199 0 : if (vn_node == NULL) {
200 0 : continue;
201 : }
202 :
203 0 : properties->interface_count++;
204 0 : if(vmi_props.service_interface_type == "left") {
205 0 : properties->vmi_inside = IdPermsGetUuid(vmi->id_perms());
206 0 : if (vmi->mac_addresses().size())
207 0 : properties->mac_addr_inside = vmi->mac_addresses().at(0);
208 0 : properties->ip_addr_inside = FindInterfaceIp(graph, adj);
209 : }
210 0 : else if(vmi_props.service_interface_type == "right") {
211 0 : properties->vmi_outside = IdPermsGetUuid(vmi->id_perms());
212 0 : if (vmi->mac_addresses().size())
213 0 : properties->mac_addr_outside = vmi->mac_addresses().at(0);
214 0 : properties->ip_addr_outside = FindInterfaceIp(graph, adj);
215 : }
216 0 : else if(vmi_props.service_interface_type == "management") {
217 0 : properties->vmi_management = IdPermsGetUuid(vmi->id_perms());
218 0 : if (vmi->mac_addresses().size())
219 0 : properties->mac_addr_management = vmi->mac_addresses().at(0);
220 0 : properties->ip_addr_management = FindInterfaceIp(graph, adj);
221 : }
222 :
223 0 : for (DBGraphVertex::adjacency_iterator iter = vn_node->begin(graph);
224 0 : iter != vn_node->end(graph); ++iter) {
225 : IFMapNode *vn_ipam_node =
226 0 : static_cast<IFMapNode *>(iter.operator->());
227 0 : if (!IsNodeType(vn_ipam_node, "virtual-network-network-ipam")) {
228 0 : continue;
229 : }
230 : autogen::VirtualNetworkNetworkIpam *ipam =
231 : static_cast<autogen::VirtualNetworkNetworkIpam *>
232 0 : (vn_ipam_node->GetObject());
233 0 : IFMapNode *ipam_node = FindNetworkIpam(graph, vn_ipam_node);
234 0 : if (ipam_node == NULL) {
235 0 : continue;
236 : }
237 : autogen::NetworkIpam *network_ipam =
238 0 : static_cast<autogen::NetworkIpam *>(ipam_node->GetObject());
239 : const std::string subnet_method =
240 0 : boost::to_lower_copy(network_ipam->ipam_subnet_method());
241 : const std::vector<autogen::IpamSubnetType> &subnets =
242 0 : (subnet_method == "flat-subnet") ?
243 0 : network_ipam->ipam_subnets() : ipam->data().ipam_subnets;
244 0 : for (unsigned int i = 0; i < subnets.size(); ++i) {
245 0 : int prefix_len = subnets[i].subnet.ip_prefix_len;
246 0 : int service_type = properties->service_type;
247 0 : if (vmi_props.service_interface_type == "left") {
248 0 : std::string &ip_addr = properties->ip_addr_inside;
249 0 : if (SubNetContainsIpv4(subnets[i], ip_addr)) {
250 0 : properties->ip_prefix_len_inside = prefix_len;
251 0 : if (service_type == ServiceInstance::SourceNAT)
252 0 : properties->gw_ip = subnets[i].default_gateway;
253 : }
254 0 : } else if (vmi_props.service_interface_type == "right") {
255 0 : std::string &ip_addr = properties->ip_addr_outside;
256 0 : if (SubNetContainsIpv4(subnets[i], ip_addr)) {
257 0 : properties->ip_prefix_len_outside = prefix_len;
258 0 : if (service_type == ServiceInstance::LoadBalancer)
259 0 : properties->gw_ip = subnets[i].default_gateway;
260 : }
261 0 : } else if (vmi_props.service_interface_type == "management") {
262 0 : std::string &ip_addr = properties->ip_addr_management;
263 0 : if (SubNetContainsIpv4(subnets[i], ip_addr))
264 0 : properties->ip_prefix_len_management = prefix_len;
265 : }
266 : }
267 0 : }
268 : }
269 0 : }
270 :
271 : /*
272 : * Walks through the graph in order to get the template associated to the
273 : * Service Instance Node and set the types in the ServiceInstanceData object.
274 : */
275 0 : static void FindAndSetTypes(DBGraph *graph, IFMapNode *si_node,
276 : ServiceInstance::Properties *properties) {
277 0 : IFMapNode *st_node = NULL;
278 :
279 0 : for (DBGraphVertex::adjacency_iterator iter = si_node->begin(graph);
280 0 : iter != si_node->end(graph); ++iter) {
281 0 : IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
282 0 : if (IsNodeType(adj, "service-template")) {
283 0 : st_node = adj;
284 0 : break;
285 : }
286 : }
287 :
288 0 : if (st_node == NULL) {
289 0 : return;
290 : }
291 :
292 : autogen::ServiceTemplate *svc_template =
293 0 : static_cast<autogen::ServiceTemplate *>(st_node->GetObject());
294 : autogen::ServiceTemplateType svc_template_props =
295 0 : svc_template->properties();
296 :
297 0 : properties->service_type =
298 0 : ServiceInstanceTypesMapping::StrServiceTypeToInt(
299 : svc_template_props.service_type);
300 :
301 0 : properties->virtualization_type =
302 0 : ServiceInstanceTypesMapping::StrVirtualizationTypeToInt(
303 : svc_template_props.service_virtualization_type);
304 :
305 0 : properties->vrouter_instance_type =
306 0 : ServiceInstanceTypesMapping::StrVRouterInstanceTypeToInt(
307 : svc_template_props.vrouter_instance_type);
308 :
309 0 : properties->image_name = svc_template_props.image_name;
310 0 : properties->instance_data = svc_template_props.instance_data;
311 0 : }
312 :
313 0 : static void FindAndSetLoadbalancer(ServiceInstance::Properties *properties) {
314 0 : const std::vector<autogen::KeyValuePair> &kvps = properties->instance_kvps;
315 0 : std::vector<autogen::KeyValuePair>::const_iterator iter;
316 0 : for (iter = kvps.begin(); iter != kvps.end(); ++iter) {
317 0 : autogen::KeyValuePair kvp = *iter;
318 0 : if (kvp.key == "lb_uuid") {
319 0 : properties->loadbalancer_id = kvp.value;
320 0 : break;
321 : }
322 0 : }
323 0 : }
324 :
325 : /*
326 : * ServiceInstance Properties
327 : */
328 0 : void ServiceInstance::Properties::Clear() {
329 0 : service_type = 0;
330 0 : virtualization_type = 0;
331 0 : vrouter_instance_type = 0;
332 :
333 0 : instance_id = boost::uuids::nil_uuid();
334 :
335 0 : vmi_inside = boost::uuids::nil_uuid();
336 0 : vmi_outside = boost::uuids::nil_uuid();
337 0 : vmi_management = boost::uuids::nil_uuid();
338 :
339 0 : mac_addr_inside.clear();
340 0 : mac_addr_outside.clear();
341 0 : mac_addr_management.clear();
342 :
343 0 : ip_addr_inside.clear();
344 0 : ip_addr_outside.clear();
345 0 : ip_addr_management.clear();
346 :
347 0 : gw_ip.clear();
348 0 : image_name.clear();
349 :
350 0 : ip_prefix_len_inside = -1;
351 0 : ip_prefix_len_outside = -1;
352 0 : ip_prefix_len_management = -1;
353 :
354 0 : interface_count = 0;
355 :
356 0 : instance_data.clear();
357 0 : std::vector<autogen::KeyValuePair>::const_iterator iter;
358 0 : for (iter = instance_kvps.begin(); iter != instance_kvps.end(); ++iter) {
359 0 : autogen::KeyValuePair kvp = *iter;
360 0 : kvp.Clear();
361 0 : }
362 :
363 0 : loadbalancer_id.clear();
364 0 : }
365 :
366 0 : static int compare_kvps(const std::vector<autogen::KeyValuePair> &lhs,
367 : const std::vector<autogen::KeyValuePair> &rhs) {
368 0 : int ret = 0;
369 : int match;
370 : int remining_rhs_items;
371 0 : std::vector<autogen::KeyValuePair>::const_iterator iter1;
372 0 : std::vector<autogen::KeyValuePair>::const_iterator iter2;
373 :
374 0 : iter1 = lhs.begin();
375 0 : iter2 = rhs.begin();
376 0 : match = 0;
377 0 : remining_rhs_items = rhs.end() - rhs.begin();
378 0 : while (iter1 != lhs.end()) {
379 0 : while (iter2 != rhs.end()) {
380 0 : if (iter1->key.compare(iter2->key) == 0) {
381 0 : if ((ret = iter1->value.compare(iter2->value)) != 0) {
382 0 : return ret;
383 : }
384 0 : remining_rhs_items--;
385 0 : match = 1;
386 0 : break;
387 : }
388 0 : iter2++;
389 : }
390 0 : if (match == 0) {
391 0 : return 1;
392 : }
393 0 : match = 0;
394 0 : iter2 = rhs.begin();
395 0 : iter1++;
396 : }
397 :
398 0 : if (remining_rhs_items)
399 0 : return -1;
400 :
401 0 : return 0;
402 : }
403 :
404 : template <typename Type>
405 0 : static int compare(const Type &lhs, const Type &rhs) {
406 0 : if (lhs < rhs) {
407 0 : return -1;
408 : }
409 0 : if (rhs < lhs) {
410 0 : return 1;
411 : }
412 0 : return 0;
413 : }
414 :
415 0 : int ServiceInstance::Properties::CompareTo(const Properties &rhs) const {
416 0 : int cmp = 0;
417 0 : cmp = compare(service_type, rhs.service_type);
418 0 : if (cmp != 0) {
419 0 : return cmp;
420 : }
421 0 : cmp = compare(vrouter_instance_type, rhs.vrouter_instance_type);
422 0 : if (cmp != 0) {
423 0 : return cmp;
424 : }
425 0 : cmp = compare(virtualization_type, rhs.virtualization_type);
426 0 : if (cmp != 0) {
427 0 : return cmp;
428 : }
429 0 : cmp = compare(instance_id, rhs.instance_id);
430 0 : if (cmp != 0) {
431 0 : return cmp;
432 : }
433 0 : cmp = compare(vmi_inside, rhs.vmi_inside);
434 0 : if (cmp != 0) {
435 0 : return cmp;
436 : }
437 0 : cmp = compare(vmi_outside, rhs.vmi_outside);
438 0 : if (cmp != 0) {
439 0 : return cmp;
440 : }
441 0 : cmp = compare(ip_addr_inside, rhs.ip_addr_inside);
442 0 : if (cmp != 0) {
443 0 : return cmp;
444 : }
445 0 : cmp = compare(ip_addr_outside, rhs.ip_addr_outside);
446 0 : if (cmp != 0) {
447 0 : return cmp;
448 : }
449 0 : cmp = compare(ip_prefix_len_inside, rhs.ip_prefix_len_inside);
450 0 : if (cmp != 0) {
451 0 : return cmp;
452 : }
453 0 : cmp = compare(ip_prefix_len_outside, rhs.ip_prefix_len_outside);
454 0 : if (cmp != 0) {
455 0 : return cmp;
456 : }
457 0 : cmp = compare(interface_count, rhs.interface_count);
458 0 : if (cmp != 0) {
459 0 : return cmp;
460 : }
461 :
462 0 : cmp = compare(gw_ip, rhs.gw_ip);
463 0 : if (cmp != 0) {
464 0 : return cmp;
465 : }
466 0 : cmp = compare(image_name, rhs.image_name);
467 0 : if (cmp != 0) {
468 0 : return cmp;
469 : }
470 :
471 0 : cmp = compare(instance_data, rhs.instance_data);
472 0 : if (cmp != 0) {
473 0 : return cmp;
474 : }
475 :
476 0 : cmp = compare_kvps(instance_kvps, rhs.instance_kvps);
477 0 : if (cmp != 0) {
478 0 : return cmp;
479 : }
480 :
481 0 : cmp = compare(loadbalancer_id, rhs.loadbalancer_id);
482 0 : if (cmp != 0) {
483 0 : return cmp;
484 : }
485 0 : return cmp;
486 : }
487 :
488 0 : void InstanceKvpsDiffString(const std::vector<autogen::KeyValuePair> &lhs,
489 : const std::vector<autogen::KeyValuePair> &rhs,
490 : std::stringstream *ss) {
491 0 : int ret = 0;
492 : int match;
493 : int remining_rhs_items;
494 0 : std::vector<autogen::KeyValuePair>::const_iterator iter1;
495 0 : std::vector<autogen::KeyValuePair>::const_iterator iter2;
496 :
497 0 : iter1 = lhs.begin();
498 0 : iter2 = rhs.begin();
499 0 : match = 0;
500 0 : remining_rhs_items = rhs.size();
501 0 : while (iter1 != lhs.end()) {
502 0 : while (iter2 != rhs.end()) {
503 0 : if (iter1->key.compare(iter2->key) == 0) {
504 0 : remining_rhs_items--;
505 0 : match = 1;
506 0 : if ((ret = iter1->value.compare(iter2->value)) != 0) {
507 0 : *ss << iter1->key << ": -" << iter1->value;
508 0 : *ss << " +" << iter2->value;
509 0 : break;
510 : }
511 : }
512 0 : iter2++;
513 : }
514 0 : if (match == 0) {
515 0 : *ss << " -" << iter1->key << ": " << iter1->value;
516 : }
517 0 : match = 0;
518 0 : iter2 = rhs.begin();
519 0 : iter1++;
520 : }
521 :
522 0 : if (remining_rhs_items == 0)
523 0 : return;
524 :
525 0 : iter1 = rhs.begin();
526 0 : iter2 = lhs.begin();
527 0 : match = 0;
528 0 : while (iter1 != rhs.end()) {
529 0 : while (iter2 != lhs.end()) {
530 0 : if (iter1->key.compare(iter2->key) == 0) {
531 0 : match = 1;
532 0 : break;
533 : }
534 0 : iter2++;
535 : }
536 0 : if (match == 0) {
537 0 : *ss << " +" << iter1->key << ": " << iter1->value;
538 : }
539 0 : match = 0;
540 0 : iter2 = lhs.begin();
541 0 : iter1++;
542 : }
543 : }
544 :
545 0 : std::string ServiceInstance::Properties::DiffString(
546 : const Properties &rhs) const {
547 0 : std::stringstream ss;
548 :
549 0 : if (compare(service_type, rhs.service_type)) {
550 0 : ss << " type: -" << service_type << " +" << rhs.service_type;
551 : }
552 0 : if (compare(virtualization_type, rhs.virtualization_type)) {
553 0 : ss << " virtualization: -" << virtualization_type
554 0 : << " +" << rhs.virtualization_type;
555 : }
556 0 : if (compare(vrouter_instance_type, rhs.vrouter_instance_type)) {
557 0 : ss << " vrouter-instance-type: -" << vrouter_instance_type
558 0 : << " +" << rhs.vrouter_instance_type;
559 : }
560 0 : if (compare(instance_id, rhs.instance_id)) {
561 0 : ss << " id: -" << instance_id << " +" << rhs.instance_id;
562 : }
563 0 : if (compare(vmi_inside, rhs.vmi_inside)) {
564 0 : ss << " vmi-inside: -" << vmi_inside << " +" << rhs.vmi_inside;
565 : }
566 0 : if (compare(vmi_outside, rhs.vmi_outside)) {
567 0 : ss << " vmi-outside: -" << vmi_outside << " +" << rhs.vmi_outside;
568 : }
569 0 : if (compare(ip_addr_inside, rhs.ip_addr_inside)) {
570 0 : ss << " ip-inside: -" << ip_addr_inside
571 0 : << " +" << rhs.ip_addr_inside;
572 : }
573 0 : if (compare(ip_addr_outside, rhs.ip_addr_outside)) {
574 0 : ss << " ip-outside: -" << ip_addr_outside
575 0 : << " +" << rhs.ip_addr_outside;
576 : }
577 0 : if (compare(ip_prefix_len_inside, rhs.ip_prefix_len_inside)) {
578 0 : ss << " pfx-inside: -" << ip_prefix_len_inside
579 0 : << " +" << rhs.ip_prefix_len_inside;
580 : }
581 0 : if (compare(ip_prefix_len_outside, rhs.ip_prefix_len_outside)) {
582 0 : ss << " pfx-outside: -" << ip_prefix_len_outside
583 0 : << " +" << rhs.ip_prefix_len_outside;
584 : }
585 :
586 0 : if (compare(loadbalancer_id, rhs.loadbalancer_id)) {
587 0 : ss << " loadbalancer_id: -" << loadbalancer_id << " +"
588 0 : << rhs.loadbalancer_id;
589 : }
590 :
591 0 : if (compare(gw_ip, rhs.gw_ip)) {
592 0 : ss << " gw_ip: -" << gw_ip << " +" << rhs.gw_ip;
593 : }
594 0 : if (compare(image_name, rhs.image_name)) {
595 0 : ss << " image: -" << image_name << " +" << rhs.image_name;
596 : }
597 0 : if (compare(instance_data, rhs.instance_data)) {
598 0 : ss << " image: -" << instance_data << " +" << rhs.instance_data;
599 : }
600 0 : if (compare_kvps(instance_kvps, rhs.instance_kvps)) {
601 0 : InstanceKvpsDiffString(instance_kvps, rhs.instance_kvps, &ss);
602 : }
603 0 : return ss.str();
604 0 : }
605 :
606 0 : bool ServiceInstance::Properties::Usable() const {
607 0 : if (instance_id.is_nil()) {
608 0 : return false;
609 : }
610 :
611 0 : if (virtualization_type == ServiceInstance::VRouterInstance) {
612 : //TODO: investigate for docker
613 0 : return true;
614 : }
615 :
616 0 : bool common = (!vmi_outside.is_nil() &&
617 0 : !ip_addr_outside.empty() &&
618 0 : (ip_prefix_len_outside >= 0));
619 0 : if (!common) {
620 0 : return false;
621 : }
622 :
623 0 : if (service_type == SourceNAT || interface_count == 2) {
624 0 : bool outside = (!vmi_inside.is_nil() &&
625 0 : !ip_addr_inside.empty() &&
626 0 : (ip_prefix_len_inside >= 0));
627 0 : if (!outside) {
628 0 : return false;
629 : }
630 : }
631 :
632 0 : if (gw_ip.empty())
633 0 : return false;
634 :
635 0 : if (service_type == LoadBalancer) {
636 0 : if (loadbalancer_id.empty())
637 0 : return false;
638 : }
639 :
640 0 : return true;
641 : }
642 :
643 0 : const std::string &ServiceInstance::Properties::ServiceTypeString() const {
644 0 : return ServiceInstanceTypesMapping::IntServiceTypeToStr(
645 0 : static_cast<ServiceType>(service_type));
646 : }
647 :
648 : /*
649 : * ServiceInstance class
650 : */
651 0 : ServiceInstance::ServiceInstance() {
652 0 : properties_.Clear();
653 0 : }
654 :
655 0 : bool ServiceInstance::IsLess(const DBEntry &rhs) const {
656 0 : const ServiceInstance &si = static_cast<const ServiceInstance &>(rhs);
657 0 : return uuid_ < si.uuid_;
658 : }
659 :
660 0 : std::string ServiceInstance::ToString() const {
661 0 : return UuidToString(uuid_);
662 : }
663 :
664 0 : void ServiceInstance::SetKey(const DBRequestKey *key) {
665 0 : const ServiceInstanceKey *si_key =
666 : static_cast<const ServiceInstanceKey *>(key);
667 0 : uuid_ = si_key->instance_id();
668 0 : }
669 :
670 0 : DBEntryBase::KeyPtr ServiceInstance::GetDBRequestKey() const {
671 0 : ServiceInstanceKey *key = new ServiceInstanceKey(uuid_);
672 0 : return KeyPtr(key);
673 : }
674 :
675 0 : bool ServiceInstance::DBEntrySandesh(Sandesh *sresp, std::string &name) const {
676 0 : ServiceInstanceResp *resp = static_cast<ServiceInstanceResp *> (sresp);
677 :
678 0 : std::string str_uuid = UuidToString(uuid_);
679 0 : if (! name.empty() && str_uuid != name) {
680 0 : return false;
681 : }
682 :
683 0 : ServiceInstanceSandeshData data;
684 :
685 0 : data.set_uuid(str_uuid);
686 0 : data.set_instance_id(UuidToString(properties_.instance_id));
687 :
688 0 : data.set_service_type(ServiceInstanceTypesMapping::IntServiceTypeToStr(
689 0 : static_cast<ServiceType>(properties_.service_type)));
690 0 : data.set_virtualization_type(
691 : ServiceInstanceTypesMapping::IntVirtualizationTypeToStr(
692 0 : static_cast<VirtualizationType>(
693 0 : properties_.virtualization_type)));
694 :
695 0 : data.set_vmi_inside(UuidToString(properties_.vmi_inside));
696 0 : data.set_vmi_outside(UuidToString(properties_.vmi_outside));
697 :
698 0 : Agent *agent = Agent::GetInstance();
699 0 : DBTableBase *si_table = agent->db()->FindTable("db.service-instance.0");
700 0 : assert(si_table);
701 :
702 0 : InstanceManager *manager = agent->oper_db()->instance_manager();
703 0 : assert(manager);
704 :
705 0 : InstanceState *state = manager->GetState(const_cast<ServiceInstance *>(this));
706 0 : if (state != NULL) {
707 0 : NamespaceStateSandeshData state_data;
708 :
709 0 : state_data.set_cmd(state->cmd());
710 0 : state_data.set_errors(state->errors());
711 0 : state_data.set_pid(state->pid());
712 0 : state_data.set_status(state->status());
713 0 : state_data.set_status_type(state->status_type());
714 :
715 0 : data.set_ns_state(state_data);
716 0 : }
717 :
718 : std::vector<ServiceInstanceSandeshData> &list =
719 : const_cast<std::vector<ServiceInstanceSandeshData>&>
720 0 : (resp->get_service_instance_list());
721 0 : list.push_back(data);
722 :
723 0 : return true;
724 0 : }
725 :
726 0 : bool ServiceInstance::IsUsable() const {
727 0 : return properties_.Usable();
728 : }
729 :
730 0 : void ServiceInstanceReq::HandleRequest() const {
731 0 : AgentSandeshPtr sand(new AgentServiceInstanceSandesh(context(),
732 0 : get_uuid()));
733 0 : sand->DoSandesh(sand);
734 0 : }
735 :
736 0 : AgentSandeshPtr ServiceInstanceTable::GetAgentSandesh
737 : (const AgentSandeshArguments *args, const std::string &context){
738 : return AgentSandeshPtr
739 0 : (new AgentServiceInstanceSandesh(context, args->GetString("name")));
740 : }
741 :
742 : /*
743 : * ServiceInstanceTable class
744 : */
745 1 : ServiceInstanceTable::ServiceInstanceTable(DB *db, const std::string &name)
746 : : AgentDBTable(db, name),
747 1 : graph_(NULL), dependency_manager_(NULL) {
748 1 : }
749 :
750 0 : std::unique_ptr<DBEntry> ServiceInstanceTable::AllocEntry(
751 : const DBRequestKey *key) const {
752 0 : std::unique_ptr<DBEntry> entry(new ServiceInstance());
753 0 : entry->SetKey(key);
754 0 : return entry;
755 0 : }
756 :
757 0 : bool ServiceInstanceTable::HandleAddChange(ServiceInstance
758 : **svc_instancep, const DBRequest *request) {
759 :
760 : ServiceInstanceCreate *data =
761 0 : static_cast<ServiceInstanceCreate *>(request->data.get());
762 0 : if (!data)
763 0 : return false;
764 :
765 0 : IFMapNode *node = data->node();
766 0 : ServiceInstance *svc_instance = *svc_instancep;
767 :
768 0 : assert(graph_);
769 0 : ServiceInstance::Properties properties;
770 0 : properties.Clear();
771 0 : CalculateProperties(graph_, node, &properties);
772 :
773 0 : assert(dependency_manager_);
774 :
775 0 : if (!svc_instance) {
776 0 : svc_instance = new ServiceInstance();
777 0 : *svc_instancep = svc_instance;
778 : }
779 :
780 0 : if (!svc_instance->ifmap_node()) {
781 0 : svc_instance->SetKey(request->key.get());
782 : svc_instance->SetIFMapNodeState
783 0 : (dependency_manager_->SetState(node));
784 0 : dependency_manager_->SetObject(node, svc_instance);
785 : }
786 :
787 0 : if (properties.CompareTo(svc_instance->properties()) == 0)
788 0 : return false;
789 :
790 0 : if (svc_instance->properties().Usable() != properties.Usable()) {
791 0 : LOG(DEBUG, "service-instance properties change" <<
792 : svc_instance->properties().DiffString(properties));
793 : }
794 :
795 0 : svc_instance->set_properties(properties);
796 0 : return true;
797 0 : }
798 :
799 :
800 0 : DBEntry *ServiceInstanceTable::Add(const DBRequest *request) {
801 0 : ServiceInstance *svc_instance = NULL;
802 0 : HandleAddChange(&svc_instance, request);
803 0 : return svc_instance;
804 : }
805 :
806 0 : bool ServiceInstanceTable::Delete(DBEntry *entry, const DBRequest *request) {
807 0 : ServiceInstance *svc_instance = static_cast<ServiceInstance *>(entry);
808 0 : assert(dependency_manager_);
809 0 : if (svc_instance->ifmap_node()) {
810 0 : dependency_manager_->SetObject(svc_instance->ifmap_node(), NULL);
811 0 : svc_instance->SetIFMapNodeState(NULL);
812 : }
813 0 : return true;
814 : }
815 :
816 0 : bool ServiceInstanceTable::OnChange(DBEntry *entry, const DBRequest *request) {
817 0 : ServiceInstance *svc_instance = static_cast<ServiceInstance *>(entry);
818 :
819 0 : return HandleAddChange(&svc_instance, request);
820 : }
821 :
822 1 : void ServiceInstanceTable::Initialize(
823 : DBGraph *graph, IFMapDependencyManager *dependency_manager) {
824 :
825 1 : graph_ = graph;
826 1 : dependency_manager_ = dependency_manager;
827 :
828 1 : dependency_manager_->Register(
829 : "service-instance",
830 : boost::bind(&ServiceInstanceTable::ChangeEventHandler, this, _1, _2));
831 1 : }
832 :
833 0 : bool ServiceInstanceTable::IFNodeToReq(IFMapNode *node, DBRequest
834 : &request, const boost::uuids::uuid &id) {
835 :
836 0 : assert(!id.is_nil());
837 :
838 0 : request.key.reset(new ServiceInstanceKey(id));
839 0 : if ((request.oper == DBRequest::DB_ENTRY_DELETE) || node->IsDeleted()) {
840 0 : request.oper = DBRequest::DB_ENTRY_DELETE;
841 0 : return true;
842 : }
843 :
844 0 : request.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
845 0 : request.data.reset(new ServiceInstanceCreate(node));
846 0 : return true;
847 : }
848 :
849 0 : void ServiceInstanceTable::CalculateProperties(
850 : DBGraph *graph, IFMapNode *node, ServiceInstance::Properties *properties) {
851 :
852 0 : properties->Clear();
853 :
854 0 : if (node->IsDeleted()) {
855 0 : return;
856 : }
857 :
858 0 : FindAndSetTypes(graph, node, properties);
859 :
860 : /*
861 : * The vrouter agent is only interest in the properties of service
862 : * instances that are implemented as a network-namespace.
863 : */
864 0 : if ((properties->virtualization_type != ServiceInstance::NetworkNamespace) &&
865 0 : (properties->virtualization_type != ServiceInstance::VRouterInstance)) {
866 0 : return;
867 : }
868 :
869 0 : IFMapNode *vm_node = FindAndSetVirtualMachine(graph, node, properties);
870 0 : if (vm_node == NULL) {
871 0 : return;
872 : }
873 :
874 : autogen::ServiceInstance *svc_instance =
875 0 : static_cast<autogen::ServiceInstance *>(node->GetObject());
876 0 : properties->instance_kvps = svc_instance->bindings();
877 0 : FindAndSetInterfaces(graph, vm_node, svc_instance, properties);
878 :
879 0 : if (properties->service_type == ServiceInstance::LoadBalancer) {
880 0 : FindAndSetLoadbalancer(properties);
881 : }
882 : }
883 :
884 0 : bool ServiceInstanceTable::IFNodeToUuid(IFMapNode *node, uuid &idperms_uuid) {
885 : autogen::ServiceInstance *svc_instance =
886 0 : static_cast<autogen::ServiceInstance *>(node->GetObject());
887 0 : const autogen::IdPermsType &id = svc_instance->id_perms();
888 0 : idperms_uuid = IdPermsGetUuid(id);
889 0 : return true;
890 : }
891 0 : void ServiceInstanceTable::ChangeEventHandler(IFMapNode *node, DBEntry *entry) {
892 :
893 0 : DBRequest req;
894 : boost::uuids::uuid new_uuid;
895 0 : IFNodeToUuid(node, new_uuid);
896 0 : IFMapNodeState *state = dependency_manager_->IFMapNodeGet(node);
897 0 : boost::uuids::uuid old_uuid = state->uuid();
898 :
899 0 : if (!node->IsDeleted()) {
900 0 : if (entry) {
901 0 : if ((old_uuid != new_uuid)) {
902 0 : if (old_uuid != boost::uuids::nil_uuid()) {
903 0 : req.oper = DBRequest::DB_ENTRY_DELETE;
904 0 : if (IFNodeToReq(node, req, old_uuid) == true) {
905 0 : assert(req.oper == DBRequest::DB_ENTRY_DELETE);
906 0 : Enqueue(&req);
907 : }
908 : }
909 : }
910 : }
911 0 : assert(new_uuid != boost::uuids::nil_uuid());
912 0 : state->set_uuid(new_uuid);
913 0 : req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
914 : } else {
915 0 : if (old_uuid == boost::uuids::nil_uuid()) {
916 : //Node was never added so no point sending delete
917 0 : return;
918 : }
919 0 : req.oper = DBRequest::DB_ENTRY_DELETE;
920 0 : new_uuid = old_uuid;
921 : }
922 :
923 0 : if (IFNodeToReq(node, req, new_uuid) == true) {
924 0 : Enqueue(&req);
925 : }
926 0 : }
927 :
928 1 : DBTableBase *ServiceInstanceTable::CreateTable(
929 : DB *db, const std::string &name) {
930 1 : ServiceInstanceTable *table = new ServiceInstanceTable(db, name);
931 1 : table->Init();
932 1 : return table;
933 : }
934 :
935 : /*
936 : * ServiceInstanceTypeMapping class
937 : */
938 : ServiceInstanceTypesMapping::StrTypeToIntMap
939 : ServiceInstanceTypesMapping::service_type_map_ = InitServiceTypeMap();
940 : ServiceInstanceTypesMapping::StrTypeToIntMap
941 : ServiceInstanceTypesMapping::virtualization_type_map_ = InitVirtualizationTypeMap();
942 : ServiceInstanceTypesMapping::StrTypeToIntMap
943 : ServiceInstanceTypesMapping::vrouter_instance_type_map_ = InitVRouterInstanceTypeMap();
944 : const std::string ServiceInstanceTypesMapping::kOtherType = "Other";
945 :
946 0 : int ServiceInstanceTypesMapping::StrServiceTypeToInt(const std::string &type) {
947 0 : StrTypeToIntMap::const_iterator it = service_type_map_.find(type);
948 0 : if (it != service_type_map_.end()) {
949 0 : return it->second;
950 : }
951 0 : return 0;
952 : }
953 :
954 0 : int ServiceInstanceTypesMapping::StrVirtualizationTypeToInt(
955 : const std::string &type) {
956 0 : StrTypeToIntMap::const_iterator it = virtualization_type_map_.find(type);
957 0 : if (it != virtualization_type_map_.end()) {
958 0 : return it->second;
959 : }
960 0 : return 0;
961 : }
962 :
963 0 : int ServiceInstanceTypesMapping::StrVRouterInstanceTypeToInt(
964 : const std::string &type) {
965 0 : StrTypeToIntMap::const_iterator it = vrouter_instance_type_map_.find(type);
966 0 : if (it != vrouter_instance_type_map_.end()) {
967 0 : return it->second;
968 : }
969 0 : return 0;
970 : }
971 :
972 0 : const std::string &ServiceInstanceTypesMapping::IntServiceTypeToStr(
973 : const ServiceInstance::ServiceType &type) {
974 0 : for (StrTypeToIntMap::const_iterator it = service_type_map_.begin();
975 0 : it != service_type_map_.end(); ++it) {
976 0 : if (it->second == type) {
977 0 : return it->first;
978 : }
979 : }
980 0 : return kOtherType;
981 : }
982 :
983 0 : const std::string &ServiceInstanceTypesMapping::IntVirtualizationTypeToStr(
984 : const ServiceInstance::VirtualizationType &type) {
985 0 : for (StrTypeToIntMap::const_iterator it = virtualization_type_map_.begin();
986 0 : it != virtualization_type_map_.end(); ++it) {
987 0 : if (it->second == type) {
988 0 : return it->first;
989 : }
990 : }
991 0 : return kOtherType;
992 : }
993 :
994 0 : const std::string &ServiceInstanceTypesMapping::IntVRouterInstanceTypeToStr(
995 : const ServiceInstance::VRouterInstanceType &type) {
996 0 : for (StrTypeToIntMap::const_iterator it = vrouter_instance_type_map_.begin();
997 0 : it != virtualization_type_map_.end(); ++it) {
998 0 : if (it->second == type) {
999 0 : return it->first;
1000 : }
1001 : }
1002 0 : return kOtherType;
1003 : }
|