X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-link.c;h=63c7a8bf248195f1aad1dd7298a7d6464925a4c7;hb=9b15b7846d4de01bb5d9700a24077787e984e8ab;hp=b46ac5c3c308005aaafea8503df05fcb17af8d13;hpb=79008bddf679a5e0900369950eb346c9fa687107;p=elogind.git diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index b46ac5c3c..63c7a8bf2 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -75,6 +75,19 @@ static bool link_ipv4ll_enabled(Link *link) { return link->network->ipv4ll; } +static bool link_lldp_enabled(Link *link) { + if (link->flags & IFF_LOOPBACK) + return false; + + if (!link->network) + return false; + + if(link->network->bridge) + return false; + + return link->network->lldp; +} + #define FLAG_STRING(string, flag, old, new) \ (((old ^ new) & flag) \ ? ((old & flag) ? (" -" string) : (" +" string)) \ @@ -206,6 +219,12 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) { if (r < 0) return -ENOMEM; + r = asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", + link->ifindex); + if (r < 0) + return -ENOMEM; + + r = hashmap_ensure_allocated(&manager->links, NULL); if (r < 0) return r; @@ -240,12 +259,16 @@ static void link_free(Link *link) { address_free(address); } + sd_dhcp_server_unref(link->dhcp_server); sd_dhcp_client_unref(link->dhcp_client); sd_dhcp_lease_unref(link->dhcp_lease); unlink(link->lease_file); free(link->lease_file); + unlink(link->lldp_file); + free(link->lldp_file); + sd_ipv4ll_unref(link->ipv4ll); sd_dhcp6_client_unref(link->dhcp6_client); sd_icmp6_nd_unref(link->icmp6_router_discovery); @@ -364,6 +387,16 @@ static int link_stop_clients(Link *link) { } } + if (link->lldp) { + + k = sd_lldp_stop(link->lldp); + if (k < 0) { + log_link_warning(link, "Could not stop LLDP : %s", + strerror(-r)); + r = k; + } + } + return r; } @@ -515,12 +548,7 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -EEXIST) - log_link_struct(LOG_WARNING, link, - "MESSAGE=%-*s: could not set route: %s", - IFNAMSIZ, - link->ifname, strerror(-r), - "ERRNO=%d", -r, - NULL); + log_link_warning_errno(link, -r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname); if (link->link_messages == 0) { log_link_debug(link, "routes set"); @@ -576,38 +604,7 @@ int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -ESRCH) - log_link_struct(LOG_WARNING, link, - "MESSAGE=%-*s: could not drop route: %s", - IFNAMSIZ, - link->ifname, strerror(-r), - "ERRNO=%d", -r, - NULL); - - return 1; -} - -int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { - _cleanup_link_unref_ Link *link = userdata; - int r; - - assert(rtnl); - assert(m); - assert(link); - assert(link->manager); - - for (; m; m = sd_rtnl_message_next(m)) { - r = sd_rtnl_message_get_errno(m); - if (r < 0) { - log_link_debug(link, "getting address failed: %s", - strerror(-r)); - continue; - } - - r = link_rtnl_process_address(rtnl, m, link->manager); - if (r < 0) - log_link_warning(link, "could not process address: %s", - strerror(-r)); - } + log_link_warning_errno(link, -r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname); return 1; } @@ -631,17 +628,9 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -EEXIST) - log_link_struct(LOG_WARNING, link, - "MESSAGE=%-*s: could not set address: %s", - IFNAMSIZ, - link->ifname, strerror(-r), - "ERRNO=%d", -r, - NULL); - else if (r >= 0) { - /* calling handler directly so take a ref */ - link_ref(link); - link_get_address_handler(rtnl, m, link); - } + log_link_warning_errno(link, -r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname); + else if (r >= 0) + link_rtnl_process_address(rtnl, m, link->manager); if (link->link_messages == 0) { log_link_debug(link, "addresses set"); @@ -695,14 +684,45 @@ int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -EADDRNOTAVAIL) - log_link_struct(LOG_WARNING, link, - "MESSAGE=%-*s: could not drop address: %s", + log_link_warning_errno(link, -r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname); + + return 1; +} + +static int link_set_bridge_fdb(const Link *const link) { + FdbEntry *fdb_entry; + int r = 0; + + LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) { + r = fdb_entry_configure(link->manager->rtnl, fdb_entry, link->ifindex); + if(r < 0) { + log_link_error(link, "Failed to add MAC entry to static MAC table: %s", strerror(-r)); + break; + } + } + + return r; +} + +static int link_set_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + _cleanup_link_unref_ Link *link = userdata; + int r; + + log_link_debug(link, "set link"); + + r = sd_rtnl_message_get_errno(m); + if (r < 0 && r != -EEXIST) { + log_link_struct(link, LOG_ERR, + "MESSAGE=%-*s: could not join netdev: %s", IFNAMSIZ, link->ifname, strerror(-r), "ERRNO=%d", -r, NULL); + link_enter_failed(link); + return 1; + } - return 1; + return 0; } static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, @@ -780,11 +800,7 @@ static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { r = sd_rtnl_message_get_errno(m); if (r < 0) - log_link_struct(LOG_WARNING, link, - "MESSAGE=%-*s: could not set MTU: %s", - IFNAMSIZ, link->ifname, strerror(-r), - "ERRNO=%d", -r, - NULL); + log_link_warning_errno(link, -r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname); return 1; } @@ -826,104 +842,84 @@ int link_set_mtu(Link *link, uint32_t mtu) { return 0; } -static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { - Link *link = userdata; - - assert(link); - assert(link->network); - assert(link->manager); - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return; - - switch(event) { - case DHCP6_EVENT_STOP: - case DHCP6_EVENT_RESEND_EXPIRE: - case DHCP6_EVENT_RETRANS_MAX: - case DHCP6_EVENT_IP_ACQUIRE: - log_link_debug(link, "DHCPv6 event %d", event); - - break; - - default: - if (event < 0) - log_link_warning(link, "DHCPv6 error: %s", - strerror(-event)); - else - log_link_warning(link, "DHCPv6 unknown event: %d", - event); - return; - } -} - -static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) { - Link *link = userdata; +static int link_set_bridge(Link *link) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; int r; assert(link); assert(link->network); - assert(link->manager); - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return; - - switch(event) { - case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE: - case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER: - return; - case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT: - case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED: - break; - - default: - if (event < 0) - log_link_warning(link, "ICMPv6 error: %s", - strerror(-event)); - else - log_link_warning(link, "ICMPv6 unknown event: %d", - event); + if(link->network->cost == 0) + return 0; - return; + r = sd_rtnl_message_new_link(link->manager->rtnl, &req, + RTM_SETLINK, link->ifindex); + if (r < 0) { + log_link_error(link, "Could not allocate RTM_SETLINK message"); + return r; } - if (link->dhcp6_client) - return; - - r = sd_dhcp6_client_new(&link->dhcp6_client); - if (r < 0) - return; - - r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0); + r = sd_rtnl_message_link_set_family(req, PF_BRIDGE); if (r < 0) { - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); - return; + log_link_error(link, + "Could not set message family %s", strerror(-r)); + return r; } - r = sd_dhcp6_client_set_mac(link->dhcp6_client, - (const uint8_t *) &link->mac, - sizeof (link->mac), ARPHRD_ETHER); + r = sd_rtnl_message_open_container(req, IFLA_PROTINFO); if (r < 0) { - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); - return; + log_link_error(link, + "Could not append IFLA_PROTINFO attribute: %s", + strerror(-r)); + return r; + } + + if(link->network->cost != 0) { + r = sd_rtnl_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost); + if (r < 0) { + log_link_error(link, + "Could not append IFLA_BRPORT_COST attribute: %s", + strerror(-r)); + return r; + } } - r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex); + r = sd_rtnl_message_close_container(req); if (r < 0) { - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); - return; + log_link_error(link, + "Could not append IFLA_LINKINFO attribute: %s", + strerror(-r)); + return r; } - r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler, - link); + r = sd_rtnl_call_async(link->manager->rtnl, req, link_set_handler, link, 0, NULL); if (r < 0) { - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); - return; + log_link_error(link, + "Could not send rtnetlink message: %s", + strerror(-r)); + return r; } - r = sd_dhcp6_client_start(link->dhcp6_client); + link_ref(link); + + return r; +} + +static void lldp_handler(sd_lldp *lldp, int event, void *userdata) { + Link *link = userdata; + int r; + + assert(link); + assert(link->network); + assert(link->manager); + + if (event != UPDATE_INFO) + return; + + r = sd_lldp_save(link->lldp, link->lldp_file); if (r < 0) - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); + log_link_warning(link, "could not save LLDP"); + } static int link_acquire_conf(Link *link) { @@ -973,6 +969,18 @@ static int link_acquire_conf(Link *link) { } } + if (link_lldp_enabled(link)) { + assert(link->lldp); + + log_link_debug(link, "Starting LLDP"); + + r = sd_lldp_start(link->lldp); + if (r < 0) { + log_link_warning(link, "could not start LLDP "); + return r; + } + } + return 0; } @@ -1003,12 +1011,7 @@ static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { if (r < 0) { /* we warn but don't fail the link, as it may be brought up later */ - log_link_struct(LOG_WARNING, link, - "MESSAGE=%-*s: could not bring up interface: %s", - IFNAMSIZ, - link->ifname, strerror(-r), - "ERRNO=%d", -r, - NULL); + log_link_warning_errno(link, -r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname); } return 1; @@ -1019,6 +1022,7 @@ static int link_up(Link *link) { int r; assert(link); + assert(link->network); assert(link->manager); assert(link->manager->rtnl); @@ -1038,6 +1042,22 @@ static int link_up(Link *link) { return r; } + if (link->network->mac) { + r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac); + if (r < 0) { + log_link_error(link, "Could not set MAC address: %s", strerror(-r)); + return r; + } + } + + if (link->network->mtu) { + r = sd_rtnl_message_append_u32(req, IFLA_MTU, link->network->mtu); + if (r < 0) { + log_link_error(link, "Could not set MTU: %s", strerror(-r)); + return r; + } + } + r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL); if (r < 0) { @@ -1066,6 +1086,15 @@ static int link_joined(Link *link) { } } + if(link->network->bridge) { + r = link_set_bridge(link); + if (r < 0) { + log_link_error(link, + "Could not set bridge message: %s", + strerror(-r)); + } + } + return link_enter_set_addresses(link); } @@ -1084,12 +1113,7 @@ static int netdev_join_handler(sd_rtnl *rtnl, sd_rtnl_message *m, r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_struct(LOG_ERR, link, - "MESSAGE=%-*s: could not join netdev: %s", - IFNAMSIZ, - link->ifname, strerror(-r), - "ERRNO=%d", -r, - NULL); + log_link_error_errno(link, -r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname); link_enter_failed(link); return 1; } else @@ -1120,7 +1144,7 @@ static int link_enter_join_netdev(Link *link) { return link_joined(link); if (link->network->bond) { - log_link_struct(LOG_DEBUG, link, + log_link_struct(link, LOG_DEBUG, "MESSAGE=%-*s: enslaving by '%s'", IFNAMSIZ, link->ifname, link->network->bond->ifname, @@ -1129,7 +1153,7 @@ static int link_enter_join_netdev(Link *link) { r = netdev_join(link->network->bond, link, &netdev_join_handler); if (r < 0) { - log_link_struct(LOG_WARNING, link, + log_link_struct(link, LOG_WARNING, "MESSAGE=%-*s: could not join netdev '%s': %s", IFNAMSIZ, link->ifname, link->network->bond->ifname, @@ -1144,7 +1168,7 @@ static int link_enter_join_netdev(Link *link) { } if (link->network->bridge) { - log_link_struct(LOG_DEBUG, link, + log_link_struct(link, LOG_DEBUG, "MESSAGE=%-*s: enslaving by '%s'", IFNAMSIZ, link->ifname, link->network->bridge->ifname, @@ -1154,7 +1178,7 @@ static int link_enter_join_netdev(Link *link) { r = netdev_join(link->network->bridge, link, &netdev_join_handler); if (r < 0) { - log_link_struct(LOG_WARNING, link, + log_link_struct(link, LOG_WARNING, "MESSAGE=%-*s: could not join netdev '%s': %s", IFNAMSIZ, link->ifname, link->network->bridge->ifname, @@ -1169,7 +1193,7 @@ static int link_enter_join_netdev(Link *link) { } HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) { - log_link_struct(LOG_DEBUG, link, + log_link_struct(link, LOG_DEBUG, "MESSAGE=%-*s: enslaving by '%s'", IFNAMSIZ, link->ifname, netdev->ifname, NETDEVIF(netdev), @@ -1177,7 +1201,7 @@ static int link_enter_join_netdev(Link *link) { r = netdev_join(netdev, link, &netdev_join_handler); if (r < 0) { - log_link_struct(LOG_WARNING, link, + log_link_struct(link, LOG_WARNING, "MESSAGE=%-*s: could not join netdev '%s': %s", IFNAMSIZ, link->ifname, netdev->ifname, @@ -1200,6 +1224,10 @@ static int link_configure(Link *link) { assert(link->network); assert(link->state == LINK_STATE_PENDING); + r = link_set_bridge_fdb(link); + if (r < 0) + return r; + if (link_ipv4ll_enabled(link)) { r = ipv4ll_configure(link); if (r < 0) @@ -1223,27 +1251,22 @@ static int link_configure(Link *link) { } if (link_dhcp6_enabled(link)) { - r = sd_icmp6_nd_new(&link->icmp6_router_discovery); - if (r < 0) - return r; - - r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery, - NULL, 0); + r = icmp6_configure(link); if (r < 0) return r; + } - r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery, - &link->mac); + if (link_lldp_enabled(link)) { + r = sd_lldp_new(link->ifindex, link->ifname, &link->mac, &link->lldp); if (r < 0) return r; - r = sd_icmp6_nd_set_index(link->icmp6_router_discovery, - link->ifindex); + r = sd_lldp_attach_event(link->lldp, NULL, 0); if (r < 0) return r; - r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery, - icmp6_router_handler, link); + r = sd_lldp_set_callback(link->lldp, + lldp_handler, link); if (r < 0) return r; } @@ -1341,8 +1364,7 @@ int link_initialized(Link *link, struct udev_device *device) { return 0; } -int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, - void *userdata) { +int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) { Manager *m = userdata; Link *link = NULL; uint16_t type; @@ -1358,6 +1380,14 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, assert(message); assert(m); + if (sd_rtnl_message_is_error(message)) { + r = sd_rtnl_message_get_errno(message); + if (r < 0) + log_warning_errno(r, "rtnl: failed to receive address: %m"); + + return 0; + } + r = sd_rtnl_message_get_type(message, &type); if (r < 0) { log_warning("rtnl: could not get message type"); @@ -1365,13 +1395,16 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, } r = sd_rtnl_message_addr_get_ifindex(message, &ifindex); - if (r < 0 || ifindex <= 0) { - log_warning("rtnl: received address message without valid ifindex, ignoring"); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get ifindex: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received address message with invalid ifindex: %d", ifindex); return 0; } else { r = link_get(m, ifindex, &link); if (r < 0 || !link) { - log_warning("rtnl: received address for a nonexistent link (%d), ignoring", ifindex); + log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex); return 0; } } @@ -1500,7 +1533,6 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, int link_add(Manager *m, sd_rtnl_message *message, Link **ret) { Link *link; - _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; _cleanup_udev_device_unref_ struct udev_device *device = NULL; char ifindex_str[2 + DECIMAL_STR_MAX(int)]; int r; @@ -1518,18 +1550,6 @@ int link_add(Manager *m, sd_rtnl_message *message, Link **ret) { log_link_debug(link, "link %d added", link->ifindex); - r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, link->ifindex, - 0); - if (r < 0) - return r; - - r = sd_rtnl_call_async(m->rtnl, req, link_get_address_handler, link, 0, - NULL); - if (r < 0) - return r; - - link_ref(link); - if (detect_container(NULL) <= 0) { /* not in a container, udev will be around */ sprintf(ifindex_str, "n%d", link->ifindex); @@ -1867,6 +1887,19 @@ int link_save(Link *link) { } else unlink(link->lease_file); + if (link->lldp) { + assert(link->network); + + r = sd_lldp_save(link->lldp, link->lldp_file); + if (r < 0) + goto fail; + + fprintf(f, + "LLDP_FILE=%s\n", + link->lldp_file); + } else + unlink(link->lldp_file); + r = fflush_and_check(f); if (r < 0) goto fail;