]>
Commit | Line | Data |
---|---|---|
0ad19a3f | 1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
9afe19d6 | 7 | * Daniel Lezcano <daniel.lezcano at free.fr> |
0ad19a3f | 8 | * |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
250b1eec | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0ad19a3f | 22 | */ |
cb0dc11b CB |
23 | |
24 | #include "config.h" | |
25 | ||
26 | #include <ctype.h> | |
27 | #include <errno.h> | |
28 | #include <fcntl.h> | |
0ad19a3f | 29 | #include <stdio.h> |
0ad19a3f | 30 | #include <stdlib.h> |
0ad19a3f | 31 | #include <string.h> |
dd1d77f9 | 32 | #include <time.h> |
cb0dc11b | 33 | #include <unistd.h> |
0ad19a3f | 34 | #include <arpa/inet.h> |
0ad19a3f | 35 | #include <linux/netlink.h> |
36 | #include <linux/rtnetlink.h> | |
37 | #include <linux/sockios.h> | |
cb0dc11b CB |
38 | #include <net/ethernet.h> |
39 | #include <net/if.h> | |
40 | #include <net/if_arp.h> | |
41 | #include <netinet/in.h> | |
42 | #include <sys/inotify.h> | |
43 | #include <sys/ioctl.h> | |
44 | #include <sys/param.h> | |
45 | #include <sys/socket.h> | |
46 | #include <sys/stat.h> | |
47 | #include <sys/types.h> | |
f549edcc | 48 | |
72d0e1cb | 49 | #include "conf.h" |
cb0dc11b CB |
50 | #include "log.h" |
51 | #include "network.h" | |
52 | #include "nl.h" | |
0d204771 | 53 | #include "utils.h" |
0ad19a3f | 54 | |
a0265685 SG |
55 | #if HAVE_IFADDRS_H |
56 | #include <ifaddrs.h> | |
57 | #else | |
58 | #include <../include/ifaddrs.h> | |
59 | #endif | |
60 | ||
0ad19a3f | 61 | #ifndef IFLA_LINKMODE |
cb0dc11b | 62 | #define IFLA_LINKMODE 17 |
0ad19a3f | 63 | #endif |
64 | ||
65 | #ifndef IFLA_LINKINFO | |
cb0dc11b | 66 | #define IFLA_LINKINFO 18 |
0ad19a3f | 67 | #endif |
68 | ||
69 | #ifndef IFLA_NET_NS_PID | |
cb0dc11b | 70 | #define IFLA_NET_NS_PID 19 |
0ad19a3f | 71 | #endif |
72 | ||
73 | #ifndef IFLA_INFO_KIND | |
cb0dc11b | 74 | #define IFLA_INFO_KIND 1 |
0ad19a3f | 75 | #endif |
76 | ||
26c39028 | 77 | #ifndef IFLA_VLAN_ID |
cb0dc11b | 78 | #define IFLA_VLAN_ID 1 |
26c39028 JHS |
79 | #endif |
80 | ||
0ad19a3f | 81 | #ifndef IFLA_INFO_DATA |
cb0dc11b | 82 | #define IFLA_INFO_DATA 2 |
0ad19a3f | 83 | #endif |
84 | ||
85 | #ifndef VETH_INFO_PEER | |
cb0dc11b | 86 | #define VETH_INFO_PEER 1 |
0ad19a3f | 87 | #endif |
88 | ||
e892973e | 89 | #ifndef IFLA_MACVLAN_MODE |
cb0dc11b | 90 | #define IFLA_MACVLAN_MODE 1 |
e892973e DL |
91 | #endif |
92 | ||
cb0dc11b | 93 | lxc_log_define(lxc_network, lxc); |
f8fee0e2 | 94 | |
ebc73a67 | 95 | int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char *ifname) |
0ad19a3f | 96 | { |
ebc73a67 | 97 | int err; |
0ad19a3f | 98 | struct nl_handler nlh; |
06f976ca | 99 | struct ifinfomsg *ifi; |
ebc73a67 | 100 | struct nlmsg *nlmsg = NULL; |
0ad19a3f | 101 | |
3cfc0f3a MN |
102 | err = netlink_open(&nlh, NETLINK_ROUTE); |
103 | if (err) | |
104 | return err; | |
0ad19a3f | 105 | |
3cfc0f3a | 106 | err = -ENOMEM; |
0ad19a3f | 107 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
108 | if (!nlmsg) | |
109 | goto out; | |
110 | ||
ebc73a67 | 111 | nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
06f976ca SZ |
112 | nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; |
113 | ||
114 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); | |
25a9939b WC |
115 | if (!ifi) |
116 | goto out; | |
06f976ca SZ |
117 | ifi->ifi_family = AF_UNSPEC; |
118 | ifi->ifi_index = ifindex; | |
0ad19a3f | 119 | |
120 | if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid)) | |
121 | goto out; | |
122 | ||
8d357196 DY |
123 | if (ifname != NULL) { |
124 | if (nla_put_string(nlmsg, IFLA_IFNAME, ifname)) | |
125 | goto out; | |
126 | } | |
127 | ||
3cfc0f3a | 128 | err = netlink_transaction(&nlh, nlmsg, nlmsg); |
0ad19a3f | 129 | out: |
130 | netlink_close(&nlh); | |
131 | nlmsg_free(nlmsg); | |
132 | return err; | |
133 | } | |
134 | ||
ebc73a67 CB |
135 | /* If we are asked to move a wireless interface, then we must actually move its |
136 | * phyN device. Detect that condition and return the physname here. The physname | |
137 | * will be passed to lxc_netdev_move_wlan() which will free it when done. | |
e5848d39 SH |
138 | */ |
139 | #define PHYSNAME "/sys/class/net/%s/phy80211/name" | |
ebc73a67 | 140 | static char *is_wlan(const char *ifname) |
e5848d39 | 141 | { |
ebc73a67 | 142 | int i, ret; |
e5848d39 | 143 | long physlen; |
ebc73a67 CB |
144 | size_t len; |
145 | char *path; | |
e5848d39 | 146 | FILE *f; |
ebc73a67 CB |
147 | struct stat sb; |
148 | char *physname = NULL; | |
e5848d39 | 149 | |
ebc73a67 CB |
150 | len = strlen(ifname) + strlen(PHYSNAME) - 1; |
151 | path = alloca(len + 1); | |
e5848d39 | 152 | ret = snprintf(path, len, PHYSNAME, ifname); |
ebc73a67 | 153 | if (ret < 0 || (size_t)ret >= len) |
e5848d39 | 154 | goto bad; |
ebc73a67 | 155 | |
e5848d39 SH |
156 | ret = stat(path, &sb); |
157 | if (ret) | |
158 | goto bad; | |
ebc73a67 CB |
159 | |
160 | f = fopen(path, "r"); | |
161 | if (!f) | |
e5848d39 | 162 | goto bad; |
ebc73a67 | 163 | |
1a0e70ac | 164 | /* Feh - sb.st_size is always 4096. */ |
e5848d39 SH |
165 | fseek(f, 0, SEEK_END); |
166 | physlen = ftell(f); | |
167 | fseek(f, 0, SEEK_SET); | |
ebc73a67 CB |
168 | |
169 | physname = malloc(physlen + 1); | |
ee54ea9a | 170 | if (!physname) { |
acf47e1b | 171 | fclose(f); |
e5848d39 | 172 | goto bad; |
ee54ea9a | 173 | } |
ebc73a67 CB |
174 | |
175 | memset(physname, 0, physlen + 1); | |
e5848d39 SH |
176 | ret = fread(physname, 1, physlen, f); |
177 | fclose(f); | |
178 | if (ret < 0) | |
179 | goto bad; | |
180 | ||
ebc73a67 | 181 | for (i = 0; i < physlen; i++) { |
e5848d39 SH |
182 | if (physname[i] == '\n') |
183 | physname[i] = '\0'; | |
ebc73a67 | 184 | |
e5848d39 SH |
185 | if (physname[i] == '\0') |
186 | break; | |
187 | } | |
188 | ||
189 | return physname; | |
190 | ||
191 | bad: | |
f10fad2f | 192 | free(physname); |
e5848d39 SH |
193 | return NULL; |
194 | } | |
195 | ||
ebc73a67 CB |
196 | static int lxc_netdev_rename_by_name_in_netns(pid_t pid, const char *old, |
197 | const char *new) | |
e5848d39 | 198 | { |
ebc73a67 | 199 | pid_t fpid; |
e5848d39 | 200 | |
ebc73a67 | 201 | fpid = fork(); |
e5848d39 SH |
202 | if (fpid < 0) |
203 | return -1; | |
ebc73a67 | 204 | |
e5848d39 SH |
205 | if (fpid != 0) |
206 | return wait_for_pid(fpid); | |
ebc73a67 | 207 | |
e5848d39 SH |
208 | if (!switch_to_ns(pid, "net")) |
209 | return -1; | |
ebc73a67 | 210 | |
e5848d39 SH |
211 | exit(lxc_netdev_rename_by_name(old, new)); |
212 | } | |
213 | ||
ebc73a67 CB |
214 | static int lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid, |
215 | const char *newname) | |
e5848d39 | 216 | { |
e5848d39 | 217 | char *cmd; |
ebc73a67 CB |
218 | pid_t fpid; |
219 | int err = -1; | |
e5848d39 SH |
220 | |
221 | /* Move phyN into the container. TODO - do this using netlink. | |
ebc73a67 CB |
222 | * However, IIUC this involves a bit more complicated work to talk to |
223 | * the 80211 module, so for now just call out to iw. | |
e5848d39 SH |
224 | */ |
225 | cmd = on_path("iw", NULL); | |
226 | if (!cmd) | |
227 | goto out1; | |
228 | free(cmd); | |
229 | ||
230 | fpid = fork(); | |
231 | if (fpid < 0) | |
232 | goto out1; | |
ebc73a67 | 233 | |
e5848d39 SH |
234 | if (fpid == 0) { |
235 | char pidstr[30]; | |
236 | sprintf(pidstr, "%d", pid); | |
ebc73a67 CB |
237 | execlp("iw", "iw", "phy", physname, "set", "netns", pidstr, |
238 | (char *)NULL); | |
239 | exit(EXIT_FAILURE); | |
e5848d39 | 240 | } |
ebc73a67 | 241 | |
e5848d39 SH |
242 | if (wait_for_pid(fpid)) |
243 | goto out1; | |
244 | ||
245 | err = 0; | |
246 | if (newname) | |
247 | err = lxc_netdev_rename_by_name_in_netns(pid, ifname, newname); | |
248 | ||
249 | out1: | |
250 | free(physname); | |
251 | return err; | |
252 | } | |
253 | ||
8d357196 | 254 | int lxc_netdev_move_by_name(const char *ifname, pid_t pid, const char* newname) |
8befa924 SH |
255 | { |
256 | int index; | |
e5848d39 | 257 | char *physname; |
8befa924 | 258 | |
8befa924 SH |
259 | if (!ifname) |
260 | return -EINVAL; | |
261 | ||
32571606 | 262 | index = if_nametoindex(ifname); |
49428bf3 DY |
263 | if (!index) |
264 | return -EINVAL; | |
32571606 | 265 | |
ebc73a67 CB |
266 | physname = is_wlan(ifname); |
267 | if (physname) | |
e5848d39 SH |
268 | return lxc_netdev_move_wlan(physname, ifname, pid, newname); |
269 | ||
8d357196 | 270 | return lxc_netdev_move_by_index(index, pid, newname); |
8befa924 SH |
271 | } |
272 | ||
b84f58b9 | 273 | int lxc_netdev_delete_by_index(int ifindex) |
0ad19a3f | 274 | { |
b84f58b9 | 275 | int err; |
ebc73a67 CB |
276 | struct ifinfomsg *ifi; |
277 | struct nl_handler nlh; | |
278 | struct nlmsg *answer = NULL, *nlmsg = NULL; | |
0ad19a3f | 279 | |
3cfc0f3a MN |
280 | err = netlink_open(&nlh, NETLINK_ROUTE); |
281 | if (err) | |
282 | return err; | |
0ad19a3f | 283 | |
3cfc0f3a | 284 | err = -ENOMEM; |
0ad19a3f | 285 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
286 | if (!nlmsg) | |
287 | goto out; | |
288 | ||
06f976ca | 289 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
0ad19a3f | 290 | if (!answer) |
291 | goto out; | |
292 | ||
ebc73a67 | 293 | nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST; |
06f976ca SZ |
294 | nlmsg->nlmsghdr->nlmsg_type = RTM_DELLINK; |
295 | ||
296 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); | |
25a9939b WC |
297 | if (!ifi) |
298 | goto out; | |
06f976ca SZ |
299 | ifi->ifi_family = AF_UNSPEC; |
300 | ifi->ifi_index = ifindex; | |
0ad19a3f | 301 | |
3cfc0f3a | 302 | err = netlink_transaction(&nlh, nlmsg, answer); |
0ad19a3f | 303 | out: |
304 | netlink_close(&nlh); | |
305 | nlmsg_free(answer); | |
306 | nlmsg_free(nlmsg); | |
307 | return err; | |
308 | } | |
309 | ||
b84f58b9 DL |
310 | int lxc_netdev_delete_by_name(const char *name) |
311 | { | |
312 | int index; | |
313 | ||
314 | index = if_nametoindex(name); | |
315 | if (!index) | |
316 | return -EINVAL; | |
317 | ||
318 | return lxc_netdev_delete_by_index(index); | |
319 | } | |
320 | ||
321 | int lxc_netdev_rename_by_index(int ifindex, const char *newname) | |
b9a5bb58 | 322 | { |
ebc73a67 | 323 | int err, len; |
06f976ca | 324 | struct ifinfomsg *ifi; |
ebc73a67 CB |
325 | struct nl_handler nlh; |
326 | struct nlmsg *answer = NULL, *nlmsg = NULL; | |
b9a5bb58 | 327 | |
3cfc0f3a MN |
328 | err = netlink_open(&nlh, NETLINK_ROUTE); |
329 | if (err) | |
330 | return err; | |
b9a5bb58 | 331 | |
b84f58b9 | 332 | len = strlen(newname); |
dae3fdf6 | 333 | if (len == 1 || len >= IFNAMSIZ) |
b84f58b9 DL |
334 | goto out; |
335 | ||
3cfc0f3a | 336 | err = -ENOMEM; |
b9a5bb58 DL |
337 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
338 | if (!nlmsg) | |
339 | goto out; | |
340 | ||
06f976ca | 341 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
b9a5bb58 DL |
342 | if (!answer) |
343 | goto out; | |
344 | ||
ebc73a67 | 345 | nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST; |
06f976ca SZ |
346 | nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; |
347 | ||
348 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); | |
25a9939b WC |
349 | if (!ifi) |
350 | goto out; | |
06f976ca SZ |
351 | ifi->ifi_family = AF_UNSPEC; |
352 | ifi->ifi_index = ifindex; | |
b84f58b9 DL |
353 | |
354 | if (nla_put_string(nlmsg, IFLA_IFNAME, newname)) | |
355 | goto out; | |
b9a5bb58 | 356 | |
3cfc0f3a | 357 | err = netlink_transaction(&nlh, nlmsg, answer); |
b9a5bb58 DL |
358 | out: |
359 | netlink_close(&nlh); | |
360 | nlmsg_free(answer); | |
361 | nlmsg_free(nlmsg); | |
362 | return err; | |
363 | } | |
364 | ||
b84f58b9 DL |
365 | int lxc_netdev_rename_by_name(const char *oldname, const char *newname) |
366 | { | |
367 | int len, index; | |
368 | ||
369 | len = strlen(oldname); | |
dae3fdf6 | 370 | if (len == 1 || len >= IFNAMSIZ) |
b84f58b9 DL |
371 | return -EINVAL; |
372 | ||
373 | index = if_nametoindex(oldname); | |
374 | if (!index) | |
375 | return -EINVAL; | |
376 | ||
377 | return lxc_netdev_rename_by_index(index, newname); | |
378 | } | |
379 | ||
8befa924 | 380 | int netdev_set_flag(const char *name, int flag) |
0ad19a3f | 381 | { |
ebc73a67 | 382 | int err, index, len; |
06f976ca | 383 | struct ifinfomsg *ifi; |
ebc73a67 CB |
384 | struct nl_handler nlh; |
385 | struct nlmsg *answer = NULL, *nlmsg = NULL; | |
0ad19a3f | 386 | |
3cfc0f3a MN |
387 | err = netlink_open(&nlh, NETLINK_ROUTE); |
388 | if (err) | |
389 | return err; | |
0ad19a3f | 390 | |
3cfc0f3a | 391 | err = -EINVAL; |
0ad19a3f | 392 | len = strlen(name); |
dae3fdf6 | 393 | if (len == 1 || len >= IFNAMSIZ) |
0ad19a3f | 394 | goto out; |
395 | ||
3cfc0f3a | 396 | err = -ENOMEM; |
0ad19a3f | 397 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
398 | if (!nlmsg) | |
399 | goto out; | |
400 | ||
06f976ca | 401 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
0ad19a3f | 402 | if (!answer) |
403 | goto out; | |
404 | ||
3cfc0f3a | 405 | err = -EINVAL; |
0ad19a3f | 406 | index = if_nametoindex(name); |
407 | if (!index) | |
408 | goto out; | |
409 | ||
ebc73a67 | 410 | nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
06f976ca SZ |
411 | nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; |
412 | ||
413 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); | |
25a9939b WC |
414 | if (!ifi) { |
415 | err = -ENOMEM; | |
416 | goto out; | |
417 | } | |
06f976ca SZ |
418 | ifi->ifi_family = AF_UNSPEC; |
419 | ifi->ifi_index = index; | |
420 | ifi->ifi_change |= IFF_UP; | |
421 | ifi->ifi_flags |= flag; | |
0ad19a3f | 422 | |
423 | err = netlink_transaction(&nlh, nlmsg, answer); | |
0ad19a3f | 424 | out: |
425 | netlink_close(&nlh); | |
426 | nlmsg_free(nlmsg); | |
427 | nlmsg_free(answer); | |
428 | return err; | |
429 | } | |
430 | ||
ebc73a67 | 431 | int netdev_get_flag(const char *name, int *flag) |
efa1cf45 | 432 | { |
ebc73a67 | 433 | int err, index, len; |
a4318300 | 434 | struct ifinfomsg *ifi; |
ebc73a67 CB |
435 | struct nl_handler nlh; |
436 | struct nlmsg *answer = NULL, *nlmsg = NULL; | |
efa1cf45 DY |
437 | |
438 | if (!name) | |
439 | return -EINVAL; | |
440 | ||
441 | err = netlink_open(&nlh, NETLINK_ROUTE); | |
442 | if (err) | |
443 | return err; | |
444 | ||
445 | err = -EINVAL; | |
446 | len = strlen(name); | |
447 | if (len == 1 || len >= IFNAMSIZ) | |
448 | goto out; | |
449 | ||
450 | err = -ENOMEM; | |
451 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
452 | if (!nlmsg) | |
453 | goto out; | |
454 | ||
06f976ca | 455 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
efa1cf45 DY |
456 | if (!answer) |
457 | goto out; | |
458 | ||
459 | err = -EINVAL; | |
460 | index = if_nametoindex(name); | |
461 | if (!index) | |
462 | goto out; | |
463 | ||
06f976ca SZ |
464 | nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST; |
465 | nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK; | |
466 | ||
467 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); | |
25a9939b WC |
468 | if (!ifi) { |
469 | err = -ENOMEM; | |
470 | goto out; | |
471 | } | |
06f976ca SZ |
472 | ifi->ifi_family = AF_UNSPEC; |
473 | ifi->ifi_index = index; | |
efa1cf45 DY |
474 | |
475 | err = netlink_transaction(&nlh, nlmsg, answer); | |
476 | if (err) | |
477 | goto out; | |
478 | ||
06f976ca | 479 | ifi = NLMSG_DATA(answer->nlmsghdr); |
efa1cf45 DY |
480 | |
481 | *flag = ifi->ifi_flags; | |
482 | out: | |
483 | netlink_close(&nlh); | |
484 | nlmsg_free(nlmsg); | |
485 | nlmsg_free(answer); | |
486 | return err; | |
487 | } | |
488 | ||
489 | /* | |
490 | * \brief Check a interface is up or not. | |
491 | * | |
492 | * \param name: name for the interface. | |
493 | * | |
494 | * \return int. | |
495 | * 0 means interface is down. | |
496 | * 1 means interface is up. | |
497 | * Others means error happened, and ret-value is the error number. | |
498 | */ | |
ebc73a67 | 499 | int lxc_netdev_isup(const char *name) |
efa1cf45 | 500 | { |
ebc73a67 | 501 | int err, flag; |
efa1cf45 DY |
502 | |
503 | err = netdev_get_flag(name, &flag); | |
504 | if (err) | |
ebc73a67 CB |
505 | return err; |
506 | ||
efa1cf45 DY |
507 | if (flag & IFF_UP) |
508 | return 1; | |
ebc73a67 | 509 | |
efa1cf45 | 510 | return 0; |
efa1cf45 DY |
511 | } |
512 | ||
0130df54 SH |
513 | int netdev_get_mtu(int ifindex) |
514 | { | |
ebc73a67 | 515 | int answer_len, err, res; |
0130df54 | 516 | struct nl_handler nlh; |
06f976ca | 517 | struct ifinfomsg *ifi; |
0130df54 | 518 | struct nlmsghdr *msg; |
ebc73a67 CB |
519 | int readmore = 0, recv_len = 0; |
520 | struct nlmsg *answer = NULL, *nlmsg = NULL; | |
0130df54 SH |
521 | |
522 | err = netlink_open(&nlh, NETLINK_ROUTE); | |
523 | if (err) | |
524 | return err; | |
525 | ||
526 | err = -ENOMEM; | |
527 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
528 | if (!nlmsg) | |
529 | goto out; | |
530 | ||
06f976ca | 531 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
0130df54 SH |
532 | if (!answer) |
533 | goto out; | |
534 | ||
535 | /* Save the answer buffer length, since it will be overwritten | |
536 | * on the first receive (and we might need to receive more than | |
ebc73a67 CB |
537 | * once. |
538 | */ | |
06f976ca SZ |
539 | answer_len = answer->nlmsghdr->nlmsg_len; |
540 | ||
ebc73a67 | 541 | nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; |
06f976ca | 542 | nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK; |
0130df54 | 543 | |
06f976ca | 544 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); |
25a9939b WC |
545 | if (!ifi) |
546 | goto out; | |
06f976ca | 547 | ifi->ifi_family = AF_UNSPEC; |
0130df54 SH |
548 | |
549 | /* Send the request for addresses, which returns all addresses | |
550 | * on all interfaces. */ | |
551 | err = netlink_send(&nlh, nlmsg); | |
552 | if (err < 0) | |
553 | goto out; | |
554 | ||
555 | do { | |
556 | /* Restore the answer buffer length, it might have been | |
ebc73a67 CB |
557 | * overwritten by a previous receive. |
558 | */ | |
06f976ca | 559 | answer->nlmsghdr->nlmsg_len = answer_len; |
0130df54 SH |
560 | |
561 | /* Get the (next) batch of reply messages */ | |
562 | err = netlink_rcv(&nlh, answer); | |
563 | if (err < 0) | |
564 | goto out; | |
565 | ||
566 | recv_len = err; | |
567 | err = 0; | |
568 | ||
569 | /* Satisfy the typing for the netlink macros */ | |
06f976ca | 570 | msg = answer->nlmsghdr; |
0130df54 SH |
571 | |
572 | while (NLMSG_OK(msg, recv_len)) { | |
573 | ||
574 | /* Stop reading if we see an error message */ | |
575 | if (msg->nlmsg_type == NLMSG_ERROR) { | |
ebc73a67 CB |
576 | struct nlmsgerr *errmsg = |
577 | (struct nlmsgerr *)NLMSG_DATA(msg); | |
0130df54 SH |
578 | err = errmsg->error; |
579 | goto out; | |
580 | } | |
581 | ||
582 | /* Stop reading if we see a NLMSG_DONE message */ | |
583 | if (msg->nlmsg_type == NLMSG_DONE) { | |
584 | readmore = 0; | |
585 | break; | |
586 | } | |
587 | ||
06f976ca | 588 | ifi = NLMSG_DATA(msg); |
0130df54 SH |
589 | if (ifi->ifi_index == ifindex) { |
590 | struct rtattr *rta = IFLA_RTA(ifi); | |
ebc73a67 CB |
591 | int attr_len = |
592 | msg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); | |
0130df54 | 593 | res = 0; |
ebc73a67 CB |
594 | while (RTA_OK(rta, attr_len)) { |
595 | /* Found a local address for the | |
596 | * requested interface, return it. | |
597 | */ | |
0130df54 | 598 | if (rta->rta_type == IFLA_MTU) { |
ebc73a67 CB |
599 | memcpy(&res, RTA_DATA(rta), |
600 | sizeof(int)); | |
0130df54 SH |
601 | err = res; |
602 | goto out; | |
603 | } | |
604 | rta = RTA_NEXT(rta, attr_len); | |
605 | } | |
0130df54 SH |
606 | } |
607 | ||
ebc73a67 CB |
608 | /* Keep reading more data from the socket if the last |
609 | * message had the NLF_F_MULTI flag set. | |
610 | */ | |
0130df54 SH |
611 | readmore = (msg->nlmsg_flags & NLM_F_MULTI); |
612 | ||
ebc73a67 | 613 | /* Look at the next message received in this buffer. */ |
0130df54 SH |
614 | msg = NLMSG_NEXT(msg, recv_len); |
615 | } | |
616 | } while (readmore); | |
617 | ||
ebc73a67 | 618 | /* If we end up here, we didn't find any result, so signal an error. */ |
0130df54 SH |
619 | err = -1; |
620 | ||
621 | out: | |
622 | netlink_close(&nlh); | |
623 | nlmsg_free(answer); | |
624 | nlmsg_free(nlmsg); | |
625 | return err; | |
626 | } | |
627 | ||
d472214b | 628 | int lxc_netdev_set_mtu(const char *name, int mtu) |
75d09f83 | 629 | { |
ebc73a67 | 630 | int err, index, len; |
06f976ca | 631 | struct ifinfomsg *ifi; |
ebc73a67 CB |
632 | struct nl_handler nlh; |
633 | struct nlmsg *answer = NULL, *nlmsg = NULL; | |
75d09f83 | 634 | |
3cfc0f3a MN |
635 | err = netlink_open(&nlh, NETLINK_ROUTE); |
636 | if (err) | |
637 | return err; | |
75d09f83 | 638 | |
3cfc0f3a | 639 | err = -EINVAL; |
75d09f83 | 640 | len = strlen(name); |
dae3fdf6 | 641 | if (len == 1 || len >= IFNAMSIZ) |
75d09f83 DL |
642 | goto out; |
643 | ||
3cfc0f3a | 644 | err = -ENOMEM; |
75d09f83 DL |
645 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
646 | if (!nlmsg) | |
647 | goto out; | |
648 | ||
06f976ca | 649 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
75d09f83 DL |
650 | if (!answer) |
651 | goto out; | |
652 | ||
3cfc0f3a | 653 | err = -EINVAL; |
75d09f83 DL |
654 | index = if_nametoindex(name); |
655 | if (!index) | |
656 | goto out; | |
657 | ||
ebc73a67 | 658 | nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
06f976ca SZ |
659 | nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; |
660 | ||
661 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); | |
25a9939b WC |
662 | if (!ifi) { |
663 | err = -ENOMEM; | |
664 | goto out; | |
665 | } | |
06f976ca SZ |
666 | ifi->ifi_family = AF_UNSPEC; |
667 | ifi->ifi_index = index; | |
75d09f83 DL |
668 | |
669 | if (nla_put_u32(nlmsg, IFLA_MTU, mtu)) | |
670 | goto out; | |
671 | ||
672 | err = netlink_transaction(&nlh, nlmsg, answer); | |
75d09f83 DL |
673 | out: |
674 | netlink_close(&nlh); | |
675 | nlmsg_free(nlmsg); | |
676 | nlmsg_free(answer); | |
677 | return err; | |
678 | } | |
679 | ||
d472214b | 680 | int lxc_netdev_up(const char *name) |
0ad19a3f | 681 | { |
d472214b | 682 | return netdev_set_flag(name, IFF_UP); |
0ad19a3f | 683 | } |
684 | ||
d472214b | 685 | int lxc_netdev_down(const char *name) |
0ad19a3f | 686 | { |
d472214b | 687 | return netdev_set_flag(name, 0); |
0ad19a3f | 688 | } |
689 | ||
497353b6 | 690 | int lxc_veth_create(const char *name1, const char *name2) |
0ad19a3f | 691 | { |
ebc73a67 | 692 | int err, len; |
06f976ca | 693 | struct ifinfomsg *ifi; |
ebc73a67 | 694 | struct nl_handler nlh; |
0ad19a3f | 695 | struct rtattr *nest1, *nest2, *nest3; |
ebc73a67 | 696 | struct nlmsg *answer = NULL, *nlmsg = NULL; |
0ad19a3f | 697 | |
3cfc0f3a MN |
698 | err = netlink_open(&nlh, NETLINK_ROUTE); |
699 | if (err) | |
700 | return err; | |
0ad19a3f | 701 | |
3cfc0f3a | 702 | err = -EINVAL; |
0ad19a3f | 703 | len = strlen(name1); |
dae3fdf6 | 704 | if (len == 1 || len >= IFNAMSIZ) |
0ad19a3f | 705 | goto out; |
706 | ||
707 | len = strlen(name2); | |
dae3fdf6 | 708 | if (len == 1 || len >= IFNAMSIZ) |
0ad19a3f | 709 | goto out; |
710 | ||
3cfc0f3a | 711 | err = -ENOMEM; |
0ad19a3f | 712 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
713 | if (!nlmsg) | |
714 | goto out; | |
715 | ||
06f976ca | 716 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
0ad19a3f | 717 | if (!answer) |
718 | goto out; | |
719 | ||
06f976ca | 720 | nlmsg->nlmsghdr->nlmsg_flags = |
ebc73a67 | 721 | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK; |
06f976ca SZ |
722 | nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; |
723 | ||
724 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); | |
25a9939b WC |
725 | if (!ifi) |
726 | goto out; | |
06f976ca | 727 | ifi->ifi_family = AF_UNSPEC; |
0ad19a3f | 728 | |
3cfc0f3a | 729 | err = -EINVAL; |
79e68309 | 730 | nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO); |
0ad19a3f | 731 | if (!nest1) |
732 | goto out; | |
733 | ||
734 | if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth")) | |
735 | goto out; | |
736 | ||
737 | nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); | |
738 | if (!nest2) | |
739 | goto out; | |
740 | ||
741 | nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER); | |
742 | if (!nest3) | |
743 | goto out; | |
744 | ||
06f976ca | 745 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); |
25a9939b WC |
746 | if (!ifi) { |
747 | err = -ENOMEM; | |
06f976ca | 748 | goto out; |
25a9939b | 749 | } |
0ad19a3f | 750 | |
751 | if (nla_put_string(nlmsg, IFLA_IFNAME, name2)) | |
752 | goto out; | |
753 | ||
754 | nla_end_nested(nlmsg, nest3); | |
0ad19a3f | 755 | nla_end_nested(nlmsg, nest2); |
0ad19a3f | 756 | nla_end_nested(nlmsg, nest1); |
757 | ||
758 | if (nla_put_string(nlmsg, IFLA_IFNAME, name1)) | |
759 | goto out; | |
760 | ||
3cfc0f3a | 761 | err = netlink_transaction(&nlh, nlmsg, answer); |
0ad19a3f | 762 | out: |
763 | netlink_close(&nlh); | |
764 | nlmsg_free(answer); | |
765 | nlmsg_free(nlmsg); | |
766 | return err; | |
767 | } | |
768 | ||
ebc73a67 | 769 | /* TODO: merge with lxc_macvlan_create */ |
7c11d57a | 770 | int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid) |
26c39028 | 771 | { |
ebc73a67 | 772 | int err, len, lindex; |
06f976ca | 773 | struct ifinfomsg *ifi; |
ebc73a67 | 774 | struct nl_handler nlh; |
26c39028 | 775 | struct rtattr *nest, *nest2; |
ebc73a67 | 776 | struct nlmsg *answer = NULL, *nlmsg = NULL; |
26c39028 | 777 | |
3cfc0f3a MN |
778 | err = netlink_open(&nlh, NETLINK_ROUTE); |
779 | if (err) | |
780 | return err; | |
26c39028 | 781 | |
3cfc0f3a | 782 | err = -EINVAL; |
26c39028 | 783 | len = strlen(master); |
dae3fdf6 | 784 | if (len == 1 || len >= IFNAMSIZ) |
26c39028 JHS |
785 | goto err3; |
786 | ||
787 | len = strlen(name); | |
dae3fdf6 | 788 | if (len == 1 || len >= IFNAMSIZ) |
26c39028 JHS |
789 | goto err3; |
790 | ||
3cfc0f3a | 791 | err = -ENOMEM; |
26c39028 JHS |
792 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
793 | if (!nlmsg) | |
794 | goto err3; | |
795 | ||
06f976ca | 796 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
26c39028 JHS |
797 | if (!answer) |
798 | goto err2; | |
799 | ||
3cfc0f3a | 800 | err = -EINVAL; |
26c39028 JHS |
801 | lindex = if_nametoindex(master); |
802 | if (!lindex) | |
803 | goto err1; | |
804 | ||
06f976ca | 805 | nlmsg->nlmsghdr->nlmsg_flags = |
ebc73a67 | 806 | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK; |
06f976ca SZ |
807 | nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; |
808 | ||
809 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); | |
25a9939b WC |
810 | if (!ifi) { |
811 | err = -ENOMEM; | |
812 | goto err1; | |
813 | } | |
06f976ca | 814 | ifi->ifi_family = AF_UNSPEC; |
26c39028 | 815 | |
79e68309 | 816 | nest = nla_begin_nested(nlmsg, IFLA_LINKINFO); |
26c39028 JHS |
817 | if (!nest) |
818 | goto err1; | |
819 | ||
820 | if (nla_put_string(nlmsg, IFLA_INFO_KIND, "vlan")) | |
821 | goto err1; | |
822 | ||
823 | nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); | |
824 | if (!nest2) | |
825 | goto err1; | |
e892973e | 826 | |
26c39028 JHS |
827 | if (nla_put_u16(nlmsg, IFLA_VLAN_ID, vlanid)) |
828 | goto err1; | |
e892973e | 829 | |
26c39028 | 830 | nla_end_nested(nlmsg, nest2); |
26c39028 JHS |
831 | nla_end_nested(nlmsg, nest); |
832 | ||
833 | if (nla_put_u32(nlmsg, IFLA_LINK, lindex)) | |
834 | goto err1; | |
835 | ||
836 | if (nla_put_string(nlmsg, IFLA_IFNAME, name)) | |
837 | goto err1; | |
838 | ||
3cfc0f3a | 839 | err = netlink_transaction(&nlh, nlmsg, answer); |
26c39028 JHS |
840 | err1: |
841 | nlmsg_free(answer); | |
842 | err2: | |
843 | nlmsg_free(nlmsg); | |
844 | err3: | |
845 | netlink_close(&nlh); | |
846 | return err; | |
847 | } | |
848 | ||
e892973e | 849 | int lxc_macvlan_create(const char *master, const char *name, int mode) |
0ad19a3f | 850 | { |
ebc73a67 | 851 | int err, index, len; |
06f976ca | 852 | struct ifinfomsg *ifi; |
ebc73a67 | 853 | struct nl_handler nlh; |
e892973e | 854 | struct rtattr *nest, *nest2; |
ebc73a67 | 855 | struct nlmsg *answer = NULL, *nlmsg = NULL; |
0ad19a3f | 856 | |
3cfc0f3a MN |
857 | err = netlink_open(&nlh, NETLINK_ROUTE); |
858 | if (err) | |
859 | return err; | |
0ad19a3f | 860 | |
3cfc0f3a | 861 | err = -EINVAL; |
0ad19a3f | 862 | len = strlen(master); |
dae3fdf6 | 863 | if (len == 1 || len >= IFNAMSIZ) |
0ad19a3f | 864 | goto out; |
865 | ||
866 | len = strlen(name); | |
dae3fdf6 | 867 | if (len == 1 || len >= IFNAMSIZ) |
0ad19a3f | 868 | goto out; |
869 | ||
3cfc0f3a | 870 | err = -ENOMEM; |
0ad19a3f | 871 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
872 | if (!nlmsg) | |
873 | goto out; | |
874 | ||
06f976ca | 875 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
0ad19a3f | 876 | if (!answer) |
877 | goto out; | |
878 | ||
3cfc0f3a | 879 | err = -EINVAL; |
0ad19a3f | 880 | index = if_nametoindex(master); |
881 | if (!index) | |
882 | goto out; | |
883 | ||
06f976ca | 884 | nlmsg->nlmsghdr->nlmsg_flags = |
ebc73a67 | 885 | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK; |
06f976ca SZ |
886 | nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; |
887 | ||
888 | ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); | |
25a9939b WC |
889 | if (!ifi) { |
890 | err = -ENOMEM; | |
891 | goto out; | |
892 | } | |
06f976ca | 893 | ifi->ifi_family = AF_UNSPEC; |
0ad19a3f | 894 | |
79e68309 | 895 | nest = nla_begin_nested(nlmsg, IFLA_LINKINFO); |
0ad19a3f | 896 | if (!nest) |
897 | goto out; | |
898 | ||
899 | if (nla_put_string(nlmsg, IFLA_INFO_KIND, "macvlan")) | |
900 | goto out; | |
901 | ||
e892973e DL |
902 | if (mode) { |
903 | nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); | |
904 | if (!nest2) | |
905 | goto out; | |
906 | ||
907 | if (nla_put_u32(nlmsg, IFLA_MACVLAN_MODE, mode)) | |
908 | goto out; | |
909 | ||
910 | nla_end_nested(nlmsg, nest2); | |
911 | } | |
912 | ||
0ad19a3f | 913 | nla_end_nested(nlmsg, nest); |
914 | ||
915 | if (nla_put_u32(nlmsg, IFLA_LINK, index)) | |
916 | goto out; | |
917 | ||
918 | if (nla_put_string(nlmsg, IFLA_IFNAME, name)) | |
919 | goto out; | |
920 | ||
3cfc0f3a | 921 | err = netlink_transaction(&nlh, nlmsg, answer); |
0ad19a3f | 922 | out: |
923 | netlink_close(&nlh); | |
924 | nlmsg_free(answer); | |
925 | nlmsg_free(nlmsg); | |
926 | return err; | |
927 | } | |
928 | ||
929 | static int proc_sys_net_write(const char *path, const char *value) | |
930 | { | |
ebc73a67 CB |
931 | int fd; |
932 | int err = 0; | |
0ad19a3f | 933 | |
934 | fd = open(path, O_WRONLY); | |
935 | if (fd < 0) | |
936 | return -errno; | |
937 | ||
938 | if (write(fd, value, strlen(value)) < 0) | |
939 | err = -errno; | |
940 | ||
941 | close(fd); | |
942 | return err; | |
943 | } | |
944 | ||
945 | static int ip_forward_set(const char *ifname, int family, int flag) | |
946 | { | |
9ba8130c | 947 | int rc; |
ebc73a67 | 948 | char path[MAXPATHLEN]; |
0ad19a3f | 949 | |
950 | if (family != AF_INET && family != AF_INET6) | |
3cfc0f3a | 951 | return -EINVAL; |
0ad19a3f | 952 | |
9ba8130c | 953 | rc = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/forwarding", |
ebc73a67 CB |
954 | family == AF_INET ? "ipv4" : "ipv6", ifname); |
955 | if (rc < 0 || (size_t)rc >= MAXPATHLEN) | |
9ba8130c | 956 | return -E2BIG; |
0ad19a3f | 957 | |
ebc73a67 | 958 | return proc_sys_net_write(path, flag ? "1" : "0"); |
0ad19a3f | 959 | } |
960 | ||
497353b6 | 961 | int lxc_ip_forward_on(const char *ifname, int family) |
0ad19a3f | 962 | { |
963 | return ip_forward_set(ifname, family, 1); | |
964 | } | |
965 | ||
497353b6 | 966 | int lxc_ip_forward_off(const char *ifname, int family) |
0ad19a3f | 967 | { |
968 | return ip_forward_set(ifname, family, 0); | |
969 | } | |
970 | ||
971 | static int neigh_proxy_set(const char *ifname, int family, int flag) | |
972 | { | |
9ba8130c | 973 | int ret; |
ebc73a67 | 974 | char path[MAXPATHLEN]; |
0ad19a3f | 975 | |
976 | if (family != AF_INET && family != AF_INET6) | |
3cfc0f3a | 977 | return -EINVAL; |
0ad19a3f | 978 | |
9ba8130c | 979 | ret = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/%s", |
ebc73a67 CB |
980 | family == AF_INET ? "ipv4" : "ipv6", ifname, |
981 | family == AF_INET ? "proxy_arp" : "proxy_ndp"); | |
982 | if (ret < 0 || (size_t)ret >= MAXPATHLEN) | |
9ba8130c | 983 | return -E2BIG; |
0ad19a3f | 984 | |
ebc73a67 | 985 | return proc_sys_net_write(path, flag ? "1" : "0"); |
0ad19a3f | 986 | } |
987 | ||
497353b6 | 988 | int lxc_neigh_proxy_on(const char *name, int family) |
0ad19a3f | 989 | { |
990 | return neigh_proxy_set(name, family, 1); | |
991 | } | |
992 | ||
497353b6 | 993 | int lxc_neigh_proxy_off(const char *name, int family) |
0ad19a3f | 994 | { |
995 | return neigh_proxy_set(name, family, 0); | |
996 | } | |
997 | ||
998 | int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr) | |
999 | { | |
1f1b18e7 DL |
1000 | int i = 0; |
1001 | unsigned val; | |
ebc73a67 CB |
1002 | char c; |
1003 | unsigned char *data; | |
1f1b18e7 DL |
1004 | |
1005 | sockaddr->sa_family = ARPHRD_ETHER; | |
1006 | data = (unsigned char *)sockaddr->sa_data; | |
1007 | ||
1008 | while ((*macaddr != '\0') && (i < ETH_ALEN)) { | |
ebc73a67 CB |
1009 | val = 0; |
1010 | c = *macaddr++; | |
1011 | if (isdigit(c)) | |
1012 | val = c - '0'; | |
1013 | else if (c >= 'a' && c <= 'f') | |
1014 | val = c - 'a' + 10; | |
1015 | else if (c >= 'A' && c <= 'F') | |
1016 | val = c - 'A' + 10; | |
1017 | else | |
1018 | return -EINVAL; | |
1019 | ||
1020 | val <<= 4; | |
1021 | c = *macaddr; | |
1022 | if (isdigit(c)) | |
1023 | val |= c - '0'; | |
1024 | else if (c >= 'a' && c <= 'f') | |
1025 | val |= c - 'a' + 10; | |
1026 | else if (c >= 'A' && c <= 'F') | |
1027 | val |= c - 'A' + 10; | |
1028 | else if (c == ':' || c == 0) | |
1029 | val >>= 4; | |
1030 | else | |
1031 | return -EINVAL; | |
1032 | if (c != 0) | |
1033 | macaddr++; | |
1034 | *data++ = (unsigned char)(val & 0377); | |
1035 | i++; | |
1036 | ||
1037 | if (*macaddr == ':') | |
1038 | macaddr++; | |
0ad19a3f | 1039 | } |
0ad19a3f | 1040 | |
1f1b18e7 | 1041 | return 0; |
0ad19a3f | 1042 | } |
1043 | ||
ebc73a67 CB |
1044 | static int ip_addr_add(int family, int ifindex, void *addr, void *bcast, |
1045 | void *acast, int prefix) | |
0ad19a3f | 1046 | { |
ebc73a67 | 1047 | int addrlen, err; |
06f976ca | 1048 | struct ifaddrmsg *ifa; |
ebc73a67 CB |
1049 | struct nl_handler nlh; |
1050 | struct nlmsg *answer = NULL, *nlmsg = NULL; | |
0ad19a3f | 1051 | |
ebc73a67 CB |
1052 | addrlen = family == AF_INET ? sizeof(struct in_addr) |
1053 | : sizeof(struct in6_addr); | |
4bf1968d | 1054 | |
3cfc0f3a MN |
1055 | err = netlink_open(&nlh, NETLINK_ROUTE); |
1056 | if (err) | |
1057 | return err; | |
0ad19a3f | 1058 | |
3cfc0f3a | 1059 | err = -ENOMEM; |
0ad19a3f | 1060 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
1061 | if (!nlmsg) | |
1062 | goto out; | |
1063 | ||
06f976ca | 1064 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
0ad19a3f | 1065 | if (!answer) |
1066 | goto out; | |
1067 | ||
06f976ca | 1068 | nlmsg->nlmsghdr->nlmsg_flags = |
ebc73a67 | 1069 | NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; |
06f976ca SZ |
1070 | nlmsg->nlmsghdr->nlmsg_type = RTM_NEWADDR; |
1071 | ||
1072 | ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg)); | |
acf47e1b | 1073 | if (!ifa) |
25a9939b | 1074 | goto out; |
06f976ca SZ |
1075 | ifa->ifa_prefixlen = prefix; |
1076 | ifa->ifa_index = ifindex; | |
1077 | ifa->ifa_family = family; | |
1078 | ifa->ifa_scope = 0; | |
acf47e1b | 1079 | |
3cfc0f3a | 1080 | err = -EINVAL; |
4bf1968d | 1081 | if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen)) |
0ad19a3f | 1082 | goto out; |
1083 | ||
4bf1968d | 1084 | if (nla_put_buffer(nlmsg, IFA_ADDRESS, addr, addrlen)) |
0ad19a3f | 1085 | goto out; |
1086 | ||
d8948a52 | 1087 | if (nla_put_buffer(nlmsg, IFA_BROADCAST, bcast, addrlen)) |
1f1b18e7 DL |
1088 | goto out; |
1089 | ||
ebc73a67 | 1090 | /* TODO: multicast, anycast with ipv6 */ |
7ddc8f24 | 1091 | err = -EPROTONOSUPPORT; |
79881dc6 DL |
1092 | if (family == AF_INET6 && |
1093 | (memcmp(bcast, &in6addr_any, sizeof(in6addr_any)) || | |
1094 | memcmp(acast, &in6addr_any, sizeof(in6addr_any)))) | |
1f1b18e7 | 1095 | goto out; |
0ad19a3f | 1096 | |
3cfc0f3a | 1097 | err = netlink_transaction(&nlh, nlmsg, answer); |
0ad19a3f | 1098 | out: |
1099 | netlink_close(&nlh); | |
1100 | nlmsg_free(answer); | |
1101 | nlmsg_free(nlmsg); | |
1102 | return err; | |
1103 | } | |
1104 | ||
1f1b18e7 | 1105 | int lxc_ipv6_addr_add(int ifindex, struct in6_addr *addr, |
ebc73a67 CB |
1106 | struct in6_addr *mcast, struct in6_addr *acast, |
1107 | int prefix) | |
1f1b18e7 DL |
1108 | { |
1109 | return ip_addr_add(AF_INET6, ifindex, addr, mcast, acast, prefix); | |
1110 | } | |
1111 | ||
ebc73a67 CB |
1112 | int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr, struct in_addr *bcast, |
1113 | int prefix) | |
1f1b18e7 DL |
1114 | { |
1115 | return ip_addr_add(AF_INET, ifindex, addr, bcast, NULL, prefix); | |
1116 | } | |
1117 | ||
ebc73a67 CB |
1118 | /* Find an IFA_LOCAL (or IFA_ADDRESS if not IFA_LOCAL is present) address from |
1119 | * the given RTM_NEWADDR message. Allocates memory for the address and stores | |
1120 | * that pointer in *res (so res should be an in_addr** or in6_addr**). | |
19a26f82 | 1121 | */ |
ebc73a67 CB |
1122 | static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void **res) |
1123 | { | |
1124 | int addrlen; | |
06f976ca SZ |
1125 | struct ifaddrmsg *ifa = NLMSG_DATA(msg); |
1126 | struct rtattr *rta = IFA_RTA(ifa); | |
1127 | int attr_len = NLMSG_PAYLOAD(msg, sizeof(struct ifaddrmsg)); | |
19a26f82 | 1128 | |
06f976ca | 1129 | if (ifa->ifa_family != family) |
19a26f82 MK |
1130 | return 0; |
1131 | ||
ebc73a67 CB |
1132 | addrlen = family == AF_INET ? sizeof(struct in_addr) |
1133 | : sizeof(struct in6_addr); | |
19a26f82 MK |
1134 | |
1135 | /* Loop over the rtattr's in this message */ | |
ebc73a67 | 1136 | while (RTA_OK(rta, attr_len)) { |
19a26f82 | 1137 | /* Found a local address for the requested interface, |
ebc73a67 CB |
1138 | * return it. |
1139 | */ | |
1140 | if (rta->rta_type == IFA_LOCAL || | |
1141 | rta->rta_type == IFA_ADDRESS) { | |
1142 | /* Sanity check. The family check above should make sure | |
1143 | * the address length is correct, but check here just in | |
1144 | * case. | |
1145 | */ | |
19a26f82 MK |
1146 | if (RTA_PAYLOAD(rta) != addrlen) |
1147 | return -1; | |
1148 | ||
ebc73a67 CB |
1149 | /* We might have found an IFA_ADDRESS before, which we |
1150 | * now overwrite with an IFA_LOCAL. | |
1151 | */ | |
dd66e5ad | 1152 | if (!*res) { |
19a26f82 | 1153 | *res = malloc(addrlen); |
dd66e5ad DE |
1154 | if (!*res) |
1155 | return -1; | |
1156 | } | |
19a26f82 MK |
1157 | |
1158 | memcpy(*res, RTA_DATA(rta), addrlen); | |
19a26f82 MK |
1159 | if (rta->rta_type == IFA_LOCAL) |
1160 | break; | |
1161 | } | |
1162 | rta = RTA_NEXT(rta, attr_len); | |
1163 | } | |
1164 | return 0; | |
1165 | } | |
1166 | ||
1167 | static int ip_addr_get(int family, int ifindex, void **res) | |
1168 | { | |
ebc73a67 | 1169 | int answer_len, err; |
06f976ca | 1170 | struct ifaddrmsg *ifa; |
ebc73a67 | 1171 | struct nl_handler nlh; |
19a26f82 | 1172 | struct nlmsghdr *msg; |
ebc73a67 CB |
1173 | int readmore = 0, recv_len = 0; |
1174 | struct nlmsg *answer = NULL, *nlmsg = NULL; | |
19a26f82 MK |
1175 | |
1176 | err = netlink_open(&nlh, NETLINK_ROUTE); | |
1177 | if (err) | |
1178 | return err; | |
1179 | ||
1180 | err = -ENOMEM; | |
1181 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
1182 | if (!nlmsg) | |
1183 | goto out; | |
1184 | ||
06f976ca | 1185 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
19a26f82 MK |
1186 | if (!answer) |
1187 | goto out; | |
1188 | ||
ebc73a67 CB |
1189 | /* Save the answer buffer length, since it will be overwritten on the |
1190 | * first receive (and we might need to receive more than once). | |
1191 | */ | |
06f976ca SZ |
1192 | answer_len = answer->nlmsghdr->nlmsg_len; |
1193 | ||
ebc73a67 | 1194 | nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; |
06f976ca | 1195 | nlmsg->nlmsghdr->nlmsg_type = RTM_GETADDR; |
19a26f82 | 1196 | |
06f976ca | 1197 | ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg)); |
25a9939b WC |
1198 | if (!ifa) |
1199 | goto out; | |
06f976ca | 1200 | ifa->ifa_family = family; |
19a26f82 | 1201 | |
ebc73a67 CB |
1202 | /* Send the request for addresses, which returns all addresses on all |
1203 | * interfaces. | |
1204 | */ | |
19a26f82 MK |
1205 | err = netlink_send(&nlh, nlmsg); |
1206 | if (err < 0) | |
1207 | goto out; | |
19a26f82 MK |
1208 | |
1209 | do { | |
1210 | /* Restore the answer buffer length, it might have been | |
ebc73a67 CB |
1211 | * overwritten by a previous receive. |
1212 | */ | |
06f976ca | 1213 | answer->nlmsghdr->nlmsg_len = answer_len; |
19a26f82 | 1214 | |
ebc73a67 | 1215 | /* Get the (next) batch of reply messages. */ |
19a26f82 MK |
1216 | err = netlink_rcv(&nlh, answer); |
1217 | if (err < 0) | |
1218 | goto out; | |
1219 | ||
1220 | recv_len = err; | |
1221 | err = 0; | |
1222 | ||
ebc73a67 | 1223 | /* Satisfy the typing for the netlink macros. */ |
06f976ca | 1224 | msg = answer->nlmsghdr; |
19a26f82 MK |
1225 | |
1226 | while (NLMSG_OK(msg, recv_len)) { | |
ebc73a67 | 1227 | /* Stop reading if we see an error message. */ |
19a26f82 | 1228 | if (msg->nlmsg_type == NLMSG_ERROR) { |
ebc73a67 CB |
1229 | struct nlmsgerr *errmsg = |
1230 | (struct nlmsgerr *)NLMSG_DATA(msg); | |
19a26f82 MK |
1231 | err = errmsg->error; |
1232 | goto out; | |
1233 | } | |
1234 | ||
ebc73a67 | 1235 | /* Stop reading if we see a NLMSG_DONE message. */ |
19a26f82 MK |
1236 | if (msg->nlmsg_type == NLMSG_DONE) { |
1237 | readmore = 0; | |
1238 | break; | |
1239 | } | |
1240 | ||
1241 | if (msg->nlmsg_type != RTM_NEWADDR) { | |
1242 | err = -1; | |
1243 | goto out; | |
1244 | } | |
1245 | ||
06f976ca SZ |
1246 | ifa = (struct ifaddrmsg *)NLMSG_DATA(msg); |
1247 | if (ifa->ifa_index == ifindex) { | |
1248 | if (ifa_get_local_ip(family, msg, res) < 0) { | |
51e7a874 SG |
1249 | err = -1; |
1250 | goto out; | |
1251 | } | |
1252 | ||
ebc73a67 | 1253 | /* Found a result, stop searching. */ |
19a26f82 MK |
1254 | if (*res) |
1255 | goto out; | |
1256 | } | |
1257 | ||
ebc73a67 CB |
1258 | /* Keep reading more data from the socket if the last |
1259 | * message had the NLF_F_MULTI flag set. | |
1260 | */ | |
19a26f82 MK |
1261 | readmore = (msg->nlmsg_flags & NLM_F_MULTI); |
1262 | ||
ebc73a67 | 1263 | /* Look at the next message received in this buffer. */ |
19a26f82 MK |
1264 | msg = NLMSG_NEXT(msg, recv_len); |
1265 | } | |
1266 | } while (readmore); | |
1267 | ||
1268 | /* If we end up here, we didn't find any result, so signal an | |
ebc73a67 CB |
1269 | * error. |
1270 | */ | |
19a26f82 MK |
1271 | err = -1; |
1272 | ||
1273 | out: | |
1274 | netlink_close(&nlh); | |
1275 | nlmsg_free(answer); | |
1276 | nlmsg_free(nlmsg); | |
1277 | return err; | |
1278 | } | |
1279 | ||
1280 | int lxc_ipv6_addr_get(int ifindex, struct in6_addr **res) | |
1281 | { | |
ebc73a67 | 1282 | return ip_addr_get(AF_INET6, ifindex, (void **)res); |
19a26f82 MK |
1283 | } |
1284 | ||
ebc73a67 | 1285 | int lxc_ipv4_addr_get(int ifindex, struct in_addr **res) |
19a26f82 | 1286 | { |
ebc73a67 | 1287 | return ip_addr_get(AF_INET, ifindex, (void **)res); |
19a26f82 MK |
1288 | } |
1289 | ||
f8fee0e2 MK |
1290 | static int ip_gateway_add(int family, int ifindex, void *gw) |
1291 | { | |
ebc73a67 | 1292 | int addrlen, err; |
f8fee0e2 | 1293 | struct nl_handler nlh; |
06f976ca | 1294 | struct rtmsg *rt; |
ebc73a67 | 1295 | struct nlmsg *answer = NULL, *nlmsg = NULL; |
f8fee0e2 | 1296 | |
ebc73a67 CB |
1297 | addrlen = family == AF_INET ? sizeof(struct in_addr) |
1298 | : sizeof(struct in6_addr); | |
f8fee0e2 MK |
1299 | |
1300 | err = netlink_open(&nlh, NETLINK_ROUTE); | |
1301 | if (err) | |
1302 | return err; | |
1303 | ||
1304 | err = -ENOMEM; | |
1305 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
1306 | if (!nlmsg) | |
1307 | goto out; | |
1308 | ||
06f976ca | 1309 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
f8fee0e2 MK |
1310 | if (!answer) |
1311 | goto out; | |
1312 | ||
06f976ca | 1313 | nlmsg->nlmsghdr->nlmsg_flags = |
ebc73a67 | 1314 | NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; |
06f976ca SZ |
1315 | nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE; |
1316 | ||
1317 | rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg)); | |
25a9939b WC |
1318 | if (!rt) |
1319 | goto out; | |
06f976ca SZ |
1320 | rt->rtm_family = family; |
1321 | rt->rtm_table = RT_TABLE_MAIN; | |
1322 | rt->rtm_scope = RT_SCOPE_UNIVERSE; | |
1323 | rt->rtm_protocol = RTPROT_BOOT; | |
1324 | rt->rtm_type = RTN_UNICAST; | |
f8fee0e2 | 1325 | /* "default" destination */ |
06f976ca | 1326 | rt->rtm_dst_len = 0; |
f8fee0e2 MK |
1327 | |
1328 | err = -EINVAL; | |
1329 | if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen)) | |
1330 | goto out; | |
1331 | ||
1332 | /* Adding the interface index enables the use of link-local | |
ebc73a67 CB |
1333 | * addresses for the gateway. |
1334 | */ | |
f8fee0e2 MK |
1335 | if (nla_put_u32(nlmsg, RTA_OIF, ifindex)) |
1336 | goto out; | |
1337 | ||
1338 | err = netlink_transaction(&nlh, nlmsg, answer); | |
1339 | out: | |
1340 | netlink_close(&nlh); | |
1341 | nlmsg_free(answer); | |
1342 | nlmsg_free(nlmsg); | |
1343 | return err; | |
1344 | } | |
1345 | ||
1346 | int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw) | |
1347 | { | |
1348 | return ip_gateway_add(AF_INET, ifindex, gw); | |
1349 | } | |
1350 | ||
1351 | int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw) | |
1352 | { | |
1353 | return ip_gateway_add(AF_INET6, ifindex, gw); | |
1354 | } | |
1355 | ||
77dcf03a GL |
1356 | static int ip_route_dest_add(int family, int ifindex, void *dest) |
1357 | { | |
ebc73a67 | 1358 | int addrlen, err; |
77dcf03a | 1359 | struct nl_handler nlh; |
06f976ca | 1360 | struct rtmsg *rt; |
ebc73a67 | 1361 | struct nlmsg *answer = NULL, *nlmsg = NULL; |
acf47e1b | 1362 | |
ebc73a67 CB |
1363 | addrlen = family == AF_INET ? sizeof(struct in_addr) |
1364 | : sizeof(struct in6_addr); | |
acf47e1b | 1365 | |
77dcf03a GL |
1366 | err = netlink_open(&nlh, NETLINK_ROUTE); |
1367 | if (err) | |
1368 | return err; | |
acf47e1b | 1369 | |
77dcf03a GL |
1370 | err = -ENOMEM; |
1371 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
1372 | if (!nlmsg) | |
1373 | goto out; | |
acf47e1b | 1374 | |
06f976ca | 1375 | answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE); |
77dcf03a GL |
1376 | if (!answer) |
1377 | goto out; | |
acf47e1b | 1378 | |
06f976ca | 1379 | nlmsg->nlmsghdr->nlmsg_flags = |
ebc73a67 | 1380 | NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; |
06f976ca SZ |
1381 | nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE; |
1382 | ||
1383 | rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg)); | |
25a9939b WC |
1384 | if (!rt) |
1385 | goto out; | |
06f976ca SZ |
1386 | rt->rtm_family = family; |
1387 | rt->rtm_table = RT_TABLE_MAIN; | |
1388 | rt->rtm_scope = RT_SCOPE_LINK; | |
1389 | rt->rtm_protocol = RTPROT_BOOT; | |
1390 | rt->rtm_type = RTN_UNICAST; | |
ebc73a67 | 1391 | rt->rtm_dst_len = addrlen * 8; |
acf47e1b | 1392 | |
77dcf03a GL |
1393 | err = -EINVAL; |
1394 | if (nla_put_buffer(nlmsg, RTA_DST, dest, addrlen)) | |
1395 | goto out; | |
1396 | if (nla_put_u32(nlmsg, RTA_OIF, ifindex)) | |
1397 | goto out; | |
1398 | err = netlink_transaction(&nlh, nlmsg, answer); | |
1399 | out: | |
1400 | netlink_close(&nlh); | |
1401 | nlmsg_free(answer); | |
1402 | nlmsg_free(nlmsg); | |
1403 | return err; | |
1404 | } | |
1405 | ||
1406 | int lxc_ipv4_dest_add(int ifindex, struct in_addr *dest) | |
1407 | { | |
1408 | return ip_route_dest_add(AF_INET, ifindex, dest); | |
1409 | } | |
1410 | ||
1411 | int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest) | |
1412 | { | |
1413 | return ip_route_dest_add(AF_INET6, ifindex, dest); | |
1414 | } | |
1415 | ||
0d204771 SH |
1416 | static bool is_ovs_bridge(const char *bridge) |
1417 | { | |
ebc73a67 | 1418 | int ret; |
0d204771 | 1419 | struct stat sb; |
ebc73a67 | 1420 | char brdirname[22 + IFNAMSIZ + 1] = {0}; |
0d204771 | 1421 | |
ebc73a67 CB |
1422 | ret = snprintf(brdirname, 22 + IFNAMSIZ + 1, "/sys/class/net/%s/bridge", |
1423 | bridge); | |
1424 | if (ret < 0 || (size_t)ret >= 22 + IFNAMSIZ + 1) | |
1425 | return false; | |
1426 | ||
1427 | ret = stat(brdirname, &sb); | |
1428 | if (ret < 0 && errno == ENOENT) | |
0d204771 | 1429 | return true; |
ebc73a67 | 1430 | |
0d204771 SH |
1431 | return false; |
1432 | } | |
1433 | ||
cb0dc11b CB |
1434 | /* Called from a background thread - when nic goes away, remove it from the |
1435 | * bridge. | |
c43cbc04 | 1436 | */ |
cb0dc11b CB |
1437 | static void ovs_cleanup_nic(const char *lxcpath, const char *name, |
1438 | const char *bridge, const char *nic) | |
c43cbc04 | 1439 | { |
cb0dc11b CB |
1440 | int ret; |
1441 | ||
1442 | ret = lxc_check_inherited(NULL, true, &(int){-1}, 1); | |
1443 | if (ret < 0) | |
c43cbc04 | 1444 | return; |
cb0dc11b CB |
1445 | |
1446 | TRACE("Registering cleanup thread to remove nic \"%s\" from " | |
1447 | "openvswitch bridge \"%s\"", nic, bridge); | |
1448 | ||
1449 | ret = lxc_wait(name, "STOPPED", -1, lxcpath); | |
1450 | if (ret < 0) { | |
1451 | ERROR("Failed to register cleanup thread to remove nic \"%s\" " | |
1452 | "from openvswitch bridge \"%s\"", nic, bridge); | |
c43cbc04 | 1453 | return; |
cb0dc11b CB |
1454 | } |
1455 | ||
acf47e1b | 1456 | execlp("ovs-vsctl", "ovs-vsctl", "del-port", bridge, nic, (char *)NULL); |
cb0dc11b | 1457 | exit(EXIT_FAILURE); |
c43cbc04 SH |
1458 | } |
1459 | ||
ebc73a67 CB |
1460 | static int attach_to_ovs_bridge(const char *lxcpath, const char *name, |
1461 | const char *bridge, const char *nic) | |
0d204771 SH |
1462 | { |
1463 | pid_t pid; | |
6ad22d06 | 1464 | char *cmd; |
c43cbc04 | 1465 | int ret; |
6ad22d06 SH |
1466 | |
1467 | cmd = on_path("ovs-vsctl", NULL); | |
1468 | if (!cmd) | |
1469 | return -1; | |
1470 | free(cmd); | |
0d204771 SH |
1471 | |
1472 | pid = fork(); | |
1473 | if (pid < 0) | |
1474 | return -1; | |
ebc73a67 | 1475 | |
c43cbc04 SH |
1476 | if (pid > 0) { |
1477 | ret = wait_for_pid(pid); | |
1478 | if (ret < 0) | |
1479 | return ret; | |
ebc73a67 | 1480 | |
c43cbc04 SH |
1481 | pid = fork(); |
1482 | if (pid < 0) | |
ebc73a67 CB |
1483 | return -1; |
1484 | ||
c43cbc04 SH |
1485 | if (pid > 0) |
1486 | return 0; | |
ebc73a67 | 1487 | |
c43cbc04 | 1488 | ovs_cleanup_nic(lxcpath, name, bridge, nic); |
ebc73a67 | 1489 | exit(EXIT_SUCCESS); |
c43cbc04 | 1490 | } |
0d204771 | 1491 | |
ebc73a67 CB |
1492 | execlp("ovs-vsctl", "ovs-vsctl", "add-port", bridge, nic, (char *)NULL); |
1493 | exit(EXIT_FAILURE); | |
0d204771 | 1494 | } |
0d204771 | 1495 | |
1a0e70ac CB |
1496 | /* There is a lxc_bridge_attach, but no need of a bridge detach as automatically |
1497 | * done by kernel when a netdev is deleted. | |
7d163508 | 1498 | */ |
ebc73a67 CB |
1499 | int lxc_bridge_attach(const char *lxcpath, const char *name, const char *bridge, |
1500 | const char *ifname) | |
0ad19a3f | 1501 | { |
ebc73a67 | 1502 | int err, fd, index; |
0ad19a3f | 1503 | struct ifreq ifr; |
1504 | ||
dae3fdf6 | 1505 | if (strlen(ifname) >= IFNAMSIZ) |
3cfc0f3a | 1506 | return -EINVAL; |
0ad19a3f | 1507 | |
1508 | index = if_nametoindex(ifname); | |
1509 | if (!index) | |
3cfc0f3a | 1510 | return -EINVAL; |
0ad19a3f | 1511 | |
0d204771 | 1512 | if (is_ovs_bridge(bridge)) |
c43cbc04 | 1513 | return attach_to_ovs_bridge(lxcpath, name, bridge, ifname); |
0d204771 | 1514 | |
0ad19a3f | 1515 | fd = socket(AF_INET, SOCK_STREAM, 0); |
1516 | if (fd < 0) | |
3cfc0f3a | 1517 | return -errno; |
0ad19a3f | 1518 | |
ebc73a67 CB |
1519 | strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1); |
1520 | ifr.ifr_name[IFNAMSIZ - 1] = '\0'; | |
0ad19a3f | 1521 | ifr.ifr_ifindex = index; |
7d163508 | 1522 | err = ioctl(fd, SIOCBRADDIF, &ifr); |
0ad19a3f | 1523 | close(fd); |
3cfc0f3a MN |
1524 | if (err) |
1525 | err = -errno; | |
0ad19a3f | 1526 | |
1527 | return err; | |
1528 | } | |
72d0e1cb | 1529 | |
ebc73a67 | 1530 | static const char *const lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = { |
b343592b | 1531 | [LXC_NET_EMPTY] = "empty", |
72d0e1cb SG |
1532 | [LXC_NET_VETH] = "veth", |
1533 | [LXC_NET_MACVLAN] = "macvlan", | |
72d0e1cb | 1534 | [LXC_NET_PHYS] = "phys", |
b343592b BP |
1535 | [LXC_NET_VLAN] = "vlan", |
1536 | [LXC_NET_NONE] = "none", | |
72d0e1cb SG |
1537 | }; |
1538 | ||
1539 | const char *lxc_net_type_to_str(int type) | |
1540 | { | |
1541 | if (type < 0 || type > LXC_NET_MAXCONFTYPE) | |
1542 | return NULL; | |
ebc73a67 | 1543 | |
72d0e1cb SG |
1544 | return lxc_network_types[type]; |
1545 | } | |
8befa924 | 1546 | |
ebc73a67 | 1547 | static const char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
a0265685 SG |
1548 | |
1549 | char *lxc_mkifname(char *template) | |
1550 | { | |
ebc73a67 | 1551 | int ifexists = 0; |
84760c11 | 1552 | size_t i = 0; |
ebc73a67 | 1553 | char *name = NULL; |
a0265685 | 1554 | unsigned int seed; |
ebc73a67 CB |
1555 | FILE *urandom; |
1556 | struct ifaddrs *ifa, *ifaddr; | |
a0265685 | 1557 | |
ebc73a67 | 1558 | /* Get all the network interfaces. */ |
a0265685 SG |
1559 | getifaddrs(&ifaddr); |
1560 | ||
ebc73a67 CB |
1561 | /* Initialize the random number generator. */ |
1562 | urandom = fopen("/dev/urandom", "r"); | |
a0265685 | 1563 | if (urandom != NULL) { |
ebc73a67 | 1564 | if (fread(&seed, sizeof(seed), 1, urandom) <= 0) |
a0265685 | 1565 | seed = time(0); |
a0265685 | 1566 | fclose(urandom); |
ebc73a67 | 1567 | } else { |
a0265685 | 1568 | seed = time(0); |
ebc73a67 | 1569 | } |
a0265685 SG |
1570 | |
1571 | #ifndef HAVE_RAND_R | |
1572 | srand(seed); | |
1573 | #endif | |
1574 | ||
ebc73a67 CB |
1575 | /* Generate random names until we find one that doesn't exist. */ |
1576 | while (true) { | |
a0265685 SG |
1577 | ifexists = 0; |
1578 | name = strdup(template); | |
1579 | ||
1580 | if (name == NULL) | |
1581 | return NULL; | |
1582 | ||
1583 | for (i = 0; i < strlen(name); i++) { | |
1584 | if (name[i] == 'X') { | |
1585 | #ifdef HAVE_RAND_R | |
ebc73a67 CB |
1586 | name[i] = padchar[rand_r(&seed) % |
1587 | (strlen(padchar) - 1)]; | |
a0265685 SG |
1588 | #else |
1589 | name[i] = padchar[rand() % (strlen(padchar) - 1)]; | |
1590 | #endif | |
1591 | } | |
1592 | } | |
1593 | ||
1594 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | |
1595 | if (strcmp(ifa->ifa_name, name) == 0) { | |
1596 | ifexists = 1; | |
1597 | break; | |
1598 | } | |
1599 | } | |
1600 | ||
1601 | if (ifexists == 0) | |
1602 | break; | |
1603 | ||
1604 | free(name); | |
1605 | } | |
1606 | ||
1607 | freeifaddrs(ifaddr); | |
1608 | return name; | |
1609 | } | |
1610 | ||
8befa924 SH |
1611 | int setup_private_host_hw_addr(char *veth1) |
1612 | { | |
ebc73a67 | 1613 | int err, sockfd; |
8befa924 | 1614 | struct ifreq ifr; |
8befa924 | 1615 | |
8befa924 | 1616 | sockfd = socket(AF_INET, SOCK_DGRAM, 0); |
8befa924 SH |
1617 | if (sockfd < 0) |
1618 | return -errno; | |
1619 | ||
ebc73a67 CB |
1620 | err = snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1); |
1621 | if (err < 0 || (size_t)err >= IFNAMSIZ) | |
1622 | return -E2BIG; | |
1623 | ||
8befa924 SH |
1624 | err = ioctl(sockfd, SIOCGIFHWADDR, &ifr); |
1625 | if (err < 0) { | |
8befa924 | 1626 | close(sockfd); |
8befa924 SH |
1627 | return -errno; |
1628 | } | |
1629 | ||
1630 | ifr.ifr_hwaddr.sa_data[0] = 0xfe; | |
1631 | err = ioctl(sockfd, SIOCSIFHWADDR, &ifr); | |
8befa924 | 1632 | close(sockfd); |
8befa924 SH |
1633 | if (err < 0) |
1634 | return -errno; | |
1635 | ||
1636 | return 0; | |
1637 | } |