libmultipath: add "protocol" blacklist option.
authorBenjamin Marzinski <bmarzins@redhat.com>
Wed, 1 Aug 2018 20:56:53 +0000 (15:56 -0500)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Tue, 7 Aug 2018 13:30:14 +0000 (15:30 +0200)
Multiple users have requested an easy way to setup blacklists that do
things such as blacklisting all non FC and iSCSI devices. Currently
there is no easy way to do this, without knowing in advance what the
devices are.  Looking into the udev property values, I didn't see a
consistent set of values that would worked for all the different types
of requests like this (which would have allowed us to solve this by
extending the "property" blacklist option to allow comparing values,
instead of just keywords).

Instead I've opted to allow multipath to blacklist/whitelist devices
by the protocol strings printed by "multipathd: add new protocol path
wildcard". This check happens after multipath checks the "device"
keyword, and before it checks wwid. This gives users an easily
understandible method to set up these types of blacklists, without
needing to know the exact arrays being used.

Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
libmultipath/blacklist.c
libmultipath/blacklist.h
libmultipath/config.c
libmultipath/config.h
libmultipath/dict.c
libmultipath/discovery.c
libmultipath/print.c
multipath/multipath.conf.5

index 361c603..fdd36f7 100644 (file)
@@ -12,6 +12,8 @@
 #include "structs.h"
 #include "config.h"
 #include "blacklist.h"
+#include "structs_vec.h"
+#include "print.h"
 
 int store_ble(vector blist, char * str, int origin)
 {
@@ -240,12 +242,14 @@ setup_default_blist (struct config * conf)
                condlog(3, "%s: %s %s %s", dev, (M), wwid, (S));        \
        else if (env)                                                   \
                condlog(3, "%s: %s %s %s", dev, (M), env, (S));         \
+       else if (protocol)                                              \
+               condlog(3, "%s: %s %s %s", dev, (M), protocol, (S));    \
        else                                                            \
                condlog(3, "%s: %s %s", dev, (M), (S))
 
 void
 log_filter (const char *dev, char *vendor, char *product, char *wwid,
-           const char *env, int r)
+           const char *env, const char *protocol, int r)
 {
        /*
         * Try to sort from most likely to least.
@@ -265,6 +269,9 @@ log_filter (const char *dev, char *vendor, char *product, char *wwid,
        case MATCH_PROPERTY_BLIST:
                LOG_BLIST("udev property", "blacklisted");
                break;
+       case MATCH_PROTOCOL_BLIST:
+               LOG_BLIST("protocol", "blacklisted");
+               break;
        case MATCH_DEVICE_BLIST_EXCEPT:
                LOG_BLIST("vendor/product", "whitelisted");
                break;
@@ -280,6 +287,9 @@ log_filter (const char *dev, char *vendor, char *product, char *wwid,
        case MATCH_PROPERTY_BLIST_MISSING:
                LOG_BLIST("blacklisted,", "udev property missing");
                break;
+       case MATCH_PROTOCOL_BLIST_EXCEPT:
+               LOG_BLIST("protocol", "whitelisted");
+               break;
        }
 }
 
@@ -299,7 +309,7 @@ int
 filter_device (vector blist, vector elist, char * vendor, char * product)
 {
        int r = _filter_device(blist, elist, vendor, product);
-       log_filter(NULL, vendor, product, NULL, NULL, r);
+       log_filter(NULL, vendor, product, NULL, NULL, NULL, r);
        return r;
 }
 
@@ -319,7 +329,7 @@ int
 filter_devnode (vector blist, vector elist, char * dev)
 {
        int r = _filter_devnode(blist, elist, dev);
-       log_filter(dev, NULL, NULL, NULL, NULL, r);
+       log_filter(dev, NULL, NULL, NULL, NULL, NULL, r);
        return r;
 }
 
@@ -339,7 +349,29 @@ int
 filter_wwid (vector blist, vector elist, char * wwid, char * dev)
 {
        int r = _filter_wwid(blist, elist, wwid);
-       log_filter(dev, NULL, NULL, wwid, NULL, r);
+       log_filter(dev, NULL, NULL, wwid, NULL, NULL, r);
+       return r;
+}
+
+static int
+_filter_protocol (vector blist, vector elist, const char * protocol_str)
+{
+       if (_blacklist_exceptions(elist, protocol_str))
+               return MATCH_PROTOCOL_BLIST_EXCEPT;
+       if (_blacklist(blist, protocol_str))
+               return MATCH_PROTOCOL_BLIST;
+       return 0;
+}
+
+int
+filter_protocol(vector blist, vector elist, struct path * pp)
+{
+       char buf[PROTOCOL_BUF_SIZE];
+       int r;
+
+       snprint_path_protocol(buf, sizeof(buf), pp);
+       r = _filter_protocol(blist, elist, buf);
+       log_filter(pp->dev, NULL, NULL, NULL, NULL, buf, r);
        return r;
 }
 
@@ -351,12 +383,14 @@ _filter_path (struct config * conf, struct path * pp)
        r = filter_property(conf, pp->udev);
        if (r > 0)
                return r;
-
        r = _filter_devnode(conf->blist_devnode, conf->elist_devnode,pp->dev);
        if (r > 0)
                return r;
        r = _filter_device(conf->blist_device, conf->elist_device,
                           pp->vendor_id, pp->product_id);
+       if (r > 0)
+               return r;
+       r = filter_protocol(conf->blist_protocol, conf->elist_protocol, pp);
        if (r > 0)
                return r;
        r = _filter_wwid(conf->blist_wwid, conf->elist_wwid, pp->wwid);
@@ -367,7 +401,8 @@ int
 filter_path (struct config * conf, struct path * pp)
 {
        int r=_filter_path(conf, pp);
-       log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, NULL, r);
+       log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, NULL,
+                  NULL, r);
        return r;
 }
 
@@ -402,7 +437,7 @@ filter_property(struct config * conf, struct udev_device * udev)
 
                r = _filter_property(conf, env);
                if (r) {
-                       log_filter(devname, NULL, NULL, NULL, env, r);
+                       log_filter(devname, NULL, NULL, NULL, env, NULL, r);
                        return r;
                }
        }
@@ -411,7 +446,7 @@ filter_property(struct config * conf, struct udev_device * udev)
         * This is the inverse of the 'normal' matching;
         * the environment variable _has_ to match.
         */
-       log_filter(devname, NULL, NULL, NULL, NULL,
+       log_filter(devname, NULL, NULL, NULL, NULL, NULL,
                   MATCH_PROPERTY_BLIST_MISSING);
        return MATCH_PROPERTY_BLIST_MISSING;
 }
index 0b028d4..f7beef2 100644 (file)
 #define MATCH_DEVNODE_BLIST  3
 #define MATCH_PROPERTY_BLIST 4
 #define MATCH_PROPERTY_BLIST_MISSING 5
+#define MATCH_PROTOCOL_BLIST 6
 #define MATCH_WWID_BLIST_EXCEPT     -MATCH_WWID_BLIST
 #define MATCH_DEVICE_BLIST_EXCEPT   -MATCH_DEVICE_BLIST
 #define MATCH_DEVNODE_BLIST_EXCEPT  -MATCH_DEVNODE_BLIST
 #define MATCH_PROPERTY_BLIST_EXCEPT -MATCH_PROPERTY_BLIST
+#define MATCH_PROTOCOL_BLIST_EXCEPT -MATCH_PROTOCOL_BLIST
 
 struct blentry {
        char * str;
@@ -36,6 +38,7 @@ int filter_wwid (vector, vector, char *, char *);
 int filter_device (vector, vector, char *, char *);
 int filter_path (struct config *, struct path *);
 int filter_property(struct config *, struct udev_device *);
+int filter_protocol(vector, vector, struct path *);
 int store_ble (vector, char *, int);
 int set_ble_device (vector, char *, char *, int);
 void free_blacklist (vector);
index afa309d..0aef186 100644 (file)
@@ -623,11 +623,13 @@ free_config (struct config * conf)
        free_blacklist(conf->blist_devnode);
        free_blacklist(conf->blist_wwid);
        free_blacklist(conf->blist_property);
+       free_blacklist(conf->blist_protocol);
        free_blacklist_device(conf->blist_device);
 
        free_blacklist(conf->elist_devnode);
        free_blacklist(conf->elist_wwid);
        free_blacklist(conf->elist_property);
+       free_blacklist(conf->elist_protocol);
        free_blacklist_device(conf->elist_device);
 
        free_mptable(conf->mptable);
@@ -780,6 +782,12 @@ load_config (char * file)
                if (!conf->blist_property)
                        goto out;
        }
+       if (conf->blist_protocol == NULL) {
+               conf->blist_protocol = vector_alloc();
+
+               if (!conf->blist_protocol)
+                       goto out;
+       }
 
        if (conf->elist_devnode == NULL) {
                conf->elist_devnode = vector_alloc();
@@ -807,6 +815,13 @@ load_config (char * file)
                if (!conf->elist_property)
                        goto out;
        }
+       if (conf->elist_protocol == NULL) {
+               conf->elist_protocol = vector_alloc();
+
+               if (!conf->elist_protocol)
+                       goto out;
+       }
+
        if (setup_default_blist(conf))
                goto out;
 
index 6bd42f0..7d0cd9a 100644 (file)
@@ -210,10 +210,12 @@ struct config {
        vector blist_wwid;
        vector blist_device;
        vector blist_property;
+       vector blist_protocol;
        vector elist_devnode;
        vector elist_wwid;
        vector elist_device;
        vector elist_property;
+       vector elist_protocol;
 };
 
 extern struct udev * udev;
index 15e7582..32524d5 100644 (file)
@@ -1291,9 +1291,12 @@ blacklist_handler(struct config *conf, vector strvec)
                conf->blist_device = vector_alloc();
        if (!conf->blist_property)
                conf->blist_property = vector_alloc();
+       if (!conf->blist_protocol)
+               conf->blist_protocol = vector_alloc();
 
        if (!conf->blist_devnode || !conf->blist_wwid ||
-           !conf->blist_device || !conf->blist_property)
+           !conf->blist_device || !conf->blist_property ||
+           !conf->blist_protocol)
                return 1;
 
        return 0;
@@ -1310,9 +1313,12 @@ blacklist_exceptions_handler(struct config *conf, vector strvec)
                conf->elist_device = vector_alloc();
        if (!conf->elist_property)
                conf->elist_property = vector_alloc();
+       if (!conf->elist_protocol)
+               conf->elist_protocol = vector_alloc();
 
        if (!conf->elist_devnode || !conf->elist_wwid ||
-           !conf->elist_device || !conf->elist_property)
+           !conf->elist_device || !conf->elist_property ||
+           !conf->elist_protocol)
                return 1;
 
        return 0;
@@ -1356,6 +1362,8 @@ declare_ble_handler(blist_wwid)
 declare_ble_handler(elist_wwid)
 declare_ble_handler(blist_property)
 declare_ble_handler(elist_property)
+declare_ble_handler(blist_protocol)
+declare_ble_handler(elist_protocol)
 
 static int
 snprint_def_uxsock_timeout(struct config *conf, char * buff, int len,
@@ -1627,6 +1635,7 @@ init_keywords(vector keywords)
        install_keyword_multi("devnode", &ble_blist_devnode_handler, &snprint_ble_simple);
        install_keyword_multi("wwid", &ble_blist_wwid_handler, &snprint_ble_simple);
        install_keyword_multi("property", &ble_blist_property_handler, &snprint_ble_simple);
+       install_keyword_multi("protocol", &ble_blist_protocol_handler, &snprint_ble_simple);
        install_keyword_multi("device", &ble_device_handler, NULL);
        install_sublevel();
        install_keyword("vendor", &ble_blist_device_vendor_handler, &snprint_bled_vendor);
@@ -1636,6 +1645,7 @@ init_keywords(vector keywords)
        install_keyword_multi("devnode", &ble_elist_devnode_handler, &snprint_ble_simple);
        install_keyword_multi("wwid", &ble_elist_wwid_handler, &snprint_ble_simple);
        install_keyword_multi("property", &ble_elist_property_handler, &snprint_ble_simple);
+       install_keyword_multi("protocol", &ble_elist_protocol_handler, &snprint_ble_simple);
        install_keyword_multi("device", &ble_except_device_handler, NULL);
        install_sublevel();
        install_keyword("vendor", &ble_elist_device_vendor_handler, &snprint_bled_vendor);
index 573d98b..e58a3fa 100644 (file)
@@ -1887,9 +1887,10 @@ int pathinfo(struct path *pp, struct config *conf, int mask)
 
        if (mask & DI_BLACKLIST && mask & DI_SYSFS) {
                if (filter_device(conf->blist_device, conf->elist_device,
-                                 pp->vendor_id, pp->product_id) > 0) {
+                                 pp->vendor_id, pp->product_id) > 0 ||
+                   filter_protocol(conf->blist_protocol, conf->elist_protocol,
+                                   pp) > 0)
                        return PATHINFO_SKIPPED;
-               }
        }
 
        path_state = path_offline(pp);
index ecfcb48..9da6a77 100644 (file)
@@ -1686,6 +1686,19 @@ int snprint_blacklist_report(struct config *conf, char *buff, int len)
        if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_property) == 0)
                return len;
 
+       if ((len - fwd - threshold) <= 0)
+               return len;
+       fwd += snprintf(buff + fwd, len - fwd, "protocol rules:\n"
+                                              "- blacklist:\n");
+       if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_protocol))
+               return len;
+
+       if ((len - fwd - threshold) <= 0)
+               return len;
+       fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
+       if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_protocol) == 0)
+               return len;
+
        if ((len - fwd - threshold) <= 0)
                return len;
        fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n"
@@ -1761,6 +1774,15 @@ static int snprint_blacklist(const struct config *conf, char *buff, int len)
                if (fwd >= len)
                        return len;
        }
+       vector_foreach_slot (conf->blist_protocol, ble, i) {
+               kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
+               if (!kw)
+                       return 0;
+               fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+                                      kw, ble);
+               if (fwd >= len)
+                       return len;
+       }
        rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
        if (!rootkw)
                return 0;
@@ -1838,6 +1860,15 @@ static int snprint_blacklist_except(const struct config *conf,
                if (fwd >= len)
                        return len;
        }
+       vector_foreach_slot (conf->elist_protocol, ele, i) {
+               kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
+               if (!kw)
+                       return 0;
+               fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+                                      kw, ele);
+               if (fwd >= len)
+                       return len;
+       }
        rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
        if (!rootkw)
                return 0;
index fb863fd..6333366 100644 (file)
@@ -1205,9 +1205,21 @@ The default \fIblacklist exception\fR is: \fB(SCSI_IDENT_|ID_WWN)\fR, causing
 well-behaved SCSI devices and devices that provide a WWN (World Wide Number)
 to be included, and all others to be excluded.
 .RE
+.TP
+.B protocol
+Regular expression for the protocol of a device to be excluded/included.
+.RS
+.PP
+The protocol strings that multipath recognizes are \fIscsi:fcp\fR,
+\fIscsi:spi\fR, \fIscsi:ssa\fR, \fIscsi:sbp\fR, \fIscsi:srp\fR,
+\fIscsi:iscsi\fR, \fIscsi:sas\fR, \fIscsi:adt\fR, \fIscsi:ata\fR,
+\fIscsi:unspec\fR, \fIccw\fR, \fIcciss\fR, \fInvme\fR, and \fIundef\fR.
+The protocol that a path is using can be viewed by running
+\fBmultipathd show paths format "%d %P"\fR
+.RE
 .LP
-For every device, these 4 blacklist criteria are evaluated in the the order
-"property, dev\%node, device, wwid". If a device turns out to be
+For every device, these 5 blacklist criteria are evaluated in the the order
+"property, dev\%node, device, protocol, wwid". If a device turns out to be
 blacklisted by any criterion, it's excluded from handling by multipathd, and
 the later criteria aren't evaluated any more. For each
 criterion, the whitelist takes precedence over the blacklist if a device