config: Introduce a unicast master table.

This patch adds configuration file support for a table of unicast
masters.  Each table lives in its own section and has a unique,
positive numerical ID.  Entries in the table are a pair of transport
type and protocol address.

Each port may specify a table id to be used for unicast negotiation.
Tables may not be shared between ports, but nothing prevents table
entries from appearing in more than table.

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
master
Richard Cochran 2018-03-08 21:59:15 -08:00
parent 1d450540c7
commit e22dc6b113
5 changed files with 213 additions and 0 deletions

152
config.c
View File

@ -33,6 +33,7 @@
enum config_section { enum config_section {
GLOBAL_SECTION, GLOBAL_SECTION,
UC_MTAB_SECTION,
PORT_SECTION, PORT_SECTION,
UNKNOWN_SECTION, UNKNOWN_SECTION,
}; };
@ -264,12 +265,16 @@ struct config_item config_tab[] = {
PORT_ITEM_INT("udp_ttl", 1, 1, 255), PORT_ITEM_INT("udp_ttl", 1, 1, 255),
PORT_ITEM_INT("udp6_scope", 0x0E, 0x00, 0x0F), PORT_ITEM_INT("udp6_scope", 0x0E, 0x00, 0x0F),
GLOB_ITEM_STR("uds_address", "/var/run/ptp4l"), GLOB_ITEM_STR("uds_address", "/var/run/ptp4l"),
PORT_ITEM_INT("unicast_master_table", 0, 0, INT_MAX),
PORT_ITEM_INT("unicast_req_duration", 3600, 10, INT_MAX),
GLOB_ITEM_INT("use_syslog", 1, 0, 1), GLOB_ITEM_INT("use_syslog", 1, 0, 1),
GLOB_ITEM_STR("userDescription", ""), GLOB_ITEM_STR("userDescription", ""),
GLOB_ITEM_INT("utc_offset", CURRENT_UTC_OFFSET, 0, INT_MAX), GLOB_ITEM_INT("utc_offset", CURRENT_UTC_OFFSET, 0, INT_MAX),
GLOB_ITEM_INT("verbose", 0, 0, 1), GLOB_ITEM_INT("verbose", 0, 0, 1),
}; };
static struct unicast_master_table *current_uc_mtab;
static enum parser_result static enum parser_result
parse_fault_interval(struct config *cfg, const char *section, parse_fault_interval(struct config *cfg, const char *section,
const char *option, const char *value); const char *option, const char *value);
@ -340,10 +345,103 @@ static void config_item_free(void *ptr)
free(ci); free(ci);
} }
static int config_switch_unicast_mtab(struct config *cfg, int idx, int line_num)
{
struct unicast_master_table *table;
if (idx < 1) {
fprintf(stderr, "line %d: table_id %d is out of range. "
"Must be in the range %d to %d\n",
line_num, idx, 1, INT_MAX);
return -1;
}
STAILQ_FOREACH(table, &cfg->unicast_master_tables, list) {
if (table->table_index == idx) {
fprintf(stderr, "line %d: table_id %d already taken\n",
line_num, idx);
return -1;
}
}
table = calloc(1, sizeof(*table));
if (!table) {
fprintf(stderr, "low memory\n");
return -1;
}
STAILQ_INIT(&table->addrs);
table->table_index = idx;
memset(&table->peer_addr.portIdentity, 0xff,
sizeof(table->peer_addr.portIdentity));
STAILQ_INSERT_TAIL(&cfg->unicast_master_tables, table, list);
current_uc_mtab = table;
return 0;
}
static int config_unicast_mtab_address(enum transport_type type, char *address,
int line_num)
{
struct unicast_master_address *item;
if (!current_uc_mtab) {
fprintf(stderr, "line %d: missing table_id\n", line_num);
return -1;
}
item = calloc(1, sizeof(*item));
if (!item) {
fprintf(stderr, "low memory\n");
return -1;
}
if (str2addr(type, address, &item->address)) {
fprintf(stderr, "line %d: bad address\n", line_num);
free(item);
return -1;
}
memset(&item->portIdentity, 0xff, sizeof(item->portIdentity));
item->type = type;
STAILQ_INSERT_TAIL(&current_uc_mtab->addrs, item, list);
current_uc_mtab->count++;
return 0;
}
static int config_unicast_mtab_peer(char *address, int line_num)
{
if (!current_uc_mtab) {
fprintf(stderr, "line %d: missing table_id\n", line_num);
return -1;
}
if (current_uc_mtab->peer_name) {
free(current_uc_mtab->peer_name);
}
current_uc_mtab->peer_name = strdup(address);
if (!current_uc_mtab->peer_name) {
fprintf(stderr, "low memory\n");
return -1;
}
return 0;
}
static int config_unicast_mtab_query_interval(int lqi, int line_num)
{
if (!current_uc_mtab) {
fprintf(stderr, "line %d: missing table_id\n", line_num);
return -1;
}
if (lqi < INT8_MIN || lqi > INT8_MAX) {
fprintf(stderr, "line %d: logQueryInterval %d out of range\n",
line_num, lqi);
return -1;
}
current_uc_mtab->logQueryInterval = lqi;
return 0;
}
static enum parser_result parse_section_line(char *s, enum config_section *section) static enum parser_result parse_section_line(char *s, enum config_section *section)
{ {
if (!strcasecmp(s, "[global]")) { if (!strcasecmp(s, "[global]")) {
*section = GLOBAL_SECTION; *section = GLOBAL_SECTION;
} else if (!strcasecmp(s, "[unicast_master_table]")) {
*section = UC_MTAB_SECTION;
current_uc_mtab = NULL;
} else if (s[0] == '[') { } else if (s[0] == '[') {
char c; char c;
*section = PORT_SECTION; *section = PORT_SECTION;
@ -484,6 +582,39 @@ static enum parser_result parse_fault_interval(struct config *cfg,
return NOT_PARSED; return NOT_PARSED;
} }
static int parse_unicast_mtab_line(struct config *cfg, char *line, int line_num)
{
char address[64 + 1] = {0}, transport[16 + 1] = {0};
enum transport_type type = TRANS_UDS;
struct config_enum *cte;
int cnt, lqi, table_id;
cnt = sscanf(line, " table_id %d", &table_id);
if (cnt == 1) {
return config_switch_unicast_mtab(cfg, table_id, line_num);
}
cnt = sscanf(line, " logQueryInterval %d", &lqi);
if (cnt == 1) {
return config_unicast_mtab_query_interval(lqi, line_num);
}
cnt = sscanf(line, " peer_address %64s", address);
if (cnt == 1) {
return config_unicast_mtab_peer(address, line_num);
}
cnt = sscanf(line, " %16s %64s", transport, address);
if (cnt != 2) {
fprintf(stderr, "bad master table at line %d\n", line_num);
return -1;
}
for (cte = nw_trans_enu; cte->label; cte++) {
if (!strcasecmp(cte->label, transport)) {
type = cte->value;
break;
}
}
return config_unicast_mtab_address(type, address, line_num);
}
static enum parser_result parse_setting_line(char *line, static enum parser_result parse_setting_line(char *line,
const char **option, const char **option,
const char **value) const char **value)
@ -594,6 +725,13 @@ int config_read(char *name, struct config *cfg)
continue; continue;
} }
if (current_section == UC_MTAB_SECTION) {
if (parse_unicast_mtab_line(cfg, line, line_num)) {
goto parse_error;
}
continue;
}
if (current_section == UNKNOWN_SECTION) { if (current_section == UNKNOWN_SECTION) {
fprintf(stderr, "line %d is not in a section\n", line_num); fprintf(stderr, "line %d is not in a section\n", line_num);
goto parse_error; goto parse_error;
@ -679,6 +817,7 @@ struct config *config_create(void)
return NULL; return NULL;
} }
STAILQ_INIT(&cfg->interfaces); STAILQ_INIT(&cfg->interfaces);
STAILQ_INIT(&cfg->unicast_master_tables);
cfg->opts = config_alloc_longopts(); cfg->opts = config_alloc_longopts();
if (!cfg->opts) { if (!cfg->opts) {
@ -724,12 +863,25 @@ fail:
void config_destroy(struct config *cfg) void config_destroy(struct config *cfg)
{ {
struct unicast_master_address *address;
struct unicast_master_table *table;
struct interface *iface; struct interface *iface;
while ((iface = STAILQ_FIRST(&cfg->interfaces))) { while ((iface = STAILQ_FIRST(&cfg->interfaces))) {
STAILQ_REMOVE_HEAD(&cfg->interfaces, list); STAILQ_REMOVE_HEAD(&cfg->interfaces, list);
free(iface); free(iface);
} }
while ((table = STAILQ_FIRST(&cfg->unicast_master_tables))) {
while ((address = STAILQ_FIRST(&table->addrs))) {
STAILQ_REMOVE_HEAD(&table->addrs, list);
free(address);
}
if (table->peer_name) {
free(table->peer_name);
}
STAILQ_REMOVE_HEAD(&cfg->unicast_master_tables, list);
free(table);
}
hash_destroy(cfg->htab, config_item_free); hash_destroy(cfg->htab, config_item_free);
free(cfg->opts); free(cfg->opts);
free(cfg); free(cfg);

View File

@ -26,6 +26,7 @@
#include "ds.h" #include "ds.h"
#include "dm.h" #include "dm.h"
#include "filter.h" #include "filter.h"
#include "mtab.h"
#include "transport.h" #include "transport.h"
#include "servo.h" #include "servo.h"
#include "sk.h" #include "sk.h"
@ -54,6 +55,9 @@ struct config {
/* hash of all non-legacy items */ /* hash of all non-legacy items */
struct hash *htab; struct hash *htab;
/* unicast master tables */
STAILQ_HEAD(ucmtab_head, unicast_master_table) unicast_master_tables;
}; };
int config_read(char *name, struct config *cfg); int config_read(char *name, struct config *cfg);

View File

@ -42,6 +42,8 @@ hybrid_e2e 0
net_sync_monitor 0 net_sync_monitor 0
tc_spanning_tree 0 tc_spanning_tree 0
tx_timestamp_timeout 1 tx_timestamp_timeout 1
unicast_master_table 0
unicast_req_duration 3600
use_syslog 1 use_syslog 1
verbose 0 verbose 0
summary_interval 0 summary_interval 0

52
mtab.h 100644
View File

@ -0,0 +1,52 @@
/**
* @file mtab.h
* @brief master table implementation
* @note Copyright (C) 2018 Richard Cochran <richardcochran@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA.
*/
#ifndef HAVE_MTAB_H
#define HAVE_MTAB_H
#include <sys/queue.h>
#include <time.h>
#include "address.h"
#include "pdt.h"
#include "transport.h"
struct unicast_master_address {
STAILQ_ENTRY(unicast_master_address) list;
struct PortIdentity portIdentity;
enum transport_type type;
struct address address;
unsigned int granted;
unsigned int sydymsk;
time_t renewal_tmo;
};
struct unicast_master_table {
STAILQ_HEAD(addrs_head, unicast_master_address) addrs;
STAILQ_ENTRY(unicast_master_table) list;
Integer8 logQueryInterval;
int table_index;
int count;
int port;
/* for use with P2P delay mechanism: */
struct unicast_master_address peer_addr;
char *peer_name;
};
#endif

View File

@ -123,6 +123,7 @@ struct port {
int tc_spanning_tree; int tc_spanning_tree;
Integer64 rx_timestamp_offset; Integer64 rx_timestamp_offset;
Integer64 tx_timestamp_offset; Integer64 tx_timestamp_offset;
int unicast_req_duration;
enum link_state link_status; enum link_state link_status;
struct fault_interval flt_interval_pertype[FT_CNT]; struct fault_interval flt_interval_pertype[FT_CNT];
enum fault_type last_fault_type; enum fault_type last_fault_type;
@ -131,6 +132,8 @@ struct port {
LIST_HEAD(fm, foreign_clock) foreign_masters; LIST_HEAD(fm, foreign_clock) foreign_masters;
/* TC book keeping */ /* TC book keeping */
TAILQ_HEAD(tct, tc_txd) tc_transmitted; TAILQ_HEAD(tct, tc_txd) tc_transmitted;
/* unicast client mode */
struct unicast_master_table *unicast_master_table;
}; };
#define portnum(p) (p->portIdentity.portNumber) #define portnum(p) (p->portIdentity.portNumber)