libmultipath: make pgpolicyfn take a paths vector
[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->priority > pgp1->priority ||
76                             (pgp2->priority == pgp1->priority &&
77                              pgp2->enabled_paths >= pgp1->enabled_paths)) {
78                                 vector_move_up(mp->pg, i, j + 1);
79                                 break;
80                         }
81                 }
82                 if (j < 0 && i != 0)
83                 vector_move_up(mp->pg, i, 0);
84         }
85 }
86
87
88 int group_paths(struct multipath *mp)
89 {
90         if (!mp->pg)
91                 mp->pg = vector_alloc();
92         if (!mp->pg)
93                 return 1;
94
95         if (VECTOR_SIZE(mp->paths) > 0 &&
96             (!mp->pgpolicyfn || mp->pgpolicyfn(mp, mp->paths))) {
97                 vector_free(mp->pg);
98                 mp->pg = NULL;
99                 return 1;
100         }
101
102         sort_pathgroups(mp);
103         vector_free(mp->paths);
104         mp->paths = NULL;
105         return 0;
106 }
107
108 typedef bool (path_match_fn)(struct path *pp1, struct path *pp2);
109
110 bool
111 node_names_match(struct path *pp1, struct path *pp2)
112 {
113         return (strncmp(pp1->tgt_node_name, pp2->tgt_node_name,
114                         NODE_NAME_SIZE) == 0);
115 }
116
117 bool
118 serials_match(struct path *pp1, struct path *pp2)
119 {
120         return (strncmp(pp1->serial, pp2->serial, SERIAL_SIZE) == 0);
121 }
122
123 bool
124 prios_match(struct path *pp1, struct path *pp2)
125 {
126         return (pp1->priority == pp2->priority);
127 }
128
129 int group_by_match(struct multipath * mp, vector paths,
130                    bool (*path_match_fn)(struct path *, struct path *))
131 {
132         int i, j;
133         int * bitmap;
134         struct path * pp;
135         struct pathgroup * pgp;
136         struct path * pp2;
137
138         /* init the bitmap */
139         bitmap = (int *)MALLOC(VECTOR_SIZE(paths) * sizeof (int));
140
141         if (!bitmap)
142                 goto out;
143
144         for (i = 0; i < VECTOR_SIZE(paths); i++) {
145
146                 if (bitmap[i])
147                         continue;
148
149                 pp = VECTOR_SLOT(paths, i);
150
151                 /* here, we really got a new pg */
152                 pgp = alloc_pathgroup();
153
154                 if (!pgp)
155                         goto out1;
156
157                 if (add_pathgroup(mp, pgp))
158                         goto out2;
159
160                 /* feed the first path */
161                 if (store_path(pgp->paths, pp))
162                         goto out1;
163
164                 bitmap[i] = 1;
165
166                 for (j = i + 1; j < VECTOR_SIZE(paths); j++) {
167
168                         if (bitmap[j])
169                                 continue;
170
171                         pp2 = VECTOR_SLOT(paths, j);
172
173                         if (path_match_fn(pp, pp2)) {
174                                 if (store_path(pgp->paths, pp2))
175                                         goto out1;
176
177                                 bitmap[j] = 1;
178                         }
179                 }
180         }
181         FREE(bitmap);
182         return 0;
183 out2:
184         free_pathgroup(pgp, KEEP_PATHS);
185 out1:
186         FREE(bitmap);
187 out:
188         free_pgvec(mp->pg, KEEP_PATHS);
189         mp->pg = NULL;
190         return 1;
191 }
192
193 /*
194  * One path group per unique tgt_node_name present in the path vector
195  */
196 int group_by_node_name(struct multipath * mp, vector paths)
197 {
198         return group_by_match(mp, paths, node_names_match);
199 }
200
201 /*
202  * One path group per unique serial number present in the path vector
203  */
204 int group_by_serial(struct multipath * mp, vector paths)
205 {
206         return group_by_match(mp, paths, serials_match);
207 }
208
209 /*
210  * One path group per priority present in the path vector
211  */
212 int group_by_prio(struct multipath *mp, vector paths)
213 {
214         return group_by_match(mp, paths, prios_match);
215 }
216
217 int one_path_per_group(struct multipath *mp, vector paths)
218 {
219         int i;
220         struct path * pp;
221         struct pathgroup * pgp;
222
223         for (i = 0; i < VECTOR_SIZE(paths); i++) {
224                 pp = VECTOR_SLOT(paths, i);
225                 pgp = alloc_pathgroup();
226
227                 if (!pgp)
228                         goto out;
229
230                 if (add_pathgroup(mp, pgp))
231                         goto out1;
232
233                 if (store_path(pgp->paths, pp))
234                         goto out;
235         }
236         return 0;
237 out1:
238         free_pathgroup(pgp, KEEP_PATHS);
239 out:
240         free_pgvec(mp->pg, KEEP_PATHS);
241         mp->pg = NULL;
242         return 1;
243 }
244
245 int one_group(struct multipath *mp, vector paths)       /* aka multibus */
246 {
247         int i;
248         struct path * pp;
249         struct pathgroup * pgp;
250
251         pgp = alloc_pathgroup();
252
253         if (!pgp)
254                 goto out;
255
256         if (add_pathgroup(mp, pgp))
257                 goto out1;
258
259         for (i = 0; i < VECTOR_SIZE(paths); i++) {
260                 pp = VECTOR_SLOT(paths, i);
261
262                 if (store_path(pgp->paths, pp))
263                         goto out;
264         }
265         return 0;
266 out1:
267         free_pathgroup(pgp, KEEP_PATHS);
268 out:
269         free_pgvec(mp->pg, KEEP_PATHS);
270         mp->pg = NULL;
271         return 1;
272 }