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