2 * swlib.c: Switch configuration API (user space part)
4 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
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.
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.
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <linux/switch.h>
30 #define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__)
32 #define DPRINTF(fmt, ...) do {} while (0)
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;
41 static struct nla_policy port_policy
[] = {
42 [SWITCH_PORT_ID
] = { .type
= NLA_U32
},
43 [SWITCH_PORT_FLAG_TAGGED
] = { .type
= NLA_FLAG
},
47 swlib_alloc(size_t size
)
61 wait_handler(struct nl_msg
*msg
, void *arg
)
69 /* helper function for performing netlink requests */
71 swlib_call(int cmd
, int (*call
)(struct nl_msg
*, void *),
72 int (*data
)(struct nl_msg
*, void *), void *arg
)
75 struct nl_cb
*cb
= NULL
;
82 fprintf(stderr
, "Out of memory!\n");
89 genlmsg_put(msg
, NL_AUTO_PID
, NL_AUTO_SEQ
, genl_family_get_id(family
), 0, flags
, cmd
, 0);
91 if (data(msg
, arg
) < 0)
95 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
97 fprintf(stderr
, "nl_cb_alloc failed.\n");
101 err
= nl_send_auto_complete(handle
, msg
);
103 fprintf(stderr
, "nl_send_auto_complete failed: %d\n", err
);
110 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, call
, arg
);
113 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, wait_handler
, &finished
);
115 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, wait_handler
, &finished
);
117 err
= nl_recvmsgs(handle
, cb
);
123 err
= nl_wait_for_ack(handle
);
134 send_attr(struct nl_msg
*msg
, void *arg
)
136 struct switch_val
*val
= arg
;
137 struct switch_attr
*attr
= val
->attr
;
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
);
145 case SWLIB_ATTR_GROUP_VLAN
:
146 NLA_PUT_U32(msg
, SWITCH_ATTR_OP_VLAN
, val
->port_vlan
);
159 store_port_val(struct nl_msg
*msg
, struct nlattr
*nla
, struct switch_val
*val
)
162 int ports
= val
->attr
->dev
->ports
;
166 if (!val
->value
.ports
)
167 val
->value
.ports
= malloc(sizeof(struct switch_port
) * ports
);
169 nla_for_each_nested(p
, nla
, remaining
) {
170 struct nlattr
*tb
[SWITCH_PORT_ATTR_MAX
+1];
171 struct switch_port
*port
;
173 if (val
->len
>= ports
)
176 err
= nla_parse_nested(tb
, SWITCH_PORT_ATTR_MAX
, p
, port_policy
);
180 if (!tb
[SWITCH_PORT_ID
])
183 port
= &val
->value
.ports
[val
->len
];
184 port
->id
= nla_get_u32(tb
[SWITCH_PORT_ID
]);
186 if (tb
[SWITCH_PORT_FLAG_TAGGED
])
187 port
->flags
|= SWLIB_PORT_FLAG_TAGGED
;
197 store_val(struct nl_msg
*msg
, void *arg
)
199 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
200 struct switch_val
*val
= arg
;
201 struct switch_attr
*attr
= val
->attr
;
206 if (nla_parse(tb
, SWITCH_ATTR_MAX
- 1, genlmsg_attrdata(gnlh
, 0),
207 genlmsg_attrlen(gnlh
, 0), NULL
) < 0) {
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
);
226 swlib_get_attr(struct switch_dev
*dev
, struct switch_attr
*attr
, struct switch_val
*val
)
231 switch(attr
->atype
) {
232 case SWLIB_ATTR_GROUP_GLOBAL
:
233 cmd
= SWITCH_CMD_GET_GLOBAL
;
235 case SWLIB_ATTR_GROUP_PORT
:
236 cmd
= SWITCH_CMD_GET_PORT
;
238 case SWLIB_ATTR_GROUP_VLAN
:
239 cmd
= SWITCH_CMD_GET_VLAN
;
245 memset(&val
->value
, 0, sizeof(val
->value
));
249 err
= swlib_call(cmd
, store_val
, send_attr
, val
);
257 send_attr_ports(struct nl_msg
*msg
, struct switch_val
*val
)
262 /* TODO implement multipart? */
265 n
= nla_nest_start(msg
, SWITCH_ATTR_OP_VALUE_PORTS
);
267 goto nla_put_failure
;
268 for (i
= 0; i
< val
->len
; i
++) {
269 struct switch_port
*port
= &val
->value
.ports
[i
];
272 np
= nla_nest_start(msg
, SWITCH_ATTR_PORT
);
274 goto nla_put_failure
;
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
);
280 nla_nest_end(msg
, np
);
282 nla_nest_end(msg
, n
);
291 send_attr_val(struct nl_msg
*msg
, void *arg
)
293 struct switch_val
*val
= arg
;
294 struct switch_attr
*attr
= val
->attr
;
296 if (send_attr(msg
, arg
))
297 goto nla_put_failure
;
300 case SWITCH_TYPE_NOVAL
:
302 case SWITCH_TYPE_INT
:
303 NLA_PUT_U32(msg
, SWITCH_ATTR_OP_VALUE_INT
, val
->value
.i
);
305 case SWITCH_TYPE_STRING
:
307 goto nla_put_failure
;
308 NLA_PUT_STRING(msg
, SWITCH_ATTR_OP_VALUE_STR
, val
->value
.s
);
310 case SWITCH_TYPE_PORTS
:
311 if (send_attr_ports(msg
, val
) < 0)
312 goto nla_put_failure
;
315 goto nla_put_failure
;
324 swlib_set_attr(struct switch_dev
*dev
, struct switch_attr
*attr
, struct switch_val
*val
)
328 switch(attr
->atype
) {
329 case SWLIB_ATTR_GROUP_GLOBAL
:
330 cmd
= SWITCH_CMD_SET_GLOBAL
;
332 case SWLIB_ATTR_GROUP_PORT
:
333 cmd
= SWITCH_CMD_SET_PORT
;
335 case SWLIB_ATTR_GROUP_VLAN
:
336 cmd
= SWITCH_CMD_SET_VLAN
;
343 return swlib_call(cmd
, NULL
, send_attr_val
, val
);
346 int swlib_set_attr_string(struct switch_dev
*dev
, struct switch_attr
*a
, int port_vlan
, const char *str
)
348 struct switch_port
*ports
;
349 struct switch_val val
;
352 memset(&val
, 0, sizeof(val
));
353 val
.port_vlan
= port_vlan
;
355 case SWITCH_TYPE_INT
:
356 val
.value
.i
= atoi(str
);
358 case SWITCH_TYPE_STRING
:
361 case SWITCH_TYPE_PORTS
:
362 ports
= alloca(sizeof(struct switch_port
) * dev
->ports
);
363 memset(ports
, 0, sizeof(struct switch_port
) * dev
->ports
);
368 ports
[val
.len
].flags
= 0;
369 ports
[val
.len
].id
= strtoul(ptr
, &ptr
, 10);
370 while(*ptr
&& !isspace(*ptr
)) {
372 ports
[val
.len
].flags
|= SWLIB_PORT_FLAG_TAGGED
;
379 val
.value
.ports
= ports
;
381 case SWITCH_TYPE_NOVAL
:
386 return swlib_set_attr(dev
, a
, &val
);
390 struct attrlist_arg
{
393 struct switch_dev
*dev
;
394 struct switch_attr
*prev
;
395 struct switch_attr
**head
;
399 add_id(struct nl_msg
*msg
, void *arg
)
401 struct attrlist_arg
*l
= arg
;
403 NLA_PUT_U32(msg
, SWITCH_ATTR_ID
, l
->id
);
411 add_attr(struct nl_msg
*msg
, void *ptr
)
413 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
414 struct attrlist_arg
*arg
= ptr
;
415 struct switch_attr
*new;
417 if (nla_parse(tb
, SWITCH_ATTR_MAX
- 1, genlmsg_attrdata(gnlh
, 0),
418 genlmsg_attrlen(gnlh
, 0), NULL
) < 0)
421 new = swlib_alloc(sizeof(struct switch_attr
));
426 new->atype
= arg
->atype
;
428 arg
->prev
->next
= new;
430 arg
->prev
= *arg
->head
;
433 arg
->head
= &new->next
;
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
]));
449 swlib_scan(struct switch_dev
*dev
)
451 struct attrlist_arg arg
;
453 if (dev
->ops
|| dev
->port_ops
|| dev
->vlan_ops
)
456 arg
.atype
= SWLIB_ATTR_GROUP_GLOBAL
;
460 arg
.head
= &dev
->ops
;
461 swlib_call(SWITCH_CMD_LIST_GLOBAL
, add_attr
, add_id
, &arg
);
463 arg
.atype
= SWLIB_ATTR_GROUP_PORT
;
465 arg
.head
= &dev
->port_ops
;
466 swlib_call(SWITCH_CMD_LIST_PORT
, add_attr
, add_id
, &arg
);
468 arg
.atype
= SWLIB_ATTR_GROUP_VLAN
;
470 arg
.head
= &dev
->vlan_ops
;
471 swlib_call(SWITCH_CMD_LIST_VLAN
, add_attr
, add_id
, &arg
);
476 struct switch_attr
*swlib_lookup_attr(struct switch_dev
*dev
,
477 enum swlib_attr_group atype
, const char *name
)
479 struct switch_attr
*head
;
485 case SWLIB_ATTR_GROUP_GLOBAL
:
488 case SWLIB_ATTR_GROUP_PORT
:
489 head
= dev
->port_ops
;
491 case SWLIB_ATTR_GROUP_VLAN
:
492 head
= dev
->vlan_ops
;
496 if (!strcmp(name
, head
->name
))
505 swlib_priv_free(void)
508 nl_cache_free(cache
);
510 nl_handle_destroy(handle
);
516 swlib_priv_init(void)
518 handle
= nl_handle_alloc();
520 DPRINTF("Failed to create handle\n");
524 if (genl_connect(handle
)) {
525 DPRINTF("Failed to connect to generic netlink\n");
529 cache
= genl_ctrl_alloc_cache(handle
);
531 DPRINTF("Failed to allocate netlink cache\n");
535 family
= genl_ctrl_search_by_name(cache
, "switch");
537 DPRINTF("Switch API not present\n");
547 struct swlib_scan_arg
{
549 struct switch_dev
*head
;
550 struct switch_dev
*ptr
;
554 add_switch(struct nl_msg
*msg
, void *arg
)
556 struct swlib_scan_arg
*sa
= arg
;
557 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
558 struct switch_dev
*dev
;
561 if (nla_parse(tb
, SWITCH_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0), genlmsg_attrlen(gnlh
, 0), NULL
) < 0)
564 if (!tb
[SWITCH_ATTR_DEV_NAME
])
567 name
= nla_get_string(tb
[SWITCH_ATTR_DEV_NAME
]);
568 if (sa
->name
&& (strcmp(name
, sa
->name
) != 0))
571 dev
= swlib_alloc(sizeof(struct switch_dev
));
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
]);
600 swlib_connect(const char *name
)
602 struct swlib_scan_arg arg
;
606 if (swlib_priv_init() < 0)
613 swlib_call(SWITCH_CMD_GET_SWITCH
, add_switch
, NULL
, &arg
);
622 swlib_free_attributes(struct switch_attr
**head
)
624 struct switch_attr
*a
= *head
;
625 struct switch_attr
*next
;
636 swlib_free(struct switch_dev
*dev
)
638 swlib_free_attributes(&dev
->ops
);
639 swlib_free_attributes(&dev
->port_ops
);
640 swlib_free_attributes(&dev
->vlan_ops
);
648 swlib_free_all(struct switch_dev
*dev
)
650 struct switch_dev
*p
;