swconfig: implement uci loading support
[10.03/openwrt.git] / package / swconfig / src / swlib.c
1 /*
2  * swlib.c: Switch configuration API (user space part)
3  *
4  * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * version 2.1 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <inttypes.h>
20 #include <errno.h>
21 #include <stdint.h>
22 #include <getopt.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <linux/switch.h>
26 #include "swlib.h"
27
28 //#define DEBUG 1
29 #ifdef DEBUG
30 #define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__)
31 #else
32 #define DPRINTF(fmt, ...) do {} while (0)
33 #endif
34
35 static struct nl_handle *handle;
36 static struct nl_cache *cache;
37 static struct genl_family *family;
38 static struct nlattr *tb[SWITCH_ATTR_MAX];
39 static int refcount = 0;
40
41 static struct nla_policy port_policy[] = {
42         [SWITCH_PORT_ID] = { .type = NLA_U32 },
43         [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
44 };
45
46 static inline void *
47 swlib_alloc(size_t size)
48 {
49         void *ptr;
50
51         ptr = malloc(size);
52         if (!ptr)
53                 goto done;
54         memset(ptr, 0, size);
55
56 done:
57         return ptr;
58 }
59
60 static int
61 wait_handler(struct nl_msg *msg, void *arg)
62 {
63         int *finished = arg;
64
65         *finished = 1;
66         return NL_STOP;
67 }
68
69 /* helper function for performing netlink requests */
70 static int
71 swlib_call(int cmd, int (*call)(struct nl_msg *, void *),
72                 int (*data)(struct nl_msg *, void *), void *arg)
73 {
74         struct nl_msg *msg;
75         struct nl_cb *cb = NULL;
76         int finished;
77         int flags = 0;
78         int err;
79
80         msg = nlmsg_alloc();
81         if (!msg) {
82                 fprintf(stderr, "Out of memory!\n");
83                 exit(1);
84         }
85
86         if (!data)
87                 flags |= NLM_F_DUMP;
88
89         genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family), 0, flags, cmd, 0);
90         if (data) {
91                 if (data(msg, arg) < 0)
92                         goto nla_put_failure;
93         }
94
95         cb = nl_cb_alloc(NL_CB_CUSTOM);
96         if (!cb) {
97                 fprintf(stderr, "nl_cb_alloc failed.\n");
98                 exit(1);
99         }
100
101         err = nl_send_auto_complete(handle, msg);
102         if (err < 0) {
103                 fprintf(stderr, "nl_send_auto_complete failed: %d\n", err);
104                 goto out;
105         }
106
107         finished = 0;
108
109         if (call)
110                 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, call, arg);
111
112         if (data)
113                 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
114         else
115                 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler, &finished);
116
117         err = nl_recvmsgs(handle, cb);
118         if (err < 0) {
119                 goto out;
120         }
121
122         if (!finished)
123                 err = nl_wait_for_ack(handle);
124
125 out:
126         if (cb)
127                 nl_cb_put(cb);
128 nla_put_failure:
129         nlmsg_free(msg);
130         return err;
131 }
132
133 static int
134 send_attr(struct nl_msg *msg, void *arg)
135 {
136         struct switch_val *val = arg;
137         struct switch_attr *attr = val->attr;
138
139         NLA_PUT_U32(msg, SWITCH_ATTR_ID, attr->dev->id);
140         NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, attr->id);
141         switch(attr->atype) {
142         case SWLIB_ATTR_GROUP_PORT:
143                 NLA_PUT_U32(msg, SWITCH_ATTR_OP_PORT, val->port_vlan);
144                 break;
145         case SWLIB_ATTR_GROUP_VLAN:
146                 NLA_PUT_U32(msg, SWITCH_ATTR_OP_VLAN, val->port_vlan);
147                 break;
148         default:
149                 break;
150         }
151
152         return 0;
153
154 nla_put_failure:
155         return -1;
156 }
157
158 static int
159 store_port_val(struct nl_msg *msg, struct nlattr *nla, struct switch_val *val)
160 {
161         struct nlattr *p;
162         int ports = val->attr->dev->ports;
163         int err = 0;
164         int remaining;
165
166         if (!val->value.ports)
167                 val->value.ports = malloc(sizeof(struct switch_port) * ports);
168
169         nla_for_each_nested(p, nla, remaining) {
170                 struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
171                 struct switch_port *port;
172
173                 if (val->len >= ports)
174                         break;
175
176                 err = nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, p, port_policy);
177                 if (err < 0)
178                         goto out;
179
180                 if (!tb[SWITCH_PORT_ID])
181                         continue;
182
183                 port = &val->value.ports[val->len];
184                 port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
185                 port->flags = 0;
186                 if (tb[SWITCH_PORT_FLAG_TAGGED])
187                         port->flags |= SWLIB_PORT_FLAG_TAGGED;
188
189                 val->len++;
190         }
191
192 out:
193         return err;
194 }
195
196 static int
197 store_val(struct nl_msg *msg, void *arg)
198 {
199         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
200         struct switch_val *val = arg;
201         struct switch_attr *attr = val->attr;
202
203         if (!val)
204                 goto error;
205
206         if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0),
207                         genlmsg_attrlen(gnlh, 0), NULL) < 0) {
208                 goto error;
209         }
210
211         if (tb[SWITCH_ATTR_OP_VALUE_INT])
212                 val->value.i = nla_get_u32(tb[SWITCH_ATTR_OP_VALUE_INT]);
213         else if (tb[SWITCH_ATTR_OP_VALUE_STR])
214                 val->value.s = strdup(nla_get_string(tb[SWITCH_ATTR_OP_VALUE_STR]));
215         else if (tb[SWITCH_ATTR_OP_VALUE_PORTS])
216                 val->err = store_port_val(msg, tb[SWITCH_ATTR_OP_VALUE_PORTS], val);
217
218         val->err = 0;
219         return 0;
220
221 error:
222         return NL_SKIP;
223 }
224
225 int
226 swlib_get_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
227 {
228         int cmd;
229         int err;
230
231         switch(attr->atype) {
232         case SWLIB_ATTR_GROUP_GLOBAL:
233                 cmd = SWITCH_CMD_GET_GLOBAL;
234                 break;
235         case SWLIB_ATTR_GROUP_PORT:
236                 cmd = SWITCH_CMD_GET_PORT;
237                 break;
238         case SWLIB_ATTR_GROUP_VLAN:
239                 cmd = SWITCH_CMD_GET_VLAN;
240                 break;
241         default:
242                 return -EINVAL;
243         }
244
245         memset(&val->value, 0, sizeof(val->value));
246         val->len = 0;
247         val->attr = attr;
248         val->err = -EINVAL;
249         err = swlib_call(cmd, store_val, send_attr, val);
250         if (!err)
251                 err = val->err;
252
253         return err;
254 }
255
256 static int
257 send_attr_ports(struct nl_msg *msg, struct switch_val *val)
258 {
259         struct nlattr *n;
260         int i;
261
262         /* TODO implement multipart? */
263         if (val->len == 0)
264                 goto done;
265         n = nla_nest_start(msg, SWITCH_ATTR_OP_VALUE_PORTS);
266         if (!n)
267                 goto nla_put_failure;
268         for (i = 0; i < val->len; i++) {
269                 struct switch_port *port = &val->value.ports[i];
270                 struct nlattr *np;
271
272                 np = nla_nest_start(msg, SWITCH_ATTR_PORT);
273                 if (!np)
274                         goto nla_put_failure;
275
276                 NLA_PUT_U32(msg, SWITCH_PORT_ID, port->id);
277                 if (port->flags & SWLIB_PORT_FLAG_TAGGED)
278                         NLA_PUT_FLAG(msg, SWITCH_PORT_FLAG_TAGGED);
279
280                 nla_nest_end(msg, np);
281         }
282         nla_nest_end(msg, n);
283 done:
284         return 0;
285
286 nla_put_failure:
287         return -1;
288 }
289
290 static int
291 send_attr_val(struct nl_msg *msg, void *arg)
292 {
293         struct switch_val *val = arg;
294         struct switch_attr *attr = val->attr;
295
296         if (send_attr(msg, arg))
297                 goto nla_put_failure;
298
299         switch(attr->type) {
300         case SWITCH_TYPE_NOVAL:
301                 break;
302         case SWITCH_TYPE_INT:
303                 NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val->value.i);
304                 break;
305         case SWITCH_TYPE_STRING:
306                 if (!val->value.s)
307                         goto nla_put_failure;
308                 NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val->value.s);
309                 break;
310         case SWITCH_TYPE_PORTS:
311                 if (send_attr_ports(msg, val) < 0)
312                         goto nla_put_failure;
313                 break;
314         default:
315                 goto nla_put_failure;
316         }
317         return 0;
318
319 nla_put_failure:
320         return -1;
321 }
322
323 int
324 swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
325 {
326         int cmd;
327
328         switch(attr->atype) {
329         case SWLIB_ATTR_GROUP_GLOBAL:
330                 cmd = SWITCH_CMD_SET_GLOBAL;
331                 break;
332         case SWLIB_ATTR_GROUP_PORT:
333                 cmd = SWITCH_CMD_SET_PORT;
334                 break;
335         case SWLIB_ATTR_GROUP_VLAN:
336                 cmd = SWITCH_CMD_SET_VLAN;
337                 break;
338         default:
339                 return -EINVAL;
340         }
341
342         val->attr = attr;
343         return swlib_call(cmd, NULL, send_attr_val, val);
344 }
345
346 int swlib_set_attr_string(struct switch_dev *dev, struct switch_attr *a, int port_vlan, const char *str)
347 {
348         struct switch_port *ports;
349         struct switch_val val;
350         char *ptr;
351
352         memset(&val, 0, sizeof(val));
353         val.port_vlan = port_vlan;
354         switch(a->type) {
355         case SWITCH_TYPE_INT:
356                 val.value.i = atoi(str);
357                 break;
358         case SWITCH_TYPE_STRING:
359                 val.value.s = str;
360                 break;
361         case SWITCH_TYPE_PORTS:
362                 ports = alloca(sizeof(struct switch_port) * dev->ports);
363                 memset(ports, 0, sizeof(struct switch_port) * dev->ports);
364                 val.len = 0;
365                 ptr = (char *)str;
366                 while(ptr && *ptr)
367                 {
368                         ports[val.len].flags = 0;
369                         ports[val.len].id = strtoul(ptr, &ptr, 10);
370                         while(*ptr && !isspace(*ptr)) {
371                                 if (*ptr == 't')
372                                         ports[val.len].flags |= SWLIB_PORT_FLAG_TAGGED;
373                                 ptr++;
374                         }
375                         if (*ptr)
376                                 ptr++;
377                         val.len++;
378                 }
379                 val.value.ports = ports;
380                 break;
381         case SWITCH_TYPE_NOVAL:
382                 break;
383         default:
384                 return -1;
385         }
386         return swlib_set_attr(dev, a, &val);
387 }
388
389
390 struct attrlist_arg {
391         int id;
392         int atype;
393         struct switch_dev *dev;
394         struct switch_attr *prev;
395         struct switch_attr **head;
396 };
397
398 static int
399 add_id(struct nl_msg *msg, void *arg)
400 {
401         struct attrlist_arg *l = arg;
402
403         NLA_PUT_U32(msg, SWITCH_ATTR_ID, l->id);
404
405         return 0;
406 nla_put_failure:
407         return -1;
408 }
409
410 static int
411 add_attr(struct nl_msg *msg, void *ptr)
412 {
413         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
414         struct attrlist_arg *arg = ptr;
415         struct switch_attr *new;
416
417         if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0),
418                         genlmsg_attrlen(gnlh, 0), NULL) < 0)
419                 goto done;
420
421         new = swlib_alloc(sizeof(struct switch_attr));
422         if (!new)
423                 goto done;
424
425         new->dev = arg->dev;
426         new->atype = arg->atype;
427         if (arg->prev) {
428                 arg->prev->next = new;
429         } else {
430                 arg->prev = *arg->head;
431         }
432         *arg->head = new;
433         arg->head = &new->next;
434
435         if (tb[SWITCH_ATTR_OP_ID])
436                 new->id = nla_get_u32(tb[SWITCH_ATTR_OP_ID]);
437         if (tb[SWITCH_ATTR_OP_TYPE])
438                 new->type = nla_get_u32(tb[SWITCH_ATTR_OP_TYPE]);
439         if (tb[SWITCH_ATTR_OP_NAME])
440                 new->name = strdup(nla_get_string(tb[SWITCH_ATTR_OP_NAME]));
441         if (tb[SWITCH_ATTR_OP_DESCRIPTION])
442                 new->description = strdup(nla_get_string(tb[SWITCH_ATTR_OP_DESCRIPTION]));
443
444 done:
445         return NL_SKIP;
446 }
447
448 int
449 swlib_scan(struct switch_dev *dev)
450 {
451         struct attrlist_arg arg;
452
453         if (dev->ops || dev->port_ops || dev->vlan_ops)
454                 return 0;
455
456         arg.atype = SWLIB_ATTR_GROUP_GLOBAL;
457         arg.dev = dev;
458         arg.id = dev->id;
459         arg.prev = NULL;
460         arg.head = &dev->ops;
461         swlib_call(SWITCH_CMD_LIST_GLOBAL, add_attr, add_id, &arg);
462
463         arg.atype = SWLIB_ATTR_GROUP_PORT;
464         arg.prev = NULL;
465         arg.head = &dev->port_ops;
466         swlib_call(SWITCH_CMD_LIST_PORT, add_attr, add_id, &arg);
467
468         arg.atype = SWLIB_ATTR_GROUP_VLAN;
469         arg.prev = NULL;
470         arg.head = &dev->vlan_ops;
471         swlib_call(SWITCH_CMD_LIST_VLAN, add_attr, add_id, &arg);
472
473         return 0;
474 }
475
476 struct switch_attr *swlib_lookup_attr(struct switch_dev *dev,
477                 enum swlib_attr_group atype, const char *name)
478 {
479         struct switch_attr *head;
480
481         if (!name || !dev)
482                 return NULL;
483
484         switch(atype) {
485         case SWLIB_ATTR_GROUP_GLOBAL:
486                 head = dev->ops;
487                 break;
488         case SWLIB_ATTR_GROUP_PORT:
489                 head = dev->port_ops;
490                 break;
491         case SWLIB_ATTR_GROUP_VLAN:
492                 head = dev->vlan_ops;
493                 break;
494         }
495         while(head) {
496                 if (!strcmp(name, head->name))
497                         return head;
498                 head = head->next;
499         }
500
501         return NULL;
502 }
503
504 static void
505 swlib_priv_free(void)
506 {
507         if (cache)
508                 nl_cache_free(cache);
509         if (handle)
510                 nl_handle_destroy(handle);
511         handle = NULL;
512         cache = NULL;
513 }
514
515 static int
516 swlib_priv_init(void)
517 {
518         handle = nl_handle_alloc();
519         if (!handle) {
520                 DPRINTF("Failed to create handle\n");
521                 goto err;
522         }
523
524         if (genl_connect(handle)) {
525                 DPRINTF("Failed to connect to generic netlink\n");
526                 goto err;
527         }
528
529         cache = genl_ctrl_alloc_cache(handle);
530         if (!cache) {
531                 DPRINTF("Failed to allocate netlink cache\n");
532                 goto err;
533         }
534
535         family = genl_ctrl_search_by_name(cache, "switch");
536         if (!family) {
537                 DPRINTF("Switch API not present\n");
538                 goto err;
539         }
540         return 0;
541
542 err:
543         swlib_priv_free();
544         return -EINVAL;
545 }
546
547 struct swlib_scan_arg {
548         const char *name;
549         struct switch_dev *head;
550         struct switch_dev *ptr;
551 };
552
553 static int
554 add_switch(struct nl_msg *msg, void *arg)
555 {
556         struct swlib_scan_arg *sa = arg;
557         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
558         struct switch_dev *dev;
559         const char *name;
560
561         if (nla_parse(tb, SWITCH_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
562                 goto done;
563
564         if (!tb[SWITCH_ATTR_DEV_NAME])
565                 goto done;
566
567         name = nla_get_string(tb[SWITCH_ATTR_DEV_NAME]);
568         if (sa->name && (strcmp(name, sa->name) != 0))
569                 goto done;
570
571         dev = swlib_alloc(sizeof(struct switch_dev));
572         if (!dev)
573                 goto done;
574
575         dev->dev_name = strdup(name);
576         if (tb[SWITCH_ATTR_ID])
577                 dev->id = nla_get_u32(tb[SWITCH_ATTR_ID]);
578         if (tb[SWITCH_ATTR_NAME])
579                 dev->name = strdup(nla_get_string(tb[SWITCH_ATTR_DEV_NAME]));
580         if (tb[SWITCH_ATTR_PORTS])
581                 dev->ports = nla_get_u32(tb[SWITCH_ATTR_PORTS]);
582         if (tb[SWITCH_ATTR_VLANS])
583                 dev->vlans = nla_get_u32(tb[SWITCH_ATTR_VLANS]);
584
585         if (!sa->head) {
586                 sa->head = dev;
587                 sa->ptr = dev;
588         } else {
589                 sa->ptr->next = dev;
590                 sa->ptr = dev;
591         }
592
593         refcount++;
594 done:
595         return NL_SKIP;
596 }
597
598
599 struct switch_dev *
600 swlib_connect(const char *name)
601 {
602         struct swlib_scan_arg arg;
603         int err;
604
605         if (!refcount) {
606                 if (swlib_priv_init() < 0)
607                         return NULL;
608         };
609
610         arg.head = NULL;
611         arg.ptr = NULL;
612         arg.name = name;
613         swlib_call(SWITCH_CMD_GET_SWITCH, add_switch, NULL, &arg);
614
615         if (!refcount)
616                 swlib_priv_free();
617
618         return arg.head;
619 }
620
621 static void
622 swlib_free_attributes(struct switch_attr **head)
623 {
624         struct switch_attr *a = *head;
625         struct switch_attr *next;
626
627         while (a) {
628                 next = a->next;
629                 free(a);
630                 a = next;
631         }
632         *head = NULL;
633 }
634
635 void
636 swlib_free(struct switch_dev *dev)
637 {
638         swlib_free_attributes(&dev->ops);
639         swlib_free_attributes(&dev->port_ops);
640         swlib_free_attributes(&dev->vlan_ops);
641         free(dev);
642
643         if (--refcount == 0)
644                 swlib_priv_free();
645 }
646
647 void
648 swlib_free_all(struct switch_dev *dev)
649 {
650         struct switch_dev *p;
651
652         while (dev) {
653                 p = dev->next;
654                 swlib_free(dev);
655                 dev = p;
656         }
657 }