Whamcloud - gitweb
LU-9121 lnet: Delete a selection policy
[fs/lustre-release.git] / lnet / utils / lnetconfig / liblnetconfig_udsp.c
index f0a05d6..6193c98 100644 (file)
@@ -42,6 +42,7 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #include <ctype.h>
+#include <linux/lnet/lnet-dlc.h>
 #include "liblnetconfig.h"
 
 static inline bool
@@ -274,3 +275,342 @@ failed:
        lnet_udsp_free(udsp, true);
        return NULL;
 }
+
+static inline int
+lnet_get_list_len(struct list_head *list)
+{
+       struct list_head *l;
+       int count = 0;
+
+       list_for_each(l, list)
+               count++;
+
+       return count;
+}
+
+static size_t
+lnet_size_marshaled_nid_descr(struct lnet_ud_nid_descr *descr)
+{
+       struct cfs_expr_list *expr;
+       int expr_count = 0;
+       int range_count = 0;
+       size_t size = sizeof(struct lnet_ioctl_udsp_descr);
+
+       if (!lnet_udsp_criteria_present(descr))
+               return size;
+
+       if (!list_empty(&descr->ud_net_id.udn_net_num_range)) {
+               expr = list_entry(descr->ud_net_id.udn_net_num_range.next,
+                                 struct cfs_expr_list, el_link);
+               range_count = lnet_get_list_len(&expr->el_exprs);
+       }
+
+       /* count the number of cfs_range_expr in the address expressions */
+       list_for_each_entry(expr, &descr->ud_addr_range, el_link) {
+               expr_count++;
+               range_count += lnet_get_list_len(&expr->el_exprs);
+       }
+
+       size += (sizeof(struct lnet_expressions) * expr_count);
+       size += (sizeof(struct lnet_range_expr) * range_count);
+
+       return size;
+}
+
+size_t
+lnet_get_udsp_size(struct lnet_udsp *udsp)
+{
+       size_t size = sizeof(struct lnet_ioctl_udsp);
+
+       size += lnet_size_marshaled_nid_descr(&udsp->udsp_src);
+       size += lnet_size_marshaled_nid_descr(&udsp->udsp_dst);
+       size += lnet_size_marshaled_nid_descr(&udsp->udsp_rte);
+
+       return size;
+}
+
+static void
+copy_exprs(struct cfs_expr_list *expr, void __user **bulk,
+          __s32 *bulk_size)
+{
+       struct cfs_range_expr *range;
+       struct lnet_range_expr range_expr;
+
+       /* copy over the net range expressions to the bulk */
+       list_for_each_entry(range, &expr->el_exprs, re_link) {
+               range_expr.re_lo = range->re_lo;
+               range_expr.re_hi = range->re_hi;
+               range_expr.re_stride = range->re_stride;
+               memcpy(*bulk, &range_expr, sizeof(range_expr));
+               *bulk += sizeof(range_expr);
+               *bulk_size -= sizeof(range_expr);
+       }
+}
+
+static int
+copy_nid_range(struct lnet_ud_nid_descr *nid_descr, char *type,
+               void __user **bulk, __s32 *bulk_size)
+{
+       struct lnet_ioctl_udsp_descr ioc_udsp_descr = { { 0 } };
+       struct cfs_expr_list *expr;
+       struct lnet_expressions ioc_expr;
+       int expr_count;
+       int net_expr_count = 0;
+
+       ioc_udsp_descr.iud_src_hdr.ud_descr_type = *(__u32 *)type;
+
+       /* if criteria not present, copy over the static part of the NID
+        * descriptor
+        */
+       if (!lnet_udsp_criteria_present(nid_descr)) {
+               memcpy(*bulk, &ioc_udsp_descr,
+                       sizeof(ioc_udsp_descr));
+               *bulk += sizeof(ioc_udsp_descr);
+               *bulk_size -= sizeof(ioc_udsp_descr);
+               return 0;
+       }
+
+       expr_count = lnet_get_list_len(&nid_descr->ud_addr_range);
+
+       /* copy the net information */
+       if (!list_empty(&nid_descr->ud_net_id.udn_net_num_range)) {
+               expr = list_entry(nid_descr->ud_net_id.udn_net_num_range.next,
+                                 struct cfs_expr_list, el_link);
+               net_expr_count = lnet_get_list_len(&expr->el_exprs);
+       } else {
+               net_expr_count = 0;
+       }
+
+       /* set the total expression count */
+       ioc_udsp_descr.iud_src_hdr.ud_descr_count = expr_count;
+       ioc_udsp_descr.iud_net.ud_net_type =
+               nid_descr->ud_net_id.udn_net_type;
+       ioc_udsp_descr.iud_net.ud_net_num_expr.le_count = net_expr_count;
+
+       /* copy over the header info to the bulk */
+       memcpy(*bulk, &ioc_udsp_descr, sizeof(ioc_udsp_descr));
+       *bulk += sizeof(ioc_udsp_descr);
+       *bulk_size -= sizeof(ioc_udsp_descr);
+
+       /* copy over the net num expression if it exists */
+       if (net_expr_count)
+               copy_exprs(expr, bulk, bulk_size);
+
+       /* copy the address range */
+       list_for_each_entry(expr, &nid_descr->ud_addr_range, el_link) {
+               ioc_expr.le_count = lnet_get_list_len(&expr->el_exprs);
+               memcpy(*bulk, &ioc_expr, sizeof(ioc_expr));
+               *bulk += sizeof(ioc_expr);
+               *bulk_size -= sizeof(ioc_expr);
+
+               copy_exprs(expr, bulk, bulk_size);
+       }
+
+       return 0;
+}
+
+static int
+lnet_udsp_marshal(struct lnet_udsp *udsp, void *bulk,
+                 __s32 bulk_size)
+{
+       struct lnet_ioctl_udsp *ioc_udsp;
+       int rc = -ENOMEM;
+
+       /* make sure user space allocated enough buffer to marshal the
+        * udsp
+        */
+       if (bulk_size < lnet_get_udsp_size(udsp))
+               return -EINVAL;
+
+       ioc_udsp = bulk;
+
+       ioc_udsp->iou_idx = udsp->udsp_idx;
+       ioc_udsp->iou_action_type = udsp->udsp_action_type;
+       ioc_udsp->iou_action.priority = udsp->udsp_action.udsp_priority;
+
+       bulk += sizeof(*ioc_udsp);
+       bulk_size -= sizeof(*ioc_udsp);
+
+       rc = copy_nid_range(&udsp->udsp_src, "SRC", &bulk, &bulk_size);
+       if (rc != 0)
+               return rc;
+
+       rc = copy_nid_range(&udsp->udsp_dst, "DST", &bulk, &bulk_size);
+       if (rc != 0)
+               return rc;
+
+       rc = copy_nid_range(&udsp->udsp_rte, "RTE", &bulk, &bulk_size);
+
+       return rc;
+}
+
+static enum lnet_udsp_action_type
+lnet_str2udsp_action(char *type)
+{
+       if (!type)
+               return EN_LNET_UDSP_ACTION_NONE;
+
+       if (!strncmp(type, "priority", strlen("priority")))
+               return EN_LNET_UDSP_ACTION_PRIORITY;
+
+       if (!strncmp(type, "pref", strlen("pref")))
+               return EN_LNET_UDSP_ACTION_PREFERRED_LIST;
+
+       return EN_LNET_UDSP_ACTION_NONE;
+}
+
+int lustre_lnet_add_udsp(char *src, char *dst, char *rte,
+                        char *type, union lnet_udsp_action *action,
+                        int idx, int seq_no, struct cYAML **err_rc)
+{
+       struct lnet_udsp *udsp = NULL;
+       struct lnet_ioctl_udsp *udsp_bulk;
+       int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+       void *bulk = NULL;
+       __u32 bulk_size;
+       char err_str[LNET_MAX_STR_LEN];
+       enum lnet_udsp_action_type action_type;
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+
+       action_type = lnet_str2udsp_action(type);
+       if (action_type == EN_LNET_UDSP_ACTION_NONE) {
+               snprintf(err_str, sizeof(err_str),
+                        "\"bad action type specified: %s\"", type);
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       /* sanitize parameters:
+        * src-dst can be simultaneously present
+        * dst-rte can be simultaneously present
+        */
+       if ((!src && !rte && !dst) ||
+           (src && rte && dst) ||
+           (src && rte && !dst)) {
+               snprintf(err_str, sizeof(err_str),
+                 "\"The combination of src, dst and rte is not supported\"");
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       udsp = lnet_udsp_alloc();
+       if (!udsp) {
+               snprintf(err_str, sizeof(err_str), "\"out of memory\"");
+               goto out;
+       }
+
+       udsp->udsp_idx = idx;
+       udsp->udsp_action_type = action_type;
+
+       /* a priority of -1 will result in the lowest possible priority */
+       if (action_type == EN_LNET_UDSP_ACTION_PRIORITY)
+               udsp->udsp_action.udsp_priority = action->udsp_priority;
+
+        /* override with the default
+         * if priority is expected, but not specified
+         */
+       if (!rte && ((dst && !src) || (src && !dst)) &&
+            action_type != EN_LNET_UDSP_ACTION_PRIORITY) {
+               udsp->udsp_action_type = EN_LNET_UDSP_ACTION_PRIORITY;
+               udsp->udsp_action.udsp_priority = 0;
+       }
+
+       if (src) {
+               rc = cfs_parse_nid_parts(src, &udsp->udsp_src.ud_addr_range,
+                               &udsp->udsp_src.ud_net_id.udn_net_num_range,
+                               &udsp->udsp_src.ud_net_id.udn_net_type);
+               if (rc < 0) {
+                       snprintf(err_str,
+                                sizeof(err_str),
+                                "\failed to parse src parameter\"");
+                       goto out;
+               }
+       }
+       if (dst) {
+               rc = cfs_parse_nid_parts(dst, &udsp->udsp_dst.ud_addr_range,
+                               &udsp->udsp_dst.ud_net_id.udn_net_num_range,
+                               &udsp->udsp_dst.ud_net_id.udn_net_type);
+               if (rc < 0) {
+                       snprintf(err_str,
+                                sizeof(err_str),
+                                "\failed to parse dst parameter\"");
+                       goto out;
+               }
+       }
+       if (rte) {
+               rc = cfs_parse_nid_parts(rte, &udsp->udsp_rte.ud_addr_range,
+                               &udsp->udsp_rte.ud_net_id.udn_net_num_range,
+                               &udsp->udsp_rte.ud_net_id.udn_net_type);
+               if (rc < 0) {
+                       snprintf(err_str,
+                                sizeof(err_str),
+                                "\failed to parse rte parameter\"");
+                       goto out;
+               }
+       }
+
+       bulk_size = lnet_get_udsp_size(udsp);
+       bulk = calloc(1, bulk_size);
+       if (!bulk) {
+               rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+               snprintf(err_str, sizeof(err_str), "\"out of memory\"");
+               goto out;
+       }
+
+       udsp_bulk = bulk;
+       LIBCFS_IOC_INIT_V2(*udsp_bulk, iou_hdr);
+       udsp_bulk->iou_hdr.ioc_len = bulk_size;
+       udsp_bulk->iou_bulk_size = bulk_size - sizeof(*udsp_bulk);
+
+       rc = lnet_udsp_marshal(udsp, bulk, bulk_size);
+       if (rc != LUSTRE_CFG_RC_NO_ERR) {
+               rc = LUSTRE_CFG_RC_MARSHAL_FAIL;
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"failed to marshal udsp\"");
+               goto out;
+       }
+
+       udsp_bulk->iou_bulk = bulk + sizeof(*udsp_bulk);
+
+       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_UDSP, bulk);
+       if (rc < 0) {
+               rc = errno;
+               snprintf(err_str, sizeof(err_str),
+                        "\"cannot add udsp: %s\"", strerror(errno));
+               goto out;
+       }
+
+       rc = LUSTRE_CFG_RC_NO_ERR;
+
+out:
+       if (bulk)
+               free(bulk);
+       if (udsp)
+               lnet_udsp_free(udsp, false);
+       cYAML_build_error(rc, seq_no, ADD_CMD, "udsp", err_str, err_rc);
+       return rc;
+}
+
+int lustre_lnet_del_udsp(unsigned int idx, int seq_no, struct cYAML **err_rc)
+{
+       int rc;
+       char err_str[LNET_MAX_STR_LEN];
+       struct lnet_ioctl_udsp udsp_bulk;
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+
+       LIBCFS_IOC_INIT_V2(udsp_bulk, iou_hdr);
+       udsp_bulk.iou_idx = idx;
+
+       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_UDSP, &udsp_bulk);
+       if (rc < 0) {
+               rc = -errno;
+               snprintf(err_str, sizeof(err_str),
+                        "\"cannot del udsp: %s\"", strerror(rc));
+       }
+
+       cYAML_build_error(rc, seq_no, ADD_CMD, "udsp", err_str, err_rc);
+       return rc;
+}