summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Leech <cleech@redhat.com>2018-06-13 08:08:27 -0700
committerChris Leech <cleech@redhat.com>2018-06-13 09:00:01 -0700
commit4bf7a9898f9536a0a8a32c94e6e6555da18b2391 (patch)
tree29c26c94bd265ed9ee8b0356c56d6952f9b36c5d
parent0cfebb10d29382ac1058c950a60a946c28b01e53 (diff)
downloadopen-iscsi-4bf7a9898f9536a0a8a32c94e6e6555da18b2391.tar.gz
vlan setting sync across ipv4/ipv6 for be2iscsi
be2iscsi exports two ifaces per host port for ipv4 and ipv6 network configurations. But, they need to have the same link level configuration including vlan settings. If vlan setting are modified in only one iface record, then whichever record is applied last (filesystem dependant I think) will take effect and things may not work. This change to iscsiadm applies vlan updates to all records with matching MAC addresses if a flag is set on the transport. The new transport flag is only set for be2iscsi.
-rw-r--r--usr/iscsiadm.c132
-rw-r--r--usr/transport.c1
-rw-r--r--usr/transport.h3
3 files changed, 108 insertions, 28 deletions
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index b7bdb76..e3ba03c 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -2451,6 +2451,89 @@ out:
return rc;
}
+static int iface_param_update(struct iface_rec *iface, struct list_head *params)
+{
+ struct node_rec *rec;
+ int rc = 0;
+
+ rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1);
+ if (!rec) {
+ rc = ISCSI_ERR_INVAL;
+ goto update_fail;
+ }
+
+ if (iscsi_check_for_running_session(rec))
+ log_warning("Updating iface while iscsi sessions "
+ "are using it. You must logout the running "
+ "sessions then log back in for the "
+ "new settings to take affect.");
+
+ rc = verify_iface_params(params, rec);
+ if (rc)
+ goto update_fail;
+
+ rc = iface_conf_update(params, &rec->iface);
+ if (rc)
+ goto update_fail;
+
+ rc = __for_each_matched_rec(0, rec, params, idbm_node_set_param);
+ if (rc == ISCSI_ERR_NO_OBJS_FOUND)
+ rc = 0;
+ else if (rc)
+ goto update_fail;
+
+ printf("%s updated.\n", iface->name);
+ free(rec);
+ return rc;
+
+update_fail:
+ log_error("Could not update iface %s: %s",
+ iface->name, iscsi_err_to_str(rc));
+ free(rec);
+ return rc;
+}
+
+struct iface_param_sync {
+ struct iface_rec *primary;
+ struct list_head *params;
+ int count;
+};
+
+static int update_sync_params(void *data, struct iface_rec *iface)
+{
+ struct iface_param_sync *iface_params = data;
+ struct iface_rec *primary = iface_params->primary;
+ struct list_head *params = iface_params->params;
+
+ if ((strcmp(primary->transport_name, iface->transport_name)) ||
+ (strcmp(primary->hwaddress, iface->hwaddress)) ||
+ (primary->iface_num != iface->iface_num))
+ return 0;
+
+ return iface_param_update(iface, params);
+}
+
+static int split_vlan_params(struct list_head *params, struct list_head *vlan_params)
+{
+ struct user_param *param, *tmp;
+
+ list_for_each_entry_safe(param, tmp, params, list) {
+ if (!strncmp(param->name, "iface.vlan", 10)) {
+ list_move_tail(&param->list, vlan_params);
+ }
+ }
+ return 0;
+}
+
+static inline void list_splice_tail(struct list_head *list, struct list_head *head)
+{
+ list->prev->next = head;
+ list->next->prev = head->prev;
+ head->prev->next = list->next;
+ head->prev = list->prev;
+ INIT_LIST_HEAD(list);
+}
+
/* TODO: merge iter helpers and clean them up, so we can use them here */
static int exec_iface_op(struct iscsi_context *ctx, int op, int do_show,
int info_level, struct iface_rec *iface,
@@ -2464,6 +2547,8 @@ static int exec_iface_op(struct iscsi_context *ctx, int op, int do_show,
uint32_t iface_count = 0;
uint32_t i = 0;
+ LIST_HEAD(vlan_params);
+ struct iscsi_transport *t;
switch (op) {
case OP_NEW:
if (!iface) {
@@ -2525,36 +2610,27 @@ delete_fail:
rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1);
if (!rec) {
rc = ISCSI_ERR_INVAL;
- goto update_fail;
+ break;
}
-
- if (iscsi_check_for_running_session(rec))
- log_warning("Updating iface while iscsi sessions "
- "are using it. You must logout the running "
- "sessions then log back in for the "
- "new settings to take affect.");
-
- rc = verify_iface_params(params, rec);
- if (rc)
+ t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
+ if (!t) {
+ log_error("Cound not locate transport for iface %s", iface->name);
+ rc = ISCSI_ERR_INVAL;
break;
-
- /* pass rec's iface because it has the db values */
- rc = iface_conf_update(params, &rec->iface);
- if (rc)
- goto update_fail;
-
- rc = __for_each_matched_rec(0, rec, params,
- idbm_node_set_param);
- if (rc == ISCSI_ERR_NO_OBJS_FOUND)
- rc = 0;
- else if (rc)
- goto update_fail;
-
- printf("%s updated.\n", iface->name);
- break;
-update_fail:
- log_error("Could not update iface %s: %s",
- iface->name, iscsi_err_to_str(rc));
+ }
+ if (t->template->sync_vlan_settings) {
+ /* sync shared vlan settings across ifaces */
+ int nr_found = 0;
+ struct iface_param_sync sync_params = {
+ .primary = &rec->iface,
+ .params = &vlan_params,
+ .count = 0,
+ };
+ split_vlan_params(params, &vlan_params);
+ iface_for_each_iface(&sync_params, 1, &nr_found, update_sync_params);
+ }
+ iface_param_update(&rec->iface, params);
+ list_splice_tail(&vlan_params, params);
break;
case OP_APPLY:
if (!iface) {
diff --git a/usr/transport.c b/usr/transport.c
index 3b7a00a..35a8ccd 100644
--- a/usr/transport.c
+++ b/usr/transport.c
@@ -91,6 +91,7 @@ struct iscsi_transport_template bnx2i = {
struct iscsi_transport_template be2iscsi = {
.name = "be2iscsi",
.bind_ep_required = 1,
+ .sync_vlan_settings = 1,
.create_conn = be2iscsi_create_conn,
.ep_connect = ktransport_ep_connect,
.ep_poll = ktransport_ep_poll,
diff --git a/usr/transport.h b/usr/transport.h
index b67776b..0702756 100644
--- a/usr/transport.h
+++ b/usr/transport.h
@@ -40,6 +40,9 @@ struct iscsi_transport_template {
uint8_t use_boot_info;
uint8_t bind_ep_required;
uint8_t no_netdev;
+ /* be2iscsi has a single host vlan setting,
+ * but uses 2 ifaces for ipv4 and ipv6 settings; keep them in sync */
+ uint8_t sync_vlan_settings;
int (*ep_connect) (struct iscsi_conn *conn, int non_blocking);
int (*ep_poll) (struct iscsi_conn *conn, int timeout_ms);
void (*ep_disconnect) (struct iscsi_conn *conn);