linkd

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

main.c (3354B)


      1 // Broadcom XGS plugin for linkd: a RESP server on stdin/stdout.
      2 //
      3 // Skeleton. Every operation below is unimplemented and answers with an error,
      4 // which linkd surfaces rather than silently treating as applied. INFO reports
      5 // hardware_detected, which is how linkd decides whether to use this plugin at
      6 // all -- see the /dev/linux-kernel-bde probe in hardware_present().
      7 #define _GNU_SOURCE
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <strings.h>
     12 #include <unistd.h>
     13 
     14 #include "finwo/resp.h"
     15 
     16 static int hardware_present(void) {
     17   // The legacy BDE character device. A box with the module loaded and a
     18   // supported ASIC has it; anything else does not.
     19   //
     20   // Note /proc/devices on captured hardware also lists linux_ngbde (the newer
     21   // BDE) alongside this one. Which of the two bcm.so binds to is still an
     22   // open question, so this check may need widening.
     23   return access("/dev/linux-kernel-bde", F_OK) == 0;
     24 }
     25 
     26 static void emit(resp_object *o) {
     27   char  *buf = NULL;
     28   size_t len = 0;
     29   if (resp_serialize(o, &buf, &len) == 0) {
     30     fwrite(buf, 1, len, stdout);
     31     fflush(stdout);
     32     free(buf);
     33   }
     34   resp_free(o);
     35 }
     36 
     37 static void reply_ok(void)                { emit(resp_simple_init("OK")); }
     38 static void reply_err(const char *msg)    { emit(resp_error_init(msg)); }
     39 
     40 static void reply_commands(void) {
     41   resp_object *a = resp_array_init();
     42   resp_array_append_bulk(a, "COMMAND");
     43   resp_array_append_bulk(a, "INFO");
     44   resp_array_append_bulk(a, "PORT");
     45   resp_array_append_bulk(a, "RIF");
     46   resp_array_append_bulk(a, "NEIGH");
     47   resp_array_append_bulk(a, "ROUTE");
     48   resp_array_append_bulk(a, "RESYNC");
     49   emit(a);
     50 }
     51 
     52 // resp.c has no bulk constructor, only simple/error/array, so build it here.
     53 static resp_object *bulk_init(const char *s) {
     54   resp_object *o = calloc(1, sizeof(*o));
     55   if (!o) return NULL;
     56   o->type = RESPT_BULK;
     57   o->u.s  = strdup(s);
     58   return o;
     59 }
     60 
     61 static void reply_info(void) {
     62   char buf[256];
     63   snprintf(buf, sizeof(buf),
     64            "# Server\r\n"
     65            "name:bcm\r\n"
     66            "version:0.1.0\r\n"
     67            "\r\n"
     68            "# Stats\r\n"
     69            "hardware_detected:%d\r\n",
     70            hardware_present() ? 1 : 0);
     71   emit(bulk_init(buf));
     72 }
     73 
     74 static const char *arg(const resp_object *cmd, size_t i) {
     75   if (!cmd || cmd->type != RESPT_ARRAY || i >= cmd->u.arr.n) return NULL;
     76   const resp_object *e = &cmd->u.arr.elem[i];
     77   if (e->type != RESPT_BULK && e->type != RESPT_SIMPLE) return NULL;
     78   return e->u.s;
     79 }
     80 
     81 int main(void) {
     82   for (;;) {
     83     resp_object *cmd = resp_read(STDIN_FILENO);
     84     if (!cmd) break; // EOF or malformed: linkd will restart us
     85 
     86     const char *verb = arg(cmd, 0);
     87     if (!verb) {
     88       reply_err("ERR malformed command");
     89       resp_free(cmd);
     90       continue;
     91     }
     92 
     93     if (!strcasecmp(verb, "COMMAND")) {
     94       reply_commands();
     95     } else if (!strcasecmp(verb, "INFO")) {
     96       reply_info();
     97     } else if (!strcasecmp(verb, "AUTH")) {
     98       reply_ok();
     99     } else if (!strcasecmp(verb, "PORT")   || !strcasecmp(verb, "RIF") ||
    100                !strcasecmp(verb, "NEIGH")  || !strcasecmp(verb, "ROUTE") ||
    101                !strcasecmp(verb, "RESYNC")) {
    102       // TODO: program the ASIC through the OpenBCM SDK.
    103       reply_err("ERR not implemented");
    104     } else {
    105       reply_err("ERR unknown command");
    106     }
    107 
    108     resp_free(cmd);
    109   }
    110   return 0;
    111 }