67
static void *BODY; /* cached dlopen(NULL) handle */
68
static struct link_util *linkutil_list;
70
struct link_util *get_link_kind(const char *id)
76
for (l = linkutil_list; l; l = l->next)
77
if (strcmp(l->id, id) == 0)
80
snprintf(buf, sizeof(buf), "/usr/lib/ip/link_%s.so", id);
81
dlh = dlopen(buf, RTLD_LAZY);
83
/* look in current binary, only open once */
86
dlh = BODY = dlopen(NULL, RTLD_LAZY);
92
snprintf(buf, sizeof(buf), "%s_link_util", id);
97
l->next = linkutil_list;
102
#if IPLINK_IOCTL_COMPAT
103
static int have_rtnl_newlink = -1;
105
static int accept_msg(const struct sockaddr_nl *who,
106
struct nlmsghdr *n, void *arg)
108
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
110
if (n->nlmsg_type == NLMSG_ERROR && err->error == -EOPNOTSUPP)
111
have_rtnl_newlink = 0;
113
have_rtnl_newlink = 1;
117
static int iplink_have_newlink(void)
125
if (have_rtnl_newlink < 0) {
126
memset(&req, 0, sizeof(req));
128
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
129
req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
130
req.n.nlmsg_type = RTM_NEWLINK;
131
req.i.ifi_family = AF_UNSPEC;
133
rtnl_send(&rth, (char *)&req.n, req.n.nlmsg_len);
134
rtnl_listen(&rth, accept_msg, NULL);
136
return have_rtnl_newlink;
138
#else /* IPLINK_IOCTL_COMPAT */
139
static int iplink_have_newlink(void)
143
#endif /* ! IPLINK_IOCTL_COMPAT */
145
static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
155
struct link_util *lu = NULL;
162
memset(&req, 0, sizeof(req));
164
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
165
req.n.nlmsg_flags = NLM_F_REQUEST|flags;
166
req.n.nlmsg_type = cmd;
167
req.i.ifi_family = preferred_family;
170
if (strcmp(*argv, "up") == 0) {
171
req.i.ifi_change |= IFF_UP;
172
req.i.ifi_flags |= IFF_UP;
173
} else if (strcmp(*argv, "down") == 0) {
174
req.i.ifi_change |= IFF_UP;
175
req.i.ifi_flags &= ~IFF_UP;
176
} else if (strcmp(*argv, "name") == 0) {
179
} else if (matches(*argv, "link") == 0) {
182
} else if (matches(*argv, "address") == 0) {
184
len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
185
addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, abuf, len);
186
} else if (matches(*argv, "broadcast") == 0 ||
187
strcmp(*argv, "brd") == 0) {
189
len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
190
addattr_l(&req.n, sizeof(req), IFLA_BROADCAST, abuf, len);
191
} else if (matches(*argv, "txqueuelen") == 0 ||
192
strcmp(*argv, "qlen") == 0 ||
193
matches(*argv, "txqlen") == 0) {
196
duparg("txqueuelen", *argv);
197
if (get_integer(&qlen, *argv, 0))
198
invarg("Invalid \"txqueuelen\" value\n", *argv);
199
addattr_l(&req.n, sizeof(req), IFLA_TXQLEN, &qlen, 4);
200
} else if (strcmp(*argv, "mtu") == 0) {
203
duparg("mtu", *argv);
204
if (get_integer(&mtu, *argv, 0))
205
invarg("Invalid \"mtu\" value\n", *argv);
206
addattr_l(&req.n, sizeof(req), IFLA_MTU, &mtu, 4);
207
} else if (strcmp(*argv, "multicast") == 0) {
209
req.i.ifi_change |= IFF_MULTICAST;
210
if (strcmp(*argv, "on") == 0) {
211
req.i.ifi_flags |= IFF_MULTICAST;
212
} else if (strcmp(*argv, "off") == 0) {
213
req.i.ifi_flags &= ~IFF_MULTICAST;
215
return on_off("multicast");
216
} else if (strcmp(*argv, "allmulticast") == 0) {
218
req.i.ifi_change |= IFF_ALLMULTI;
219
if (strcmp(*argv, "on") == 0) {
220
req.i.ifi_flags |= IFF_ALLMULTI;
221
} else if (strcmp(*argv, "off") == 0) {
222
req.i.ifi_flags &= ~IFF_ALLMULTI;
224
return on_off("allmulticast");
225
} else if (strcmp(*argv, "promisc") == 0) {
227
req.i.ifi_change |= IFF_PROMISC;
228
if (strcmp(*argv, "on") == 0) {
229
req.i.ifi_flags |= IFF_PROMISC;
230
} else if (strcmp(*argv, "off") == 0) {
231
req.i.ifi_flags &= ~IFF_PROMISC;
233
return on_off("promisc");
234
} else if (strcmp(*argv, "trailers") == 0) {
236
req.i.ifi_change |= IFF_NOTRAILERS;
237
if (strcmp(*argv, "off") == 0) {
238
req.i.ifi_flags |= IFF_NOTRAILERS;
239
} else if (strcmp(*argv, "on") == 0) {
240
req.i.ifi_flags &= ~IFF_NOTRAILERS;
242
return on_off("trailers");
243
} else if (strcmp(*argv, "arp") == 0) {
245
req.i.ifi_change |= IFF_NOARP;
246
if (strcmp(*argv, "on") == 0) {
247
req.i.ifi_flags &= ~IFF_NOARP;
248
} else if (strcmp(*argv, "off") == 0) {
249
req.i.ifi_flags |= IFF_NOARP;
251
return on_off("noarp");
253
} else if (matches(*argv, "dynamic") == 0) {
255
req.i.ifi_change |= IFF_DYNAMIC;
256
if (strcmp(*argv, "on") == 0) {
257
req.i.ifi_flags |= IFF_DYNAMIC;
258
} else if (strcmp(*argv, "off") == 0) {
259
req.i.ifi_flags &= ~IFF_DYNAMIC;
261
return on_off("dynamic");
263
} else if (matches(*argv, "type") == 0) {
269
if (strcmp(*argv, "dev") == 0) {
273
duparg2("dev", *argv);
282
struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
283
addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
284
addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
287
lu = get_link_kind(type);
289
struct rtattr * data = NLMSG_TAIL(&req.n);
290
addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
293
lu->parse_opt(lu, argc, argv, &req.n))
296
data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
298
if (matches(*argv, "help") == 0)
300
fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
301
"Try \"ip link help\".\n", *argv);
304
linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
307
if (!(flags & NLM_F_CREATE)) {
309
fprintf(stderr, "Not enough information: \"dev\" "
310
"argument is required.\n");
314
req.i.ifi_index = ll_name_to_index(dev);
315
if (req.i.ifi_index == 0) {
316
fprintf(stderr, "Cannot find device \"%s\"\n", dev);
320
/* Allow "ip link add dev" and "ip link add name" */
327
ifindex = ll_name_to_index(link);
329
fprintf(stderr, "Cannot find device \"%s\"\n",
333
addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
338
len = strlen(name) + 1;
340
invarg("\"\" is not a valid device identifier\n", "name");
342
invarg("\"name\" too long\n", name);
343
addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
346
if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
352
#if IPLINK_IOCTL_COMPAT
65
353
static int get_ctl_fd(void)