660768a4d64069e96fd2bad493c362deacbfc9dc
[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 /*
88  * One path group per unique tgt_node_name present in the path vector
89  */
90 int group_by_node_name(struct multipath * mp)
91 {
92         int i, j;
93         int * bitmap;
94         struct path * pp;
95         struct pathgroup * pgp;
96         struct path * pp2;
97
98         if (!mp->pg)
99                 mp->pg = vector_alloc();
100
101         if (!mp->pg)
102                 return 1;
103
104         /* init the bitmap */
105         bitmap = (int *)MALLOC(VECTOR_SIZE(mp->paths) * sizeof (int));
106
107         if (!bitmap)
108                 goto out;
109
110         for (i = 0; i < VECTOR_SIZE(mp->paths); i++) {
111
112                 if (bitmap[i])
113                         continue;
114
115                 pp = VECTOR_SLOT(mp->paths, i);
116
117                 /* here, we really got a new pg */
118                 pgp = alloc_pathgroup();
119
120                 if (!pgp)
121                         goto out1;
122
123                 if (add_pathgroup(mp, pgp))
124                         goto out2;
125
126                 /* feed the first path */
127                 if (store_path(pgp->paths, pp))
128                         goto out2;
129
130                 bitmap[i] = 1;
131
132                 for (j = i + 1; j < VECTOR_SIZE(mp->paths); j++) {
133
134                         if (bitmap[j])
135                                 continue;
136
137                         pp2 = VECTOR_SLOT(mp->paths, j);
138
139                         if (!strncmp(pp->tgt_node_name, pp2->tgt_node_name,
140                                         NODE_NAME_SIZE)) {
141                                 if (store_path(pgp->paths, pp2))
142                                         goto out2;
143
144                                 bitmap[j] = 1;
145                         }
146                 }
147         }
148         FREE(bitmap);
149         sort_pathgroups(mp);
150         free_pathvec(mp->paths, KEEP_PATHS);
151         mp->paths = NULL;
152         return 0;
153 out2:
154         free_pathgroup(pgp, KEEP_PATHS);
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 int group_by_serial(struct multipath * mp)
167 {
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 (add_pathgroup(mp, pgp))
200                         goto out2;
201
202                 /* feed the first path */
203                 if (store_path(pgp->paths, pp))
204                         goto out2;
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 out2;
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 out2:
229         free_pathgroup(pgp, KEEP_PATHS);
230 out1:
231         FREE(bitmap);
232 out:
233         free_pgvec(mp->pg, KEEP_PATHS);
234         mp->pg = NULL;
235         return 1;
236 }
237
238 int one_path_per_group(struct multipath *mp)
239 {
240         int i;
241         struct path * pp;
242         struct pathgroup * pgp;
243
244         if (!mp->pg)
245                 mp->pg = vector_alloc();
246
247         if (!mp->pg)
248                 return 1;
249
250         for (i = 0; i < VECTOR_SIZE(mp->paths); i++) {
251                 pp = VECTOR_SLOT(mp->paths, i);
252                 pgp = alloc_pathgroup();
253
254                 if (!pgp)
255                         goto out;
256
257                 if (add_pathgroup(mp, pgp))
258                         goto out1;
259
260                 if (store_path(pgp->paths, pp))
261                         goto out1;
262         }
263         sort_pathgroups(mp);
264         free_pathvec(mp->paths, KEEP_PATHS);
265         mp->paths = NULL;
266         return 0;
267 out1:
268         free_pathgroup(pgp, KEEP_PATHS);
269 out:
270         free_pgvec(mp->pg, KEEP_PATHS);
271         mp->pg = NULL;
272         return 1;
273 }
274
275 int one_group(struct multipath *mp)     /* aka multibus */
276 {
277         struct pathgroup * pgp;
278
279         if (VECTOR_SIZE(mp->paths) < 0)
280                 return 0;
281
282         if (!mp->pg)
283                 mp->pg = vector_alloc();
284
285         if (!mp->pg)
286                 return 1;
287
288         if (VECTOR_SIZE(mp->paths) > 0) {
289                 pgp = alloc_pathgroup();
290
291                 if (!pgp)
292                         goto out;
293
294                 vector_free(pgp->paths);
295
296                 if (add_pathgroup(mp, pgp))
297                         goto out1;
298
299                 pgp->paths = mp->paths;
300                 mp->paths = NULL;
301         }
302
303         return 0;
304 out1:
305         free_pathgroup(pgp, KEEP_PATHS);
306 out:
307         free_pgvec(mp->pg, KEEP_PATHS);
308         mp->pg = NULL;
309         return 1;
310 }
311
312 int group_by_prio(struct multipath *mp)
313 {
314         int i;
315         int prio;
316         struct path * pp;
317         struct pathgroup * pgp;
318         vector pathvec = NULL;
319
320         if (!mp->pg)
321                 mp->pg = vector_alloc();
322
323         if (!mp->pg)
324                 return 1;
325
326         pathvec = vector_alloc();
327         if (!pathvec)
328                 goto out;
329
330         vector_foreach_slot(mp->paths, pp, i) {
331                 if (!vector_alloc_slot(pathvec))
332                         goto out1;
333                 vector_set_slot(pathvec, pp);
334         }
335
336         while (VECTOR_SIZE(pathvec) > 0) {
337                 pp = VECTOR_SLOT(pathvec, 0);
338                 prio = pp->priority;
339
340                 /*
341                  * Find the position to insert the new path group. All groups
342                  * are ordered by the priority value (higher value first).
343                  */
344                 vector_foreach_slot(mp->pg, pgp, i) {
345                         pp  = VECTOR_SLOT(pgp->paths, 0);
346
347                         if (prio > pp->priority)
348                                 break;
349                 }
350
351                 /*
352                  * Initialize the new path group.
353                  */
354                 pgp = alloc_pathgroup();
355
356                 if (!pgp)
357                         goto out1;
358
359                 if (store_path(pgp->paths, VECTOR_SLOT(pathvec, 0)))
360                         goto out2;
361
362                 vector_del_slot(pathvec, 0);
363
364                 /*
365                  * Store the new path group into the vector.
366                  */
367                 if (i < VECTOR_SIZE(mp->pg)) {
368                         if (!vector_insert_slot(mp->pg, i, pgp))
369                                 goto out2;
370                         pgp->mpp = mp;
371                 } else {
372                         if (add_pathgroup(mp, pgp))
373                                 goto out2;
374                 }
375
376                 /*
377                  * add the other paths with the same prio
378                  */
379                 vector_foreach_slot(pathvec, pp, i) {
380                         if (pp->priority == prio) {
381                                 if (store_path(pgp->paths, pp))
382                                         goto out2;
383
384                                 vector_del_slot(pathvec, i);
385                                 i--;
386                         }
387                 }
388         }
389         free_pathvec(pathvec, KEEP_PATHS);
390         free_pathvec(mp->paths, KEEP_PATHS);
391         mp->paths = NULL;
392         return 0;
393 out2:
394         free_pathgroup(pgp, KEEP_PATHS);
395 out1:
396         free_pathvec(pathvec, KEEP_PATHS);
397 out:
398         free_pgvec(mp->pg, KEEP_PATHS);
399         mp->pg = NULL;
400         return 1;
401
402 }