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 <richardcoch...@gmail.com>
---
 config.c            | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 config.h            |   4 ++
 configs/default.cfg |   2 +
 mtab.h              |  52 ++++++++++++++++++
 port_private.h      |   3 ++
 5 files changed, 213 insertions(+)
 create mode 100644 mtab.h

diff --git a/config.c b/config.c
index 98e8f1c..cc3055c 100644
--- a/config.c
+++ b/config.c
@@ -33,6 +33,7 @@
 
 enum config_section {
        GLOBAL_SECTION,
+       UC_MTAB_SECTION,
        PORT_SECTION,
        UNKNOWN_SECTION,
 };
@@ -264,12 +265,16 @@ struct config_item config_tab[] = {
        PORT_ITEM_INT("udp_ttl", 1, 1, 255),
        PORT_ITEM_INT("udp6_scope", 0x0E, 0x00, 0x0F),
        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_STR("userDescription", ""),
        GLOB_ITEM_INT("utc_offset", CURRENT_UTC_OFFSET, 0, INT_MAX),
        GLOB_ITEM_INT("verbose", 0, 0, 1),
 };
 
+static struct unicast_master_table *current_uc_mtab;
+
 static enum parser_result
 parse_fault_interval(struct config *cfg, const char *section,
                     const char *option, const char *value);
@@ -340,10 +345,103 @@ static void config_item_free(void *ptr)
        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)
 {
        if (!strcasecmp(s, "[global]")) {
                *section = GLOBAL_SECTION;
+       } else if (!strcasecmp(s, "[unicast_master_table]")) {
+               *section = UC_MTAB_SECTION;
+               current_uc_mtab = NULL;
        } else if (s[0] == '[') {
                char c;
                *section = PORT_SECTION;
@@ -484,6 +582,39 @@ static enum parser_result parse_fault_interval(struct 
config *cfg,
        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,
                                             const char **option,
                                             const char **value)
@@ -594,6 +725,13 @@ int config_read(char *name, struct config *cfg)
                        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) {
                        fprintf(stderr, "line %d is not in a section\n", 
line_num);
                        goto parse_error;
@@ -679,6 +817,7 @@ struct config *config_create(void)
                return NULL;
        }
        STAILQ_INIT(&cfg->interfaces);
+       STAILQ_INIT(&cfg->unicast_master_tables);
 
        cfg->opts = config_alloc_longopts(cfg);
        if (!cfg->opts) {
@@ -724,12 +863,25 @@ fail:
 
 void config_destroy(struct config *cfg)
 {
+       struct unicast_master_address *address;
+       struct unicast_master_table *table;
        struct interface *iface;
 
        while ((iface = STAILQ_FIRST(&cfg->interfaces))) {
                STAILQ_REMOVE_HEAD(&cfg->interfaces, list);
                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);
        free(cfg->opts);
        free(cfg);
diff --git a/config.h b/config.h
index b7f6592..f237fb2 100644
--- a/config.h
+++ b/config.h
@@ -26,6 +26,7 @@
 #include "ds.h"
 #include "dm.h"
 #include "filter.h"
+#include "mtab.h"
 #include "transport.h"
 #include "servo.h"
 #include "sk.h"
@@ -54,6 +55,9 @@ struct config {
 
        /* hash of all non-legacy items */
        struct hash *htab;
+
+       /* unicast master tables */
+       STAILQ_HEAD(ucmtab_head, unicast_master_table) unicast_master_tables;
 };
 
 int config_read(char *name, struct config *cfg);
diff --git a/configs/default.cfg b/configs/default.cfg
index 86eb15e..33c808e 100644
--- a/configs/default.cfg
+++ b/configs/default.cfg
@@ -42,6 +42,8 @@ hybrid_e2e            0
 net_sync_monitor       0
 tc_spanning_tree       0
 tx_timestamp_timeout   1
+unicast_master_table   0
+unicast_req_duration   3600
 use_syslog             1
 verbose                        0
 summary_interval       0
diff --git a/mtab.h b/mtab.h
new file mode 100644
index 0000000..d34bf9c
--- /dev/null
+++ b/mtab.h
@@ -0,0 +1,52 @@
+/**
+ * @file mtab.h
+ * @brief master table implementation
+ * @note Copyright (C) 2018 Richard Cochran <richardcoch...@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
diff --git a/port_private.h b/port_private.h
index 07bd04e..0413f9f 100644
--- a/port_private.h
+++ b/port_private.h
@@ -123,6 +123,7 @@ struct port {
        int                 tc_spanning_tree;
        Integer64           rx_timestamp_offset;
        Integer64           tx_timestamp_offset;
+       int                 unicast_req_duration;
        enum link_state     link_status;
        struct fault_interval flt_interval_pertype[FT_CNT];
        enum fault_type     last_fault_type;
@@ -131,6 +132,8 @@ struct port {
        LIST_HEAD(fm, foreign_clock) foreign_masters;
        /* TC book keeping */
        TAILQ_HEAD(tct, tc_txd) tc_transmitted;
+       /* unicast client mode */
+       struct unicast_master_table *unicast_master_table;
 };
 
 #define portnum(p) (p->portIdentity.portNumber)
-- 
2.11.0


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to