Blob Blame History Raw
commit ea9c14d9ab10d1070a8d3c032e64bb946a279a02
Author: Chris Leech <cleech@redhat.com>
Date:   Thu Nov 30 12:05:28 2017 -0800

    vlan setting sync for be2iscsi

diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index b30518a293db..f269fc406a13 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -2311,6 +2311,89 @@ static int verify_iface_params(struct list_head *params, struct node_rec *rec)
 	return 0;
 }
 
+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(int op, int do_show, int info_level,
 			 struct iface_rec *iface, uint64_t host_no,
@@ -2319,6 +2402,8 @@ static int exec_iface_op(int op, int do_show, int info_level,
 	struct host_info hinfo;
 	struct node_rec *rec = NULL;
 	int rc = 0;
+	LIST_HEAD(vlan_params);
+	struct iscsi_transport *t;
 
 	switch (op) {
 	case OP_NEW:
@@ -2381,36 +2466,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 3b7a00a2245e..35a8ccd4a400 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 b67776b47288..07027564e46b 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);