/* * Copyright (c) 2004, 2005 Christophe Varoqui */ #include #include #include #include #include "checkers.h" #include "util.h" #include "memory.h" #include "vector.h" #include "structs.h" #include "pgpolicies.h" #include "switchgroup.h" int get_pgpolicy_id(char * str) { if (0 == strncmp(str, "failover", 8)) return FAILOVER; if (0 == strncmp(str, "multibus", 8)) return MULTIBUS; if (0 == strncmp(str, "group_by_serial", 15)) return GROUP_BY_SERIAL; if (0 == strncmp(str, "group_by_prio", 13)) return GROUP_BY_PRIO; if (0 == strncmp(str, "group_by_node_name", 18)) return GROUP_BY_NODE_NAME; return IOPOLICY_UNDEF; } int get_pgpolicy_name(char * buff, int len, int id) { char * s; switch (id) { case FAILOVER: s = "failover"; break; case MULTIBUS: s = "multibus"; break; case GROUP_BY_SERIAL: s = "group_by_serial"; break; case GROUP_BY_PRIO: s = "group_by_prio"; break; case GROUP_BY_NODE_NAME: s = "group_by_node_name"; break; default: s = "undefined"; break; } return snprintf(buff, len, "%s", s); } void sort_pathgroups (struct multipath *mp) { int i, j; struct pathgroup * pgp1, * pgp2; if (!mp->pg) return; vector_foreach_slot(mp->pg, pgp1, i) { path_group_prio_update(pgp1); for (j = i - 1; j >= 0; j--) { pgp2 = VECTOR_SLOT(mp->pg, j); if (!pgp2) continue; if (pgp2->marginal < pgp1->marginal || (pgp2->marginal == pgp1->marginal && (pgp2->priority > pgp1->priority || (pgp2->priority == pgp1->priority && pgp2->enabled_paths >= pgp1->enabled_paths)))) { vector_move_up(mp->pg, i, j + 1); break; } } if (j < 0 && i != 0) vector_move_up(mp->pg, i, 0); } } static int split_marginal_paths(vector paths, vector *normal_p, vector *marginal_p) { int i; int has_marginal = 0; int has_normal = 0; struct path *pp; vector normal = NULL; vector marginal = NULL; *normal_p = *marginal_p = NULL; vector_foreach_slot(paths, pp, i) { if (pp->marginal) has_marginal = 1; else has_normal = 1; } if (!has_marginal || !has_normal) return -1; normal = vector_alloc(); marginal = vector_alloc(); if (!normal || !marginal) goto fail; vector_foreach_slot(paths, pp, i) { if (pp->marginal) { if (store_path(marginal, pp)) goto fail; } else { if (store_path(normal, pp)) goto fail; } } *normal_p = normal; *marginal_p = marginal; return 0; fail: vector_free(normal); vector_free(marginal); return -1; } int group_paths(struct multipath *mp, int marginal_pathgroups) { vector normal, marginal; if (!mp->pg) mp->pg = vector_alloc(); if (!mp->pg) return 1; if (VECTOR_SIZE(mp->paths) == 0) goto out; if (!mp->pgpolicyfn) goto fail; if (!marginal_pathgroups || split_marginal_paths(mp->paths, &normal, &marginal) != 0) { if (mp->pgpolicyfn(mp, mp->paths) != 0) goto fail; } else { if (mp->pgpolicyfn(mp, normal) != 0) goto fail_marginal; if (mp->pgpolicyfn(mp, marginal) != 0) goto fail_marginal; vector_free(normal); vector_free(marginal); } sort_pathgroups(mp); out: vector_free(mp->paths); mp->paths = NULL; return 0; fail_marginal: vector_free(normal); vector_free(marginal); fail: vector_free(mp->pg); mp->pg = NULL; return 1; } typedef bool (path_match_fn)(struct path *pp1, struct path *pp2); bool node_names_match(struct path *pp1, struct path *pp2) { return (strncmp(pp1->tgt_node_name, pp2->tgt_node_name, NODE_NAME_SIZE) == 0); } bool serials_match(struct path *pp1, struct path *pp2) { return (strncmp(pp1->serial, pp2->serial, SERIAL_SIZE) == 0); } bool prios_match(struct path *pp1, struct path *pp2) { return (pp1->priority == pp2->priority); } int group_by_match(struct multipath * mp, vector paths, bool (*path_match_fn)(struct path *, struct path *)) { int i, j; int * bitmap; struct path * pp; struct pathgroup * pgp; struct path * pp2; /* init the bitmap */ bitmap = (int *)MALLOC(VECTOR_SIZE(paths) * sizeof (int)); if (!bitmap) goto out; for (i = 0; i < VECTOR_SIZE(paths); i++) { if (bitmap[i]) continue; pp = VECTOR_SLOT(paths, i); /* here, we really got a new pg */ pgp = alloc_pathgroup(); if (!pgp) goto out1; if (add_pathgroup(mp, pgp)) goto out2; /* feed the first path */ if (store_path(pgp->paths, pp)) goto out1; bitmap[i] = 1; for (j = i + 1; j < VECTOR_SIZE(paths); j++) { if (bitmap[j]) continue; pp2 = VECTOR_SLOT(paths, j); if (path_match_fn(pp, pp2)) { if (store_path(pgp->paths, pp2)) goto out1; bitmap[j] = 1; } } } FREE(bitmap); return 0; out2: free_pathgroup(pgp, KEEP_PATHS); out1: FREE(bitmap); out: free_pgvec(mp->pg, KEEP_PATHS); mp->pg = NULL; return 1; } /* * One path group per unique tgt_node_name present in the path vector */ int group_by_node_name(struct multipath * mp, vector paths) { return group_by_match(mp, paths, node_names_match); } /* * One path group per unique serial number present in the path vector */ int group_by_serial(struct multipath * mp, vector paths) { return group_by_match(mp, paths, serials_match); } /* * One path group per priority present in the path vector */ int group_by_prio(struct multipath *mp, vector paths) { return group_by_match(mp, paths, prios_match); } int one_path_per_group(struct multipath *mp, vector paths) { int i; struct path * pp; struct pathgroup * pgp; for (i = 0; i < VECTOR_SIZE(paths); i++) { pp = VECTOR_SLOT(paths, i); pgp = alloc_pathgroup(); if (!pgp) goto out; if (add_pathgroup(mp, pgp)) goto out1; if (store_path(pgp->paths, pp)) goto out; } return 0; out1: free_pathgroup(pgp, KEEP_PATHS); out: free_pgvec(mp->pg, KEEP_PATHS); mp->pg = NULL; return 1; } int one_group(struct multipath *mp, vector paths) /* aka multibus */ { int i; struct path * pp; struct pathgroup * pgp; pgp = alloc_pathgroup(); if (!pgp) goto out; if (add_pathgroup(mp, pgp)) goto out1; for (i = 0; i < VECTOR_SIZE(paths); i++) { pp = VECTOR_SLOT(paths, i); if (store_path(pgp->paths, pp)) goto out; } return 0; out1: free_pathgroup(pgp, KEEP_PATHS); out: free_pgvec(mp->pg, KEEP_PATHS); mp->pg = NULL; return 1; }