X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fnetwork.c;h=bc7e186a1921e8531bb2fd37ed026f5e47e5977e;hp=28e3a29cb2b3621beb3c7ea69c6a06927fc86fe0;hb=d67d5beceef94686818ce264b2ca93f82b66e8f4;hpb=51c6aaf7864eb65779d548ee2549caa357f71e2c diff --git a/discover/network.c b/discover/network.c index 28e3a29..bc7e186 100644 --- a/discover/network.c +++ b/discover/network.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -19,9 +20,12 @@ #include "file.h" #include "network.h" +#include "sysinfo.h" +#include "device-handler.h" #define HWADDR_SIZE 6 #define PIDFILE_BASE (LOCAL_STATE_DIR "/petitboot/") +#define INITIAL_BUFSIZE 4096 #define for_each_nlmsg(buf, nlmsg, len) \ for (nlmsg = (struct nlmsghdr *)buf; \ @@ -47,21 +51,25 @@ struct interface { struct list_item list; struct process *udhcpc_process; + struct discover_device *dev; }; struct network { - struct list interfaces; - struct waiter *waiter; - int netlink_sd; - bool manual_config; - bool dry_run; + struct list interfaces; + struct device_handler *handler; + struct waiter *waiter; + int netlink_sd; + void *netlink_buf; + unsigned int netlink_buf_size; + bool manual_config; + bool dry_run; }; static const struct interface_config *find_config_by_hwaddr( uint8_t *hwaddr) { const struct config *config; - int i; + unsigned int i; config = config_get(); if (!config) @@ -111,6 +119,10 @@ static int network_init_netlink(struct network *network) return -1; } + network->netlink_buf_size = INITIAL_BUFSIZE; + network->netlink_buf = talloc_array(network, char, + network->netlink_buf_size); + return 0; } @@ -138,6 +150,24 @@ static int network_send_link_query(struct network *network) return 0; } +static void add_interface(struct network *network, + struct interface *interface) +{ + list_add(&network->interfaces, &interface->list); + interface->dev = discover_device_create(network->handler, + interface->name); + interface->dev->device->type = DEVICE_TYPE_NETWORK; + device_handler_add_device(network->handler, interface->dev); +} + +static void remove_interface(struct network *network, + struct interface *interface) +{ + device_handler_remove(network->handler, interface->dev); + list_remove(&interface->list); + talloc_free(interface); +} + static int interface_change(struct interface *interface, bool up) { const char *statestr = up ? "up" : "down"; @@ -174,7 +204,7 @@ static int interface_down(struct interface *interface) static void udhcpc_process_exit(struct process *process) { struct interface *interface = process->data; - pb_log("udhcp client [pid %d] for interface %s exited, rc %d\n", + pb_debug("udhcp client [pid %d] for interface %s exited, rc %d\n", process->pid, interface->name, process->exit_status); interface->udhcpc_process = NULL; process_release(process); @@ -189,6 +219,7 @@ static void configure_interface_dhcp(struct interface *interface) pb_system_apps.udhcpc, "-R", "-n", + "-O", "pxeconffile", "-p", pidfile, "-i", interface->name, NULL, @@ -325,6 +356,7 @@ static int network_handle_nlmsg(struct network *network, struct nlmsghdr *nlmsg) struct interface *interface; struct ifinfomsg *info; struct rtattr *attr; + unsigned int mtu; uint8_t ifaddr[6]; char ifname[IFNAMSIZ+1]; int attrlen, type; @@ -338,6 +370,7 @@ static int network_handle_nlmsg(struct network *network, struct nlmsghdr *nlmsg) info = NLMSG_DATA(nlmsg); have_ifaddr = have_ifname = false; + mtu = 1; attrlen = nlmsg->nlmsg_len - sizeof(*info); @@ -355,19 +388,22 @@ static int network_handle_nlmsg(struct network *network, struct nlmsghdr *nlmsg) strncpy(ifname, data, IFNAMSIZ); have_ifname = true; break; + + case IFLA_MTU: + mtu = *(unsigned int *)data; + break; } } if (!have_ifaddr || !have_ifname) return -1; - if (type == RTM_DELLINK) { + if (type == RTM_DELLINK || mtu == 0) { interface = find_interface_by_ifindex(network, info->ifi_index); if (!interface) return 0; pb_log("network: interface %s removed\n", interface->name); - list_remove(&interface->list); - talloc_free(interface); + remove_interface(network, interface); return 0; } @@ -379,6 +415,13 @@ static int network_handle_nlmsg(struct network *network, struct nlmsghdr *nlmsg) interface->state = IFSTATE_NEW; memcpy(interface->hwaddr, ifaddr, sizeof(interface->hwaddr)); strncpy(interface->name, ifname, sizeof(interface->name) - 1); + add_interface(network, interface); + + /* tell the sysinfo code about this interface */ + if (strcmp(interface->name, "lo")) + system_info_register_interface( + sizeof(interface->hwaddr), + interface->hwaddr, interface->name); } configure_interface(network, interface, @@ -392,19 +435,48 @@ static int network_netlink_process(void *arg) { struct network *network = arg; struct nlmsghdr *nlmsg; + struct msghdr msg; + struct iovec iov; unsigned int len; - char buf[4096]; - int rc; + int rc, flags; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + flags = MSG_PEEK; + +retry: + iov.iov_len = network->netlink_buf_size; + iov.iov_base = network->netlink_buf; + + rc = recvmsg(network->netlink_sd, &msg, flags); - rc = recv(network->netlink_sd, buf, sizeof(buf), 0); if (rc < 0) { - perror("netlink recv"); + perror("netlink recv header"); return -1; } len = rc; - for_each_nlmsg(buf, nlmsg, len) + /* if the netlink message was larger than our buffer, realloc + * before reading again */ + if (len > network->netlink_buf_size || msg.msg_flags & MSG_TRUNC) { + network->netlink_buf_size *= 2; + network->netlink_buf = talloc_realloc(network, + network->netlink_buf, + char *, + network->netlink_buf_size); + goto retry; + } + + /* otherwise, we're good to read the entire message without PEEK */ + if (flags == MSG_PEEK) { + flags = 0; + goto retry; + } + + for_each_nlmsg(network->netlink_buf, nlmsg, len) network_handle_nlmsg(network, nlmsg); return 0; @@ -413,7 +485,8 @@ static int network_netlink_process(void *arg) static void network_init_dns(struct network *network) { const struct config *config; - int i, rc, len; + unsigned int i; + int rc, len; bool modified; char *buf; @@ -446,9 +519,10 @@ static void network_init_dns(struct network *network) } dns_conf_len = strlen(dns_conf); - buf = talloc_realloc(network, buf, char, len + dns_conf_len); + buf = talloc_realloc(network, buf, char, len + dns_conf_len + 1); memcpy(buf + len, dns_conf, dns_conf_len); len += dns_conf_len; + buf[len - 1] = '\0'; modified = true; talloc_free(dns_conf); @@ -464,15 +538,17 @@ static void network_init_dns(struct network *network) talloc_free(buf); } -struct network *network_init(void *ctx, struct waitset *waitset, bool dry_run) +struct network *network_init(struct device_handler *handler, + struct waitset *waitset, bool dry_run) { struct network *network; int rc; - network = talloc(ctx, struct network); + network = talloc(handler, struct network); list_init(&network->interfaces); - network->manual_config = false; + network->handler = handler; network->dry_run = dry_run; + network->manual_config = config_get()->network.n_interfaces != 0; network_init_dns(network);