multipath-tools: add alias_prefix to multipath.conf.5
[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
8 #include "checkers.h"
9 #include "util.h"
10 #include "memory.h"
11 #include "vector.h"
12 #include "structs.h"
13 #include "pgpolicies.h"
14 #include "switchgroup.h"
15
16 extern int
17 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 extern int
34 get_pgpolicy_name (char * buff, int len, int id)
35 {
36         char * s;
37
38         switch (id) {
39         case FAILOVER:
40                 s = "failover";
41                 break;
42         case MULTIBUS:
43                 s = "multibus";
44                 break;
45         case GROUP_BY_SERIAL:
46                 s = "group_by_serial";
47                 break;
48         case GROUP_BY_PRIO:
49                 s = "group_by_prio";
50                 break;
51         case GROUP_BY_NODE_NAME:
52                 s = "group_by_node_name";
53                 break;
54         default:
55                 s = "undefined";
56                 break;
57         }
58         return snprintf(buff, POLICY_NAME_SIZE, "%s", s);
59 }
60
61
62 void
63 sort_pathgroups (struct multipath *mp) {
64         int i, j;
65         struct pathgroup * pgp1, * pgp2;
66
67         if (!mp->pg)
68                 return;
69
70         vector_foreach_slot(mp->pg, pgp1, i) {
71                 path_group_prio_update(pgp1);
72                 for (j = i - 1; j >= 0; j--) {
73                         pgp2 = VECTOR_SLOT(mp->pg, j);
74                         if (!pgp2)
75                                 continue;
76                         if (pgp2->priority > pgp1->priority ||
77                             (pgp2->priority == pgp1->priority &&
78                              pgp2->enabled_paths >= pgp1->enabled_paths)) {
79                                 vector_move_up(mp->pg, i, j + 1);
80                                 break;
81                         }
82                 }
83                 if (j < 0 && i != 0)
84                 vector_move_up(mp->pg, i, 0);
85         }
86 }
87
88
89 /*
90  * One path group per unique tgt_node_name present in the path vector
91  */
92 extern int
93 group_by_node_name (struct multipath * mp) {
94         int i, j;
95         int * bitmap;
96         struct path * pp;
97         struct pathgroup * pgp;
98         struct path * pp2;
99
100         if (!mp->pg)
101                 mp->pg = vector_alloc();
102
103         if (!mp->pg)
104                 return 1;
105
106         /* init the bitmap */
107         bitmap = (int *)MALLOC(VECTOR_SIZE(mp->paths) * sizeof (int));
108
109         if (!bitmap)
110                 goto out;
111
112         for (i = 0; i < VECTOR_SIZE(mp->paths); i++) {
113
114                 if (bitmap[i])
115                         continue;
116
117                 pp = VECTOR_SLOT(mp->paths, i);
118
119                 /* here, we really got a new pg */
120                 pgp = alloc_pathgroup();
121
122                 if (!pgp)
123                         goto out1;
124
125                 if (store_pathgroup(mp->pg, pgp))
126                         goto out1;
127
128                 /* feed the first path */
129                 if (store_path(pgp->paths, pp))
130                         goto out1;
131
132                 bitmap[i] = 1;
133
134                 for (j = i + 1; j < VECTOR_SIZE(mp->paths); j++) {
135
136                         if (bitmap[j])
137                                 continue;
138
139                         pp2 = VECTOR_SLOT(mp->paths, j);
140
141                         if (!strncmp(pp->tgt_node_name, pp2->tgt_node_name,
142                                         NODE_NAME_SIZE)) {
143                                 if (store_path(pgp->paths, pp2))
144                                         goto out1;
145
146                                 bitmap[j] = 1;
147                         }
148                 }
149         }
150         FREE(bitmap);
151         sort_pathgroups(mp);
152         free_pathvec(mp->paths, KEEP_PATHS);
153         mp->paths = NULL;
154         return 0;
155 out1:
156         FREE(bitmap);
157 out:
158         free_pgvec(mp->pg, KEEP_PATHS);
159         mp->pg = NULL;
160         return 1;
161 }
162
163 /*
164  * One path group per unique serial number present in the path vector
165  */
166 extern int
167 group_by_serial (struct multipath * mp) {
168         int i, j;
169         int * bitmap;
170         struct path * pp;
171         struct pathgroup * pgp;
172         struct path * pp2;
173
174         if (!mp->pg)
175                 mp->pg = vector_alloc();
176
177         if (!mp->pg)
178                 return 1;
179
180         /* init the bitmap */
181         bitmap = (int *)MALLOC(VECTOR_SIZE(mp->paths) * sizeof (int));
182
183         if (!bitmap)
184                 goto out;
185
186         for (i = 0; i < VECTOR_SIZE(mp->paths); i++) {
187
188                 if (bitmap[i])
189                         continue;
190
191                 pp = VECTOR_SLOT(mp->paths, i);
192
193                 /* here, we really got a new pg */
194                 pgp = alloc_pathgroup();
195
196                 if (!pgp)
197                         goto out1;
198
199                 if (store_pathgroup(mp->pg, pgp))
200                         goto out1;
201
202                 /* feed the first path */
203                 if (store_path(pgp->paths, pp))
204                         goto out1;
205
206                 bitmap[i] = 1;
207
208                 for (j = i + 1; j < VECTOR_SIZE(mp->paths); j++) {
209
210                         if (bitmap[j])
211                                 continue;
212
213                         pp2 = VECTOR_SLOT(mp->paths, j);
214
215                         if (0 == strcmp(pp->serial, pp2->serial)) {
216                                 if (store_path(pgp->paths, pp2))
217                                         goto out1;
218
219                                 bitmap[j] = 1;
220                         }
221                 }
222         }
223         FREE(bitmap);
224         sort_pathgroups(mp);
225         free_pathvec(mp->paths, KEEP_PATHS);
226         mp->paths = NULL;
227         return 0;
228 out1:
229         FREE(bitmap);
230 out:
231         free_pgvec(mp->pg, KEEP_PATHS);
232         mp->pg = NULL;
233         return 1;
234 }
235
236 extern int
237 one_path_per_group (struct multipath * mp)
238 {
239         int i;
240         struct path * pp;
241         struct pathgroup * pgp;
242
243         if (!mp->pg)
244                 mp->pg = vector_alloc();
245
246         if (!mp->pg)
247                 return 1;
248
249         for (i = 0; i < VECTOR_SIZE(mp->paths); i++) {
250                 pp = VECTOR_SLOT(mp->paths, i);
251                 pgp = alloc_pathgroup();
252
253                 if (!pgp)
254                         goto out;
255
256                 if (store_pathgroup(mp->pg, pgp))
257                         goto out;
258
259                 if (store_path(pgp->paths, pp))
260                         goto out;
261         }
262         sort_pathgroups(mp);
263         free_pathvec(mp->paths, KEEP_PATHS);
264         mp->paths = NULL;
265         return 0;
266 out:
267         free_pgvec(mp->pg, KEEP_PATHS);
268         mp->pg = NULL;
269         return 1;
270 }
271
272 extern int
273 one_group (struct multipath * mp)       /* aka multibus */
274 {
275         struct pathgroup * pgp;
276
277         if (VECTOR_SIZE(mp->paths) < 0)
278                 return 0;
279
280         if (!mp->pg)
281                 mp->pg = vector_alloc();
282
283         if (!mp->pg)
284                 return 1;
285
286         if (VECTOR_SIZE(mp->paths) > 0) {
287                 pgp = alloc_pathgroup();
288
289                 if (!pgp)
290                         goto out;
291
292                 vector_free(pgp->paths);
293                 pgp->paths = mp->paths;
294                 mp->paths = NULL;
295
296                 if (store_pathgroup(mp->pg, pgp))
297                         goto out;
298         }
299
300         return 0;
301 out:
302         free_pgvec(mp->pg, KEEP_PATHS);
303         mp->pg = NULL;
304         return 1;
305 }
306
307 extern int
308 group_by_prio (struct multipath * mp)
309 {
310         int i;
311         unsigned int prio;
312         struct path * pp;
313         struct pathgroup * pgp;
314
315         if (!mp->pg)
316                 mp->pg = vector_alloc();
317
318         if (!mp->pg)
319                 return 1;
320
321         while (VECTOR_SIZE(mp->paths) > 0) {
322                 pp = VECTOR_SLOT(mp->paths, 0);
323                 prio = pp->priority;
324
325                 /*
326                  * Find the position to insert the new path group. All groups
327                  * are ordered by the priority value (higher value first).
328                  */
329                 vector_foreach_slot(mp->pg, pgp, i) {
330                         pp  = VECTOR_SLOT(pgp->paths, 0);
331
332                         if (prio > pp->priority)
333                                 break;
334                 }
335
336                 /*
337                  * Initialize the new path group.
338                  */
339                 pgp = alloc_pathgroup();
340
341                 if (!pgp)
342                         goto out;
343
344                 if (store_path(pgp->paths, VECTOR_SLOT(mp->paths, 0))) {
345                         free_pathgroup(pgp, KEEP_PATHS);
346                         goto out;
347                 }
348
349                 vector_del_slot(mp->paths, 0);
350
351                 /*
352                  * Store the new path group into the vector.
353                  */
354                 if (i < VECTOR_SIZE(mp->pg)) {
355                         if (!vector_insert_slot(mp->pg, i, pgp)) {
356                                 free_pathgroup(pgp, KEEP_PATHS);
357                                 goto out;
358                         }
359                 } else {
360                         if (store_pathgroup(mp->pg, pgp)) {
361                                 free_pathgroup(pgp, KEEP_PATHS);
362                                 goto out;
363                         }
364                 }
365
366                 /*
367                  * add the other paths with the same prio
368                  */
369                 vector_foreach_slot(mp->paths, pp, i) {
370                         if (pp->priority == prio) {
371                                 if (store_path(pgp->paths, pp))
372                                         goto out;
373
374                                 vector_del_slot(mp->paths, i);
375                                 i--;
376                         }
377                 }
378         }
379         free_pathvec(mp->paths, KEEP_PATHS);
380         mp->paths = NULL;
381         return 0;
382 out:
383         free_pgvec(mp->pg, KEEP_PATHS);
384         mp->pg = NULL;
385         return 1;
386
387 }