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