Linux - Failure to assign ipv6 address to virtual interface without error
Clash Royale CLAN TAG#URR8PPP
I'm working on NixOS, creating some functions in C to programmatically manipulate veth pairs and assign IPv6 addresses in order to create a program for setting up a network for containers on a single host.
To do so, I'm using libnftnl and libmnl to handle the fine details of constructing rtnetlink packets and setns()
to set the network namespace of the calling thread to the correct network namespace before performing actions such as bringing an interface up.
The general flow of the program goes like:
- create veth pairs in the host network namespace
- move one end of each veth pair to the corresponding network namespace
- set all the veth endpoints in the host network namespace to UP
- call `setns()` into each other network namespace to set
the loopback interface and vethpair end to UP
- add an IPv6 address to each of the veth ends in the host network namespace
- call `setns()` into each other network namespace to set the IPv6 address
of the other veth endpoints
The Problem
When I run the program, IPv6 addresses in the host network namespace aren't always assigned to the interfaces. All the previous steps occur and exist and even the IPv6 addresses are assigned to all interfaces in other network namespaces but not always in the host network namespace.
This happens when I run the program, delete all the interfaces and rerun the program within about a minute of each other.
Some solutions that I've come up with are that if I make the program sleep for, say 5 seconds, before assigning addresses to interfaces in the host namespace, I can run the program, delete the interfaces and rerun the program nonstop and the addresses are all assigned. I can also wait a while after deleting the interfaces before rerunning the program and this will also cause all IPv6 addresses to be assigned correctly.
Other weird stuff
When running the program, there are times when some IPv6 addresses in the host network namespace are added and some aren't. The netlink ACK message returned for the packets also indicate that no error occurred so I can't tell that an address has failed to be assigned until I run ip address
after the program exits.
Since this program is eventually going to be part of a larger container orchestration system, I'm looking to see if there's a way to either detect or prevent this kind of error.
I've thought about it potentially being duplicate address detection or the IP address being still stored somewhere in the kernel for a while after being delete but I receive no error from the netlink module.
EDIT 1
Here's a bit of code showing the C code which deals with creating a rtnetlink message and the sending and receiving of netlink messages.
1 #include <stdlib.h>
2 #include <time.h>
3 #include <poll.h>
4
5 /* Linux specific headers */
6 #include <linux/if_link.h>
7 #include <linux/rtnetlink.h>
8
9 /* Libmnl dependency */
10 #include <libmnl/libmnl.h>
11
13 int send_recv(struct mnl_socket *sock,
14 struct mnl_nlmsg_batch *batch,
15 void *receive_buffer, uint32_t receive_size,
16 const int portid)
17
18 int fd = mnl_socket_get_fd(sock);
19 int timeout = 0;
20 int status;
21 nfds_t nfds = 1;
22 ssize_t receive_size;
23 struct pollfd fds[nfds];
24
25 /* Send the buffered data via a pre-created netlink socket. */
26 status = mnl_socket_sendto(sock, mnl_nlmsg_batch_head(batch),
27 mnl_nlmsg_batch_size(batch));
28 if (status < 0) return -1;
29
30 fds[0].fd = fd;
31 fds[0].events = POLLIN;
32
33 while (poll(fds, nfds, timeout) > 0)
34 /* Receive the response from the kernel. */
35 receive_size = mnl_socket_recvfrom(sock, receive_buf, receive_size);
36 if (receive_size == -1)
37 return -1;
38
39 /* Run a callback function on the response.
40 * cb_ctl_array is an array of function pointers based on the status of
41 * the response. 0 should be the sequence number, but the function also
42 * behaves correctly if the actual sequence number wasn't 0 and we feed it
43 * 0 still.
44 */
45 status = mnl_cb_run2(receive_buf, receive_size, 0, portid, NULL,
46 NULL, cb_ctl_array, MNL_ARRAY_SIZE(cb_ctl_array));
47
48 if (status != MNL_CB_OK)
49 return -1;
50
51
52 return MNL_CB_OK;
53
54
55
56 int set_interface_address_message(void *message_buffer, int seq,
57 uint8_t prefix,
58 const char if_name[IFNAMSIZ],
59 const struct in6_addr *in6_addr)
60
76 NLM_F_ACK
The sequence of ip
commands that this program is meant to mirror is
sudo ip netns add A
sudo ip link add veth1 type veth peername veth2
sudo ip link set dev veth2 netns A
sudo ip link set dev veth1 up
sudo ip -n A link set dev veth2 up
sudo ip -n A link set dev lo up
sudo ip address add fc00::1/64 dev veth1
sudo ip -n A address add fc00::2/64 dev veth2
Running the above sequence of commands in a bash script has never failed to add an ipv6 address to an interface.
linux networking kernel network-interface
add a comment |
I'm working on NixOS, creating some functions in C to programmatically manipulate veth pairs and assign IPv6 addresses in order to create a program for setting up a network for containers on a single host.
To do so, I'm using libnftnl and libmnl to handle the fine details of constructing rtnetlink packets and setns()
to set the network namespace of the calling thread to the correct network namespace before performing actions such as bringing an interface up.
The general flow of the program goes like:
- create veth pairs in the host network namespace
- move one end of each veth pair to the corresponding network namespace
- set all the veth endpoints in the host network namespace to UP
- call `setns()` into each other network namespace to set
the loopback interface and vethpair end to UP
- add an IPv6 address to each of the veth ends in the host network namespace
- call `setns()` into each other network namespace to set the IPv6 address
of the other veth endpoints
The Problem
When I run the program, IPv6 addresses in the host network namespace aren't always assigned to the interfaces. All the previous steps occur and exist and even the IPv6 addresses are assigned to all interfaces in other network namespaces but not always in the host network namespace.
This happens when I run the program, delete all the interfaces and rerun the program within about a minute of each other.
Some solutions that I've come up with are that if I make the program sleep for, say 5 seconds, before assigning addresses to interfaces in the host namespace, I can run the program, delete the interfaces and rerun the program nonstop and the addresses are all assigned. I can also wait a while after deleting the interfaces before rerunning the program and this will also cause all IPv6 addresses to be assigned correctly.
Other weird stuff
When running the program, there are times when some IPv6 addresses in the host network namespace are added and some aren't. The netlink ACK message returned for the packets also indicate that no error occurred so I can't tell that an address has failed to be assigned until I run ip address
after the program exits.
Since this program is eventually going to be part of a larger container orchestration system, I'm looking to see if there's a way to either detect or prevent this kind of error.
I've thought about it potentially being duplicate address detection or the IP address being still stored somewhere in the kernel for a while after being delete but I receive no error from the netlink module.
EDIT 1
Here's a bit of code showing the C code which deals with creating a rtnetlink message and the sending and receiving of netlink messages.
1 #include <stdlib.h>
2 #include <time.h>
3 #include <poll.h>
4
5 /* Linux specific headers */
6 #include <linux/if_link.h>
7 #include <linux/rtnetlink.h>
8
9 /* Libmnl dependency */
10 #include <libmnl/libmnl.h>
11
13 int send_recv(struct mnl_socket *sock,
14 struct mnl_nlmsg_batch *batch,
15 void *receive_buffer, uint32_t receive_size,
16 const int portid)
17
18 int fd = mnl_socket_get_fd(sock);
19 int timeout = 0;
20 int status;
21 nfds_t nfds = 1;
22 ssize_t receive_size;
23 struct pollfd fds[nfds];
24
25 /* Send the buffered data via a pre-created netlink socket. */
26 status = mnl_socket_sendto(sock, mnl_nlmsg_batch_head(batch),
27 mnl_nlmsg_batch_size(batch));
28 if (status < 0) return -1;
29
30 fds[0].fd = fd;
31 fds[0].events = POLLIN;
32
33 while (poll(fds, nfds, timeout) > 0)
34 /* Receive the response from the kernel. */
35 receive_size = mnl_socket_recvfrom(sock, receive_buf, receive_size);
36 if (receive_size == -1)
37 return -1;
38
39 /* Run a callback function on the response.
40 * cb_ctl_array is an array of function pointers based on the status of
41 * the response. 0 should be the sequence number, but the function also
42 * behaves correctly if the actual sequence number wasn't 0 and we feed it
43 * 0 still.
44 */
45 status = mnl_cb_run2(receive_buf, receive_size, 0, portid, NULL,
46 NULL, cb_ctl_array, MNL_ARRAY_SIZE(cb_ctl_array));
47
48 if (status != MNL_CB_OK)
49 return -1;
50
51
52 return MNL_CB_OK;
53
54
55
56 int set_interface_address_message(void *message_buffer, int seq,
57 uint8_t prefix,
58 const char if_name[IFNAMSIZ],
59 const struct in6_addr *in6_addr)
60
76 NLM_F_ACK
The sequence of ip
commands that this program is meant to mirror is
sudo ip netns add A
sudo ip link add veth1 type veth peername veth2
sudo ip link set dev veth2 netns A
sudo ip link set dev veth1 up
sudo ip -n A link set dev veth2 up
sudo ip -n A link set dev lo up
sudo ip address add fc00::1/64 dev veth1
sudo ip -n A address add fc00::2/64 dev veth2
Running the above sequence of commands in a bash script has never failed to add an ipv6 address to an interface.
linux networking kernel network-interface
Perhaps a very small code snippet that demonstrates the problem?
– CMCDragonkai
Mar 2 at 6:38
added code snippet in edit1 as well as corresponding sequence of iproute commands
– Ray
Mar 4 at 2:28
add a comment |
I'm working on NixOS, creating some functions in C to programmatically manipulate veth pairs and assign IPv6 addresses in order to create a program for setting up a network for containers on a single host.
To do so, I'm using libnftnl and libmnl to handle the fine details of constructing rtnetlink packets and setns()
to set the network namespace of the calling thread to the correct network namespace before performing actions such as bringing an interface up.
The general flow of the program goes like:
- create veth pairs in the host network namespace
- move one end of each veth pair to the corresponding network namespace
- set all the veth endpoints in the host network namespace to UP
- call `setns()` into each other network namespace to set
the loopback interface and vethpair end to UP
- add an IPv6 address to each of the veth ends in the host network namespace
- call `setns()` into each other network namespace to set the IPv6 address
of the other veth endpoints
The Problem
When I run the program, IPv6 addresses in the host network namespace aren't always assigned to the interfaces. All the previous steps occur and exist and even the IPv6 addresses are assigned to all interfaces in other network namespaces but not always in the host network namespace.
This happens when I run the program, delete all the interfaces and rerun the program within about a minute of each other.
Some solutions that I've come up with are that if I make the program sleep for, say 5 seconds, before assigning addresses to interfaces in the host namespace, I can run the program, delete the interfaces and rerun the program nonstop and the addresses are all assigned. I can also wait a while after deleting the interfaces before rerunning the program and this will also cause all IPv6 addresses to be assigned correctly.
Other weird stuff
When running the program, there are times when some IPv6 addresses in the host network namespace are added and some aren't. The netlink ACK message returned for the packets also indicate that no error occurred so I can't tell that an address has failed to be assigned until I run ip address
after the program exits.
Since this program is eventually going to be part of a larger container orchestration system, I'm looking to see if there's a way to either detect or prevent this kind of error.
I've thought about it potentially being duplicate address detection or the IP address being still stored somewhere in the kernel for a while after being delete but I receive no error from the netlink module.
EDIT 1
Here's a bit of code showing the C code which deals with creating a rtnetlink message and the sending and receiving of netlink messages.
1 #include <stdlib.h>
2 #include <time.h>
3 #include <poll.h>
4
5 /* Linux specific headers */
6 #include <linux/if_link.h>
7 #include <linux/rtnetlink.h>
8
9 /* Libmnl dependency */
10 #include <libmnl/libmnl.h>
11
13 int send_recv(struct mnl_socket *sock,
14 struct mnl_nlmsg_batch *batch,
15 void *receive_buffer, uint32_t receive_size,
16 const int portid)
17
18 int fd = mnl_socket_get_fd(sock);
19 int timeout = 0;
20 int status;
21 nfds_t nfds = 1;
22 ssize_t receive_size;
23 struct pollfd fds[nfds];
24
25 /* Send the buffered data via a pre-created netlink socket. */
26 status = mnl_socket_sendto(sock, mnl_nlmsg_batch_head(batch),
27 mnl_nlmsg_batch_size(batch));
28 if (status < 0) return -1;
29
30 fds[0].fd = fd;
31 fds[0].events = POLLIN;
32
33 while (poll(fds, nfds, timeout) > 0)
34 /* Receive the response from the kernel. */
35 receive_size = mnl_socket_recvfrom(sock, receive_buf, receive_size);
36 if (receive_size == -1)
37 return -1;
38
39 /* Run a callback function on the response.
40 * cb_ctl_array is an array of function pointers based on the status of
41 * the response. 0 should be the sequence number, but the function also
42 * behaves correctly if the actual sequence number wasn't 0 and we feed it
43 * 0 still.
44 */
45 status = mnl_cb_run2(receive_buf, receive_size, 0, portid, NULL,
46 NULL, cb_ctl_array, MNL_ARRAY_SIZE(cb_ctl_array));
47
48 if (status != MNL_CB_OK)
49 return -1;
50
51
52 return MNL_CB_OK;
53
54
55
56 int set_interface_address_message(void *message_buffer, int seq,
57 uint8_t prefix,
58 const char if_name[IFNAMSIZ],
59 const struct in6_addr *in6_addr)
60
76 NLM_F_ACK
The sequence of ip
commands that this program is meant to mirror is
sudo ip netns add A
sudo ip link add veth1 type veth peername veth2
sudo ip link set dev veth2 netns A
sudo ip link set dev veth1 up
sudo ip -n A link set dev veth2 up
sudo ip -n A link set dev lo up
sudo ip address add fc00::1/64 dev veth1
sudo ip -n A address add fc00::2/64 dev veth2
Running the above sequence of commands in a bash script has never failed to add an ipv6 address to an interface.
linux networking kernel network-interface
I'm working on NixOS, creating some functions in C to programmatically manipulate veth pairs and assign IPv6 addresses in order to create a program for setting up a network for containers on a single host.
To do so, I'm using libnftnl and libmnl to handle the fine details of constructing rtnetlink packets and setns()
to set the network namespace of the calling thread to the correct network namespace before performing actions such as bringing an interface up.
The general flow of the program goes like:
- create veth pairs in the host network namespace
- move one end of each veth pair to the corresponding network namespace
- set all the veth endpoints in the host network namespace to UP
- call `setns()` into each other network namespace to set
the loopback interface and vethpair end to UP
- add an IPv6 address to each of the veth ends in the host network namespace
- call `setns()` into each other network namespace to set the IPv6 address
of the other veth endpoints
The Problem
When I run the program, IPv6 addresses in the host network namespace aren't always assigned to the interfaces. All the previous steps occur and exist and even the IPv6 addresses are assigned to all interfaces in other network namespaces but not always in the host network namespace.
This happens when I run the program, delete all the interfaces and rerun the program within about a minute of each other.
Some solutions that I've come up with are that if I make the program sleep for, say 5 seconds, before assigning addresses to interfaces in the host namespace, I can run the program, delete the interfaces and rerun the program nonstop and the addresses are all assigned. I can also wait a while after deleting the interfaces before rerunning the program and this will also cause all IPv6 addresses to be assigned correctly.
Other weird stuff
When running the program, there are times when some IPv6 addresses in the host network namespace are added and some aren't. The netlink ACK message returned for the packets also indicate that no error occurred so I can't tell that an address has failed to be assigned until I run ip address
after the program exits.
Since this program is eventually going to be part of a larger container orchestration system, I'm looking to see if there's a way to either detect or prevent this kind of error.
I've thought about it potentially being duplicate address detection or the IP address being still stored somewhere in the kernel for a while after being delete but I receive no error from the netlink module.
EDIT 1
Here's a bit of code showing the C code which deals with creating a rtnetlink message and the sending and receiving of netlink messages.
1 #include <stdlib.h>
2 #include <time.h>
3 #include <poll.h>
4
5 /* Linux specific headers */
6 #include <linux/if_link.h>
7 #include <linux/rtnetlink.h>
8
9 /* Libmnl dependency */
10 #include <libmnl/libmnl.h>
11
13 int send_recv(struct mnl_socket *sock,
14 struct mnl_nlmsg_batch *batch,
15 void *receive_buffer, uint32_t receive_size,
16 const int portid)
17
18 int fd = mnl_socket_get_fd(sock);
19 int timeout = 0;
20 int status;
21 nfds_t nfds = 1;
22 ssize_t receive_size;
23 struct pollfd fds[nfds];
24
25 /* Send the buffered data via a pre-created netlink socket. */
26 status = mnl_socket_sendto(sock, mnl_nlmsg_batch_head(batch),
27 mnl_nlmsg_batch_size(batch));
28 if (status < 0) return -1;
29
30 fds[0].fd = fd;
31 fds[0].events = POLLIN;
32
33 while (poll(fds, nfds, timeout) > 0)
34 /* Receive the response from the kernel. */
35 receive_size = mnl_socket_recvfrom(sock, receive_buf, receive_size);
36 if (receive_size == -1)
37 return -1;
38
39 /* Run a callback function on the response.
40 * cb_ctl_array is an array of function pointers based on the status of
41 * the response. 0 should be the sequence number, but the function also
42 * behaves correctly if the actual sequence number wasn't 0 and we feed it
43 * 0 still.
44 */
45 status = mnl_cb_run2(receive_buf, receive_size, 0, portid, NULL,
46 NULL, cb_ctl_array, MNL_ARRAY_SIZE(cb_ctl_array));
47
48 if (status != MNL_CB_OK)
49 return -1;
50
51
52 return MNL_CB_OK;
53
54
55
56 int set_interface_address_message(void *message_buffer, int seq,
57 uint8_t prefix,
58 const char if_name[IFNAMSIZ],
59 const struct in6_addr *in6_addr)
60
76 NLM_F_ACK
The sequence of ip
commands that this program is meant to mirror is
sudo ip netns add A
sudo ip link add veth1 type veth peername veth2
sudo ip link set dev veth2 netns A
sudo ip link set dev veth1 up
sudo ip -n A link set dev veth2 up
sudo ip -n A link set dev lo up
sudo ip address add fc00::1/64 dev veth1
sudo ip -n A address add fc00::2/64 dev veth2
Running the above sequence of commands in a bash script has never failed to add an ipv6 address to an interface.
linux networking kernel network-interface
linux networking kernel network-interface
edited Mar 4 at 2:28
Ray
asked Mar 2 at 5:32
RayRay
112
112
Perhaps a very small code snippet that demonstrates the problem?
– CMCDragonkai
Mar 2 at 6:38
added code snippet in edit1 as well as corresponding sequence of iproute commands
– Ray
Mar 4 at 2:28
add a comment |
Perhaps a very small code snippet that demonstrates the problem?
– CMCDragonkai
Mar 2 at 6:38
added code snippet in edit1 as well as corresponding sequence of iproute commands
– Ray
Mar 4 at 2:28
Perhaps a very small code snippet that demonstrates the problem?
– CMCDragonkai
Mar 2 at 6:38
Perhaps a very small code snippet that demonstrates the problem?
– CMCDragonkai
Mar 2 at 6:38
added code snippet in edit1 as well as corresponding sequence of iproute commands
– Ray
Mar 4 at 2:28
added code snippet in edit1 as well as corresponding sequence of iproute commands
– Ray
Mar 4 at 2:28
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f503923%2flinux-failure-to-assign-ipv6-address-to-virtual-interface-without-error%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f503923%2flinux-failure-to-assign-ipv6-address-to-virtual-interface-without-error%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Perhaps a very small code snippet that demonstrates the problem?
– CMCDragonkai
Mar 2 at 6:38
added code snippet in edit1 as well as corresponding sequence of iproute commands
– Ray
Mar 4 at 2:28