"failed to get route param");
GOTO(report_err, rc);
}
+
+ rc = libcfs_strnid(&tmp.lrp_gateway, strim(gw));
+ if (rc < 0) {
+ NL_SET_ERR_MSG(extack,
+ "cannot parse gateway");
+ GOTO(report_err, rc = -ENODEV);
+ }
rc = 0;
- libcfs_strnid(&tmp.lrp_gateway, strim(gw));
} else if (nla_strcmp(route, "hop") == 0) {
route = nla_next(route, &rem2);
if (nla_type(route) !=
}
#endif
+static int lnet_route_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nlmsghdr *nlh = nlmsg_hdr(skb);
+ struct genlmsghdr *gnlh = nlmsg_data(nlh);
+ struct nlattr *params = genlmsg_data(gnlh);
+ int msg_len, rem, rc = 0;
+ struct nlattr *attr;
+
+ mutex_lock(&the_lnet.ln_api_mutex);
+ if (the_lnet.ln_state != LNET_STATE_RUNNING) {
+ GENL_SET_ERR_MSG(info, "Network is down");
+ mutex_unlock(&the_lnet.ln_api_mutex);
+ return -ENETDOWN;
+ }
+
+ msg_len = genlmsg_len(gnlh);
+ if (!msg_len) {
+ GENL_SET_ERR_MSG(info, "no configuration");
+ mutex_unlock(&the_lnet.ln_api_mutex);
+ return -ENOMSG;
+ }
+
+ if (!(nla_type(params) & LN_SCALAR_ATTR_LIST)) {
+ GENL_SET_ERR_MSG(info, "invalid configuration");
+ mutex_unlock(&the_lnet.ln_api_mutex);
+ return -EINVAL;
+ }
+
+ nla_for_each_nested(attr, params, rem) {
+ u32 net_id = LNET_NET_ANY, hops = LNET_UNDEFINED_HOPS;
+ u32 priority = 0, sensitivity = 1;
+ struct lnet_nid gw_nid = LNET_ANY_NID;
+ struct nlattr *route_prop;
+ int rem2;
+
+ if (nla_type(attr) != LN_SCALAR_ATTR_LIST)
+ continue;
+
+ nla_for_each_nested(route_prop, attr, rem2) {
+ char tmp[LNET_NIDSTR_SIZE];
+ ssize_t len;
+ s64 num;
+
+ if (nla_type(route_prop) != LN_SCALAR_ATTR_VALUE)
+ continue;
+
+ if (nla_strcmp(route_prop, "net") == 0) {
+ route_prop = nla_next(route_prop, &rem2);
+ if (nla_type(route_prop) !=
+ LN_SCALAR_ATTR_VALUE) {
+ GENL_SET_ERR_MSG(info,
+ "net is invalid key");
+ GOTO(report_err, rc = -EINVAL);
+ }
+
+ len = nla_strscpy(tmp, route_prop, sizeof(tmp));
+ if (len < 0) {
+ GENL_SET_ERR_MSG(info,
+ "net key string is invalid");
+ GOTO(report_err, rc = len);
+ }
+
+ net_id = libcfs_str2net(tmp);
+ if (!net_id) {
+ GENL_SET_ERR_MSG(info,
+ "cannot parse remote net");
+ GOTO(report_err, rc = -ENODEV);
+ }
+
+ if (LNET_NETTYP(net_id) == LOLND) {
+ GENL_SET_ERR_MSG(info,
+ "setting @lo not allowed");
+ GOTO(report_err, rc = -EACCES);
+ }
+
+ if (net_id == LNET_NET_ANY) {
+ GENL_SET_ERR_MSG(info,
+ "setting LNET_NET_ANY not allowed");
+ GOTO(report_err, rc = -ENXIO);
+ }
+ } else if (nla_strcmp(route_prop, "gateway") == 0) {
+ route_prop = nla_next(route_prop, &rem2);
+ if (nla_type(route_prop) !=
+ LN_SCALAR_ATTR_VALUE) {
+ GENL_SET_ERR_MSG(info,
+ "gateway is invalid key");
+ GOTO(report_err, rc = -EINVAL);
+ }
+
+ len = nla_strscpy(tmp, route_prop, sizeof(tmp));
+ if (len < 0) {
+ GENL_SET_ERR_MSG(info,
+ "gateway string is invalid");
+ GOTO(report_err, rc = len);
+ }
+
+ rc = libcfs_strnid(&gw_nid, strim(tmp));
+ if (rc < 0) {
+ GENL_SET_ERR_MSG(info,
+ "cannot parse gateway");
+ GOTO(report_err, rc = -ENODEV);
+ }
+ } else if (nla_strcmp(route_prop, "hop") == 0) {
+ route_prop = nla_next(route_prop, &rem2);
+ if (nla_type(route_prop) !=
+ LN_SCALAR_ATTR_INT_VALUE) {
+ GENL_SET_ERR_MSG(info,
+ "hop has invalid key");
+ GOTO(report_err, rc = -EINVAL);
+ }
+
+ hops = nla_get_s64(route_prop);
+ if (hops < 1 || hops > 255) {
+ GENL_SET_ERR_MSG(info,
+ "invalid hop count must be between 1 and 255");
+ GOTO(report_err, rc = -EINVAL);
+ }
+ } else if (nla_strcmp(route_prop, "priority") == 0) {
+ route_prop = nla_next(route_prop, &rem2);
+ if (nla_type(route_prop) !=
+ LN_SCALAR_ATTR_INT_VALUE) {
+ GENL_SET_ERR_MSG(info,
+ "priority has invalid key");
+ GOTO(report_err, rc = -EINVAL);
+ }
+
+ num = nla_get_s64(route_prop);
+ if (num < 0) {
+ GENL_SET_ERR_MSG(info,
+ "invalid priority, must not be negative");
+ GOTO(report_err, rc = -EINVAL);
+ }
+ priority = num;
+ } else if (nla_strcmp(route_prop,
+ "health_sensitivity") == 0) {
+ route_prop = nla_next(route_prop, &rem2);
+ if (nla_type(route_prop) !=
+ LN_SCALAR_ATTR_INT_VALUE) {
+ GENL_SET_ERR_MSG(info,
+ "sensitivity has invalid key");
+ GOTO(report_err, rc = -EINVAL);
+ }
+
+ num = nla_get_s64(route_prop);
+ if (num < 1) {
+ GENL_SET_ERR_MSG(info,
+ "invalid health sensitivity, must be 1 or greater");
+ GOTO(report_err, rc = -EINVAL);
+ }
+ sensitivity = num;
+ }
+ }
+
+ if (net_id == LNET_NET_ANY) {
+ GENL_SET_ERR_MSG(info,
+ "missing mandatory parameter: network");
+ GOTO(report_err, rc = -ENODEV);
+ }
+
+ if (LNET_NID_IS_ANY(&gw_nid)) {
+ GENL_SET_ERR_MSG(info,
+ "missing mandatory parameter: gateway");
+ GOTO(report_err, rc = -ENODEV);
+ }
+
+ if (info->nlhdr->nlmsg_flags & NLM_F_CREATE) {
+ rc = lnet_add_route(net_id, hops, &gw_nid, priority,
+ sensitivity);
+ if (rc < 0) {
+ switch (rc) {
+ case -EINVAL:
+ GENL_SET_ERR_MSG(info,
+ "invalid settings for route creation");
+ break;
+ case -EHOSTUNREACH:
+ GENL_SET_ERR_MSG(info,
+ "No interface configured on the same net as gateway");
+ break;
+ case -ESHUTDOWN:
+ GENL_SET_ERR_MSG(info,
+ "Network is down");
+ break;
+ case -EEXIST:
+ GENL_SET_ERR_MSG(info,
+ "Route already exists or the specified network is local");
+ break;
+ default:
+ GENL_SET_ERR_MSG(info,
+ "failed to create route");
+ break;
+ }
+ GOTO(report_err, rc);
+ }
+ } else if (!(info->nlhdr->nlmsg_flags & NLM_F_CREATE)) {
+ rc = lnet_del_route(net_id, &gw_nid);
+ if (rc < 0) {
+ GENL_SET_ERR_MSG(info,
+ "failed to delete route");
+ GOTO(report_err, rc);
+ }
+ }
+ }
+report_err:
+ mutex_unlock(&the_lnet.ln_api_mutex);
+
+ return rc;
+}
+
static inline struct lnet_genl_ping_list *
lnet_ping_dump_ctx(struct netlink_callback *cb)
{
},
{
.cmd = LNET_CMD_ROUTES,
+ .flags = GENL_ADMIN_PERM,
#ifdef HAVE_NETLINK_CALLBACK_START
.start = lnet_route_show_start,
.dumpit = lnet_route_show_dump,
.dumpit = lnet_old_route_show_dump,
#endif
.done = lnet_route_show_done,
+ .doit = lnet_route_cmd,
},
{
.cmd = LNET_CMD_PING,
return rc;
}
+static int yaml_lnet_router_gateways(yaml_emitter_t *output, const char *nw,
+ const char *gw, int hops, int prio,
+ int sen)
+{
+ char num[INT_STRING_LEN];
+ yaml_event_t event;
+ int rc;
+
+ yaml_mapping_start_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_MAP_TAG, 1,
+ YAML_BLOCK_MAPPING_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ if (nw) {
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)"net",
+ strlen("net"), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)nw,
+ strlen(nw), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+ }
+
+ if (gw) {
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)"gateway",
+ strlen("gateway"), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)gw,
+ strlen(gw), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+ }
+
+ if (hops != -1) {
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)"hop",
+ strlen("hop"), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ snprintf(num, sizeof(num), "%d", hops);
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_INT_TAG,
+ (yaml_char_t *)num,
+ strlen(num), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+ }
+
+ if (prio != -1) {
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)"priority",
+ strlen("priority"), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ snprintf(num, sizeof(num), "%d", prio);
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_INT_TAG,
+ (yaml_char_t *)num,
+ strlen(num), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+ }
+
+ if (sen != -1) {
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)"health_sensitivity",
+ strlen("health_sensitivity"),
+ 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ snprintf(num, sizeof(num), "%d", sen);
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_INT_TAG,
+ (yaml_char_t *)num,
+ strlen(num), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(output, &event);
+ if (rc == 0)
+ goto emitter_error;
+ }
+
+ yaml_mapping_end_event_initialize(&event);
+ rc = yaml_emitter_emit(output, &event);
+emitter_error:
+ return rc;
+}
+
static int yaml_lnet_route(char *nw, char *gw, int hops, int prio, int sen,
int version, int flags)
{
+ struct nid_node head, *entry;
struct nl_sock *sk = NULL;
const char *msg = NULL;
yaml_emitter_t output;
yaml_event_t event;
int rc;
+ if (!(flags & NLM_F_DUMP) && (!nw || !gw)) {
+ fprintf(stdout, "missing mandatory parameters:'%s'\n",
+ (!nw && !gw) ? "net , gateway" :
+ !nw ? "net" : "gateway");
+ return -EINVAL;
+ }
+
/* Create Netlink emitter to send request to kernel */
sk = nl_socket_alloc();
if (!sk)
if (rc == 0)
goto emitter_error;
- if (nw || gw || hops != -1 || prio != -1) {
- char num[INT_STRING_LEN];
+ /* NLM_F_DUMP can have no arguments */
+ if (nw || gw) {
+ NL_INIT_LIST_HEAD(&head.children);
+ nl_init_list_head(&head.list);
+ if (gw) {
+ rc = lustre_lnet_parse_nid_range(&head, gw, &msg);
+ if (rc < 0) {
+ lustre_lnet_free_list(&head);
+ yaml_emitter_delete(&output);
+ errno = rc;
+ rc = 0;
+ goto free_reply;
+ }
+ }
yaml_sequence_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_SEQ_TAG,
if (rc == 0)
goto emitter_error;
- if (nw) {
- yaml_mapping_start_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_MAP_TAG,
- 1,
- YAML_BLOCK_MAPPING_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_scalar_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_STR_TAG,
- (yaml_char_t *)"net",
- strlen("net"), 1, 0,
- YAML_PLAIN_SCALAR_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_scalar_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_STR_TAG,
- (yaml_char_t *)nw,
- strlen(nw), 1, 0,
- YAML_PLAIN_SCALAR_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_mapping_end_event_initialize(&event);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
- }
-
- if (gw) {
- yaml_mapping_start_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_MAP_TAG,
- 1,
- YAML_BLOCK_MAPPING_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_scalar_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_STR_TAG,
- (yaml_char_t *)"gateway",
- strlen("gateway"), 1, 0,
- YAML_PLAIN_SCALAR_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_scalar_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_STR_TAG,
- (yaml_char_t *)gw,
- strlen(gw), 1, 0,
- YAML_PLAIN_SCALAR_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_mapping_end_event_initialize(&event);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
- }
-
- if (hops != -1) {
- yaml_mapping_start_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_MAP_TAG,
- 1,
- YAML_BLOCK_MAPPING_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_scalar_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_STR_TAG,
- (yaml_char_t *)"hop",
- strlen("hop"), 1, 0,
- YAML_PLAIN_SCALAR_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- snprintf(num, sizeof(num), "%d", hops);
- yaml_scalar_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_INT_TAG,
- (yaml_char_t *)num,
- strlen(num), 1, 0,
- YAML_PLAIN_SCALAR_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_mapping_end_event_initialize(&event);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
- }
-
- if (prio != -1) {
- yaml_mapping_start_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_MAP_TAG,
- 1,
- YAML_BLOCK_MAPPING_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_scalar_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_STR_TAG,
- (yaml_char_t *)"priority",
- strlen("priority"), 1, 0,
- YAML_PLAIN_SCALAR_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- snprintf(num, sizeof(num), "%d", prio);
- yaml_scalar_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_INT_TAG,
- (yaml_char_t *)num,
- strlen(num), 1, 0,
- YAML_PLAIN_SCALAR_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_mapping_end_event_initialize(&event);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
- }
-
- if (sen != -1) {
- yaml_mapping_start_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_MAP_TAG,
- 1,
- YAML_BLOCK_MAPPING_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- yaml_scalar_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_STR_TAG,
- (yaml_char_t *)"health_sensitivity",
- strlen("health_sensitivity"),
- 1, 0,
- YAML_PLAIN_SCALAR_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
-
- snprintf(num, sizeof(num), "%d", sen);
- yaml_scalar_event_initialize(&event, NULL,
- (yaml_char_t *)YAML_INT_TAG,
- (yaml_char_t *)num,
- strlen(num), 1, 0,
- YAML_PLAIN_SCALAR_STYLE);
- rc = yaml_emitter_emit(&output, &event);
- if (rc == 0)
- goto emitter_error;
+ if (!nl_list_empty(&head.children)) {
+ nl_list_for_each_entry(entry, &head.children, list) {
+ const char *nid = entry->nidstr;
- yaml_mapping_end_event_initialize(&event);
- rc = yaml_emitter_emit(&output, &event);
+ rc = yaml_lnet_router_gateways(&output, nw, nid,
+ hops, prio, sen);
+ if (rc == 0)
+ goto emitter_error;
+ }
+ } else {
+ rc = yaml_lnet_router_gateways(&output, nw, NULL, hops,
+ prio, sen);
if (rc == 0)
goto emitter_error;
}
yaml_document_t errmsg;
rc = yaml_parser_load(&reply, &errmsg);
- if (rc == 1 && flags == NLM_F_DUMP) {
+ if (rc == 1 && (flags & NLM_F_DUMP)) {
yaml_emitter_t debug;
rc = yaml_emitter_initialize(&debug);
if (rc == 1) {
- yaml_emitter_set_indent(&debug, 6);
+ yaml_emitter_set_indent(&debug,
+ LNET_DEFAULT_INDENT);
yaml_emitter_set_output_file(&debug,
stdout);
rc = yaml_emitter_dump(&debug, &errmsg);
const char *const short_options = "n:g:c:p:";
static const struct option long_options[] = {
- { .name = "net", .has_arg = required_argument, .val = 'n' },
- { .name = "gateway", .has_arg = required_argument, .val = 'g' },
- { .name = "hop", .has_arg = required_argument, .val = 'c' },
- { .name = "hop-count", .has_arg = required_argument, .val = 'c' },
- { .name = "priority", .has_arg = required_argument, .val = 'p' },
- { .name = "health_sensitivity", .has_arg = required_argument, .val = 's' },
- { .name = NULL } };
+ { .name = "net", .has_arg = required_argument, .val = 'n' },
+ { .name = "gateway", .has_arg = required_argument, .val = 'g' },
+ { .name = "hop", .has_arg = required_argument, .val = 'c' },
+ { .name = "hop-count", .has_arg = required_argument, .val = 'c' },
+ { .name = "priority", .has_arg = required_argument, .val = 'p' },
+ { .name = "health_sensitivity", .has_arg = required_argument, .val = 's' },
+ { .name = NULL }
+ };
rc = check_cmd(route_cmds, "route", "add", 0, argc, argv);
if (rc)
}
}
+ rc = yaml_lnet_route(network, gateway, hop, prio, sen,
+ LNET_GENL_VERSION, NLM_F_CREATE);
+ if (rc <= 0) {
+ if (rc == -EOPNOTSUPP)
+ goto old_api;
+ return rc;
+ }
+old_api:
rc = lustre_lnet_config_route(network, gateway, hop, prio, sen, -1,
&err_rc);
char *network = NULL, *gateway = NULL;
struct cYAML *err_rc = NULL;
int rc, opt;
-
const char *const short_options = "n:g:";
static const struct option long_options[] = {
{ .name = "net", .has_arg = required_argument, .val = 'n' },
{ .name = "gateway", .has_arg = required_argument, .val = 'g' },
- { .name = NULL } };
+ { .name = NULL }
+ };
rc = check_cmd(route_cmds, "route", "del", 0, argc, argv);
if (rc)
}
}
+ rc = yaml_lnet_route(network, gateway, -1, -1, -1, LNET_GENL_VERSION,
+ 0);
+ if (rc <= 0) {
+ if (rc == -EOPNOTSUPP)
+ goto old_api;
+ return rc;
+ }
+old_api:
rc = lustre_lnet_del_route(network, gateway, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)