summaryrefslogtreecommitdiffstats
path: root/discover/network.c
diff options
context:
space:
mode:
authorSamuel Mendoza-Jonas <sam@mendozajonas.com>2017-06-15 15:23:06 +1000
committerSamuel Mendoza-Jonas <sam@mendozajonas.com>2017-07-11 14:50:00 +1000
commit58db060fbb1548a0acdfc475fa41fe86fb32dd11 (patch)
treebf23d028b13d7f5d9f694d2e2455fc8a9a2f64e6 /discover/network.c
parent515d2f03bae8d5617ee3bce5a46287203f7215c2 (diff)
downloadtalos-petitboot-58db060fbb1548a0acdfc475fa41fe86fb32dd11.tar.gz
talos-petitboot-58db060fbb1548a0acdfc475fa41fe86fb32dd11.zip
discover: Wait for net interfaces to be marked ready
If pb-discover is started before udev has settled there is a race between Petitboot configuring interfaces and udev renaming them. If an interface is set "up" the name change will fail and interfaces can be inconsistently named, eg: Device: (*) eth0 [0c:c4:7a:f4:1c:50, link up] ( ) enP1p9s0f1 [0c:c4:7a:f4:1c:51, link down] ( ) enP1p9s0f2 [0c:c4:7a:f4:1c:52, link down] ( ) enP1p9s0f3 [0c:c4:7a:f4:1c:53, link down] Add "net" devices to the udev filter and wait for them to be announced by udev before configuring them. udev_enumerate_add_match_is_initialized() ensures that by the time an interface appears via udev its name will be consistent. This also swaps the network and udev init order, but since interfaces now will not be configured until after udev is ready this should not have a user-visible effect. Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
Diffstat (limited to 'discover/network.c')
-rw-r--r--discover/network.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/discover/network.c b/discover/network.c
index 5035b7c..e2cae91 100644
--- a/discover/network.c
+++ b/discover/network.c
@@ -54,6 +54,7 @@ struct interface {
struct list_item list;
struct process *udhcpc_process;
struct discover_device *dev;
+ bool ready;
};
struct network {
@@ -598,6 +599,11 @@ static int network_handle_nlmsg(struct network *network, struct nlmsghdr *nlmsg)
if (!interface->dev)
create_interface_dev(network, interface);
+ if (!interface->ready && strncmp(interface->name, "lo", strlen("lo"))) {
+ pb_log("%s not marked ready yet\n", interface->name);
+ return 0;
+ }
+
configure_interface(network, interface,
info->ifi_flags & IFF_UP,
info->ifi_flags & IFF_LOWER_UP);
@@ -605,6 +611,72 @@ static int network_handle_nlmsg(struct network *network, struct nlmsghdr *nlmsg)
return 0;
}
+void network_mark_interface_ready(struct device_handler *handler,
+ int ifindex, const char *ifname, uint8_t *mac, int hwsize)
+{
+ struct network *network = device_handler_get_network(handler);
+ struct interface *interface, *tmp = NULL;
+ char *macstr;
+
+ if (!network) {
+ pb_log("Network not ready - can not mark interface ready\n");
+ return;
+ }
+
+ if (hwsize != HWADDR_SIZE)
+ return;
+
+ if (strncmp(ifname, "lo", strlen("lo")) == 0)
+ return;
+
+ interface = find_interface_by_ifindex(network, ifindex);
+ if (!interface) {
+ pb_debug("Creating ready interface %d - %s\n",
+ ifindex, ifname);
+ interface = talloc_zero(network, struct interface);
+ interface->ifindex = ifindex;
+ interface->state = IFSTATE_NEW;
+ memcpy(interface->hwaddr, mac, HWADDR_SIZE);
+ strncpy(interface->name, ifname, sizeof(interface->name) - 1);
+
+ list_for_each_entry(&network->interfaces, tmp, list)
+ if (memcmp(interface->hwaddr, tmp->hwaddr,
+ sizeof(interface->hwaddr)) == 0) {
+ pb_log("%s: %s has duplicate MAC address, ignoring\n",
+ __func__, interface->name);
+ talloc_free(interface);
+ return;
+ }
+
+ list_add(&network->interfaces, &interface->list);
+ create_interface_dev(network, interface);
+ }
+
+ if (interface->ready) {
+ pb_log("%s already ready\n", interface->name);
+ return;
+ }
+
+ if (strncmp(interface->name, ifname, strlen(ifname)) != 0) {
+ pb_debug("ifname update from udev: %s -> %s\n", interface->name, ifname);
+ strncpy(interface->name, ifname, sizeof(interface->name) - 1);
+ talloc_free(interface->dev->device->id);
+ interface->dev->device->id =
+ talloc_strdup(interface->dev->device, ifname);
+ }
+
+ if (memcmp(interface->hwaddr, mac, HWADDR_SIZE) != 0) {
+ macstr = mac_bytes_to_string(interface, mac, hwsize);
+ pb_log("Warning - new MAC for interface %d does not match: %s\n",
+ ifindex, macstr);
+ talloc_free(macstr);
+ }
+
+ pb_log("Interface %s ready\n", ifname);
+ interface->ready = true;
+ configure_interface(network, interface, false, false);
+}
+
static int network_netlink_process(void *arg)
{
struct network *network = arg;
OpenPOWER on IntegriCloud