2 * swlib.c: Switch configuration API (user space part)
4 * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
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>
27 #include <netlink/netlink.h>
28 #include <netlink/genl/genl.h>
29 #include <netlink/genl/family.h>
33 #define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__)
35 #define DPRINTF(fmt, ...) do {} while (0)
38 static struct nl_sock
*handle
;
39 static struct nl_cache
*cache
;
40 static struct genl_family
*family
;
41 static struct nlattr
*tb
[SWITCH_ATTR_MAX
+ 1];
42 static int refcount
= 0;
44 static struct nla_policy port_policy
[SWITCH_ATTR_MAX
] = {
45 [SWITCH_PORT_ID
] = { .type
= NLA_U32
},
46 [SWITCH_PORT_FLAG_TAGGED
] = { .type
= NLA_FLAG
},
49 static struct nla_policy link_policy
[SWITCH_LINK_ATTR_MAX
] = {
50 [SWITCH_LINK_FLAG_LINK
] = { .type
= NLA_FLAG
},
51 [SWITCH_LINK_FLAG_DUPLEX
] = { .type
= NLA_FLAG
},
52 [SWITCH_LINK_FLAG_ANEG
] = { .type
= NLA_FLAG
},
53 [SWITCH_LINK_SPEED
] = { .type
= NLA_U32
},
54 [SWITCH_LINK_FLAG_EEE_100BASET
] = { .type
= NLA_FLAG
},
55 [SWITCH_LINK_FLAG_EEE_1000BASET
] = { .type
= NLA_FLAG
},
59 swlib_alloc(size_t size
)
73 wait_handler(struct nl_msg
*msg
, void *arg
)
81 /* helper function for performing netlink requests */
83 swlib_call(int cmd
, int (*call
)(struct nl_msg
*, void *),
84 int (*data
)(struct nl_msg
*, void *), void *arg
)
87 struct nl_cb
*cb
= NULL
;
94 fprintf(stderr
, "Out of memory!\n");
101 genlmsg_put(msg
, NL_AUTO_PID
, NL_AUTO_SEQ
, genl_family_get_id(family
), 0, flags
, cmd
, 0);
103 if (data(msg
, arg
) < 0)
104 goto nla_put_failure
;
107 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
109 fprintf(stderr
, "nl_cb_alloc failed.\n");
113 err
= nl_send_auto_complete(handle
, msg
);
115 fprintf(stderr
, "nl_send_auto_complete failed: %d\n", err
);
122 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, call
, arg
);
125 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, wait_handler
, &finished
);
127 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, wait_handler
, &finished
);
129 err
= nl_recvmsgs(handle
, cb
);
135 err
= nl_wait_for_ack(handle
);
146 send_attr(struct nl_msg
*msg
, void *arg
)
148 struct switch_val
*val
= arg
;
149 struct switch_attr
*attr
= val
->attr
;
151 NLA_PUT_U32(msg
, SWITCH_ATTR_ID
, attr
->dev
->id
);
152 NLA_PUT_U32(msg
, SWITCH_ATTR_OP_ID
, attr
->id
);
153 switch(attr
->atype
) {
154 case SWLIB_ATTR_GROUP_PORT
:
155 NLA_PUT_U32(msg
, SWITCH_ATTR_OP_PORT
, val
->port_vlan
);
157 case SWLIB_ATTR_GROUP_VLAN
:
158 NLA_PUT_U32(msg
, SWITCH_ATTR_OP_VLAN
, val
->port_vlan
);
171 store_port_val(struct nl_msg
*msg
, struct nlattr
*nla
, struct switch_val
*val
)
174 int ports
= val
->attr
->dev
->ports
;
178 if (!val
->value
.ports
)
179 val
->value
.ports
= malloc(sizeof(struct switch_port
) * ports
);
181 nla_for_each_nested(p
, nla
, remaining
) {
182 struct nlattr
*tb
[SWITCH_PORT_ATTR_MAX
+1];
183 struct switch_port
*port
;
185 if (val
->len
>= ports
)
188 err
= nla_parse_nested(tb
, SWITCH_PORT_ATTR_MAX
, p
, port_policy
);
192 if (!tb
[SWITCH_PORT_ID
])
195 port
= &val
->value
.ports
[val
->len
];
196 port
->id
= nla_get_u32(tb
[SWITCH_PORT_ID
]);
198 if (tb
[SWITCH_PORT_FLAG_TAGGED
])
199 port
->flags
|= SWLIB_PORT_FLAG_TAGGED
;
209 store_link_val(struct nl_msg
*msg
, struct nlattr
*nla
, struct switch_val
*val
)
211 struct nlattr
*tb
[SWITCH_LINK_ATTR_MAX
+ 1];
212 struct switch_port_link
*link
;
215 if (!val
->value
.link
)
216 val
->value
.link
= malloc(sizeof(struct switch_port_link
));
218 err
= nla_parse_nested(tb
, SWITCH_LINK_ATTR_MAX
, nla
, link_policy
);
222 link
= val
->value
.link
;
223 link
->link
= !!tb
[SWITCH_LINK_FLAG_LINK
];
224 link
->duplex
= !!tb
[SWITCH_LINK_FLAG_DUPLEX
];
225 link
->aneg
= !!tb
[SWITCH_LINK_FLAG_ANEG
];
226 link
->tx_flow
= !!tb
[SWITCH_LINK_FLAG_TX_FLOW
];
227 link
->rx_flow
= !!tb
[SWITCH_LINK_FLAG_RX_FLOW
];
228 link
->speed
= nla_get_u32(tb
[SWITCH_LINK_SPEED
]);
230 if (tb
[SWITCH_LINK_FLAG_EEE_100BASET
])
231 link
->eee
|= SWLIB_LINK_FLAG_EEE_100BASET
;
232 if (tb
[SWITCH_LINK_FLAG_EEE_1000BASET
])
233 link
->eee
|= SWLIB_LINK_FLAG_EEE_1000BASET
;
240 store_val(struct nl_msg
*msg
, void *arg
)
242 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
243 struct switch_val
*val
= arg
;
248 if (nla_parse(tb
, SWITCH_ATTR_MAX
- 1, genlmsg_attrdata(gnlh
, 0),
249 genlmsg_attrlen(gnlh
, 0), NULL
) < 0) {
253 if (tb
[SWITCH_ATTR_OP_VALUE_INT
])
254 val
->value
.i
= nla_get_u32(tb
[SWITCH_ATTR_OP_VALUE_INT
]);
255 else if (tb
[SWITCH_ATTR_OP_VALUE_STR
])
256 val
->value
.s
= strdup(nla_get_string(tb
[SWITCH_ATTR_OP_VALUE_STR
]));
257 else if (tb
[SWITCH_ATTR_OP_VALUE_PORTS
])
258 val
->err
= store_port_val(msg
, tb
[SWITCH_ATTR_OP_VALUE_PORTS
], val
);
259 else if (tb
[SWITCH_ATTR_OP_VALUE_LINK
])
260 val
->err
= store_link_val(msg
, tb
[SWITCH_ATTR_OP_VALUE_LINK
], val
);
270 swlib_get_attr(struct switch_dev
*dev
, struct switch_attr
*attr
, struct switch_val
*val
)
275 switch(attr
->atype
) {
276 case SWLIB_ATTR_GROUP_GLOBAL
:
277 cmd
= SWITCH_CMD_GET_GLOBAL
;
279 case SWLIB_ATTR_GROUP_PORT
:
280 cmd
= SWITCH_CMD_GET_PORT
;
282 case SWLIB_ATTR_GROUP_VLAN
:
283 cmd
= SWITCH_CMD_GET_VLAN
;
289 memset(&val
->value
, 0, sizeof(val
->value
));
293 err
= swlib_call(cmd
, store_val
, send_attr
, val
);
301 send_attr_ports(struct nl_msg
*msg
, struct switch_val
*val
)
306 /* TODO implement multipart? */
309 n
= nla_nest_start(msg
, SWITCH_ATTR_OP_VALUE_PORTS
);
311 goto nla_put_failure
;
312 for (i
= 0; i
< val
->len
; i
++) {
313 struct switch_port
*port
= &val
->value
.ports
[i
];
316 np
= nla_nest_start(msg
, SWITCH_ATTR_PORT
);
318 goto nla_put_failure
;
320 NLA_PUT_U32(msg
, SWITCH_PORT_ID
, port
->id
);
321 if (port
->flags
& SWLIB_PORT_FLAG_TAGGED
)
322 NLA_PUT_FLAG(msg
, SWITCH_PORT_FLAG_TAGGED
);
324 nla_nest_end(msg
, np
);
326 nla_nest_end(msg
, n
);
335 send_attr_link(struct nl_msg
*msg
, struct switch_val
*val
)
337 struct switch_port_link
*link
= val
->value
.link
;
340 n
= nla_nest_start(msg
, SWITCH_ATTR_OP_VALUE_LINK
);
342 goto nla_put_failure
;
345 NLA_PUT_FLAG(msg
, SWITCH_LINK_FLAG_DUPLEX
);
347 NLA_PUT_FLAG(msg
, SWITCH_LINK_FLAG_ANEG
);
348 NLA_PUT_U32(msg
, SWITCH_LINK_SPEED
, link
->speed
);
350 nla_nest_end(msg
, n
);
359 send_attr_val(struct nl_msg
*msg
, void *arg
)
361 struct switch_val
*val
= arg
;
362 struct switch_attr
*attr
= val
->attr
;
364 if (send_attr(msg
, arg
))
365 goto nla_put_failure
;
368 case SWITCH_TYPE_NOVAL
:
370 case SWITCH_TYPE_INT
:
371 NLA_PUT_U32(msg
, SWITCH_ATTR_OP_VALUE_INT
, val
->value
.i
);
373 case SWITCH_TYPE_STRING
:
375 goto nla_put_failure
;
376 NLA_PUT_STRING(msg
, SWITCH_ATTR_OP_VALUE_STR
, val
->value
.s
);
378 case SWITCH_TYPE_PORTS
:
379 if (send_attr_ports(msg
, val
) < 0)
380 goto nla_put_failure
;
382 case SWITCH_TYPE_LINK
:
383 if (send_attr_link(msg
, val
))
384 goto nla_put_failure
;
387 goto nla_put_failure
;
396 swlib_set_attr(struct switch_dev
*dev
, struct switch_attr
*attr
, struct switch_val
*val
)
400 switch(attr
->atype
) {
401 case SWLIB_ATTR_GROUP_GLOBAL
:
402 cmd
= SWITCH_CMD_SET_GLOBAL
;
404 case SWLIB_ATTR_GROUP_PORT
:
405 cmd
= SWITCH_CMD_SET_PORT
;
407 case SWLIB_ATTR_GROUP_VLAN
:
408 cmd
= SWITCH_CMD_SET_VLAN
;
415 return swlib_call(cmd
, NULL
, send_attr_val
, val
);
425 int swlib_set_attr_string(struct switch_dev
*dev
, struct switch_attr
*a
, int port_vlan
, const char *str
)
427 struct switch_port
*ports
;
428 struct switch_port_link
*link
;
429 struct switch_val val
;
433 memset(&val
, 0, sizeof(val
));
434 val
.port_vlan
= port_vlan
;
436 case SWITCH_TYPE_INT
:
437 val
.value
.i
= atoi(str
);
439 case SWITCH_TYPE_STRING
:
440 val
.value
.s
= (char *)str
;
442 case SWITCH_TYPE_PORTS
:
443 ports
= alloca(sizeof(struct switch_port
) * dev
->ports
);
444 memset(ports
, 0, sizeof(struct switch_port
) * dev
->ports
);
449 while(*ptr
&& isspace(*ptr
))
458 if (val
.len
>= dev
->ports
)
461 ports
[val
.len
].flags
= 0;
462 ports
[val
.len
].id
= strtoul(ptr
, &ptr
, 10);
463 while(*ptr
&& !isspace(*ptr
)) {
465 ports
[val
.len
].flags
|= SWLIB_PORT_FLAG_TAGGED
;
475 val
.value
.ports
= ports
;
477 case SWITCH_TYPE_LINK
:
478 link
= malloc(sizeof(struct switch_port_link
));
479 memset(link
, 0, sizeof(struct switch_port_link
));
481 for (ptr
= strtok(ptr
," "); ptr
; ptr
= strtok(NULL
, " ")) {
484 if (!strcmp(ptr
, "duplex"))
486 else if (!strcmp(ptr
, "autoneg"))
488 else if (!strcmp(ptr
, "speed"))
491 fprintf(stderr
, "Unsupported option %s\n", ptr
);
494 if (!strcmp(ptr
, "half"))
496 else if (!strcmp(ptr
, "full"))
499 fprintf(stderr
, "Unsupported value %s\n", ptr
);
503 if (!strcmp(ptr
, "on"))
505 else if (!strcmp(ptr
, "off"))
508 fprintf(stderr
, "Unsupported value %s\n", ptr
);
512 link
->speed
= atoi(ptr
);
517 val
.value
.link
= link
;
519 case SWITCH_TYPE_NOVAL
:
520 if (str
&& !strcmp(str
, "0"))
527 return swlib_set_attr(dev
, a
, &val
);
531 struct attrlist_arg
{
534 struct switch_dev
*dev
;
535 struct switch_attr
*prev
;
536 struct switch_attr
**head
;
540 add_id(struct nl_msg
*msg
, void *arg
)
542 struct attrlist_arg
*l
= arg
;
544 NLA_PUT_U32(msg
, SWITCH_ATTR_ID
, l
->id
);
552 add_attr(struct nl_msg
*msg
, void *ptr
)
554 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
555 struct attrlist_arg
*arg
= ptr
;
556 struct switch_attr
*new;
558 if (nla_parse(tb
, SWITCH_ATTR_MAX
- 1, genlmsg_attrdata(gnlh
, 0),
559 genlmsg_attrlen(gnlh
, 0), NULL
) < 0)
562 new = swlib_alloc(sizeof(struct switch_attr
));
567 new->atype
= arg
->atype
;
569 arg
->prev
->next
= new;
571 arg
->prev
= *arg
->head
;
574 arg
->head
= &new->next
;
576 if (tb
[SWITCH_ATTR_OP_ID
])
577 new->id
= nla_get_u32(tb
[SWITCH_ATTR_OP_ID
]);
578 if (tb
[SWITCH_ATTR_OP_TYPE
])
579 new->type
= nla_get_u32(tb
[SWITCH_ATTR_OP_TYPE
]);
580 if (tb
[SWITCH_ATTR_OP_NAME
])
581 new->name
= strdup(nla_get_string(tb
[SWITCH_ATTR_OP_NAME
]));
582 if (tb
[SWITCH_ATTR_OP_DESCRIPTION
])
583 new->description
= strdup(nla_get_string(tb
[SWITCH_ATTR_OP_DESCRIPTION
]));
590 swlib_scan(struct switch_dev
*dev
)
592 struct attrlist_arg arg
;
594 if (dev
->ops
|| dev
->port_ops
|| dev
->vlan_ops
)
597 arg
.atype
= SWLIB_ATTR_GROUP_GLOBAL
;
601 arg
.head
= &dev
->ops
;
602 swlib_call(SWITCH_CMD_LIST_GLOBAL
, add_attr
, add_id
, &arg
);
604 arg
.atype
= SWLIB_ATTR_GROUP_PORT
;
606 arg
.head
= &dev
->port_ops
;
607 swlib_call(SWITCH_CMD_LIST_PORT
, add_attr
, add_id
, &arg
);
609 arg
.atype
= SWLIB_ATTR_GROUP_VLAN
;
611 arg
.head
= &dev
->vlan_ops
;
612 swlib_call(SWITCH_CMD_LIST_VLAN
, add_attr
, add_id
, &arg
);
617 struct switch_attr
*swlib_lookup_attr(struct switch_dev
*dev
,
618 enum swlib_attr_group atype
, const char *name
)
620 struct switch_attr
*head
;
626 case SWLIB_ATTR_GROUP_GLOBAL
:
629 case SWLIB_ATTR_GROUP_PORT
:
630 head
= dev
->port_ops
;
632 case SWLIB_ATTR_GROUP_VLAN
:
633 head
= dev
->vlan_ops
;
637 if (!strcmp(name
, head
->name
))
646 swlib_priv_free(void)
649 nl_object_put((struct nl_object
*)family
);
651 nl_cache_free(cache
);
653 nl_socket_free(handle
);
660 swlib_priv_init(void)
664 handle
= nl_socket_alloc();
666 DPRINTF("Failed to create handle\n");
670 if (genl_connect(handle
)) {
671 DPRINTF("Failed to connect to generic netlink\n");
675 ret
= genl_ctrl_alloc_cache(handle
, &cache
);
677 DPRINTF("Failed to allocate netlink cache\n");
681 family
= genl_ctrl_search_by_name(cache
, "switch");
683 DPRINTF("Switch API not present\n");
693 struct swlib_scan_arg
{
695 struct switch_dev
*head
;
696 struct switch_dev
*ptr
;
700 add_switch(struct nl_msg
*msg
, void *arg
)
702 struct swlib_scan_arg
*sa
= arg
;
703 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
704 struct switch_dev
*dev
;
708 if (nla_parse(tb
, SWITCH_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0), genlmsg_attrlen(gnlh
, 0), NULL
) < 0)
711 if (!tb
[SWITCH_ATTR_DEV_NAME
])
714 name
= nla_get_string(tb
[SWITCH_ATTR_DEV_NAME
]);
715 alias
= nla_get_string(tb
[SWITCH_ATTR_ALIAS
]);
717 if (sa
->name
&& (strcmp(name
, sa
->name
) != 0) && (strcmp(alias
, sa
->name
) != 0))
720 dev
= swlib_alloc(sizeof(struct switch_dev
));
724 strncpy(dev
->dev_name
, name
, IFNAMSIZ
- 1);
725 dev
->alias
= strdup(alias
);
726 if (tb
[SWITCH_ATTR_ID
])
727 dev
->id
= nla_get_u32(tb
[SWITCH_ATTR_ID
]);
728 if (tb
[SWITCH_ATTR_NAME
])
729 dev
->name
= strdup(nla_get_string(tb
[SWITCH_ATTR_NAME
]));
730 if (tb
[SWITCH_ATTR_PORTS
])
731 dev
->ports
= nla_get_u32(tb
[SWITCH_ATTR_PORTS
]);
732 if (tb
[SWITCH_ATTR_VLANS
])
733 dev
->vlans
= nla_get_u32(tb
[SWITCH_ATTR_VLANS
]);
734 if (tb
[SWITCH_ATTR_CPU_PORT
])
735 dev
->cpu_port
= nla_get_u32(tb
[SWITCH_ATTR_CPU_PORT
]);
751 list_switch(struct nl_msg
*msg
, void *arg
)
753 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
755 if (nla_parse(tb
, SWITCH_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0), genlmsg_attrlen(gnlh
, 0), NULL
) < 0)
758 if (!tb
[SWITCH_ATTR_DEV_NAME
] || !tb
[SWITCH_ATTR_NAME
])
761 printf("Found: %s - %s\n", nla_get_string(tb
[SWITCH_ATTR_DEV_NAME
]),
762 nla_get_string(tb
[SWITCH_ATTR_ALIAS
]));
771 if (swlib_priv_init() < 0)
773 swlib_call(SWITCH_CMD_GET_SWITCH
, list_switch
, NULL
, NULL
);
778 swlib_connect(const char *name
)
780 struct swlib_scan_arg arg
;
783 if (swlib_priv_init() < 0)
790 swlib_call(SWITCH_CMD_GET_SWITCH
, add_switch
, NULL
, &arg
);
799 swlib_free_attributes(struct switch_attr
**head
)
801 struct switch_attr
*a
= *head
;
802 struct switch_attr
*next
;
807 free(a
->description
);
815 swlib_free(struct switch_dev
*dev
)
817 swlib_free_attributes(&dev
->ops
);
818 swlib_free_attributes(&dev
->port_ops
);
819 swlib_free_attributes(&dev
->vlan_ops
);
829 swlib_free_all(struct switch_dev
*dev
)
831 struct switch_dev
*p
;