int (*nf_print_addrlist)(char *buffer, int count,
struct list_head *list);
int (*nf_match_addr)(__u32 addr, struct list_head *list);
+ int (*nf_match_netmask)(const __be32 *addr, size_t asize,
+ const __be32 *netmask,
+ const __be32 *netaddr);
int (*nf_min_max)(struct list_head *nidlist, __u32 *min_nid,
__u32 *max_nid);
int (*nf_expand_addrrange)(struct list_head *addrranges,
int cfs_ip_addr_range_gen(__u32 *ip_list, int count,
struct list_head *ip_addr_expr);
int cfs_ip_addr_match(__u32 addr, struct list_head *list);
+int libcfs_ip_in_netmask(const __be32 *addr, size_t asize,
+ const __be32 *netmask,
+ const __be32 *netaddr);
int cfs_expand_nidlist(struct list_head *nidlist, lnet_nid_t *lnet_nidlist,
int max_nids);
int cfs_parse_nid_parts(char *str, struct list_head *addr,
struct list_head *net_num, __u32 *net_type);
int cfs_abs_path(const char *request_path, char **resolved_path);
+char *strim(char *s);
#endif
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
+#include <ctype.h>
#include <libcfs/util/string.h>
#include <linux/lnet/lnet-types.h>
return i == 4;
}
+/**
+ * Matches address (\a addr) against the netmask encoded in \a netmask and
+ * \a netaddr.
+ *
+ * \retval 1 if \a addr matches
+ * \retval 0 otherwise
+ */
+int
+libcfs_ip_in_netmask(const __be32 *addr, size_t asize, const __be32 *netmask,
+ const __be32 *netaddr)
+{
+ if (asize == 4) {
+ struct in_addr nid_addr, masked_addr;
+
+ memcpy(&nid_addr.s_addr, addr, asize);
+
+ masked_addr.s_addr = nid_addr.s_addr &
+ (*(struct in_addr *)netmask).s_addr;
+
+ return memcmp(&masked_addr, netaddr, sizeof(masked_addr)) == 0;
+ } else if (asize == 16) {
+ struct in6_addr nid_addr, masked_addr;
+ int i;
+
+ memcpy(&nid_addr.s6_addr, addr, asize);
+
+ for (i = 0; i < 16; i++)
+ masked_addr.s6_addr[i] =
+ nid_addr.s6_addr[i] &
+ (*(struct in6_addr *)netmask).s6_addr[i];
+
+ return memcmp(&masked_addr, netaddr, sizeof(masked_addr)) == 0;
+ }
+
+ return 0;
+}
+
static void
libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
{
.nf_print_addrlist = libcfs_ip_addr_range_print,
.nf_match_addr = cfs_ip_addr_match,
.nf_min_max = cfs_ip_min_max,
- .nf_expand_addrrange = libcfs_ip_addr_range_expand
+ .nf_expand_addrrange = libcfs_ip_addr_range_expand,
+ .nf_match_netmask = libcfs_ip_in_netmask
},
{
.nf_type = O2IBLND,
.nf_print_addrlist = libcfs_ip_addr_range_print,
.nf_match_addr = cfs_ip_addr_match,
.nf_min_max = cfs_ip_min_max,
- .nf_expand_addrrange = libcfs_ip_addr_range_expand
+ .nf_expand_addrrange = libcfs_ip_addr_range_expand,
+ .nf_match_netmask = libcfs_ip_in_netmask
},
{
.nf_type = GNILND,
return !LNET_NID_IS_ANY(nid);
}
-/**
- * Nid range list syntax.
+/* NID range list syntax.
* \verbatim
*
- * <nidlist> :== <nidrange> [ ' ' <nidrange> ]
- * <nidrange> :== <addrrange> '@' <net>
- * <addrrange> :== '*' |
- * <ipaddr_range> |
- * <cfs_expr_list>
- * <ipaddr_range> :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
- * <cfs_expr_list>
- * <cfs_expr_list> :== <number> |
- * <expr_list>
- * <expr_list> :== '[' <range_expr> [ ',' <range_expr>] ']'
- * <range_expr> :== <number> |
- * <number> '-' <number> |
- * <number> '-' <number> '/' <number>
- * <net> :== <netname> | <netname><number>
- * <netname> :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
- * "vib" | "ra" | "elan" | "mx" | "ptl"
+ * <nidlist> :== <nidrange> [ ' ' <nidrange> ]
+ * <nidrange> :== <addrrange> '@' <net>
+ * <addrrange> :== '*' |
+ * <netmask> |
+ * <ipv6_addr> |
+ * <ipv4_addr_range> |
+ * <numaddr_range>
+ * <netmask> :== An IPv4 or IPv6 network mask in CIDR notation.
+ * e.g. 192.168.1.0/24 or 2001:0db8::/32
+ * <ipv6_addr> :== A single IPv6 address
+ * <ipv4_addr_range> :==
+ * <numaddr_range>.<numaddr_range>.<numaddr_range>.<numaddr_range>
+ * <numaddr_range> :== <number> |
+ * <expr_list>
+ * <expr_list> :== '[' <range_expr> [ ',' <range_expr>] ']'
+ * <range_expr> :== <number> |
+ * <number> '-' <number> |
+ * <number> '-' <number> '/' <number>
+ * <net> :== <netname> | <netname><number>
+ * <netname> :== "lo" | "tcp" | "o2ib" | "gni" | "gip" | "ptlf" | "kfi"
* \endverbatim
*/
*/
struct list_head nr_addrranges;
/**
+ * List head for nidmask::nm_link.
+ */
+ struct list_head nr_nidmasks;
+ /**
* Flag indicating that *@<net> is found.
*/
int nr_all;
};
/**
+ * Structure to represent \<netmask\> token of the syntax
+ */
+struct nidmask {
+ /* Link to nidrange::nr_nidmasks */
+ struct list_head nm_link;
+
+ /* This is the base address that was parsed */
+ union {
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+ } nm_addr;
+
+ /* Netmask derived from the prefix length */
+ union {
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+ } nm_netmask;
+
+ /* Network address derived from the base address and the netmask */
+ union {
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+ } nm_netaddr;
+
+ /* Address family */
+ sa_family_t nm_family;
+
+ /* Prefix length */
+ __u8 nm_prefix_len;
+};
+
+/**
* Structure to represent \<addrrange\> token of the syntax.
*/
struct addrrange {
* \retval -errno otherwise
*/
static int
-parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
+parse_addrange(char *str, struct nidrange *nidrange)
{
struct addrrange *addrrange;
- if (src->ls_len == 1 && src->ls_str[0] == '*') {
+ if (strcmp(str, "*") == 0) {
nidrange->nr_all = 1;
return 0;
}
addrrange = calloc(1, sizeof(struct addrrange));
- if (addrrange == NULL)
+ if (!addrrange)
return -ENOMEM;
list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
- return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
- src->ls_len,
+ return nidrange->nr_netstrfns->nf_parse_addrlist(str, strlen(str),
&addrrange->ar_numaddr_ranges);
}
+static void
+init_ipv4_nidmask(struct in_addr *ipv4, struct nidmask *nm)
+{
+ memcpy(&nm->nm_addr.ipv4, &ipv4->s_addr, sizeof(struct in_addr));
+
+ nm->nm_netmask.ipv4.s_addr =
+ htonl(~((1U << (32 - nm->nm_prefix_len)) - 1));
+ nm->nm_netaddr.ipv4.s_addr = ipv4->s_addr & nm->nm_netmask.ipv4.s_addr;
+}
+
+/* Note: The memory of struct nidmask is allocated via calloc, so it has been
+ * set to zero as required by this function.
+ */
+static void
+init_ipv6_nidmask(struct in6_addr *ipv6, struct nidmask *nm)
+{
+ int i, j;
+
+ memcpy(&nm->nm_addr.ipv6, &ipv6->s6_addr, sizeof(struct in6_addr));
+
+ for (i = nm->nm_prefix_len, j = 0; i > 0; i -= 8, j++) {
+ if (i >= 8)
+ nm->nm_netmask.ipv6.s6_addr[j] = 0xff;
+ else
+ nm->nm_netmask.ipv6.s6_addr[j] =
+ (unsigned long)(0xffU << (8 - i));
+ }
+
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ nm->nm_netaddr.ipv6.s6_addr[i] = ipv6->s6_addr[i] &
+ nm->nm_netmask.ipv6.s6_addr[i];
+}
+
+static __u8
+parse_prefix_len(char *str)
+{
+ unsigned int max;
+ unsigned int prefix_len;
+ char *slash = strchr(str, '/');
+
+ /* IPv4 netmask must include an explicit prefix length */
+ if (!(slash || strchr(str, ':')))
+ return 0;
+
+ /* We treat an IPv6 address without a prefix length as having /128 */
+ if (!slash)
+ return 128;
+
+ if (strchr(str, ':'))
+ max = 128;
+ else
+ max = 32;
+
+ slash++;
+ if (!cfs_str2num_check(slash, strlen(slash), &prefix_len, 1, max))
+ return 0;
+
+ return (__u8)prefix_len;
+}
+
+static int
+parse_nidmask(char *str, struct nidrange *nr)
+{
+ struct nidmask *nm;
+ char *addrstr;
+ struct netstrfns *nf = nr->nr_netstrfns;
+ size_t asize;
+ __u32 addr[4];
+
+ nm = calloc(1, sizeof(struct nidmask));
+ if (!nm) {
+ fprintf(stderr, "Failed to allocate memory for nidmask\n");
+ return -ENOMEM;
+ }
+
+ /* Add to nr_nidmasks so that our caller can free us on error */
+ list_add_tail(&nm->nm_link, &nr->nr_nidmasks);
+
+ nm->nm_prefix_len = parse_prefix_len(str);
+ if (!nm->nm_prefix_len) {
+ fprintf(stderr, "Failed to parse prefix length from \"%s\"\n",
+ str);
+ return -EINVAL;
+ }
+
+ if (!nf->nf_str2addr_size) {
+ fprintf(stderr, "Network type doesn't support nidmasks\n");
+ return -EINVAL;
+ }
+
+ addrstr = strsep(&str, "/");
+ if (!nf->nf_str2addr_size(addrstr, strlen(addrstr), addr, &asize)) {
+ fprintf(stderr, "Failed to convert \"%s\" to address\n",
+ addrstr);
+ return -EINVAL;
+ }
+
+ if (asize == 4) {
+ nm->nm_family = AF_INET;
+ init_ipv4_nidmask((struct in_addr *)&addr, nm);
+ } else if (asize == 16) {
+ nm->nm_family = AF_INET6;
+ init_ipv6_nidmask((struct in6_addr *)&addr, nm);
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/**
* Finds or creates struct nidrange.
*
* \retval NULL if \a src does not match any network
*/
static struct nidrange *
-add_nidrange(const struct cfs_lstr *src,
- struct list_head *nidlist)
+add_nidrange(char *str, struct list_head *nidlist)
{
struct netstrfns *nf;
struct nidrange *nr;
- int endlen;
- unsigned netnum;
+ char *end;
+ unsigned int netnum;
- if (src->ls_len >= LNET_NIDSTR_SIZE)
+ nf = libcfs_namenum2netstrfns(str);
+ if (!nf)
return NULL;
- nf = libcfs_namenum2netstrfns(src->ls_str);
- if (nf == NULL)
- return NULL;
- endlen = src->ls_len - strlen(nf->nf_name);
- if (endlen == 0)
+ end = str + strlen(nf->nf_name);
+ if (!*end) {
/* network name only, e.g. "elan" or "tcp" */
netnum = 0;
- else {
+ } else {
/* e.g. "elan25" or "tcp23", refuse to parse if
* network name is not appended with decimal or
* hexadecimal number */
- if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
- endlen, &netnum, 0, MAX_NUMERIC_VALUE))
+ if (!cfs_str2num_check(end, strlen(end), &netnum, 0,
+ MAX_NUMERIC_VALUE))
return NULL;
}
}
nr = calloc(1, sizeof(struct nidrange));
- if (nr == NULL)
+ if (!nr)
return NULL;
list_add_tail(&nr->nr_link, nidlist);
INIT_LIST_HEAD(&nr->nr_addrranges);
+ INIT_LIST_HEAD(&nr->nr_nidmasks);
nr->nr_netstrfns = nf;
nr->nr_all = 0;
nr->nr_netnum = netnum;
/**
* Parses \<nidrange\> token of the syntax.
*
- * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
- * \retval 0 otherwise
+ * \retval 0 if \a src parses to \<addrrange\> '@' \<net\>
+ * \retval -errno otherwise
*/
static int
-parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
+parse_nidrange(char *str, struct list_head *nidlist)
{
- struct cfs_lstr addrrange;
- struct cfs_lstr net;
- struct cfs_lstr tmp;
+ char *addrrange;
+ char *net;
+ char *slash;
struct nidrange *nr;
+ int rc;
- tmp = *src;
- if (cfs_gettok(src, '@', &addrrange) == 0)
- goto failed;
+ addrrange = strsep(&str, "@");
+ if (!str) {
+ fprintf(stderr, "nidrange \"%s\" doesn't contain '@'\n",
+ addrrange);
+ return -EINVAL;
+ }
- if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
- goto failed;
+ net = strim(str);
+ if (strchr(net, '@') || !*net) {
+ fprintf(stderr, "net \"%s\" is malformed\n", net);
+ return -EINVAL;
+ }
- nr = add_nidrange(&net, nidlist);
- if (nr == NULL)
- goto failed;
+ nr = add_nidrange(net, nidlist);
+ if (!nr) {
+ fprintf(stderr, "failed to add nidrange for network \"%s\"\n",
+ net);
+ return -EINVAL;
+ }
- if (parse_addrange(&addrrange, nr) != 0)
- goto failed;
+ /* Check for an IPv6 address or a '/' outside of '[]' */
+ slash = strchr(addrrange, '/');
+ if (strchr(addrrange, ':') || (slash && !strchr(slash, ']')))
+ rc = parse_nidmask(addrrange, nr);
+ else
+ rc = parse_addrange(addrrange, nr);
- return 1;
- failed:
- fprintf(stderr, "can't parse nidrange: \"%.*s\"\n",
- tmp.ls_len, tmp.ls_str);
- return 0;
+ if (rc)
+ fprintf(stderr, "Failed to parse addrrange \"%s\" rc = %d\n",
+ addrrange, rc);
+ return rc;
}
static __u32
}
}
+static void
+free_nidmasks(struct list_head *list)
+{
+ struct nidmask *nm;
+
+ while (!list_empty(list)) {
+ nm = list_first_entry(list, struct nidmask, nm_link);
+ list_del(&nm->nm_link);
+ free(nm);
+ }
+}
+
/**
* Frees nidrange strutures of \a list.
*
list_for_each_safe(pos, next, list) {
nr = list_entry(pos, struct nidrange, nr_link);
free_addrranges(&nr->nr_addrranges);
+ free_nidmasks(&nr->nr_nidmasks);
list_del(pos);
free(nr);
}
* \retval 0 otherwise
*/
int
-cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
+cfs_parse_nidlist(char *orig, int len, struct list_head *nidlist)
{
- struct cfs_lstr src;
- struct cfs_lstr res;
- int rc;
+ int rc = 0;
+ char *str;
+
+ orig = strndup(orig, len);
+ if (!orig)
+ return 0;
- src.ls_str = str;
- src.ls_len = len;
INIT_LIST_HEAD(nidlist);
- while (src.ls_str) {
- rc = cfs_gettok(&src, ' ', &res);
- if (rc == 0) {
- cfs_free_nidlist(nidlist);
- return 0;
- }
- rc = parse_nidrange(&res, nidlist);
- if (rc == 0) {
- cfs_free_nidlist(nidlist);
- return 0;
- }
+ str = orig;
+ while (rc == 0 && str) {
+ char *tok = strsep(&str, " ");
+
+ if (*tok)
+ rc = parse_nidrange(tok, nidlist);
}
- return 1;
+ free(orig);
+ if (rc)
+ cfs_free_nidlist(nidlist);
+ else if (list_empty(nidlist))
+ rc = -EINVAL;
+
+ return rc ? 0 : 1;
+}
+
+static int
+match_nidmask(struct lnet_nid *nid, struct nidmask *nm, struct netstrfns *nf)
+{
+ __be32 addr[4] = { nid->nid_addr[0], nid->nid_addr[1],
+ nid->nid_addr[2], nid->nid_addr[3] };
+ __be32 *netmask, *netaddr;
+
+ if (!nf->nf_match_netmask)
+ return 0;
+
+ if (nid_is_nid4(nid) && nm->nm_family == AF_INET) {
+ netmask = (__be32 *)&nm->nm_netmask.ipv4.s_addr;
+ netaddr = (__be32 *)&nm->nm_netaddr.ipv4.s_addr;
+ } else if (!nid_is_nid4(nid) && nm->nm_family == AF_INET6) {
+ netmask = (__be32 *)&nm->nm_netmask.ipv6.s6_addr;
+ netaddr = (__be32 *)&nm->nm_netaddr.ipv6.s6_addr;
+ } else {
+ return 0;
+ }
+
+ return nf->nf_match_netmask(addr, NID_ADDR_BYTES(nid), netmask,
+ netaddr);
}
/**
int cfs_match_nid(struct lnet_nid *nid, struct list_head *nidlist)
{
struct nidrange *nr;
+ struct nidmask *nm;
struct addrrange *ar;
- if (!nid_is_nid4(nid))
- return 0;
list_for_each_entry(nr, nidlist, nr_link) {
if (nr->nr_netstrfns->nf_type != nid->nid_type)
continue;
continue;
if (nr->nr_all)
return 1;
+
+ list_for_each_entry(nm, &nr->nr_nidmasks, nm_link)
+ if (match_nidmask(nid, nm, nr->nr_netstrfns))
+ return 1;
+
list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
if (nr->nr_netstrfns->nf_match_addr(
__be32_to_cpu(nid->nid_addr[0]),
return i;
}
+static int
+cfs_print_nidmasks(char *buffer, int count, struct list_head *nidmasks,
+ struct nidrange *nr)
+{
+ int i = 0;
+ struct nidmask *nm;
+ __u8 max;
+
+ list_for_each_entry(nm, nidmasks, nm_link) {
+ if (i != 0)
+ i += scnprintf(buffer + i, count - i, " ");
+
+ /* parse_nidmask() ensures nm_family is set to either AF_INET
+ * or AF_INET6
+ */
+ if (nm->nm_family == AF_INET) {
+ inet_ntop(nm->nm_family, &nm->nm_addr.ipv4.s_addr,
+ buffer + i, count - i);
+ max = 32;
+ } else {
+ inet_ntop(nm->nm_family, &nm->nm_addr.ipv6.s6_addr,
+ buffer + i, count - i);
+ max = 128;
+ }
+ i += strlen(buffer + i);
+ if (nm->nm_prefix_len < max)
+ i += scnprintf(buffer + i, count - i, "/%u",
+ nm->nm_prefix_len);
+ i += cfs_print_network(buffer + i, count - i, nr);
+ }
+
+ return i;
+}
+
/**
* Print a list of nidranges (\a nidlist) into the specified \a buffer.
* At max \a count characters can be printed into \a buffer.
{
int i = 0;
struct nidrange *nr;
+ bool need_space = false;
if (count <= 0)
return 0;
if (nr->nr_all != 0) {
assert(list_empty(&nr->nr_addrranges));
+ assert(list_empty(&nr->nr_nidmasks));
i += scnprintf(buffer + i, count - i, "*");
i += cfs_print_network(buffer + i, count - i, nr);
- } else {
+ continue;
+ }
+
+ if (!list_empty(&nr->nr_nidmasks)) {
+ i += cfs_print_nidmasks(buffer + i, count - i,
+ &nr->nr_nidmasks, nr);
+ need_space = true;
+ }
+
+ if (!list_empty(&nr->nr_addrranges)) {
+ if (need_space)
+ i += scnprintf(buffer + i, count - i, " ");
+
i += cfs_print_addrranges(buffer + i, count - i,
&nr->nr_addrranges, nr);
}
+ need_space = false;
}
return i;
}
}
return rc;
}
+
+static char *skip_spaces(const char *str)
+{
+ while (isspace(*str))
+ ++str;
+ return (char *)str;
+}
+
+char *strim(char *s)
+{
+ size_t size;
+ char *end;
+
+ size = strlen(s);
+ if (!size)
+ return s;
+
+ end = s + size - 1;
+ while (end >= s && isspace(*end))
+ end--;
+ *(end + 1) = '\0';
+
+ return skip_spaces(s);
+}
int (*nf_print_addrlist)(char *buffer, int count,
struct list_head *list);
int (*nf_match_addr)(u32 addr, struct list_head *list);
+ int (*nf_match_netmask)(const __be32 *addr, size_t asize,
+ const __be32 *netmask,
+ const __be32 *netaddr);
int (*nf_min_max)(struct list_head *nidlist, u32 *min_nid,
u32 *max_nid);
};
int libcfs_num_parse(char *str, int len, struct list_head *list);
char *libcfs_id2str(struct lnet_process_id id);
void cfs_free_nidlist(struct list_head *list);
-#ifdef __KERNEL__
-int cfs_parse_nidlist(char *str, struct list_head *list);
-#else
int cfs_parse_nidlist(char *str, int len, struct list_head *list);
-#endif
int cfs_print_nidlist(char *buffer, int count, struct list_head *list);
int cfs_match_nid(struct lnet_nid *nid, struct list_head *list);
int cfs_match_net(__u32 net_id, __u32 net_type,
int cfs_ip_addr_parse(char *str, int len, struct list_head *list);
int cfs_ip_addr_match(__u32 addr, struct list_head *list);
+int libcfs_ip_in_netmask(const __be32 *addr, size_t asize,
+ const __be32 *netmask,
+ const __be32 *netaddr);
int cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
char *max_nid, __kernel_size_t nidstr_length);
void cfs_expr_list_free_list(struct list_head *list);
#include <libcfs/libcfs.h>
#include <uapi/linux/lnet/nidstr.h>
#include <lnet/lib-types.h>
+#include <linux/ctype.h>
+#include <linux/inet.h>
+#include <linux/inetdevice.h>
/* max value for numeric network address */
#define MAX_NUMERIC_VALUE 0xffffffff
}
EXPORT_SYMBOL(libcfs_next_nidstring);
-/**
- * Nid range list syntax.
+/* NID range list syntax.
* \verbatim
*
* <nidlist> :== <nidrange> [ ' ' <nidrange> ]
* <nidrange> :== <addrrange> '@' <net>
* <addrrange> :== '*' |
- * <ipaddr_range> |
- * <cfs_expr_list>
- * <ipaddr_range> :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
- * <cfs_expr_list>
- * <cfs_expr_list> :== <number> |
+ * <netmask> |
+ * <ipv6_addr> |
+ * <ipv4_addr_range> |
+ * <numaddr_range>
+ * <netmask> :== An IPv4 or IPv6 network mask in CIDR notation.
+ * e.g. 192.168.1.0/24 or 2001:0db8::/32
+ * <ipv6_addr> :== A single IPv6 address
+ * <ipv4_addr_range> :==
+ * <numaddr_range>.<numaddr_range>.<numaddr_range>.<numaddr_range>
+ * <numaddr_range> :== <number> |
* <expr_list>
* <expr_list> :== '[' <range_expr> [ ',' <range_expr>] ']'
- * <range_expr> :== <number> |
+ * <range_expr> :== <number> |
* <number> '-' <number> |
* <number> '-' <number> '/' <number>
* <net> :== <netname> | <netname><number>
- * <netname> :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
- * "vib" | "ra" | "elan" | "mx" | "ptl"
+ * <netname> :== "lo" | "tcp" | "o2ib" | "gni" | "gip" | "ptlf" | "kfi"
* \endverbatim
*/
*/
struct list_head nr_addrranges;
/**
+ * List head for nidmask::nm_link.
+ */
+ struct list_head nr_nidmasks;
+ /**
* Flag indicating that *@<net> is found.
*/
int nr_all;
int nr_netnum;
};
+struct nidmask {
+ /* Link to nidrange::nr_nidmasks */
+ struct list_head nm_link;
+
+ /* This is the base address that was parsed */
+ union {
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+ } nm_addr;
+
+ /* Netmask derived from the prefix length */
+ union {
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+ } nm_netmask;
+
+ /* Network address derived from the base address and the netmask */
+ union {
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+ } nm_netaddr;
+
+ /* Address family */
+ sa_family_t nm_family;
+
+ /* Prefix length */
+ u8 nm_prefix_len;
+};
+
/**
* Structure to represent \<addrrange\> token of the syntax.
*/
&addrrange->ar_numaddr_ranges);
}
+static void
+init_ipv4_nidmask(struct sockaddr_in *sa, struct nidmask *nm)
+{
+ memcpy(&nm->nm_addr.ipv4, &sa->sin_addr.s_addr, sizeof(struct in_addr));
+ nm->nm_netmask.ipv4.s_addr = inet_make_mask(nm->nm_prefix_len);
+ nm->nm_netaddr.ipv4.s_addr = sa->sin_addr.s_addr &
+ nm->nm_netmask.ipv4.s_addr;
+}
+
+/* Note: The memory of struct nidmask is allocated via CFS_ALLOC_PTR, so it has
+ * been set to zero as required by this function.
+ */
+static void
+init_ipv6_nidmask(struct sockaddr_in6 *sa, struct nidmask *nm)
+{
+ int i, j;
+
+ memcpy(&nm->nm_addr.ipv6, &sa->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+
+ for (i = nm->nm_prefix_len, j = 0; i > 0; i -= 8, j++) {
+ if (i >= 8)
+ nm->nm_netmask.ipv6.s6_addr[j] = 0xff;
+ else
+ nm->nm_netmask.ipv6.s6_addr[j] =
+ (unsigned long)(0xffU << (8 - i));
+ }
+
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ nm->nm_netaddr.ipv6.s6_addr[i] = sa->sin6_addr.s6_addr[i] &
+ nm->nm_netmask.ipv6.s6_addr[i];
+}
+
+static u8
+parse_prefix_len(char *str)
+{
+ unsigned int max;
+ unsigned int prefix_len;
+ char *slash = strchr(str, '/');
+
+ /* IPv4 netmask must include an explicit prefix length */
+ if (!(slash || strchr(str, ':')))
+ return 0;
+
+ /* We treat an IPv6 address without a prefix length as having /128 */
+ if (!slash)
+ return 128;
+
+ if (strchr(str, ':'))
+ max = 128;
+ else
+ max = 32;
+
+ if (kstrtouint(slash + 1, 10, &prefix_len))
+ return 0;
+
+ if (prefix_len < 1 || prefix_len > max)
+ return 0;
+
+ return (u8)prefix_len;
+}
+
+static int
+parse_nidmask(char *str, struct nidrange *nr)
+{
+ struct nidmask *nm;
+ struct sockaddr_storage sa;
+ char *addrstr;
+
+ CFS_ALLOC_PTR(nm);
+ if (!nm)
+ return -ENOMEM;
+
+ /* Add to nr_nidmasks so that our caller can free us on error */
+ list_add_tail(&nm->nm_link, &nr->nr_nidmasks);
+
+ nm->nm_prefix_len = parse_prefix_len(str);
+ if (!nm->nm_prefix_len)
+ return -EINVAL;
+
+ addrstr = strsep(&str, "/");
+ if (rpc_pton(&init_net, addrstr, strlen(addrstr),
+ (struct sockaddr *)&sa, sizeof(sa)) == 0)
+ return -EINVAL;
+
+ nm->nm_family = sa.ss_family;
+ if (nm->nm_family == AF_INET6)
+ init_ipv6_nidmask((struct sockaddr_in6 *)&sa, nm);
+ else if (nm->nm_family == AF_INET)
+ init_ipv4_nidmask((struct sockaddr_in *)&sa, nm);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
/**
* Finds or creates struct nidrange.
*
return NULL;
list_add_tail(&nr->nr_link, nidlist);
INIT_LIST_HEAD(&nr->nr_addrranges);
+ INIT_LIST_HEAD(&nr->nr_nidmasks);
nr->nr_netstrfns = nf;
nr->nr_all = 0;
nr->nr_netnum = netnum;
{
char *addrrange;
char *net;
+ char *slash;
struct nidrange *nr;
+ int rc;
addrrange = strim(strsep(&str, "@"));
if (!str)
- goto failed;
+ return -EINVAL;
net = strim(str);
- if (strchr(net, '@') != NULL || !*net)
- goto failed;
+ if (strchr(net, '@') || !*net)
+ return -EINVAL;
nr = add_nidrange(net, nidlist);
- if (nr == NULL)
- goto failed;
+ if (!nr)
+ return -EINVAL;
- if (parse_addrange(addrrange, nr) != 0)
- goto failed;
+ /* Check for a '/' that does not appear inside '[]' */
+ slash = strchr(addrrange, '/');
+ if (strchr(addrrange, ':') || (slash && !strchr(slash, ']')))
+ rc = parse_nidmask(addrrange, nr);
+ else
+ rc = parse_addrange(addrrange, nr);
- return 0;
-failed:
- return -EINVAL;
+ return rc;
}
/**
}
}
+static void
+free_nidmasks(struct list_head *list)
+{
+ struct nidmask *nm;
+
+ while ((nm = list_first_entry_or_null(list,
+ struct nidmask,
+ nm_link)) != NULL) {
+ list_del(&nm->nm_link);
+ CFS_FREE_PTR(nm);
+ }
+}
+
/**
* Frees nidrange strutures of \a list.
*
list_for_each_safe(pos, next, list) {
nr = list_entry(pos, struct nidrange, nr_link);
free_addrranges(&nr->nr_addrranges);
+ free_nidmasks(&nr->nr_nidmasks);
list_del(pos);
CFS_FREE_PTR(nr);
}
* \retval -errno otherwise (-ENOMEM or -EINVAL)
*/
int
-cfs_parse_nidlist(char *orig, struct list_head *nidlist)
+cfs_parse_nidlist(char *orig, int len, struct list_head *nidlist)
{
int rc = 0;
char *str;
- orig = kstrdup(orig, GFP_KERNEL);
+ orig = kstrndup(orig, len, GFP_KERNEL);
if (!orig)
return -ENOMEM;
}
EXPORT_SYMBOL(cfs_parse_nidlist);
+static int
+match_nidmask(struct lnet_nid *nid, struct nidmask *nm, struct netstrfns *nf)
+{
+ __be32 addr[4] = { nid->nid_addr[0], nid->nid_addr[1],
+ nid->nid_addr[2], nid->nid_addr[3] };
+ __be32 *netmask, *netaddr;
+
+ if (!nf->nf_match_netmask)
+ return 0;
+
+ if (nid_is_nid4(nid) && nm->nm_family == AF_INET) {
+ netmask = (__be32 *)&nm->nm_netmask.ipv4.s_addr;
+ netaddr = (__be32 *)&nm->nm_netaddr.ipv4.s_addr;
+ } else if (!nid_is_nid4(nid) && nm->nm_family == AF_INET6) {
+ netmask = (__be32 *)&nm->nm_netmask.ipv6.s6_addr;
+ netaddr = (__be32 *)&nm->nm_netaddr.ipv6.s6_addr;
+ } else {
+ return 0;
+ }
+
+ return nf->nf_match_netmask(addr, NID_ADDR_BYTES(nid), netmask,
+ netaddr);
+}
+
/**
* Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
*
int cfs_match_nid(struct lnet_nid *nid, struct list_head *nidlist)
{
struct nidrange *nr;
+ struct nidmask *nm;
struct addrrange *ar;
- if (!nid_is_nid4(nid))
- return 0;
list_for_each_entry(nr, nidlist, nr_link) {
if (nr->nr_netstrfns->nf_type != nid->nid_type)
continue;
continue;
if (nr->nr_all)
return 1;
+
+ list_for_each_entry(nm, &nr->nr_nidmasks, nm_link)
+ if (match_nidmask(nid, nm, nr->nr_netstrfns))
+ return 1;
+
list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
if (nr->nr_netstrfns->nf_match_addr(
be32_to_cpu(nid->nid_addr[0]),
return i;
}
+static int
+cfs_print_nidmasks(char *buffer, int count, struct list_head *nidmasks,
+ struct nidrange *nr)
+{
+ int i = 0;
+ struct nidmask *nm;
+ struct sockaddr_storage sa = {};
+ u8 max;
+
+ list_for_each_entry(nm, nidmasks, nm_link) {
+ if (i != 0)
+ i += scnprintf(buffer + i, count - i, " ");
+
+ /* parse_nidmask() ensures nm_family is set to either AF_INET
+ * or AF_INET6
+ */
+ sa.ss_family = nm->nm_family;
+ if (nm->nm_family == AF_INET) {
+ memcpy(&((struct sockaddr_in *)(&sa))->sin_addr.s_addr,
+ &nm->nm_addr.ipv4, sizeof(struct in_addr));
+ max = 32;
+ } else {
+ memcpy(&((struct sockaddr_in6 *)(&sa))->sin6_addr.s6_addr,
+ &nm->nm_addr.ipv6, sizeof(struct in6_addr));
+ max = 128;
+ }
+ i += rpc_ntop((struct sockaddr *)&sa, buffer + i, count - i);
+ if (nm->nm_prefix_len < max)
+ i += scnprintf(buffer + i, count - i, "/%u",
+ nm->nm_prefix_len);
+ i += cfs_print_network(buffer + i, count - i, nr);
+ }
+
+ return i;
+}
+
/**
* Print a list of nidranges (\a nidlist) into the specified \a buffer.
* At max \a count characters can be printed into \a buffer.
{
int i = 0;
struct nidrange *nr;
+ bool need_space = false;
if (count <= 0)
return 0;
if (i != 0)
i += scnprintf(buffer + i, count - i, " ");
- if (nr->nr_all != 0) {
+ if (nr->nr_all) {
LASSERT(list_empty(&nr->nr_addrranges));
+ LASSERT(list_empty(&nr->nr_nidmasks));
i += scnprintf(buffer + i, count - i, "*");
i += cfs_print_network(buffer + i, count - i, nr);
- } else {
+ continue;
+ }
+
+ if (!list_empty(&nr->nr_nidmasks)) {
+ i += cfs_print_nidmasks(buffer + i, count - i,
+ &nr->nr_nidmasks, nr);
+ need_space = true;
+ }
+ if (!list_empty(&nr->nr_addrranges)) {
+ if (need_space)
+ i += scnprintf(buffer + i, count - i, " ");
i += cfs_print_addrranges(buffer + i, count - i,
&nr->nr_addrranges, nr);
}
+ need_space = false;
}
return i;
}
}
/**
+ * Matches address (\a addr) against the netmask encoded in \a netmask and
+ * \a netaddr.
+ *
+ * \retval 1 if \a addr matches
+ * \retval 0 otherwise
+ */
+int
+libcfs_ip_in_netmask(const __be32 *addr, size_t asize, const __be32 *netmask,
+ const __be32 *netaddr)
+{
+ if (asize == 4) {
+ struct in_addr nid_addr, masked_addr;
+
+ memcpy(&nid_addr.s_addr, addr, asize);
+
+ masked_addr.s_addr = nid_addr.s_addr &
+ (*(struct in_addr *)netmask).s_addr;
+
+ return memcmp(&masked_addr, netaddr, sizeof(masked_addr)) == 0;
+ } else if (asize == 16) {
+ struct in6_addr nid_addr, masked_addr;
+ int i;
+
+ memcpy(&nid_addr.s6_addr, addr, asize);
+
+ for (i = 0; i < 16; i++)
+ masked_addr.s6_addr[i] =
+ nid_addr.s6_addr[i] &
+ (*(struct in6_addr *)netmask).s6_addr[i];
+
+ return memcmp(&masked_addr, netaddr, sizeof(masked_addr)) == 0;
+ }
+
+ return 0;
+}
+
+/**
* Print the network part of the nidrange \a nr into the specified \a buffer.
*
* \retval number of characters written
.nf_str2addr_size = libcfs_ip_str2addr_size,
.nf_parse_addrlist = cfs_ip_addr_parse,
.nf_print_addrlist = libcfs_ip_addr_range_print,
- .nf_match_addr = cfs_ip_addr_match
+ .nf_match_addr = cfs_ip_addr_match,
+ .nf_match_netmask = libcfs_ip_in_netmask
},
{ .nf_type = O2IBLND,
.nf_name = "o2ib",
.nf_str2addr = libcfs_ip_str2addr,
.nf_parse_addrlist = cfs_ip_addr_parse,
.nf_print_addrlist = libcfs_ip_addr_range_print,
- .nf_match_addr = cfs_ip_addr_match
+ .nf_match_addr = cfs_ip_addr_match,
+ .nf_match_netmask = libcfs_ip_in_netmask
},
{ .nf_type = GNILND,
.nf_name = "gni",
}
}
+int lustre_lnet_debug_nidlist(char *nidstr, char *match_nid)
+{
+ struct list_head nidlist;
+ int rc;
+ char *buf = NULL;
+ size_t bsize = strlen(nidstr) + 1;
+
+ buf = malloc(bsize);
+ if (!buf) {
+ fprintf(stderr, "Cannot allocate memory for buffer\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&nidlist);
+ rc = cfs_parse_nidlist(nidstr, strlen(nidstr), &nidlist);
+ if (!rc) {
+ fprintf(stderr, "Unable to parse nidlist from: %s\n", nidstr);
+ goto failed;
+ }
+
+ if (cfs_print_nidlist(buf, bsize, &nidlist))
+ printf("nidlist parsed to: %s\n", buf);
+
+ if (match_nid) {
+ struct lnet_nid nid;
+
+ rc = libcfs_strnid(&nid, match_nid);
+ if (rc < 0) {
+ fprintf(stderr, "Invalid nid for matching %s\n",
+ match_nid);
+ goto failed;
+ }
+
+ rc = cfs_match_nid(&nid, &nidlist);
+ if (rc)
+ printf("%s matches nidlist %s\n", match_nid, nidstr);
+ else
+ printf("%s does not match nidlist %s\n", match_nid,
+ nidstr);
+ }
+
+ cfs_free_nidlist(&nidlist);
+ free(buf);
+
+ return 0;
+failed:
+ cfs_free_nidlist(&nidlist);
+ if (buf)
+ free(buf);
+ return LUSTRE_CFG_RC_BAD_PARAM;
+}
+
int lustre_lnet_parse_nidstr(char *nidstr, lnet_nid_t *lnet_nidlist,
int max_nids, char *err_str)
{
- int rc, num_nids = 0;
+ int num_nids = 0;
struct list_head nidlist;
if (!nidstr) {
}
INIT_LIST_HEAD(&nidlist);
- rc = cfs_parse_nidlist(nidstr, strlen(nidstr), &nidlist);
- if (rc == 0) {
+ if (!cfs_parse_nidlist(nidstr, strlen(nidstr), &nidlist)) {
snprintf(err_str, LNET_MAX_STR_LEN,
"Unable to parse nidlist from: %s\n", nidstr);
return LUSTRE_CFG_RC_BAD_PARAM;
}
- if (list_empty(&nidlist)) {
- snprintf(err_str, LNET_MAX_STR_LEN,
- "\"%s\" does not specify any valid nid lists", nidstr);
- return LUSTRE_CFG_RC_BAD_PARAM;
- }
-
num_nids = cfs_expand_nidlist(&nidlist, lnet_nidlist, max_nids);
cfs_free_nidlist(&nidlist);
int lustre_lnet_parse_nidstr(char *nidstr, lnet_nid_t *lnet_nidlist,
int max_nids, char *err_str);
+int lustre_lnet_debug_nidlist(char *nidstr, char *match_nid);
/* lustre_lnet_add_udsp
* Add a selection policy.
* src - source NID descriptor
static int jt_show_stats(int argc, char **argv);
static int jt_show_peer(int argc, char **argv);
static int jt_show_recovery(int argc, char **argv);
+static int jt_debug_nidlist(int argc, char **argv);
static int jt_show_global(int argc, char **argv);
static int jt_show_udsp(int argc, char **argv);
static int jt_show_fault(int argc, char **argv);
"\t--peer : list peer recovery queue\n"},
{"peer", jt_show_peer_debug_info, 0, "show peer debug info\n"
"\t--nid: peer's NID\n"},
+ {"nidlist", jt_debug_nidlist, 0, "debug nidlist parsing\n"},
{ 0, 0, 0, NULL }
};
return rc;
}
+static int jt_debug_nidlist(int argc, char **argv)
+{
+ int rc;
+
+ if (argc < 2) {
+ fprintf(stderr, "Missing nidlist argument\n");
+ return -EINVAL;
+ } else if (argc == 2) {
+ rc = lustre_lnet_debug_nidlist(argv[1], NULL);
+ } else if (argc == 3) {
+ rc = lustre_lnet_debug_nidlist(argv[1], argv[2]);
+ } else {
+ fprintf(stderr, "Too many arguments\n");
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
static int jt_show_peer_debug_info(int argc, char **argv)
{
int rc, opt;
RETURN(count);
}
- if (cfs_parse_nidlist(kernbuf, &tmp) < 0) {
+ if (cfs_parse_nidlist(kernbuf, strlen(kernbuf), &tmp)) {
errmsg = "can't parse";
GOTO(failed, rc = -EINVAL);
}
end += pos;
c = end[0];
end[0] = '\0';
- /* FIXME !!! Add IPv6 support to cfs_parse_nidlist */
- if (strchr(buf, ':')) {
- struct lnet_nid nid;
-
- if (libcfs_strnid(&nid, buf) < 0) {
- invalid = true;
- goto failed;
- }
+ if (cfs_parse_nidlist(buf, strlen(buf), &nidlist)) {
+ invalid = true;
+ goto failed;
} else {
- if (cfs_parse_nidlist(buf, &nidlist) < 0) {
- invalid = true;
- goto failed;
- } else {
- cfs_free_nidlist(&nidlist);
- }
+ cfs_free_nidlist(&nidlist);
}
end[0] = c;
end++;
struct nrs_tbf_rule *rule,
struct nrs_tbf_cmd *start)
{
+ size_t len = strlen(start->u.tc_start.ts_nids_str);
+
LASSERT(start->u.tc_start.ts_nids_str);
- OBD_ALLOC(rule->tr_nids_str,
- strlen(start->u.tc_start.ts_nids_str) + 1);
- if (rule->tr_nids_str == NULL)
- return -ENOMEM;
- memcpy(rule->tr_nids_str,
- start->u.tc_start.ts_nids_str,
- strlen(start->u.tc_start.ts_nids_str));
+ rule->tr_nids_str = kstrndup(start->u.tc_start.ts_nids_str,
+ len, GFP_KERNEL);
+ if (!rule->tr_nids_str)
+ return -ENOMEM;
INIT_LIST_HEAD(&rule->tr_nids);
if (!list_empty(&start->u.tc_start.ts_nids)) {
- if (cfs_parse_nidlist(rule->tr_nids_str,
- &rule->tr_nids) < 0) {
+ if (cfs_parse_nidlist(rule->tr_nids_str, len, &rule->tr_nids)) {
CERROR("nids {%s} illegal\n",
rule->tr_nids_str);
- OBD_FREE(rule->tr_nids_str,
- strlen(start->u.tc_start.ts_nids_str) + 1);
+ kfree(rule->tr_nids_str);
return -EINVAL;
}
}
static int nrs_tbf_nid_parse(struct nrs_tbf_cmd *cmd, char *id)
{
int rc;
+ size_t len;
rc = nrs_tbf_check_id_value(&id, "nid");
if (rc)
return rc;
- OBD_ALLOC(cmd->u.tc_start.ts_nids_str, strlen(id) + 1);
- if (cmd->u.tc_start.ts_nids_str == NULL)
- return -ENOMEM;
+ len = strlen(id);
- strcpy(cmd->u.tc_start.ts_nids_str, id);
+ cmd->u.tc_start.ts_nids_str = kstrndup(id, len, GFP_KERNEL);
+ if (!cmd->u.tc_start.ts_nids_str)
+ return -ENOMEM;
/* parse NID list */
- if (cfs_parse_nidlist(cmd->u.tc_start.ts_nids_str,
- &cmd->u.tc_start.ts_nids) < 0) {
+ if (cfs_parse_nidlist(cmd->u.tc_start.ts_nids_str, len,
+ &cmd->u.tc_start.ts_nids)) {
nrs_tbf_nid_cmd_fini(cmd);
return -EINVAL;
}
len -= 2;
if (strcmp(field, "nid") == 0) {
- if (cfs_parse_nidlist(str, &expr->te_cond) < 0)
+ if (cfs_parse_nidlist(str, len, &expr->te_cond) < 0)
GOTO(out, rc = -EINVAL);
expr->te_field = NRS_TBF_FIELD_NID;
} else if (strcmp(field, "jobid") == 0) {
}
run_test 42 "allow client/server mount/unmount with invalid config param"
+test_43a_check_nosquash_nids() {
+ local nidlist="$1"
+
+ set_persistent_param_and_check mds1 \
+ "mdt.$FSNAME-MDT0000.nosquash_nids" \
+ "$FSNAME-MDTall.mdt.nosquash_nids" \
+ "$nidlist"
+ wait_update $HOSTNAME \
+ "$LCTL get_param -n llite.${FSNAME}*.nosquash_nids" \
+ "$nidlist" ||
+ error "check llite nosquash_nids failed!"
+
+ ST=$(stat -c "%n: owner uid %u (%A)" $DIR/$tfile-rootfile)
+ dd if=$DIR/$tfile-rootfile 1>/dev/null 2>/dev/null ||
+ error "$ST: root read permission is denied"
+ echo "$ST: root read permission is granted - ok"
+
+ echo "666" |
+ dd conv=notrunc of=$DIR/$tfile-rootfile 1>/dev/null 2>/dev/null ||
+ error "$ST: root write permission is denied"
+ echo "$ST: root write permission is granted - ok"
+
+ ST=$(stat -c "%n: owner uid %u (%A)" $DIR/$tdir-rootdir)
+ rm $DIR/$tdir-rootdir/tfile-1 ||
+ error "$ST: root unlink permission is denied"
+ echo "$ST: root unlink permission is granted - ok"
+ touch $DIR/$tdir-rootdir/tfile-2 ||
+ error "$ST: root create permission is denied"
+ echo "$ST: root create permission is granted - ok"
+
+ # Re-create test file deleted above in case this function is called
+ # again
+ touch $DIR/$tdir-rootdir/tfile-1 || error "touch failed"
+}
+
test_43a() {
[[ "$MGS_VERSION" -ge $(version_code 2.5.58) ]] ||
skip "Need MDS version at least 2.5.58"
# put client's NID into nosquash_nids list,
# root should be able to access root file after that
#
- local NIDLIST=$($LCTL list_nids all | tr '\n' ' ')
- NIDLIST="2@gni $NIDLIST 192.168.0.[2,10]@tcp"
- NIDLIST=$(echo $NIDLIST | tr -s ' ' ' ')
- set_persistent_param_and_check mds1 \
- "mdt.$FSNAME-MDT0000.nosquash_nids" \
- "$FSNAME-MDTall.mdt.nosquash_nids" \
- "$NIDLIST"
- wait_update $HOSTNAME \
- "$LCTL get_param -n llite.${FSNAME}*.nosquash_nids" \
- "$NIDLIST" ||
- error "check llite nosquash_nids failed!"
+ local nidlist=$($LCTL list_nids all | tr '\n' ' ')
+ nidlist="2@gni $nidlist 192.168.0.[2,10]@tcp"
+ nidlist=$(echo $nidlist | tr -s ' ' ' ')
- ST=$(stat -c "%n: owner uid %u (%A)" $DIR/$tfile-rootfile)
- dd if=$DIR/$tfile-rootfile 1>/dev/null 2>/dev/null ||
- error "$ST: root read permission is denied"
- echo "$ST: root read permission is granted - ok"
+ test_43a_check_nosquash_nids "$nidlist"
- echo "666" |
- dd conv=notrunc of=$DIR/$tfile-rootfile 1>/dev/null 2>/dev/null ||
- error "$ST: root write permission is denied"
- echo "$ST: root write permission is granted - ok"
+ if ! [[ $NETTYPE =~ ^(tcp|o2ib) ]]; then
+ log "Skip nidmask test for NETTYPE = $NETTYPE"
+ cleanup || error "cleanup failed with $?"
+ return 0
+ fi
+
+ # check nosquash_nids:
+ # create a nidmask that contains the client's NID and place it
+ # into nosquash_nids list.
+ # root should be able to access root file after that
+ local interfaces=( $(lnet_if_list) )
+ local intf netmasks nm
+
+ for intf in ${interfaces[@]}; do
+ nm=$(ip -o -4 a s ${intf} | awk '{print $4}')
+ [[ -n $nm ]] && netmasks+=" $nm@${NETTYPE}"
+ nm=$(ip -o -6 a s ${intf} | grep -v 'fe80::' | awk '{print $4}')
+ [[ -n $nm ]] && netmasks+=" $nm@${NETTYPE}"
+ done
+
+ netmasks="${netmasks/ }"
+
+ if [[ -z $netmasks ]]; then
+ error "Unable to determine netmasks for ${interfaces[@]}"
+ fi
+
+ test_43a_check_nosquash_nids "$netmasks"
+
+ # cleanup test dir/files
+ rm -rf $DIR/$tfile-* $DIR/$tdir-rootdir ||
+ error "Failed to remove test files/dir rc = $?"
- ST=$(stat -c "%n: owner uid %u (%A)" $DIR/$tdir-rootdir)
- rm $DIR/$tdir-rootdir/tfile-1 ||
- error "$ST: root unlink permission is denied"
- echo "$ST: root unlink permission is granted - ok"
- touch $DIR/$tdir-rootdir/tfile-2 ||
- error "$ST: root create permission is denied"
- echo "$ST: root create permission is granted - ok"
cleanup || error "cleanup failed with $?"
}
run_test 43a "check root_squash and nosquash_nids"
INIT_LIST_HEAD(&nidlist);
- if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
- &nidlist) <= 0) {
+ if (!cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
+ &nidlist)) {
fprintf(stderr,
"error: nodemap_xxx_range: can't parse nid range: %s\n",
nodemap_range);