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.
---
 usr/iscsiadm.c  | 132 ++++++++++++++++++++++++++++++++++++++++++++------------
 usr/transport.c |   1 +
 usr/transport.h |   3 ++
 3 files changed, 108 insertions(+), 28 deletions(-)

diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index b7bdb76b6e45..e3ba03c838f3 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 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);
-- 
2.14.4

-- 
You received this message because you are subscribed to the Google Groups 
"open-iscsi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to open-iscsi+unsubscr...@googlegroups.com.
To post to this group, send email to open-iscsi@googlegroups.com.
Visit this group at https://groups.google.com/group/open-iscsi.
For more options, visit https://groups.google.com/d/optout.

Reply via email to