linkd

Control plane daemon for unos
git clone git://git.finwo.net/app/linkd
Log | Files | Refs | README

ports.c (4533B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <strings.h>
      5 
      6 #include "finwo/cnfparse.h"
      7 
      8 #include "util/config.h"
      9 
     10 #include "ports.h"
     11 
     12 static struct linkd_port *ports = NULL;
     13 static struct linkd_port *ports_tail = NULL;
     14 
     15 struct linkd_port * ports_list(void) {
     16   return ports;
     17 }
     18 
     19 struct linkd_port * ports_find(const char *name) {
     20   struct linkd_port *cur;
     21   for ( cur = ports ; cur ; cur = cur->next ) {
     22     if (!strcmp(cur->name, name)) return cur;
     23   }
     24   return NULL;
     25 }
     26 
     27 void ports_free(void) {
     28   struct linkd_port *cur = ports;
     29   struct linkd_port *next;
     30 
     31   while (cur) {
     32     next = cur->next;
     33     if (cur->name)     free(cur->name);
     34     if (cur->breakout) free(cur->breakout);
     35     free(cur);
     36     cur = next;
     37   }
     38 
     39   ports      = NULL;
     40   ports_tail = NULL;
     41 }
     42 
     43 static enum dp_fec ports_parse_fec(const char *value) {
     44   if (!strcasecmp("off"  , value)) return DP_FEC_OFF;
     45   if (!strcasecmp("none" , value)) return DP_FEC_OFF;
     46   if (!strcasecmp("auto" , value)) return DP_FEC_AUTO;
     47   if (!strcasecmp("rs"   , value)) return DP_FEC_RS;
     48   if (!strcasecmp("baser", value)) return DP_FEC_BASER;
     49   if (!strcasecmp("fc"   , value)) return DP_FEC_BASER;
     50   return DP_FEC_UNSET;
     51 }
     52 
     53 static int ports_parse_bool(const char *value) {
     54   if (!strcasecmp("on"  , value)) return 1;
     55   if (!strcasecmp("yes" , value)) return 1;
     56   if (!strcasecmp("true", value)) return 1;
     57   if (!strcasecmp("1"   , value)) return 1;
     58   return 0;
     59 }
     60 
     61 // Directives ifupdown already implements. Accepting them here would create a
     62 // second source of truth for the same value, so reject them loudly and point
     63 // at the right file rather than silently ignoring them.
     64 static const char *ports_reserved[] = {
     65   "address", "gateway", "netmask", "broadcast", "metric",
     66   "mtu", "hwaddress", "admin", "up", "down",
     67   NULL,
     68 };
     69 
     70 static int ports_is_reserved(const char *name) {
     71   int i;
     72   for ( i = 0 ; ports_reserved[i] ; i++ ) {
     73     if (!strcasecmp(ports_reserved[i], name)) return 1;
     74   }
     75   return 0;
     76 }
     77 
     78 static void port_free(struct linkd_port *port) {
     79   if (!port) return;
     80   free(port->name);
     81   free(port->breakout);
     82   free(port);
     83 }
     84 
     85 struct cnf_directive * cfg_parse_port(FILE *fd, struct cnf_directive *dir, void *user) {
     86   struct linkd_port *port;
     87   (void)user;
     88 
     89   if (dir->argc != 1) {
     90     cfg_error("`port` directive accepts only 1 argument");
     91     cnf_directive_free(dir);
     92     return NULL;
     93   }
     94 
     95   if (ports_find(dir->argv[0])) {
     96     cfg_error("duplicate `port` definition: %s", dir->argv[0]);
     97     cnf_directive_free(dir);
     98     return NULL;
     99   }
    100 
    101   port = calloc(1, sizeof(struct linkd_port));
    102   port->name    = strdup(dir->argv[0]);
    103   port->fec     = DP_FEC_UNSET;
    104   port->autoneg = -1;
    105 
    106   for(;;) {
    107     if (dir) cnf_directive_free(dir);
    108     dir = cnf_directive_read(fd);
    109     if (!dir) break; // EOF = done
    110 
    111     // Make following blocks identical in structure
    112     if(0) {}
    113 
    114     else if (!strcasecmp("speed", dir->name)) {
    115       if (dir->argc != 1) {
    116         cfg_error("`speed` directive accepts only 1 argument");
    117         goto fail;
    118       }
    119       port->speed = (uint32_t)strtoul(dir->argv[0], NULL, 10);
    120     }
    121 
    122     else if (!strcasecmp("fec", dir->name)) {
    123       if (dir->argc != 1) {
    124         cfg_error("`fec` directive accepts only 1 argument");
    125         goto fail;
    126       }
    127       port->fec = ports_parse_fec(dir->argv[0]);
    128       if (port->fec == DP_FEC_UNSET) {
    129         cfg_error("unknown `fec` value: %s", dir->argv[0]);
    130         goto fail;
    131       }
    132     }
    133 
    134     else if (!strcasecmp("autoneg", dir->name)) {
    135       if (dir->argc != 1) {
    136         cfg_error("`autoneg` directive accepts only 1 argument");
    137         goto fail;
    138       }
    139       port->autoneg = ports_parse_bool(dir->argv[0]);
    140     }
    141 
    142     else if (!strcasecmp("breakout", dir->name)) {
    143       if (dir->argc != 1) {
    144         cfg_error("`breakout` directive accepts only 1 argument");
    145         goto fail;
    146       }
    147       if (port->breakout) free(port->breakout);
    148       port->breakout = strdup(dir->argv[0]);
    149     }
    150 
    151     else if (ports_is_reserved(dir->name)) {
    152       cfg_error("`%s` is handled by the interfaces config, not ports", dir->name);
    153       goto fail;
    154     }
    155 
    156     else {
    157       // unknown directive
    158       break;
    159     }
    160   }
    161 
    162   // Store the completed port
    163   if (ports_tail) {
    164     ports_tail->next = port;
    165   } else {
    166     ports = port;
    167   }
    168   ports_tail = port;
    169 
    170   // Return the unparsed dir if set
    171   return dir;
    172 
    173 fail:
    174   port_free(port);
    175   cnf_directive_free(dir);
    176   return NULL;
    177 }
    178 
    179 void ports_register(void) {
    180   struct cfg_ns *ns = cfg_ns_get("ports");
    181   cfg_register_directive(ns, "port", cfg_parse_port);
    182 }