swconfig: use print_attr_val() in CMD_GET
[openwrt/openwrt.git] / package / swconfig / src / cli.c
1 /*
2 * swconfig.c: Switch configuration utility
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 General Public License
8 * version 2 as published by the Free Software Foundatio.
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 <uci.h>
26
27 #include <linux/types.h>
28 #include <linux/netlink.h>
29 #include <linux/genetlink.h>
30 #include <netlink/netlink.h>
31 #include <netlink/genl/genl.h>
32 #include <netlink/genl/ctrl.h>
33 #include <linux/switch.h>
34 #include "swlib.h"
35
36 enum {
37 CMD_NONE,
38 CMD_GET,
39 CMD_SET,
40 CMD_LOAD,
41 CMD_HELP,
42 CMD_SHOW,
43 };
44
45 static void
46 print_attrs(const struct switch_attr *attr)
47 {
48 int i = 0;
49 while (attr) {
50 const char *type;
51 switch(attr->type) {
52 case SWITCH_TYPE_INT:
53 type = "int";
54 break;
55 case SWITCH_TYPE_STRING:
56 type = "string";
57 break;
58 case SWITCH_TYPE_PORTS:
59 type = "ports";
60 break;
61 case SWITCH_TYPE_NOVAL:
62 type = "none";
63 break;
64 default:
65 type = "unknown";
66 break;
67 }
68 printf("\tAttribute %d (%s): %s (%s)\n", ++i, type, attr->name, attr->description);
69 attr = attr->next;
70 }
71 }
72
73 static void
74 list_attributes(struct switch_dev *dev)
75 {
76 printf("Switch %d: %s(%s), ports: %d, vlans: %d\n", dev->id, dev->dev_name, dev->name, dev->ports, dev->vlans);
77 printf(" --switch\n");
78 print_attrs(dev->ops);
79 printf(" --vlan\n");
80 print_attrs(dev->vlan_ops);
81 printf(" --port\n");
82 print_attrs(dev->port_ops);
83 }
84
85 static void
86 print_attr_val(const struct switch_attr *attr, const struct switch_val *val)
87 {
88 int i;
89
90 switch (attr->type) {
91 case SWITCH_TYPE_INT:
92 printf("%d", val->value.i);
93 break;
94 case SWITCH_TYPE_STRING:
95 printf("%s", val->value.s);
96 break;
97 case SWITCH_TYPE_PORTS:
98 for(i = 0; i < val->len; i++) {
99 printf("%d%s ",
100 val->value.ports[i].id,
101 (val->value.ports[i].flags &
102 SWLIB_PORT_FLAG_TAGGED) ? "t" : "");
103 }
104 break;
105 default:
106 printf("?unknown-type?");
107 }
108 }
109
110 static void
111 show_attrs(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
112 {
113 while (attr) {
114 if (attr->type != SWITCH_TYPE_NOVAL) {
115 printf("\t%s: ", attr->name);
116 if (swlib_get_attr(dev, attr, val) < 0)
117 printf("???");
118 else
119 print_attr_val(attr, val);
120 putchar('\n');
121 }
122 attr = attr->next;
123 }
124 }
125
126 static void
127 show_global(struct switch_dev *dev)
128 {
129 struct switch_val val;
130
131 printf("Global attributes:\n");
132 show_attrs(dev, dev->ops, &val);
133 }
134
135 static void
136 show_port(struct switch_dev *dev, int port)
137 {
138 struct switch_val val;
139
140 printf("Port %d:\n", port);
141 val.port_vlan = port;
142 show_attrs(dev, dev->port_ops, &val);
143 }
144
145 static void
146 show_vlan(struct switch_dev *dev, int vlan)
147 {
148 struct switch_val val;
149
150 printf("VLAN %d:\n", vlan);
151 val.port_vlan = vlan;
152 show_attrs(dev, dev->vlan_ops, &val);
153 }
154
155 static void
156 print_usage(void)
157 {
158 printf("swconfig dev <dev> [port <port>|vlan <vlan>] (help|set <key> <value>|get <key>|load <config>|show)\n");
159 exit(1);
160 }
161
162 static void
163 swconfig_load_uci(struct switch_dev *dev, const char *name)
164 {
165 struct uci_context *ctx;
166 struct uci_package *p = NULL;
167 struct uci_element *e;
168 int ret = -1;
169
170 ctx = uci_alloc_context();
171 if (!ctx)
172 return;
173
174 uci_load(ctx, name, &p);
175 if (!p) {
176 uci_perror(ctx, "Failed to load config file: ");
177 goto out;
178 }
179
180 ret = swlib_apply_from_uci(dev, p);
181 if (ret < 0)
182 fprintf(stderr, "Failed to apply configuration for switch '%s'\n", dev->dev_name);
183
184 out:
185 uci_free_context(ctx);
186 exit(ret);
187 }
188
189 int main(int argc, char **argv)
190 {
191 int retval = 0;
192 struct switch_dev *dev;
193 struct switch_attr *a;
194 struct switch_val val;
195 int err;
196 int i;
197
198 struct switch_port *ports;
199
200 int cmd = CMD_NONE;
201 char *cdev = NULL;
202 int cport = -1;
203 int cvlan = -1;
204 char *ckey = NULL;
205 char *cvalue = NULL;
206
207 if(argc < 4)
208 print_usage();
209
210 if(strcmp(argv[1], "dev"))
211 print_usage();
212
213 cdev = argv[2];
214
215 for(i = 3; i < argc; i++)
216 {
217 char *arg = argv[i];
218 if (cmd != CMD_NONE) {
219 print_usage();
220 } else if (!strcmp(arg, "port") && i+1 < argc) {
221 cport = atoi(argv[++i]);
222 } else if (!strcmp(arg, "vlan") && i+1 < argc) {
223 cvlan = atoi(argv[++i]);
224 } else if (!strcmp(arg, "help")) {
225 cmd = CMD_HELP;
226 } else if (!strcmp(arg, "set") && i+1 < argc) {
227 cmd = CMD_SET;
228 ckey = argv[++i];
229 if (i+1 < argc)
230 cvalue = argv[++i];
231 } else if (!strcmp(arg, "get") && i+1 < argc) {
232 cmd = CMD_GET;
233 ckey = argv[++i];
234 } else if (!strcmp(arg, "load") && i+1 < argc) {
235 if ((cport >= 0) || (cvlan >= 0))
236 print_usage();
237 cmd = CMD_LOAD;
238 ckey = argv[++i];
239 } else if (!strcmp(arg, "show")) {
240 cmd = CMD_SHOW;
241 } else {
242 print_usage();
243 }
244 }
245
246 if (cmd == CMD_NONE)
247 print_usage();
248 if (cport > -1 && cvlan > -1)
249 print_usage();
250
251 dev = swlib_connect(cdev);
252 if (!dev) {
253 fprintf(stderr, "Failed to connect to the switch\n");
254 return 1;
255 }
256
257 ports = malloc(sizeof(struct switch_port) * dev->ports);
258 memset(ports, 0, sizeof(struct switch_port) * dev->ports);
259 swlib_scan(dev);
260
261 if (cmd == CMD_GET || cmd == CMD_SET) {
262 if(cport > -1)
263 a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_PORT, ckey);
264 else if(cvlan > -1)
265 a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_VLAN, ckey);
266 else
267 a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_GLOBAL, ckey);
268
269 if(!a)
270 {
271 fprintf(stderr, "Unknown attribute \"%s\"\n", ckey);
272 goto out;
273 }
274 }
275
276 switch(cmd)
277 {
278 case CMD_SET:
279 if ((a->type != SWITCH_TYPE_NOVAL) &&
280 (cvalue == NULL))
281 print_usage();
282
283 if(cvlan > -1)
284 cport = cvlan;
285
286 if(swlib_set_attr_string(dev, a, cport, cvalue) < 0)
287 {
288 fprintf(stderr, "failed\n");
289 retval = -1;
290 goto out;
291 }
292 break;
293 case CMD_GET:
294 if(cvlan > -1)
295 val.port_vlan = cvlan;
296 if(cport > -1)
297 val.port_vlan = cport;
298 if(swlib_get_attr(dev, a, &val) < 0)
299 {
300 fprintf(stderr, "failed\n");
301 retval = -1;
302 goto out;
303 }
304 print_attr_val(a, &val);
305 putchar('\n');
306 break;
307 case CMD_LOAD:
308 swconfig_load_uci(dev, ckey);
309 break;
310 case CMD_HELP:
311 list_attributes(dev);
312 break;
313 case CMD_SHOW:
314 if (cport >= 0 || cvlan >= 0) {
315 if (cport >= 0)
316 show_port(dev, cport);
317 else
318 show_vlan(dev, cvlan);
319 } else {
320 show_global(dev);
321 for (i=0; i < dev->ports; i++)
322 show_port(dev, i);
323 for (i=0; i < dev->vlans; i++)
324 show_vlan(dev, i);
325 }
326 break;
327 }
328
329 out:
330 swlib_free_all(dev);
331 free(ports);
332
333 return 0;
334 }