#include #include #include #include #include /* maybe just use http://cjson.sourceforge.net/ or maybe even better: https://bitbucket.org/zserge/jsmn/src for the parsing? * /* parse downstream configuration file format: port;vlan;remote-id;subscriber-id;trusted port: interface name vlan: vlanid || 0 remote-id: string for REMOTE-ID attribute (requires enterprise number as input option) subscriber-id: string for SUBSCRIBER-ID attribute trusted: boolean 0 || 1 indicating whether we allow RELAY-FORW messages from this port example: eth2;604;123abc;hansen;0 output: we combine port+vlan into a 32bit value which is used directly as the INTERFACE-ID key a structure is allocated with pointers to the remote-id and a rather large structure is allocated for each new port: */ /* flags */ #define SUB_F_TRUSTED 1 #define SUB_F_ALL SUB_F_TRUSTED /* suscriber struct */ struct subscriber { int interfaceid; int flags; char *remoteid; char *subscriberid; }; /* bintree structure */ struct e_btree { struct subscriber data; struct e_btree *l,*r; }; static struct e_btree *head = NULL; /* simple recursive bintree insert */ struct e_btree *binsert(struct e_btree **p, struct subscriber *data) { if (!*p) { *p = malloc(sizeof(struct e_btree)); if (!*p) return NULL; /* malloc failed? */ (*p)->l = NULL; (*p)->r = NULL; memcpy(&(*p)->data, data, sizeof(struct subscriber)); return *p; } if (data->interfaceid < (*p)->data.interfaceid) { fprintf(stderr, "%d < %d\n", data->interfaceid, (*p)->data.interfaceid); return binsert(&(*p)->l, data); } fprintf(stderr, "%d > %d\n", data->interfaceid, (*p)->data.interfaceid); return binsert(&(*p)->r, data); } /* simple recursive bintree shift() */ struct subscriber *bshift(struct e_btree **p, struct subscriber *e) { static int level = 0; if (!*p) return NULL; /* finished */ /* dump right tree */ if ((*p)->r) bshift(&(*p)->r, e); /* we can now finish this node */ fprintf(stderr, "going to return ifid=%d now\n", (*p)->data.interfaceid); /* dump left tree */ if ((*p)->l) bshift(&(*p)->l, e); /* memcpy(e, &(*p)->data, sizeof(*e)); free(*p); *p = NULL; return e; */ return NULL; } /* global array holding all the entries */ static struct subscriber sentry[]; static int nsubscribers = 0; /* strategy: dynamically allocate entries as they are parsed and temporarily store them in a bintree allocate an array which is just big enough after parsing store all entries *sorted* in the array the reason for not keeping the bintree is that it most likely is very sub-optimal, as the data typically will appear in a semi-sorted order in the configuration file use binary search when looking up an entry note that lookup is only necessary for down => up packets */ int parse_config(char *fname) { FILE *f; int n, i = 0; char ifname[IFNAMSIZ]; struct subscriber e; f = fopen(fname, "r"); if (!f) { fprintf(stderr, "%s(): cannot open configuration file \"%s\": %m\n", __FUNCTION__, fname); return -1; } while (n = fscanf(f, " %[^;] ; %u ; %m[^;] ; %m[^;] ; %u ; ", &ifname, &e.interfaceid, &e.remoteid, &e.subscriberid, &e.flags) > 0) { /* FIXME: do cached lookup of ifindex for ifname and add to interfaceid */ e.interfaceid &= 0xfff; /* VLAN tags are 12bit only */ e.flags &= SUB_F_ALL; /* mask out invalid flags */ fprintf(stderr, "parsed entry %d (ifname=%s, ifid=%d)\n", i, ifname, e.interfaceid); binsert(&head, &e); i++; } fclose(f); } int main(int argc, char *argv[]) { struct subscriber e; if (argc < 2) return -1; parse_config(argv[1]); while (bshift(&head, &e)) ;; // fprintf(stderr, "ifid=%d, rid=%s, sid=%s, flags=%d\n", e.interfaceid, e.remoteid, e.subscriberid, e.flags); return 0; }