iplink: support add/delete

function                                             old     new   delta
do_change                                              -     490    +490
.rodata                                           135193  135225     +32
do_iplink                                           1146    1169     +23
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/0 up/down: 545/0)             Total: 545 bytes

Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
This commit is contained in:
Bernhard Reutner-Fischer 2010-05-25 10:34:27 +02:00
parent 49ee8393f4
commit 6faebfa663

View File

@ -283,11 +283,98 @@ static int ipaddr_list_link(char **argv)
return ipaddr_list_or_flush(argv, 0);
}
#ifndef NLMSG_TAIL
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
#endif
/* Return value becomes exitcode. It's okay to not return at all */
static int do_change(char **argv, const unsigned rtm)
{
static const char keywords[] ALIGN1 =
"link\0""name\0""type\0""dev\0";
enum {
ARG_link,
ARG_name,
ARG_type,
ARG_dev,
};
struct rtnl_handle rth;
struct {
struct nlmsghdr n;
struct ifinfomsg i;
char buf[1024];
} req;
int arg;
char *name_str = NULL, *link_str = NULL, *type_str = NULL, *dev_str = NULL;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = rtm;
req.i.ifi_family = preferred_family;
if (rtm == RTM_NEWLINK)
req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
while (*argv) {
arg = index_in_substrings(keywords, *argv);
if (arg == ARG_link) {
NEXT_ARG();
link_str = *argv;
} else if (arg == ARG_name) {
NEXT_ARG();
name_str = *argv;
} else if (arg == ARG_type) {
NEXT_ARG();
type_str = *argv;
} else {
if (arg == ARG_dev) {
if (dev_str)
duparg(*argv, "dev");
NEXT_ARG();
}
dev_str = *argv;
}
argv++;
}
xrtnl_open(&rth);
ll_init_map(&rth);
if (type_str) {
struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str,
strlen(type_str));
linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
}
if (rtm != RTM_NEWLINK) {
if (!dev_str)
return 1; /* Need a device to delete */
req.i.ifi_index = xll_name_to_index(dev_str);
} else {
if (!name_str)
name_str = dev_str;
if (link_str) {
int idx = xll_name_to_index(link_str);
addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4);
}
}
if (name_str) {
const size_t name_len = strlen(name_str) + 1;
if (name_len < 2 || name_len > IFNAMSIZ)
invarg(name_str, "name");
addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name_str, name_len);
}
if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
return 2;
return 0;
}
/* Return value becomes exitcode. It's okay to not return at all */
int do_iplink(char **argv)
{
static const char keywords[] ALIGN1 =
"set\0""show\0""lst\0""list\0";
"add\0""delete\0""set\0""show\0""lst\0""list\0";
int key;
if (!*argv)
return ipaddr_list_link(argv);
@ -295,7 +382,9 @@ int do_iplink(char **argv)
if (key < 0)
bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
argv++;
if (key == 0) /* set */
if (key <= 1) /* add/delete */
return do_change(argv, key ? RTM_DELLINK : RTM_NEWLINK);
else if (key == 2) /* set */
return do_set(argv);
/* show, lst, list */
return ipaddr_list_link(argv);