git: 969876fcee57 - main - ctld: parse config file independently of getting kernel info

From: Alan Somers <asomers_at_FreeBSD.org>
Date: Wed, 07 Aug 2024 14:37:13 UTC
The branch main has been updated by asomers:

URL: https://cgit.FreeBSD.org/src/commit/?id=969876fcee57ea1cb1c7b4d2ee757793cbfbe353

commit 969876fcee57ea1cb1c7b4d2ee757793cbfbe353
Author:     Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2024-06-10 23:48:49 +0000
Commit:     Alan Somers <asomers@FreeBSD.org>
CommitDate: 2024-08-07 14:36:52 +0000

    ctld: parse config file independently of getting kernel info
    
    Separate the parsing of the config file from the reading of kernel port
    information.  This has three benefits:
    
    * Separation of concerns makes future changes easier.
    * Allows the config file to be read earlier, which is necessary for
      fixing PR 271460.
    * Reduces total line count, by eliminating duplication between parse.y
      (for traditional config file) and uclparse.c (for UCL config file).
    
    MFC after:      2 weeks
    Sponsored by:   Axcient
    Reviewed by:    mav
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/1287
---
 usr.sbin/ctld/ctld.c     | 99 +++++++++++++++++++++++++++++++++++++-----------
 usr.sbin/ctld/ctld.h     | 25 ++++++++----
 usr.sbin/ctld/kernel.c   |  6 +--
 usr.sbin/ctld/parse.y    | 37 +-----------------
 usr.sbin/ctld/uclparse.c | 37 ++----------------
 5 files changed, 100 insertions(+), 104 deletions(-)

diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c
index bf2791040125..805648f0465f 100644
--- a/usr.sbin/ctld/ctld.c
+++ b/usr.sbin/ctld/ctld.c
@@ -98,7 +98,6 @@ conf_new(void)
 	TAILQ_INIT(&conf->conf_auth_groups);
 	TAILQ_INIT(&conf->conf_ports);
 	TAILQ_INIT(&conf->conf_portal_groups);
-	TAILQ_INIT(&conf->conf_pports);
 	TAILQ_INIT(&conf->conf_isns);
 
 	conf->conf_isns_period = 900;
@@ -117,7 +116,6 @@ conf_delete(struct conf *conf)
 	struct target *targ, *tmp;
 	struct auth_group *ag, *cagtmp;
 	struct portal_group *pg, *cpgtmp;
-	struct pport *pp, *pptmp;
 	struct isns *is, *istmp;
 
 	assert(conf->conf_pidfh == NULL);
@@ -130,8 +128,6 @@ conf_delete(struct conf *conf)
 		auth_group_delete(ag);
 	TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp)
 		portal_group_delete(pg);
-	TAILQ_FOREACH_SAFE(pp, &conf->conf_pports, pp_next, pptmp)
-		pport_delete(pp);
 	TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp)
 		isns_delete(is);
 	assert(TAILQ_EMPTY(&conf->conf_ports));
@@ -1177,27 +1173,27 @@ valid_iscsi_name(const char *name)
 }
 
 struct pport *
-pport_new(struct conf *conf, const char *name, uint32_t ctl_port)
+pport_new(struct kports *kports, const char *name, uint32_t ctl_port)
 {
 	struct pport *pp;
 
 	pp = calloc(1, sizeof(*pp));
 	if (pp == NULL)
 		log_err(1, "calloc");
-	pp->pp_conf = conf;
+	pp->pp_kports = kports;
 	pp->pp_name = checked_strdup(name);
 	pp->pp_ctl_port = ctl_port;
 	TAILQ_INIT(&pp->pp_ports);
-	TAILQ_INSERT_TAIL(&conf->conf_pports, pp, pp_next);
+	TAILQ_INSERT_TAIL(&kports->pports, pp, pp_next);
 	return (pp);
 }
 
 struct pport *
-pport_find(const struct conf *conf, const char *name)
+pport_find(const struct kports *kports, const char *name)
 {
 	struct pport *pp;
 
-	TAILQ_FOREACH(pp, &conf->conf_pports, pp_next) {
+	TAILQ_FOREACH(pp, &kports->pports, pp_next) {
 		if (strcasecmp(pp->pp_name, name) == 0)
 			return (pp);
 	}
@@ -1205,11 +1201,11 @@ pport_find(const struct conf *conf, const char *name)
 }
 
 struct pport *
-pport_copy(struct pport *pp, struct conf *conf)
+pport_copy(struct pport *pp, struct kports *kports)
 {
 	struct pport *ppnew;
 
-	ppnew = pport_new(conf, pp->pp_name, pp->pp_ctl_port);
+	ppnew = pport_new(kports, pp->pp_name, pp->pp_ctl_port);
 	return (ppnew);
 }
 
@@ -1220,7 +1216,7 @@ pport_delete(struct pport *pp)
 
 	TAILQ_FOREACH_SAFE(port, &pp->pp_ports, p_ts, tport)
 		port_delete(port);
-	TAILQ_REMOVE(&pp->pp_conf->conf_pports, pp, pp_next);
+	TAILQ_REMOVE(&pp->pp_kports->pports, pp, pp_next);
 	free(pp->pp_name);
 	free(pp);
 }
@@ -1255,7 +1251,8 @@ port_new(struct conf *conf, struct target *target, struct portal_group *pg)
 }
 
 struct port *
-port_new_ioctl(struct conf *conf, struct target *target, int pp, int vp)
+port_new_ioctl(struct conf *conf, struct kports *kports, struct target *target,
+    int pp, int vp)
 {
 	struct pport *pport;
 	struct port *port;
@@ -1269,7 +1266,7 @@ port_new_ioctl(struct conf *conf, struct target *target, int pp, int vp)
 		return (NULL);
 	}
 
-	pport = pport_find(conf, pname);
+	pport = pport_find(kports, pname);
 	if (pport != NULL) {
 		free(pname);
 		return (port_new_pp(conf, target, pport));
@@ -1424,6 +1421,7 @@ target_delete(struct target *targ)
 		port_delete(port);
 	TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next);
 
+	free(targ->t_pport);
 	free(targ->t_name);
 	free(targ->t_redirection);
 	free(targ);
@@ -2686,21 +2684,17 @@ check_perms(const char *path)
 }
 
 static struct conf *
-conf_new_from_file(const char *path, struct conf *oldconf, bool ucl)
+conf_new_from_file(const char *path, bool ucl)
 {
 	struct conf *conf;
 	struct auth_group *ag;
 	struct portal_group *pg;
-	struct pport *pp;
 	int error;
 
 	log_debugx("obtaining configuration from %s", path);
 
 	conf = conf_new();
 
-	TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next)
-		pport_copy(pp, conf);
-
 	ag = auth_group_new(conf, "default");
 	assert(ag != NULL);
 
@@ -2755,9 +2749,60 @@ conf_new_from_file(const char *path, struct conf *oldconf, bool ucl)
 	return (conf);
 }
 
+/*
+ * If the config file specifies physical ports for any target, associate them
+ * with the config file.  If necessary, create them.
+ */
+static int
+new_pports_from_conf(struct conf *conf, struct kports *kports)
+{
+	struct target *targ;
+	struct pport *pp;
+	struct port *tp;
+	int ret, i_pp, i_vp;
+
+	TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
+		if (!targ->t_pport)
+			continue;
+
+		ret = sscanf(targ->t_pport, "ioctl/%d/%d", &i_pp, &i_vp);
+		if (ret > 0) {
+			tp = port_new_ioctl(conf, kports, targ, i_pp, i_vp);
+			if (tp == NULL) {
+				log_warnx("can't create new ioctl port "
+				    "for target \"%s\"", targ->t_name);
+				return (1);
+			}
+
+			continue;
+		}
+
+		pp = pport_find(kports, targ->t_pport);
+		if (pp == NULL) {
+			log_warnx("unknown port \"%s\" for target \"%s\"",
+			    targ->t_pport, targ->t_name);
+			return (1);
+		}
+		if (!TAILQ_EMPTY(&pp->pp_ports)) {
+			log_warnx("can't link port \"%s\" to target \"%s\", "
+			    "port already linked to some target",
+			    targ->t_pport, targ->t_name);
+			return (1);
+		}
+		tp = port_new_pp(conf, targ, pp);
+		if (tp == NULL) {
+			log_warnx("can't link port \"%s\" to target \"%s\"",
+			    targ->t_pport, targ->t_name);
+			return (1);
+		}
+	}
+	return (0);
+}
+
 int
 main(int argc, char **argv)
 {
+	struct kports kports;
 	struct conf *oldconf, *newconf, *tmpconf;
 	struct isns *newns;
 	const char *config_path = DEFAULT_CONFIG_PATH;
@@ -2800,8 +2845,9 @@ main(int argc, char **argv)
 	log_init(debug);
 	kernel_init();
 
-	oldconf = conf_new_from_kernel();
-	newconf = conf_new_from_file(config_path, oldconf, use_ucl);
+	TAILQ_INIT(&kports.pports);
+	oldconf = conf_new_from_kernel(&kports);
+	newconf = conf_new_from_file(config_path, use_ucl);
 
 	if (newconf == NULL)
 		log_errx(1, "configuration error; exiting");
@@ -2814,6 +2860,9 @@ main(int argc, char **argv)
 		newconf->conf_debug = debug;
 	}
 
+	if (new_pports_from_conf(newconf, &kports))
+		log_errx(1, "Error associating physical ports; exiting");
+
 	error = conf_apply(oldconf, newconf);
 	if (error != 0)
 		log_errx(1, "failed to apply configuration; exiting");
@@ -2841,17 +2890,21 @@ main(int argc, char **argv)
 		if (sighup_received) {
 			sighup_received = false;
 			log_debugx("received SIGHUP, reloading configuration");
-			tmpconf = conf_new_from_file(config_path, newconf,
-			    use_ucl);
+			tmpconf = conf_new_from_file(config_path, use_ucl);
 
 			if (tmpconf == NULL) {
 				log_warnx("configuration error, "
 				    "continuing with old configuration");
+			} else if (new_pports_from_conf(tmpconf, &kports)) {
+				log_warnx("Error associating physical ports, "
+				    "continuing with old configuration");
+				conf_delete(tmpconf);
 			} else {
 				if (debug > 0)
 					tmpconf->conf_debug = debug;
 				oldconf = newconf;
 				newconf = tmpconf;
+
 				error = conf_apply(oldconf, newconf);
 				if (error != 0)
 					log_warnx("failed to reload "
diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h
index bcc3c1956dc4..e1bab1a8e3b8 100644
--- a/usr.sbin/ctld/ctld.h
+++ b/usr.sbin/ctld/ctld.h
@@ -131,10 +131,11 @@ struct portal_group {
 	uint16_t			pg_tag;
 };
 
+/* Ports created by the kernel.  Perhaps the "p" means "physical" ? */
 struct pport {
 	TAILQ_ENTRY(pport)		pp_next;
 	TAILQ_HEAD(, port)		pp_ports;
-	struct conf			*pp_conf;
+	struct kports			*pp_kports;
 	char				*pp_name;
 
 	uint32_t			pp_ctl_port;
@@ -190,6 +191,8 @@ struct target {
 	char				*t_name;
 	char				*t_alias;
 	char				*t_redirection;
+	/* Name of this target's physical port, if any, i.e. "isp0" */
+	char				*t_pport;
 };
 
 struct isns {
@@ -206,7 +209,6 @@ struct conf {
 	TAILQ_HEAD(, auth_group)	conf_auth_groups;
 	TAILQ_HEAD(, port)		conf_ports;
 	TAILQ_HEAD(, portal_group)	conf_portal_groups;
-	TAILQ_HEAD(, pport)		conf_pports;
 	TAILQ_HEAD(, isns)		conf_isns;
 	int				conf_isns_period;
 	int				conf_isns_timeout;
@@ -224,6 +226,11 @@ struct conf {
 	bool				conf_kernel_port_on;
 };
 
+/* Physical ports exposed by the kernel */
+struct kports {
+	TAILQ_HEAD(, pport)		pports;
+};
+
 #define	CONN_SESSION_TYPE_NONE		0
 #define	CONN_SESSION_TYPE_DISCOVERY	1
 #define	CONN_SESSION_TYPE_NORMAL	2
@@ -247,11 +254,11 @@ struct ctld_connection {
 	struct chap		*conn_chap;
 };
 
-int			parse_conf(struct conf *conf, const char *path);
+int			parse_conf(struct conf *newconf, const char *path);
 int			uclparse_conf(struct conf *conf, const char *path);
 
 struct conf		*conf_new(void);
-struct conf		*conf_new_from_kernel(void);
+struct conf		*conf_new_from_kernel(struct kports *kports);
 void			conf_delete(struct conf *conf);
 int			conf_verify(struct conf *conf);
 
@@ -305,15 +312,17 @@ void			isns_register(struct isns *isns, struct isns *oldisns);
 void			isns_check(struct isns *isns);
 void			isns_deregister(struct isns *isns);
 
-struct pport		*pport_new(struct conf *conf, const char *name,
+struct pport		*pport_new(struct kports *kports, const char *name,
 			    uint32_t ctl_port);
-struct pport		*pport_find(const struct conf *conf, const char *name);
-struct pport		*pport_copy(struct pport *pport, struct conf *conf);
+struct pport		*pport_find(const struct kports *kports,
+			    const char *name);
+struct pport		*pport_copy(struct pport *pp, struct kports *kports);
 void			pport_delete(struct pport *pport);
 
 struct port		*port_new(struct conf *conf, struct target *target,
 			    struct portal_group *pg);
-struct port		*port_new_ioctl(struct conf *conf, struct target *target,
+struct port		*port_new_ioctl(struct conf *conf,
+			    struct kports *kports, struct target *target,
 			    int pp, int vp);
 struct port		*port_new_pp(struct conf *conf, struct target *target,
 			    struct pport *pp);
diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c
index ae455e7815f7..eed9f13d42fa 100644
--- a/usr.sbin/ctld/kernel.c
+++ b/usr.sbin/ctld/kernel.c
@@ -414,7 +414,7 @@ cctl_char_handler(void *user_data, const XML_Char *str, int len)
 }
 
 struct conf *
-conf_new_from_kernel(void)
+conf_new_from_kernel(struct kports *kports)
 {
 	struct conf *conf = NULL;
 	struct target *targ;
@@ -559,13 +559,13 @@ retry_port:
 		if (port->cfiscsi_target == NULL) {
 			log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ",
 			    port->port_id, name);
-			pp = pport_find(conf, name);
+			pp = pport_find(kports, name);
 			if (pp == NULL) {
 #if 0
 				log_debugx("found new kernel port %u \"%s\"",
 				    port->port_id, name);
 #endif
-				pp = pport_new(conf, name, port->port_id);
+				pp = pport_new(kports, name, port->port_id);
 				if (pp == NULL) {
 					log_warnx("pport_new failed");
 					continue;
diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y
index 8909df2a8345..d8274b623d3a 100644
--- a/usr.sbin/ctld/parse.y
+++ b/usr.sbin/ctld/parse.y
@@ -832,42 +832,7 @@ target_portal_group:	PORTAL_GROUP STR STR
 
 target_port:	PORT STR
 	{
-		struct pport *pp;
-		struct port *tp;
-		int ret, i_pp, i_vp = 0;
-
-		ret = sscanf($2, "ioctl/%d/%d", &i_pp, &i_vp);
-		if (ret > 0) {
-			tp = port_new_ioctl(conf, target, i_pp, i_vp);
-			if (tp == NULL) {
-				log_warnx("can't create new ioctl port for "
-				    "target \"%s\"", target->t_name);
-				free($2);
-				return (1);
-			}
-		} else {
-			pp = pport_find(conf, $2);
-			if (pp == NULL) {
-				log_warnx("unknown port \"%s\" for target \"%s\"",
-				    $2, target->t_name);
-				free($2);
-				return (1);
-			}
-			if (!TAILQ_EMPTY(&pp->pp_ports)) {
-				log_warnx("can't link port \"%s\" to target \"%s\", "
-				    "port already linked to some target",
-				    $2, target->t_name);
-				free($2);
-				return (1);
-			}
-			tp = port_new_pp(conf, target, pp);
-			if (tp == NULL) {
-				log_warnx("can't link port \"%s\" to target \"%s\"",
-				    $2, target->t_name);
-				free($2);
-				return (1);
-			}
-		}
+		target->t_pport = strdup($2);
 
 		free($2);
 	}
diff --git a/usr.sbin/ctld/uclparse.c b/usr.sbin/ctld/uclparse.c
index 8bd1ca88d166..e9e42bdf953e 100644
--- a/usr.sbin/ctld/uclparse.c
+++ b/usr.sbin/ctld/uclparse.c
@@ -853,41 +853,10 @@ uclparse_target(const char *name, const ucl_object_t *top)
 		}
 
 		if (!strcmp(key, "port")) {
-			struct pport *pp;
-			struct port *tp;
-			const char *value = ucl_object_tostring(obj);
-			int ret, i_pp, i_vp = 0;
-
-			ret = sscanf(value, "ioctl/%d/%d", &i_pp, &i_vp);
-			if (ret > 0) {
-				tp = port_new_ioctl(conf, target, i_pp, i_vp);
-				if (tp == NULL) {
-					log_warnx("can't create new ioctl port "
-					    "for target \"%s\"", target->t_name);
-					return (1);
-				}
+			const char *value;
 
-				continue;
-			}
-
-			pp = pport_find(conf, value);
-			if (pp == NULL) {
-				log_warnx("unknown port \"%s\" for target \"%s\"",
-				    value, target->t_name);
-				return (1);
-			}
-			if (!TAILQ_EMPTY(&pp->pp_ports)) {
-				log_warnx("can't link port \"%s\" to target \"%s\", "
-				    "port already linked to some target",
-				    value, target->t_name);
-				return (1);
-			}
-			tp = port_new_pp(conf, target, pp);
-			if (tp == NULL) {
-				log_warnx("can't link port \"%s\" to target \"%s\"",
-				    value, target->t_name);
-				return (1);
-			}
+			value = ucl_object_tostring(obj);
+			target->t_pport = strdup(value);
 		}
 
 		if (!strcmp(key, "redirect")) {