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 }