1 #include <nm_core.h>
2 #include <nm_utils.h>
3 #include <nm_string.h>
4 #include <nm_vector.h>
5 #include <nm_network.h>
6 #include <nm_svg_map.h>
7 #include <nm_database.h>
8 #include <nm_lan_settings.h>
9 
10 #if defined (NM_WITH_NETWORK_MAP)
11 #include <gvc.h>
12 
13 static char NM_EMPTY_STR[] = "";
14 static char NM_GV_LABEL[]  = "label";
15 static char NM_GV_STYLE[]  = "style";
16 static char NM_GV_SHAPE[]  = "shape";
17 static char NM_GV_FILL[]   = "filled";
18 static char NM_GV_FCOL[]   = "fillcolor";
19 static char NM_GV_RECT[]   = "rect";
20 static char NM_GV_SVG[]    = "svg";
21 static char NM_VM_COLOR[]  = "#4fbcdd";
22 static char NM_VE_COLOR[]  = "#59e088";
23 
24 typedef Agraph_t nm_gvgraph_t;
25 typedef Agnode_t nm_gvnode_t;
26 typedef Agedge_t nm_gvedge_t;
27 typedef GVC_t    nm_gvctx_t;
28 
nm_svg_map(const char * path,const nm_vect_t * veths,int state,const nm_str_t * layout,const nm_str_t * group)29 void nm_svg_map(const char *path, const nm_vect_t *veths,
30         int state, const nm_str_t *layout, const nm_str_t *group)
31 {
32     nm_gvctx_t *gvc;
33     nm_gvgraph_t *graph;
34 
35     if ((gvc = gvContext()) == NULL)
36         nm_bug(_("%s: cannot create graphviz ctx"), __func__);
37 
38     graph = agopen("network_map", Agundirected, NULL);
39     agattr(graph, AGRAPH, "overlap", "scalexy");
40     agattr(graph, AGRAPH, "splines", "true");
41     agattr(graph, AGRAPH, "sep", "+25,25");
42 
43     //@TODO Some of variables may be moved outside, and freed only once
44     for (size_t v = 0; v < veths->n_memb; v++) {
45         nm_vect_t vms = NM_INIT_VECT;
46         nm_str_t lname = NM_INIT_STR;
47         nm_str_t rname = NM_INIT_STR;
48         nm_str_t query = NM_INIT_STR;
49         nm_gvnode_t *vnode;
50         size_t vms_count;
51 
52         nm_lan_parse_name(nm_vect_str(veths, v), &lname, &rname);
53 
54         if (!group->len) {
55             switch (state) {
56                 case NM_SVG_STATE_UP:
57                     if (nm_net_link_status(&lname) != NM_OK)
58                         goto next;
59                     break;
60                 case NM_SVG_STATE_DOWN:
61                     if (nm_net_link_status(&lname) == NM_OK)
62                         goto next;
63                     break;
64                 default:
65                     break;
66             }
67         }
68 
69         if (group->len) {
70             nm_str_format(&query, NM_GET_IFMAPGR_SQL, group->data, lname.data, rname.data);
71         } else {
72             nm_str_format(&query, NM_GET_IFMAP_SQL, lname.data, rname.data);
73         }
74         nm_db_select(query.data, &vms);
75 
76         if (group->len && !vms.n_memb) {
77             goto next;
78         }
79 
80         vnode = agnode(graph, nm_vect_str_ctx(veths, v), NM_TRUE);
81         agsafeset(vnode, NM_GV_STYLE, NM_GV_FILL, NM_EMPTY_STR);
82         agsafeset(vnode, NM_GV_FCOL, NM_VE_COLOR, NM_EMPTY_STR);
83         agsafeset(vnode, NM_GV_SHAPE, NM_GV_RECT, NM_EMPTY_STR);
84 
85         vms_count = vms.n_memb / 2;
86         for (size_t n = 0; n < vms_count; n++) {
87             size_t idx_shift = 2 * n;
88             nm_gvnode_t *node = agnode(graph, nm_vect_str_ctx(&vms, idx_shift), NM_TRUE);
89             nm_gvedge_t *edge = agedge(graph, node, vnode, NULL, NM_TRUE);
90 
91             agsafeset(edge, NM_GV_LABEL, nm_vect_str_ctx(&vms, idx_shift + 1), NM_EMPTY_STR);
92             agsafeset(node, NM_GV_STYLE, NM_GV_FILL, NM_EMPTY_STR);
93             agsafeset(node, NM_GV_FCOL, NM_VM_COLOR, NM_EMPTY_STR);
94         }
95 
96         nm_vect_free(&vms, nm_str_vect_free_cb);
97         nm_str_free(&query);
98 next:
99         nm_str_free(&lname);
100         nm_str_free(&rname);
101     }
102 
103     gvLayout(gvc, graph, layout->data);
104     gvRenderFilename(gvc, graph, NM_GV_SVG, path);
105 
106     gvFreeLayout(gvc, graph);
107     agclose(graph);
108     gvFreeContext(gvc);
109 }
110 #endif /* NM_WITH_NETWORK_MAP */
111 /* vim:set ts=4 sw=4: */
112