Dynamic allocation of interface config entries

Remove the limit of MAX_PORTS ports also when parsing command line
arguments.

Signed-off-by: Jiri Benc <jbenc@redhat.com>
master
Jiri Benc 2014-08-14 15:56:06 +02:00 committed by Richard Cochran
parent c017adc8d1
commit 5e0196d647
5 changed files with 79 additions and 67 deletions

11
clock.c
View File

@ -785,15 +785,16 @@ static void clock_remove_port(struct clock *c, struct port *p)
port_close(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 timestamp_type timestamping, struct default_ds *dds,
enum servo_type servo) 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 clock *c = &the_clock;
struct port *p; struct port *p;
char phc[32]; char phc[32];
struct interface *udsif = &c->uds_interface; struct interface *udsif = &c->uds_interface;
struct interface *iface;
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_REALTIME, &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); clock_fda_changed(c);
/* Create the ports. */ /* Create the ports. */
for (i = 0; i < count; i++) { STAILQ_FOREACH(iface, ifaces, list) {
if (clock_add_port(c, phc_index, timestamping, &iface[i])) { if (clock_add_port(c, phc_index, timestamping, iface)) {
pr_err("failed to open port %s", iface[i].name); pr_err("failed to open port %s", iface->name);
return NULL; return NULL;
} }
} }

View File

@ -63,14 +63,13 @@ UInteger8 clock_class(struct clock *c);
* *
* @param phc_index PTP hardware clock device to use. * @param phc_index PTP hardware clock device to use.
* Pass -1 to select CLOCK_REALTIME. * Pass -1 to select CLOCK_REALTIME.
* @param interface An array of network interfaces. * @param ifaces A queue of network interfaces.
* @param count The number of elements in @a interfaces.
* @param timestamping The timestamping mode for this clock. * @param timestamping The timestamping mode for this clock.
* @param dds A pointer to a default data set for the clock. * @param dds A pointer to a default data set for the clock.
* @param servo The servo that this clock will use. * @param servo The servo that this clock will use.
* @return A pointer to the single global clock instance. * @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 timestamp_type timestamping, struct default_ds *dds,
enum servo_type servo); enum servo_type servo);

View File

@ -20,6 +20,7 @@
#include <float.h> #include <float.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "config.h" #include "config.h"
#include "ether.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, static enum parser_result parse_port_setting(const char *option,
const char *value, const char *value,
struct config *cfg, struct config *cfg,
int p) struct interface *iface)
{ {
enum parser_result r; enum parser_result r;
int val; int val;
r = parse_pod_setting(option, value, &cfg->iface[p].pod); r = parse_pod_setting(option, value, &iface->pod);
if (r != NOT_PARSED) if (r != NOT_PARSED)
return r; return r;
if (!strcmp(option, "network_transport")) { if (!strcmp(option, "network_transport")) {
if (!strcasecmp("L2", value)) if (!strcasecmp("L2", value))
cfg->iface[p].transport = TRANS_IEEE_802_3; iface->transport = TRANS_IEEE_802_3;
else if (!strcasecmp("UDPv4", value)) else if (!strcasecmp("UDPv4", value))
cfg->iface[p].transport = TRANS_UDP_IPV4; iface->transport = TRANS_UDP_IPV4;
else if (!strcasecmp("UDPv6", value)) else if (!strcasecmp("UDPv6", value))
cfg->iface[p].transport = TRANS_UDP_IPV6; iface->transport = TRANS_UDP_IPV6;
else else
return BAD_VALUE; return BAD_VALUE;
} else if (!strcmp(option, "delay_mechanism")) { } else if (!strcmp(option, "delay_mechanism")) {
if (!strcasecmp("Auto", value)) if (!strcasecmp("Auto", value))
cfg->iface[p].dm = DM_AUTO; iface->dm = DM_AUTO;
else if (!strcasecmp("E2E", value)) else if (!strcasecmp("E2E", value))
cfg->iface[p].dm = DM_E2E; iface->dm = DM_E2E;
else if (!strcasecmp("P2P", value)) else if (!strcasecmp("P2P", value))
cfg->iface[p].dm = DM_P2P; iface->dm = DM_P2P;
else else
return BAD_VALUE; return BAD_VALUE;
} else if (!strcmp(option, "delay_filter")) { } else if (!strcmp(option, "delay_filter")) {
if (!strcasecmp("moving_average", value)) 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)) else if (!strcasecmp("moving_median", value))
cfg->iface[p].delay_filter = FILTER_MOVING_MEDIAN; iface->delay_filter = FILTER_MOVING_MEDIAN;
else else
return BAD_VALUE; 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); r = get_ranged_int(value, &val, 1, INT_MAX);
if (r != PARSED_OK) if (r != PARSED_OK)
return r; return r;
cfg->iface[p].delay_filter_length = val; iface->delay_filter_length = val;
} else } else
return NOT_PARSED; return NOT_PARSED;
@ -611,7 +612,8 @@ int config_read(char *name, struct config *cfg)
FILE *fp; FILE *fp;
char buf[1024], *line, *c; char buf[1024], *line, *c;
const char *option, *value; 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"); fp = 0 == strncmp(name, "-", 2) ? stdin : fopen(name, "r");
@ -647,8 +649,9 @@ int config_read(char *name, struct config *cfg)
goto parse_error; goto parse_error;
} }
current_port = config_create_interface(port, cfg); current_port = config_create_interface(port, cfg);
if (current_port < 0) if (!current_port)
goto parse_error; goto parse_error;
config_init_interface(current_port, cfg);
} }
continue; continue;
} }
@ -660,7 +663,7 @@ int config_read(char *name, struct config *cfg)
fprintf(stderr, "could not parse line %d in %s section\n", fprintf(stderr, "could not parse line %d in %s section\n",
line_num, line_num,
current_section == GLOBAL_SECTION ? current_section == GLOBAL_SECTION ?
"global" : cfg->iface[current_port].name); "global" : current_port->name);
goto parse_error; 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", fprintf(stderr, "unknown option %s at line %d in %s section\n",
option, line_num, option, line_num,
current_section == GLOBAL_SECTION ? current_section == GLOBAL_SECTION ?
"global" : cfg->iface[current_port].name); "global" : current_port->name);
goto parse_error; goto parse_error;
case BAD_VALUE: case BAD_VALUE:
fprintf(stderr, "%s is a bad value for option %s at line %d\n", fprintf(stderr, "%s is a bad value for option %s at line %d\n",
@ -712,36 +715,45 @@ parse_error:
return -2; return -2;
} }
/* returns the number matching that interface, or -1 on failure */ struct interface *config_create_interface(char *name, struct config *cfg)
int config_create_interface(char *name, struct config *cfg)
{ {
struct interface *iface; 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) */ /* only create each interface once (by name) */
for(i = 0; i < cfg->nports; i++) { STAILQ_FOREACH(iface, &cfg->interfaces, list) {
if (0 == strncmp(name, cfg->iface[i].name, MAX_IFNAME_SIZE)) if (0 == strncmp(name, iface->name, MAX_IFNAME_SIZE))
return i; 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); 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->dm = cfg->dm;
iface->transport = cfg->transport; iface->transport = cfg->transport;
memcpy(&iface->pod, &cfg->pod, sizeof(cfg->pod)); 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 = cfg->dds.delay_filter;
iface->delay_filter_length = cfg->dds.delay_filter_length; iface->delay_filter_length = cfg->dds.delay_filter_length;
}
cfg->nports++;
void config_destroy(struct config *cfg)
return i; {
struct interface *iface;
while ((iface = STAILQ_FIRST(&cfg->interfaces))) {
STAILQ_REMOVE_HEAD(&cfg->interfaces, list);
free(iface);
}
} }

View File

@ -20,6 +20,8 @@
#ifndef HAVE_CONFIG_H #ifndef HAVE_CONFIG_H
#define HAVE_CONFIG_H #define HAVE_CONFIG_H
#include <sys/queue.h>
#include "ds.h" #include "ds.h"
#include "dm.h" #include "dm.h"
#include "filter.h" #include "filter.h"
@ -27,11 +29,11 @@
#include "servo.h" #include "servo.h"
#include "sk.h" #include "sk.h"
#define MAX_PORTS 8
#define MAX_IFNAME_SIZE 108 /* = UNIX_PATH_MAX */ #define MAX_IFNAME_SIZE 108 /* = UNIX_PATH_MAX */
/** Defines a network interface, with PTP options. */ /** Defines a network interface, with PTP options. */
struct interface { struct interface {
STAILQ_ENTRY(interface) list;
char name[MAX_IFNAME_SIZE + 1]; char name[MAX_IFNAME_SIZE + 1];
enum delay_mechanism dm; enum delay_mechanism dm;
enum transport_type transport; enum transport_type transport;
@ -62,8 +64,7 @@ struct config {
int cfg_ignore; int cfg_ignore;
/* configured interfaces */ /* configured interfaces */
struct interface iface[MAX_PORTS]; STAILQ_HEAD(interfaces_head, interface) interfaces;
int nports;
enum timestamp_type timestamping; enum timestamp_type timestamping;
enum transport_type transport; enum transport_type transport;
@ -102,6 +103,8 @@ struct config {
}; };
int config_read(char *name, struct config *cfg); 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 #endif

41
ptp4l.c
View File

@ -43,6 +43,8 @@ int assume_two_step = 0;
static int running = 1; static int running = 1;
static struct config cfg_settings = { static struct config cfg_settings = {
.interfaces = STAILQ_HEAD_INITIALIZER(cfg_settings.interfaces),
.dds = { .dds = {
.dds = { .dds = {
.flags = DDS_TWO_STEP_FLAG, .flags = DDS_TWO_STEP_FLAG,
@ -173,9 +175,7 @@ int main(int argc, char *argv[])
{ {
char *config = NULL, *req_phc = NULL, *progname; char *config = NULL, *req_phc = NULL, *progname;
int c, i; int c, i;
struct interface *iface = cfg_settings.iface; struct interface *iface;
char *ports[MAX_PORTS];
int nports = 0;
int *cfg_ignore = &cfg_settings.cfg_ignore; int *cfg_ignore = &cfg_settings.cfg_ignore;
enum delay_mechanism *dm = &cfg_settings.dm; enum delay_mechanism *dm = &cfg_settings.dm;
enum transport_type *transport = &cfg_settings.transport; enum transport_type *transport = &cfg_settings.transport;
@ -248,8 +248,8 @@ int main(int argc, char *argv[])
config = optarg; config = optarg;
break; break;
case 'i': case 'i':
ports[nports] = optarg; if (!config_create_interface(optarg, &cfg_settings))
nports++; return -1;
break; break;
case 'p': case 'p':
req_phc = optarg; req_phc = optarg;
@ -310,14 +310,7 @@ int main(int argc, char *argv[])
print_set_syslog(cfg_settings.use_syslog); print_set_syslog(cfg_settings.use_syslog);
print_set_level(cfg_settings.print_level); print_set_level(cfg_settings.print_level);
for (i = 0; i < nports; i++) { if (STAILQ_EMPTY(&cfg_settings.interfaces)) {
if (config_create_interface(ports[i], &cfg_settings) < 0) {
fprintf(stderr, "too many interfaces\n");
return -1;
}
}
if (!cfg_settings.nports) {
fprintf(stderr, "no interface specified\n"); fprintf(stderr, "no interface specified\n");
usage(progname); usage(progname);
return -1; return -1;
@ -357,18 +350,21 @@ int main(int argc, char *argv[])
break; break;
} }
/* check whether timestamping mode is supported. */ /* Init interface configs and check whether timestamping mode is
for (i = 0; i < cfg_settings.nports; i++) { * supported. */
if (iface[i].ts_info.valid && STAILQ_FOREACH(iface, &cfg_settings.interfaces, list) {
((iface[i].ts_info.so_timestamping & required_modes) != required_modes)) { 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 " fprintf(stderr, "interface '%s' does not support "
"requested timestamping mode.\n", "requested timestamping mode.\n",
iface[i].name); iface->name);
return -1; return -1;
} }
} }
/* determine PHC Clock index */ /* determine PHC Clock index */
iface = STAILQ_FIRST(&cfg_settings.interfaces);
if (cfg_settings.dds.free_running) { if (cfg_settings.dds.free_running) {
phc_index = -1; phc_index = -1;
} else if (*timestamping == TS_SOFTWARE || *timestamping == TS_LEGACY_HW) { } 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"); fprintf(stderr, "bad ptp device string\n");
return -1; return -1;
} }
} else if (iface[0].ts_info.valid) { } else if (iface->ts_info.valid) {
phc_index = iface[0].ts_info.phc_index; phc_index = iface->ts_info.phc_index;
} else { } else {
fprintf(stderr, "ptp device not specified and\n" fprintf(stderr, "ptp device not specified and\n"
"automatic determination is not\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); 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"); fprintf(stderr, "failed to generate a clock identity\n");
return -1; return -1;
} }
clock = clock_create(phc_index, iface, cfg_settings.nports, clock = clock_create(phc_index, &cfg_settings.interfaces,
*timestamping, &cfg_settings.dds, *timestamping, &cfg_settings.dds,
cfg_settings.clock_servo); cfg_settings.clock_servo);
if (!clock) { if (!clock) {
@ -410,5 +406,6 @@ int main(int argc, char *argv[])
} }
clock_destroy(clock); clock_destroy(clock);
config_destroy(&cfg_settings);
return 0; return 0;
} }