6fb2d28ac8554972ccb7d91affd0c8e5ace43f15
[multipath-tools/.git] / libmultipath / pgpolicies.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdbool.h>
8
9 #include "checkers.h"
10 #include "util.h"
11 #include "memory.h"
12 #include "vector.h"
13 #include "structs.h"
14 #include "pgpolicies.h"
15 #include "switchgroup.h"
16
17 int get_pgpolicy_id(char * str)
18 {
19         if (0 == strncmp(str, "failover", 8))
20                 return FAILOVER;
21         if (0 == strncmp(str, "multibus", 8))
22                 return MULTIBUS;
23         if (0 == strncmp(str, "group_by_serial", 15))
24                 return GROUP_BY_SERIAL;
25         if (0 == strncmp(str, "group_by_prio", 13))
26                 return GROUP_BY_PRIO;
27         if (0 == strncmp(str, "group_by_node_name", 18))
28                 return GROUP_BY_NODE_NAME;
29
30         return IOPOLICY_UNDEF;
31 }
32
33 int get_pgpolicy_name(char * buff, int len, int id)
34 {
35         char * s;
36
37         switch (id) {
38         case FAILOVER:
39                 s = "failover";
40                 break;
41         case MULTIBUS:
42                 s = "multibus";
43                 break;
44         case GROUP_BY_SERIAL:
45                 s = "group_by_serial";
46                 break;
47         case GROUP_BY_PRIO:
48                 s = "group_by_prio";
49                 break;
50         case GROUP_BY_NODE_NAME:
51                 s = "group_by_node_name";
52                 break;
53         default:
54                 s = "undefined";
55                 break;
56         }
57         return snprintf(buff, POLICY_NAME_SIZE, "%s", s);
58 }
59
60
61 void
62 sort_pathgroups (struct multipath *mp) {
63         int i, j;
64         struct pathgroup * pgp1, * pgp2;
65
66         if (!mp->pg)
67                 return;
68
69         vector_foreach_slot(mp->pg, pgp1, i) {
70                 path_group_prio_update(pgp1);
71                 for (j = i - 1; j >= 0; j--) {
72                         pgp2 = VECTOR_SLOT(mp->pg, j);
73                         if (!pgp2)
74                                 continue;
75                         if (pgp2->marginal < pgp1->marginal ||
76                             (pgp2->marginal == pgp1->marginal &&
77                              (pgp2->priority > pgp1->priority ||
78                               (pgp2->priority == pgp1->priority &&
79                                pgp2->enabled_paths >= pgp1->enabled_paths)))) {
80                                 vector_move_up(mp->pg, i, j + 1);
81                                 break;
82                         }
83                 }
84                 if (j < 0 && i != 0)
85                 vector_move_up(mp->pg, i, 0);
86         }
87 }
88
89 static int
90 split_marginal_paths(vector paths, vector *normal_p, vector *marginal_p)
91 {
92         int i;
93         int has_marginal = 0;
94         int has_normal = 0;
95         struct path *pp;
96         vector normal = NULL;
97         vector marginal = NULL;
98
99         *normal_p = *marginal_p = NULL;
100         vector_foreach_slot(paths, pp, i) {
101                 if (pp->marginal)
102                         has_marginal = 1;
103                 else
104                         has_normal = 1;
105         }
106
107         if (!has_marginal || !has_normal)
108                 return -1;
109
110         normal = vector_alloc();
111         marginal = vector_alloc();
112         if (!normal || !marginal)
113                 goto fail;
114
115         vector_foreach_slot(paths, pp, i) {
116                 if (pp->marginal) {
117                         if (store_path(marginal, pp))
118                                 goto fail;
119                 }
120                 else {
121                         if (store_path(normal, pp))
122                                 goto fail;
123                 }
124         }
125         *normal_p = normal;
126         *marginal_p = marginal;
127         return 0;
128 fail:
129         vector_free(normal);
130         vector_free(marginal);
131         return -1;
132 }
133
134 int group_paths(struct multipath *mp)
135 {
136         vector normal, marginal;
137
138         if (!mp->pg)
139                 mp->pg = vector_alloc();
140         if (!mp->pg)
141                 return 1;
142
143         if (VECTOR_SIZE(mp->paths) == 0)
144                 goto out;
145         if (!mp->pgpolicyfn)
146                 goto fail;
147
148         if (split_marginal_paths(mp->paths, &normal, &marginal) != 0) {
149                 if (mp->pgpolicyfn(mp, mp->paths) != 0)
150                         goto fail;
151         } else {
152                 if (mp->pgpolicyfn(mp, normal) != 0)
153                         goto fail_marginal;
154                 if (mp->pgpolicyfn(mp, marginal) != 0)
155                         goto fail_marginal;
156                 vector_free(normal);
157                 vector_free(marginal);
158         }
159         sort_pathgroups(mp);
160 out:
161         vector_free(mp->paths);
162         mp->paths = NULL;
163         return 0;
164 fail_marginal:
165         vector_free(normal);
166         vector_free(marginal);
167 fail:
168         vector_free(mp->pg);
169         mp->pg = NULL;
170         return 1;
171 }
172
173 typedef bool (path_match_fn)(struct path *pp1, struct path *pp2);
174
175 bool
176 node_names_match(struct path *pp1, struct path *pp2)
177 {
178         return (strncmp(pp1->tgt_node_name, pp2->tgt_node_name,
179                         NODE_NAME_SIZE) == 0);
180 }
181
182 bool
183 serials_match(struct path *pp1, struct path *pp2)
184 {
185         return (strncmp(pp1->serial, pp2->serial, SERIAL_SIZE) == 0);
186 }
187
188 bool
189 prios_match(struct path *pp1, struct path *pp2)
190 {
191         return (pp1->priority == pp2->priority);
192 }
193
194 int group_by_match(struct multipath * mp, vector paths,
195                    bool (*path_match_fn)(struct path *, struct path *))
196 {
197         int i, j;
198         int * bitmap;
199         struct path * pp;
200         struct pathgroup * pgp;
201         struct path * pp2;
202
203         /* init the bitmap */
204         bitmap = (int *)MALLOC(VECTOR_SIZE(paths) * sizeof (int));
205
206         if (!bitmap)
207                 goto out;
208
209         for (i = 0; i < VECTOR_SIZE(paths); i++) {
210
211                 if (bitmap[i])
212                         continue;
213
214                 pp = VECTOR_SLOT(paths, i);
215
216                 /* here, we really got a new pg */
217                 pgp = alloc_pathgroup();
218
219                 if (!pgp)
220                         goto out1;
221
222                 if (add_pathgroup(mp, pgp))
223                         goto out2;
224
225                 /* feed the first path */
226                 if (store_path(pgp->paths, pp))
227                         goto out1;
228
229                 bitmap[i] = 1;
230
231                 for (j = i + 1; j < VECTOR_SIZE(paths); j++) {
232
233                         if (bitmap[j])
234                                 continue;
235
236                         pp2 = VECTOR_SLOT(paths, j);
237
238                         if (path_match_fn(pp, pp2)) {
239                                 if (store_path(pgp->paths, pp2))
240                                         goto out1;
241
242                                 bitmap[j] = 1;
243                         }
244                 }
245         }
246         FREE(bitmap);
247         return 0;
248 out2:
249         free_pathgroup(pgp, KEEP_PATHS);
250 out1:
251         FREE(bitmap);
252 out:
253         free_pgvec(mp->pg, KEEP_PATHS);
254         mp->pg = NULL;
255         return 1;
256 }
257
258 /*
259  * One path group per unique tgt_node_name present in the path vector
260  */
261 int group_by_node_name(struct multipath * mp, vector paths)
262 {
263         return group_by_match(mp, paths, node_names_match);
264 }
265
266 /*
267  * One path group per unique serial number present in the path vector
268  */
269 int group_by_serial(struct multipath * mp, vector paths)
270 {
271         return group_by_match(mp, paths, serials_match);
272 }
273
274 /*
275  * One path group per priority present in the path vector
276  */
277 int group_by_prio(struct multipath *mp, vector paths)
278 {
279         return group_by_match(mp, paths, prios_match);
280 }
281
282 int one_path_per_group(struct multipath *mp, vector paths)
283 {
284         int i;
285         struct path * pp;
286         struct pathgroup * pgp;
287
288         for (i = 0; i < VECTOR_SIZE(paths); i++) {
289                 pp = VECTOR_SLOT(paths, i);
290                 pgp = alloc_pathgroup();
291
292                 if (!pgp)
293                         goto out;
294
295                 if (add_pathgroup(mp, pgp))
296                         goto out1;
297
298                 if (store_path(pgp->paths, pp))
299                         goto out;
300         }
301         return 0;
302 out1:
303         free_pathgroup(pgp, KEEP_PATHS);
304 out:
305         free_pgvec(mp->pg, KEEP_PATHS);
306         mp->pg = NULL;
307         return 1;
308 }
309
310 int one_group(struct multipath *mp, vector paths)       /* aka multibus */
311 {
312         int i;
313         struct path * pp;
314         struct pathgroup * pgp;
315
316         pgp = alloc_pathgroup();
317
318         if (!pgp)
319                 goto out;
320
321         if (add_pathgroup(mp, pgp))
322                 goto out1;
323
324         for (i = 0; i < VECTOR_SIZE(paths); i++) {
325                 pp = VECTOR_SLOT(paths, i);
326
327                 if (store_path(pgp->paths, pp))
328                         goto out;
329         }
330         return 0;
331 out1:
332         free_pathgroup(pgp, KEEP_PATHS);
333 out:
334         free_pgvec(mp->pg, KEEP_PATHS);
335         mp->pg = NULL;
336         return 1;
337 }