From 5e0196d6474ddd754ba63e047a149e6206739af7 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 14 Aug 2014 15:56:06 +0200 Subject: [PATCH] Dynamic allocation of interface config entries Remove the limit of MAX_PORTS ports also when parsing command line arguments. Signed-off-by: Jiri Benc --- clock.c | 11 ++++---- clock.h | 5 ++-- config.c | 78 ++++++++++++++++++++++++++++++++------------------------ config.h | 11 +++++--- ptp4l.c | 41 ++++++++++++++--------------- 5 files changed, 79 insertions(+), 67 deletions(-) diff --git a/clock.c b/clock.c index 76670e6..726999e 100644 --- a/clock.c +++ b/clock.c @@ -785,15 +785,16 @@ static void clock_remove_port(struct clock *c, struct port *p) port_close(p); } -struct clock *clock_create(int phc_index, struct interface *iface, int count, +struct clock *clock_create(int phc_index, struct interfaces_head *ifaces, enum timestamp_type timestamping, struct default_ds *dds, enum servo_type servo) { - int i, fadj = 0, max_adj = 0.0, sw_ts = timestamping == TS_SOFTWARE ? 1 : 0; + int fadj = 0, max_adj = 0.0, sw_ts = timestamping == TS_SOFTWARE ? 1 : 0; struct clock *c = &the_clock; struct port *p; char phc[32]; struct interface *udsif = &c->uds_interface; + struct interface *iface; struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); @@ -909,9 +910,9 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, clock_fda_changed(c); /* Create the ports. */ - for (i = 0; i < count; i++) { - if (clock_add_port(c, phc_index, timestamping, &iface[i])) { - pr_err("failed to open port %s", iface[i].name); + STAILQ_FOREACH(iface, ifaces, list) { + if (clock_add_port(c, phc_index, timestamping, iface)) { + pr_err("failed to open port %s", iface->name); return NULL; } } diff --git a/clock.h b/clock.h index 0702aca..a2b46be 100644 --- a/clock.h +++ b/clock.h @@ -63,14 +63,13 @@ UInteger8 clock_class(struct clock *c); * * @param phc_index PTP hardware clock device to use. * Pass -1 to select CLOCK_REALTIME. - * @param interface An array of network interfaces. - * @param count The number of elements in @a interfaces. + * @param ifaces A queue of network interfaces. * @param timestamping The timestamping mode for this clock. * @param dds A pointer to a default data set for the clock. * @param servo The servo that this clock will use. * @return A pointer to the single global clock instance. */ -struct clock *clock_create(int phc_index, struct interface *iface, int count, +struct clock *clock_create(int phc_index, struct interfaces_head *ifaces, enum timestamp_type timestamping, struct default_ds *dds, enum servo_type servo); diff --git a/config.c b/config.c index 0bc85c1..4cee947 100644 --- a/config.c +++ b/config.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "config.h" #include "ether.h" @@ -162,40 +163,40 @@ static enum parser_result parse_pod_setting(const char *option, static enum parser_result parse_port_setting(const char *option, const char *value, struct config *cfg, - int p) + struct interface *iface) { enum parser_result r; int val; - r = parse_pod_setting(option, value, &cfg->iface[p].pod); + r = parse_pod_setting(option, value, &iface->pod); if (r != NOT_PARSED) return r; if (!strcmp(option, "network_transport")) { if (!strcasecmp("L2", value)) - cfg->iface[p].transport = TRANS_IEEE_802_3; + iface->transport = TRANS_IEEE_802_3; else if (!strcasecmp("UDPv4", value)) - cfg->iface[p].transport = TRANS_UDP_IPV4; + iface->transport = TRANS_UDP_IPV4; else if (!strcasecmp("UDPv6", value)) - cfg->iface[p].transport = TRANS_UDP_IPV6; + iface->transport = TRANS_UDP_IPV6; else return BAD_VALUE; } else if (!strcmp(option, "delay_mechanism")) { if (!strcasecmp("Auto", value)) - cfg->iface[p].dm = DM_AUTO; + iface->dm = DM_AUTO; else if (!strcasecmp("E2E", value)) - cfg->iface[p].dm = DM_E2E; + iface->dm = DM_E2E; else if (!strcasecmp("P2P", value)) - cfg->iface[p].dm = DM_P2P; + iface->dm = DM_P2P; else return BAD_VALUE; } else if (!strcmp(option, "delay_filter")) { if (!strcasecmp("moving_average", value)) - cfg->iface[p].delay_filter = FILTER_MOVING_AVERAGE; + iface->delay_filter = FILTER_MOVING_AVERAGE; else if (!strcasecmp("moving_median", value)) - cfg->iface[p].delay_filter = FILTER_MOVING_MEDIAN; + iface->delay_filter = FILTER_MOVING_MEDIAN; else return BAD_VALUE; @@ -203,7 +204,7 @@ static enum parser_result parse_port_setting(const char *option, r = get_ranged_int(value, &val, 1, INT_MAX); if (r != PARSED_OK) return r; - cfg->iface[p].delay_filter_length = val; + iface->delay_filter_length = val; } else return NOT_PARSED; @@ -611,7 +612,8 @@ int config_read(char *name, struct config *cfg) FILE *fp; char buf[1024], *line, *c; const char *option, *value; - int current_port = 0, line_num; + struct interface *current_port = NULL; + int line_num; fp = 0 == strncmp(name, "-", 2) ? stdin : fopen(name, "r"); @@ -647,8 +649,9 @@ int config_read(char *name, struct config *cfg) goto parse_error; } current_port = config_create_interface(port, cfg); - if (current_port < 0) + if (!current_port) goto parse_error; + config_init_interface(current_port, cfg); } continue; } @@ -660,7 +663,7 @@ int config_read(char *name, struct config *cfg) fprintf(stderr, "could not parse line %d in %s section\n", line_num, current_section == GLOBAL_SECTION ? - "global" : cfg->iface[current_port].name); + "global" : current_port->name); goto parse_error; } @@ -678,7 +681,7 @@ int config_read(char *name, struct config *cfg) fprintf(stderr, "unknown option %s at line %d in %s section\n", option, line_num, current_section == GLOBAL_SECTION ? - "global" : cfg->iface[current_port].name); + "global" : current_port->name); goto parse_error; case BAD_VALUE: fprintf(stderr, "%s is a bad value for option %s at line %d\n", @@ -712,36 +715,45 @@ parse_error: return -2; } -/* returns the number matching that interface, or -1 on failure */ -int config_create_interface(char *name, struct config *cfg) +struct interface *config_create_interface(char *name, struct config *cfg) { struct interface *iface; - int i; - - if (cfg->nports >= MAX_PORTS) { - fprintf(stderr, "more than %d ports specified\n", MAX_PORTS); - return -1; - } - - iface = &cfg->iface[cfg->nports]; /* only create each interface once (by name) */ - for(i = 0; i < cfg->nports; i++) { - if (0 == strncmp(name, cfg->iface[i].name, MAX_IFNAME_SIZE)) - return i; + STAILQ_FOREACH(iface, &cfg->interfaces, list) { + if (0 == strncmp(name, iface->name, MAX_IFNAME_SIZE)) + return iface; + } + + iface = calloc(1, sizeof(struct interface)); + if (!iface) { + fprintf(stderr, "cannot allocate memory for a port\n"); + return NULL; } strncpy(iface->name, name, MAX_IFNAME_SIZE); + STAILQ_INSERT_TAIL(&cfg->interfaces, iface, list); + return iface; +} + +void config_init_interface(struct interface *iface, struct config *cfg) +{ iface->dm = cfg->dm; iface->transport = cfg->transport; memcpy(&iface->pod, &cfg->pod, sizeof(cfg->pod)); - sk_get_ts_info(name, &iface->ts_info); + sk_get_ts_info(iface->name, &iface->ts_info); iface->delay_filter = cfg->dds.delay_filter; iface->delay_filter_length = cfg->dds.delay_filter_length; - - cfg->nports++; - - return i; +} + +void config_destroy(struct config *cfg) +{ + struct interface *iface; + + while ((iface = STAILQ_FIRST(&cfg->interfaces))) { + STAILQ_REMOVE_HEAD(&cfg->interfaces, list); + free(iface); + } } diff --git a/config.h b/config.h index be5a651..9b74f12 100644 --- a/config.h +++ b/config.h @@ -20,6 +20,8 @@ #ifndef HAVE_CONFIG_H #define HAVE_CONFIG_H +#include + #include "ds.h" #include "dm.h" #include "filter.h" @@ -27,11 +29,11 @@ #include "servo.h" #include "sk.h" -#define MAX_PORTS 8 #define MAX_IFNAME_SIZE 108 /* = UNIX_PATH_MAX */ /** Defines a network interface, with PTP options. */ struct interface { + STAILQ_ENTRY(interface) list; char name[MAX_IFNAME_SIZE + 1]; enum delay_mechanism dm; enum transport_type transport; @@ -62,8 +64,7 @@ struct config { int cfg_ignore; /* configured interfaces */ - struct interface iface[MAX_PORTS]; - int nports; + STAILQ_HEAD(interfaces_head, interface) interfaces; enum timestamp_type timestamping; enum transport_type transport; @@ -102,6 +103,8 @@ struct config { }; int config_read(char *name, struct config *cfg); -int config_create_interface(char *name, struct config *cfg); +struct interface *config_create_interface(char *name, struct config *cfg); +void config_init_interface(struct interface *iface, struct config *cfg); +void config_destroy(struct config *cfg); #endif diff --git a/ptp4l.c b/ptp4l.c index 25270c6..575ec64 100644 --- a/ptp4l.c +++ b/ptp4l.c @@ -43,6 +43,8 @@ int assume_two_step = 0; static int running = 1; static struct config cfg_settings = { + .interfaces = STAILQ_HEAD_INITIALIZER(cfg_settings.interfaces), + .dds = { .dds = { .flags = DDS_TWO_STEP_FLAG, @@ -173,9 +175,7 @@ int main(int argc, char *argv[]) { char *config = NULL, *req_phc = NULL, *progname; int c, i; - struct interface *iface = cfg_settings.iface; - char *ports[MAX_PORTS]; - int nports = 0; + struct interface *iface; int *cfg_ignore = &cfg_settings.cfg_ignore; enum delay_mechanism *dm = &cfg_settings.dm; enum transport_type *transport = &cfg_settings.transport; @@ -248,8 +248,8 @@ int main(int argc, char *argv[]) config = optarg; break; case 'i': - ports[nports] = optarg; - nports++; + if (!config_create_interface(optarg, &cfg_settings)) + return -1; break; case 'p': req_phc = optarg; @@ -310,14 +310,7 @@ int main(int argc, char *argv[]) print_set_syslog(cfg_settings.use_syslog); print_set_level(cfg_settings.print_level); - for (i = 0; i < nports; i++) { - if (config_create_interface(ports[i], &cfg_settings) < 0) { - fprintf(stderr, "too many interfaces\n"); - return -1; - } - } - - if (!cfg_settings.nports) { + if (STAILQ_EMPTY(&cfg_settings.interfaces)) { fprintf(stderr, "no interface specified\n"); usage(progname); return -1; @@ -357,18 +350,21 @@ int main(int argc, char *argv[]) break; } - /* check whether timestamping mode is supported. */ - for (i = 0; i < cfg_settings.nports; i++) { - if (iface[i].ts_info.valid && - ((iface[i].ts_info.so_timestamping & required_modes) != required_modes)) { + /* Init interface configs and check whether timestamping mode is + * supported. */ + STAILQ_FOREACH(iface, &cfg_settings.interfaces, list) { + config_init_interface(iface, &cfg_settings); + if (iface->ts_info.valid && + ((iface->ts_info.so_timestamping & required_modes) != required_modes)) { fprintf(stderr, "interface '%s' does not support " "requested timestamping mode.\n", - iface[i].name); + iface->name); return -1; } } /* determine PHC Clock index */ + iface = STAILQ_FIRST(&cfg_settings.interfaces); if (cfg_settings.dds.free_running) { phc_index = -1; } else if (*timestamping == TS_SOFTWARE || *timestamping == TS_LEGACY_HW) { @@ -378,8 +374,8 @@ int main(int argc, char *argv[]) fprintf(stderr, "bad ptp device string\n"); return -1; } - } else if (iface[0].ts_info.valid) { - phc_index = iface[0].ts_info.phc_index; + } else if (iface->ts_info.valid) { + phc_index = iface->ts_info.phc_index; } else { fprintf(stderr, "ptp device not specified and\n" "automatic determination is not\n" @@ -391,12 +387,12 @@ int main(int argc, char *argv[]) pr_info("selected /dev/ptp%d as PTP clock", phc_index); } - if (generate_clock_identity(&ds->clockIdentity, iface[0].name)) { + if (generate_clock_identity(&ds->clockIdentity, iface->name)) { fprintf(stderr, "failed to generate a clock identity\n"); return -1; } - clock = clock_create(phc_index, iface, cfg_settings.nports, + clock = clock_create(phc_index, &cfg_settings.interfaces, *timestamping, &cfg_settings.dds, cfg_settings.clock_servo); if (!clock) { @@ -410,5 +406,6 @@ int main(int argc, char *argv[]) } clock_destroy(clock); + config_destroy(&cfg_settings); return 0; }