chiark / gitweb /
networkd: integrate LLDP
[elogind.git] / src / network / networkd-link.c
index 7cffcb48d06aea87804f9ed9b344d4bb99b5fd38..725e22b93f69bda768e7c28fe6e164cafe55b6c7 100644 (file)
@@ -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)) \
@@ -364,6 +377,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;
 }
 
@@ -576,32 +599,6 @@ int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         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));
-        }
-
-        return 1;
-}
-
 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
@@ -622,11 +619,8 @@ 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_warning_errno(link, -r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname);
-        else if (r >= 0) {
-                /* calling handler directly so take a ref */
-                link_ref(link);
-                link_get_address_handler(rtnl, m, link);
-        }
+        else if (r >= 0)
+                link_rtnl_process_address(rtnl, m, link->manager);
 
         if (link->link_messages == 0) {
                 log_link_debug(link, "addresses set");
@@ -685,6 +679,21 @@ int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
         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;
@@ -886,106 +895,6 @@ static int link_set_bridge(Link *link) {
         return r;
 }
 
-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;
-        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);
-
-                return;
-        }
-
-        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);
-        if (r < 0) {
-                link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
-                return;
-        }
-
-        r = sd_dhcp6_client_set_mac(link->dhcp6_client,
-                                    (const uint8_t *) &link->mac,
-                                    sizeof (link->mac), ARPHRD_ETHER);
-        if (r < 0) {
-                link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
-                return;
-        }
-
-        r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
-        if (r < 0) {
-                link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
-                return;
-        }
-
-        r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
-                                         link);
-        if (r < 0) {
-                link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
-                return;
-        }
-
-        r = sd_dhcp6_client_start(link->dhcp6_client);
-        if (r < 0)
-                link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
-}
-
 static int link_acquire_conf(Link *link) {
         int r;
 
@@ -1033,6 +942,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;
 }
 
@@ -1074,6 +995,7 @@ static int link_up(Link *link) {
         int r;
 
         assert(link);
+        assert(link->network);
         assert(link->manager);
         assert(link->manager->rtnl);
 
@@ -1093,6 +1015,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) {
@@ -1259,6 +1197,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)
@@ -1282,27 +1224,17 @@ 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);
-                if (r < 0)
-                        return r;
-
-                r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery,
-                                        &link->mac);
+                r = icmp6_configure(link);
                 if (r < 0)
                         return r;
+        }
 
-                r = sd_icmp6_nd_set_index(link->icmp6_router_discovery,
-                                          link->ifindex);
+        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_callback(link->icmp6_router_discovery,
-                                             icmp6_router_handler, link);
+                r = sd_lldp_attach_event(link->lldp, NULL, 0);
                 if (r < 0)
                         return r;
         }
@@ -1400,8 +1332,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;
@@ -1417,6 +1348,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");
@@ -1424,13 +1363,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 nonexistent link (%d), ignoring", ifindex);
+                        log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
                         return 0;
                 }
         }
@@ -1559,7 +1501,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;
@@ -1577,18 +1518,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);