2013-10-17 03:18:36 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2013 Tom Gundersen <teg@jklm.no>
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
|
|
|
#include <netinet/ether.h>
|
|
|
|
#include <linux/if.h>
|
2014-07-01 20:58:49 +02:00
|
|
|
#include <unistd.h>
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2014-01-13 23:48:28 +01:00
|
|
|
#include "bus-util.h"
|
2015-08-26 20:48:21 +02:00
|
|
|
#include "dhcp-lease-internal.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "fileio.h"
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
#include "lldp.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "netlink-util.h"
|
2014-03-21 21:38:14 +01:00
|
|
|
#include "network-internal.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "networkd-link.h"
|
|
|
|
#include "networkd-netdev.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "set.h"
|
|
|
|
#include "socket-util.h"
|
2015-10-27 01:26:31 +01:00
|
|
|
#include "stdio-util.h"
|
2015-10-26 22:31:05 +01:00
|
|
|
#include "string-table.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "udev-util.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "virt.h"
|
2015-08-27 13:59:06 +02:00
|
|
|
|
2015-02-04 15:00:20 +01:00
|
|
|
bool link_dhcp6_enabled(Link *link) {
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->dhcp & ADDRESS_FAMILY_IPV6;
|
2014-09-04 20:54:08 +02:00
|
|
|
}
|
|
|
|
|
2015-02-04 15:00:20 +01:00
|
|
|
bool link_dhcp4_enabled(Link *link) {
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->dhcp & ADDRESS_FAMILY_IPV4;
|
2014-09-04 20:54:08 +02:00
|
|
|
}
|
|
|
|
|
2015-02-04 15:00:20 +01:00
|
|
|
bool link_dhcp4_server_enabled(Link *link) {
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return link->network->dhcp_server;
|
|
|
|
}
|
|
|
|
|
2015-02-04 15:00:20 +01:00
|
|
|
bool link_ipv4ll_enabled(Link *link) {
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->link_local & ADDRESS_FAMILY_IPV4;
|
2015-02-08 22:27:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool link_ipv6ll_enabled(Link *link) {
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->link_local & ADDRESS_FAMILY_IPV6;
|
2014-09-04 20:54:08 +02:00
|
|
|
}
|
|
|
|
|
2015-02-04 15:00:20 +01:00
|
|
|
bool link_lldp_enabled(Link *link) {
|
2016-02-18 22:49:02 +01:00
|
|
|
assert(link);
|
|
|
|
|
2014-11-23 05:26:14 +01:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
2016-02-18 22:49:02 +01:00
|
|
|
if (link->iftype != ARPHRD_ETHER)
|
|
|
|
return false;
|
|
|
|
|
2014-11-23 05:26:14 +01:00
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2015-01-13 13:47:08 +01:00
|
|
|
if (link->network->bridge)
|
2014-11-23 05:26:14 +01:00
|
|
|
return false;
|
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
return link->network->lldp_mode != LLDP_MODE_NO;
|
2014-11-23 05:26:14 +01:00
|
|
|
}
|
|
|
|
|
2015-01-13 20:07:13 +01:00
|
|
|
static bool link_ipv4_forward_enabled(Link *link) {
|
2015-01-13 13:47:08 +01:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
|
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->ip_forward & ADDRESS_FAMILY_IPV4;
|
2015-01-13 20:07:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool link_ipv6_forward_enabled(Link *link) {
|
2015-11-13 12:49:15 +01:00
|
|
|
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return false;
|
|
|
|
|
2015-01-13 20:07:13 +01:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
|
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
|
2015-01-13 13:47:08 +01:00
|
|
|
}
|
|
|
|
|
networkd: IPv6 router discovery - follow IPv6AcceptRouterAdvertisemnt=
The previous behavior:
When DHCPv6 was enabled, router discover was performed first, and then DHCPv6 was
enabled only if the relevant flags were passed in the Router Advertisement message.
Moreover, router discovery was performed even if AcceptRouterAdvertisements=false,
moreover, even if router advertisements were accepted (by the kernel) the flags
indicating that DHCPv6 should be performed were ignored.
New behavior:
If RouterAdvertisements are accepted, and either no routers are found, or an
advertisement is received indicating DHCPv6 should be performed, the DHCPv6
client is started. Moreover, the DHCP option now truly enables the DHCPv6
client regardless of router discovery (though it will probably not be
very useful to get a lease withotu any routes, this seems the more consistent
approach).
The recommended default setting should be to set DHCP=ipv4 and to leave
IPv6AcceptRouterAdvertisements unset.
2015-10-18 18:25:58 +02:00
|
|
|
bool link_ipv6_accept_ra_enabled(Link *link) {
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* If unset use system default (enabled if local forwarding is disabled.
|
|
|
|
* disabled if local forwarding is enabled).
|
|
|
|
* If set, ignore or enforce RA independent of local forwarding state.
|
|
|
|
*/
|
|
|
|
if (link->network->ipv6_accept_ra < 0)
|
|
|
|
/* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
|
|
|
|
return !link_ipv6_forward_enabled(link);
|
|
|
|
else if (link->network->ipv6_accept_ra > 0)
|
|
|
|
/* accept RA even if ip_forward is enabled */
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
/* ignore RA */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-06 20:29:33 +02:00
|
|
|
static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
|
2015-11-13 12:32:38 +01:00
|
|
|
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return _IPV6_PRIVACY_EXTENSIONS_INVALID;
|
|
|
|
|
2015-07-05 07:54:31 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
2015-07-06 20:29:33 +02:00
|
|
|
return _IPV6_PRIVACY_EXTENSIONS_INVALID;
|
2015-07-05 07:54:31 +02:00
|
|
|
|
|
|
|
if (!link->network)
|
2015-07-06 20:29:33 +02:00
|
|
|
return _IPV6_PRIVACY_EXTENSIONS_INVALID;
|
2015-07-05 07:54:31 +02:00
|
|
|
|
|
|
|
return link->network->ipv6_privacy_extensions;
|
|
|
|
}
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
void link_update_operstate(Link *link) {
|
|
|
|
LinkOperationalState operstate;
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (link->kernel_operstate == IF_OPER_DORMANT)
|
|
|
|
operstate = LINK_OPERSTATE_DORMANT;
|
|
|
|
else if (link_has_carrier(link)) {
|
|
|
|
Address *address;
|
|
|
|
uint8_t scope = RT_SCOPE_NOWHERE;
|
|
|
|
Iterator i;
|
|
|
|
|
|
|
|
/* if we have carrier, check what addresses we have */
|
|
|
|
SET_FOREACH(address, link->addresses, i) {
|
|
|
|
if (!address_is_ready(address))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (address->scope < scope)
|
|
|
|
scope = address->scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for operstate we also take foreign addresses into account */
|
|
|
|
SET_FOREACH(address, link->addresses_foreign, i) {
|
|
|
|
if (!address_is_ready(address))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (address->scope < scope)
|
|
|
|
scope = address->scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scope < RT_SCOPE_SITE)
|
|
|
|
/* universally accessible addresses found */
|
|
|
|
operstate = LINK_OPERSTATE_ROUTABLE;
|
|
|
|
else if (scope < RT_SCOPE_HOST)
|
|
|
|
/* only link or site local addresses found */
|
|
|
|
operstate = LINK_OPERSTATE_DEGRADED;
|
|
|
|
else
|
|
|
|
/* no useful addresses found */
|
|
|
|
operstate = LINK_OPERSTATE_CARRIER;
|
|
|
|
} else if (link->flags & IFF_UP)
|
|
|
|
operstate = LINK_OPERSTATE_NO_CARRIER;
|
|
|
|
else
|
|
|
|
operstate = LINK_OPERSTATE_OFF;
|
|
|
|
|
|
|
|
if (link->operstate != operstate) {
|
|
|
|
link->operstate = operstate;
|
|
|
|
link_send_changed(link, "OperationalState", NULL);
|
|
|
|
link_dirty(link);
|
|
|
|
manager_dirty(link->manager);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-04 14:10:43 +02:00
|
|
|
#define FLAG_STRING(string, flag, old, new) \
|
|
|
|
(((old ^ new) & flag) \
|
|
|
|
? ((old & flag) ? (" -" string) : (" +" string)) \
|
|
|
|
: "")
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int link_update_flags(Link *link, sd_netlink_message *m) {
|
2014-09-04 14:10:43 +02:00
|
|
|
unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags;
|
|
|
|
uint8_t operstate;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_link_get_flags(m, &flags);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not get link flags: %m");
|
2014-09-04 14:10:43 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_u8(m, IFLA_OPERSTATE, &operstate);
|
2014-09-04 14:10:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
/* if we got a message without operstate, take it to mean
|
|
|
|
the state was unchanged */
|
|
|
|
operstate = link->kernel_operstate;
|
|
|
|
|
|
|
|
if ((link->flags == flags) && (link->kernel_operstate == operstate))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags != flags) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
2014-09-04 14:10:43 +02:00
|
|
|
FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags),
|
|
|
|
FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags),
|
|
|
|
FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags),
|
|
|
|
FLAG_STRING("UP", IFF_UP, link->flags, flags),
|
|
|
|
FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags),
|
|
|
|
FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags),
|
|
|
|
FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags),
|
|
|
|
FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags),
|
|
|
|
FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags),
|
|
|
|
FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags),
|
|
|
|
FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags),
|
|
|
|
FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags),
|
|
|
|
FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags),
|
|
|
|
FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags),
|
|
|
|
FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags),
|
|
|
|
FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags),
|
|
|
|
FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags),
|
|
|
|
FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags),
|
|
|
|
FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags));
|
|
|
|
|
|
|
|
unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP |
|
|
|
|
IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING |
|
|
|
|
IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT |
|
|
|
|
IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL |
|
|
|
|
IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP |
|
|
|
|
IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO);
|
|
|
|
unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags);
|
|
|
|
unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags);
|
|
|
|
|
|
|
|
/* link flags are currently at most 18 bits, let's align to
|
|
|
|
* printing 20 */
|
|
|
|
if (unknown_flags_added)
|
2014-11-27 20:20:23 +01:00
|
|
|
log_link_debug(link,
|
2015-04-21 17:40:18 +02:00
|
|
|
"Unknown link flags gained: %#.5x (ignoring)",
|
2014-09-04 14:10:43 +02:00
|
|
|
unknown_flags_added);
|
|
|
|
|
|
|
|
if (unknown_flags_removed)
|
2014-11-27 20:20:23 +01:00
|
|
|
log_link_debug(link,
|
2015-04-21 17:40:18 +02:00
|
|
|
"Unknown link flags lost: %#.5x (ignoring)",
|
2014-09-04 14:10:43 +02:00
|
|
|
unknown_flags_removed);
|
|
|
|
}
|
|
|
|
|
|
|
|
link->flags = flags;
|
|
|
|
link->kernel_operstate = operstate;
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_update_operstate(link);
|
2014-09-04 14:10:43 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
2014-05-08 18:54:26 +02:00
|
|
|
_cleanup_link_unref_ Link *link = NULL;
|
2014-04-15 14:21:44 +02:00
|
|
|
uint16_t type;
|
2014-07-18 02:35:16 +02:00
|
|
|
const char *ifname;
|
2014-04-15 14:21:44 +02:00
|
|
|
int r, ifindex;
|
2016-02-18 22:49:02 +01:00
|
|
|
unsigned short iftype;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2014-02-22 20:19:49 +01:00
|
|
|
assert(manager);
|
2014-04-15 14:21:44 +02:00
|
|
|
assert(message);
|
2013-10-17 03:18:36 +02:00
|
|
|
assert(ret);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
else if (type != RTM_NEWLINK)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
else if (ifindex <= 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-02-18 22:49:02 +01:00
|
|
|
r = sd_rtnl_message_link_get_type(message, &iftype);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2013-10-17 03:18:36 +02:00
|
|
|
link = new0(Link, 1);
|
|
|
|
if (!link)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2014-05-08 18:54:26 +02:00
|
|
|
link->n_ref = 1;
|
2013-11-21 21:04:04 +01:00
|
|
|
link->manager = manager;
|
2014-08-13 15:34:27 +02:00
|
|
|
link->state = LINK_STATE_PENDING;
|
2015-04-10 13:03:18 +02:00
|
|
|
link->rtnl_extended_attrs = true;
|
2014-04-15 14:21:44 +02:00
|
|
|
link->ifindex = ifindex;
|
2016-02-18 22:49:02 +01:00
|
|
|
link->iftype = iftype;
|
2014-04-15 14:21:44 +02:00
|
|
|
link->ifname = strdup(ifname);
|
|
|
|
if (!link->ifname)
|
|
|
|
return -ENOMEM;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
|
2014-06-04 21:29:08 +02:00
|
|
|
if (r < 0)
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
|
2014-06-04 21:29:08 +02:00
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0)
|
2014-03-14 14:05:56 +01:00
|
|
|
return -ENOMEM;
|
2014-02-27 01:24:05 +01:00
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0)
|
2014-05-08 18:53:32 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0)
|
2014-12-11 05:29:55 +01:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2014-08-13 01:00:18 +02:00
|
|
|
r = hashmap_ensure_allocated(&manager->links, NULL);
|
2014-07-28 11:39:37 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = hashmap_put(manager->links, INT_TO_PTR(link->ifindex), link);
|
2013-10-17 03:18:36 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2014-09-04 14:10:43 +02:00
|
|
|
r = link_update_flags(link, message);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2013-10-17 03:18:36 +02:00
|
|
|
*ret = link;
|
|
|
|
link = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-05-08 18:54:26 +02:00
|
|
|
static void link_free(Link *link) {
|
2014-05-16 00:28:22 +02:00
|
|
|
Address *address;
|
2015-02-17 13:06:57 +01:00
|
|
|
Iterator i;
|
|
|
|
Link *carrier;
|
2014-05-16 00:28:22 +02:00
|
|
|
|
2013-10-17 03:18:36 +02:00
|
|
|
if (!link)
|
|
|
|
return;
|
|
|
|
|
2015-09-23 01:53:29 +02:00
|
|
|
while (!set_isempty(link->addresses))
|
|
|
|
address_free(set_first(link->addresses));
|
|
|
|
|
2015-09-30 14:01:44 +02:00
|
|
|
while (!set_isempty(link->addresses_foreign))
|
|
|
|
address_free(set_first(link->addresses_foreign));
|
|
|
|
|
2015-10-29 11:14:44 +01:00
|
|
|
link->addresses = set_free(link->addresses);
|
|
|
|
|
|
|
|
link->addresses_foreign = set_free(link->addresses_foreign);
|
2015-09-30 14:01:44 +02:00
|
|
|
|
2014-06-18 18:22:14 +02:00
|
|
|
while ((address = link->pool_addresses)) {
|
|
|
|
LIST_REMOVE(addresses, link->pool_addresses, address);
|
|
|
|
address_free(address);
|
|
|
|
}
|
|
|
|
|
2014-12-19 08:34:04 +01:00
|
|
|
sd_dhcp_server_unref(link->dhcp_server);
|
2014-04-09 12:12:07 +02:00
|
|
|
sd_dhcp_client_unref(link->dhcp_client);
|
2014-02-04 23:13:52 +01:00
|
|
|
sd_dhcp_lease_unref(link->dhcp_lease);
|
2014-01-01 15:16:34 +01:00
|
|
|
|
2014-05-08 18:53:32 +02:00
|
|
|
free(link->lease_file);
|
|
|
|
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
sd_lldp_unref(link->lldp);
|
2014-12-11 05:29:55 +01:00
|
|
|
free(link->lldp_file);
|
|
|
|
|
2014-04-09 12:12:09 +02:00
|
|
|
sd_ipv4ll_unref(link->ipv4ll);
|
2014-06-19 14:40:01 +02:00
|
|
|
sd_dhcp6_client_unref(link->dhcp6_client);
|
2015-10-16 17:34:58 +02:00
|
|
|
sd_ndisc_unref(link->ndisc_router_discovery);
|
2014-06-19 14:40:01 +02:00
|
|
|
|
2014-07-01 10:28:36 +02:00
|
|
|
if (link->manager)
|
2014-07-28 11:39:37 +02:00
|
|
|
hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2013-11-24 23:36:58 +01:00
|
|
|
free(link->ifname);
|
2014-05-08 18:53:32 +02:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
(void)unlink(link->state_file);
|
2014-02-27 01:24:05 +01:00
|
|
|
free(link->state_file);
|
2013-11-24 23:36:58 +01:00
|
|
|
|
2014-03-21 19:23:35 +01:00
|
|
|
udev_device_unref(link->udev_device);
|
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
HASHMAP_FOREACH (carrier, link->bound_to_links, i)
|
|
|
|
hashmap_remove(link->bound_to_links, INT_TO_PTR(carrier->ifindex));
|
|
|
|
hashmap_free(link->bound_to_links);
|
|
|
|
|
|
|
|
HASHMAP_FOREACH (carrier, link->bound_by_links, i)
|
|
|
|
hashmap_remove(link->bound_by_links, INT_TO_PTR(carrier->ifindex));
|
|
|
|
hashmap_free(link->bound_by_links);
|
|
|
|
|
2013-10-17 03:18:36 +02:00
|
|
|
free(link);
|
|
|
|
}
|
|
|
|
|
2014-05-08 18:54:26 +02:00
|
|
|
Link *link_unref(Link *link) {
|
2015-10-09 20:47:34 +02:00
|
|
|
if (!link)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
assert(link->n_ref > 0);
|
|
|
|
|
|
|
|
link->n_ref --;
|
|
|
|
|
|
|
|
if (link->n_ref > 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
link_free(link);
|
2014-05-08 18:54:26 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Link *link_ref(Link *link) {
|
2015-10-09 20:47:34 +02:00
|
|
|
if (!link)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
assert(link->n_ref > 0);
|
|
|
|
|
|
|
|
link->n_ref ++;
|
2014-05-08 18:54:26 +02:00
|
|
|
|
|
|
|
return link;
|
|
|
|
}
|
|
|
|
|
2014-02-18 21:42:05 +01:00
|
|
|
int link_get(Manager *m, int ifindex, Link **ret) {
|
|
|
|
Link *link;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(ifindex);
|
|
|
|
assert(ret);
|
|
|
|
|
2014-07-28 11:39:37 +02:00
|
|
|
link = hashmap_get(m->links, INT_TO_PTR(ifindex));
|
2014-02-18 21:42:05 +01:00
|
|
|
if (!link)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
*ret = link;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
static void link_set_state(Link *link, LinkState state) {
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (link->state == state)
|
|
|
|
return;
|
|
|
|
|
|
|
|
link->state = state;
|
|
|
|
|
|
|
|
link_send_changed(link, "AdministrativeState", NULL);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-04-20 19:49:00 +02:00
|
|
|
static void link_enter_unmanaged(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Unmanaged");
|
2014-04-20 19:49:00 +02:00
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
link_set_state(link, LINK_STATE_UNMANAGED);
|
2014-04-20 19:49:00 +02:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2014-04-20 19:49:00 +02:00
|
|
|
}
|
|
|
|
|
2014-04-22 19:25:31 +02:00
|
|
|
static int link_stop_clients(Link *link) {
|
|
|
|
int r = 0, k;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->event);
|
|
|
|
|
2014-07-25 01:13:47 +02:00
|
|
|
if (link->dhcp_client) {
|
2014-04-22 19:25:31 +02:00
|
|
|
k = sd_dhcp_client_stop(link->dhcp_client);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (k < 0)
|
2016-02-18 22:49:48 +01:00
|
|
|
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
|
2014-04-22 19:25:31 +02:00
|
|
|
}
|
|
|
|
|
2014-07-25 01:13:47 +02:00
|
|
|
if (link->ipv4ll) {
|
2014-04-22 19:25:31 +02:00
|
|
|
k = sd_ipv4ll_stop(link->ipv4ll);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (k < 0)
|
2016-02-18 22:49:48 +01:00
|
|
|
r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m");
|
2014-03-05 08:13:30 +01:00
|
|
|
}
|
|
|
|
|
networkd: IPv6 router discovery - follow IPv6AcceptRouterAdvertisemnt=
The previous behavior:
When DHCPv6 was enabled, router discover was performed first, and then DHCPv6 was
enabled only if the relevant flags were passed in the Router Advertisement message.
Moreover, router discovery was performed even if AcceptRouterAdvertisements=false,
moreover, even if router advertisements were accepted (by the kernel) the flags
indicating that DHCPv6 should be performed were ignored.
New behavior:
If RouterAdvertisements are accepted, and either no routers are found, or an
advertisement is received indicating DHCPv6 should be performed, the DHCPv6
client is started. Moreover, the DHCP option now truly enables the DHCPv6
client regardless of router discovery (though it will probably not be
very useful to get a lease withotu any routes, this seems the more consistent
approach).
The recommended default setting should be to set DHCP=ipv4 and to leave
IPv6AcceptRouterAdvertisements unset.
2015-10-18 18:25:58 +02:00
|
|
|
if (link->dhcp6_client) {
|
|
|
|
k = sd_dhcp6_client_stop(link->dhcp6_client);
|
|
|
|
if (k < 0)
|
2016-02-18 22:49:48 +01:00
|
|
|
r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
|
networkd: IPv6 router discovery - follow IPv6AcceptRouterAdvertisemnt=
The previous behavior:
When DHCPv6 was enabled, router discover was performed first, and then DHCPv6 was
enabled only if the relevant flags were passed in the Router Advertisement message.
Moreover, router discovery was performed even if AcceptRouterAdvertisements=false,
moreover, even if router advertisements were accepted (by the kernel) the flags
indicating that DHCPv6 should be performed were ignored.
New behavior:
If RouterAdvertisements are accepted, and either no routers are found, or an
advertisement is received indicating DHCPv6 should be performed, the DHCPv6
client is started. Moreover, the DHCP option now truly enables the DHCPv6
client regardless of router discovery (though it will probably not be
very useful to get a lease withotu any routes, this seems the more consistent
approach).
The recommended default setting should be to set DHCP=ipv4 and to leave
IPv6AcceptRouterAdvertisements unset.
2015-10-18 18:25:58 +02:00
|
|
|
}
|
2014-06-19 14:40:01 +02:00
|
|
|
|
networkd: IPv6 router discovery - follow IPv6AcceptRouterAdvertisemnt=
The previous behavior:
When DHCPv6 was enabled, router discover was performed first, and then DHCPv6 was
enabled only if the relevant flags were passed in the Router Advertisement message.
Moreover, router discovery was performed even if AcceptRouterAdvertisements=false,
moreover, even if router advertisements were accepted (by the kernel) the flags
indicating that DHCPv6 should be performed were ignored.
New behavior:
If RouterAdvertisements are accepted, and either no routers are found, or an
advertisement is received indicating DHCPv6 should be performed, the DHCPv6
client is started. Moreover, the DHCP option now truly enables the DHCPv6
client regardless of router discovery (though it will probably not be
very useful to get a lease withotu any routes, this seems the more consistent
approach).
The recommended default setting should be to set DHCP=ipv4 and to leave
IPv6AcceptRouterAdvertisements unset.
2015-10-18 18:25:58 +02:00
|
|
|
if (link->ndisc_router_discovery) {
|
2015-10-16 17:34:58 +02:00
|
|
|
k = sd_ndisc_stop(link->ndisc_router_discovery);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (k < 0)
|
2016-02-18 22:49:48 +01:00
|
|
|
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
|
2014-06-19 14:40:01 +02:00
|
|
|
}
|
|
|
|
|
2014-04-22 19:25:31 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-08-06 15:54:03 +02:00
|
|
|
void link_enter_failed(Link *link) {
|
2013-12-14 19:09:04 +01:00
|
|
|
assert(link);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-05-08 20:50:05 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2014-04-22 19:26:04 +02:00
|
|
|
return;
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_warning(link, "Failed");
|
2014-01-02 15:30:46 +01:00
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
link_set_state(link, LINK_STATE_FAILED);
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2014-04-22 19:25:31 +02:00
|
|
|
link_stop_clients(link);
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2013-11-14 16:22:51 +01:00
|
|
|
}
|
|
|
|
|
2014-06-18 18:26:03 +02:00
|
|
|
static Address* link_find_dhcp_server_address(Link *link) {
|
|
|
|
Address *address;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
|
2015-01-30 19:54:01 +01:00
|
|
|
/* The first statically configured address if there is any */
|
2014-06-18 18:26:03 +02:00
|
|
|
LIST_FOREACH(addresses, address, link->network->static_addresses) {
|
|
|
|
|
|
|
|
if (address->family != AF_INET)
|
|
|
|
continue;
|
|
|
|
|
2014-07-30 00:48:59 +02:00
|
|
|
if (in_addr_is_null(address->family, &address->in_addr))
|
2014-06-18 18:26:03 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
return address;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If that didn't work, find a suitable address we got from the pool */
|
|
|
|
LIST_FOREACH(addresses, address, link->pool_addresses) {
|
|
|
|
if (address->family != AF_INET)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return address;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-03-05 08:13:30 +01:00
|
|
|
static int link_enter_configured(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
assert(link->state == LINK_STATE_SETTING_ROUTES);
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_info(link, "Configured");
|
2014-03-05 08:13:30 +01:00
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURED);
|
2014-03-05 08:13:30 +01:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2014-03-05 08:13:30 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-28 13:38:43 +02:00
|
|
|
void link_check_ready(Link *link) {
|
|
|
|
Address *a;
|
|
|
|
Iterator i;
|
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
assert(link);
|
2015-09-30 14:01:44 +02:00
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return;
|
2014-08-08 12:12:17 +02:00
|
|
|
|
|
|
|
if (!link->static_configured)
|
|
|
|
return;
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link_ipv4ll_enabled(link))
|
2014-08-08 12:12:17 +02:00
|
|
|
if (!link->ipv4ll_address ||
|
|
|
|
!link->ipv4ll_route)
|
|
|
|
return;
|
|
|
|
|
2015-11-10 21:30:59 +01:00
|
|
|
if (link_ipv6ll_enabled(link))
|
2015-11-16 17:43:08 +01:00
|
|
|
if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0)
|
2015-11-10 21:30:59 +01:00
|
|
|
return;
|
|
|
|
|
2015-09-24 14:04:17 +02:00
|
|
|
if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
|
|
|
|
!link->dhcp4_configured) ||
|
|
|
|
(link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
|
|
|
|
!link->dhcp6_configured) ||
|
|
|
|
(link_dhcp4_enabled(link) && link_dhcp6_enabled(link) &&
|
|
|
|
!link->dhcp4_configured && !link->dhcp6_configured))
|
2015-09-23 13:52:03 +02:00
|
|
|
return;
|
|
|
|
|
2015-11-18 21:32:43 +01:00
|
|
|
if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
|
|
|
|
return;
|
|
|
|
|
2015-09-28 13:38:43 +02:00
|
|
|
SET_FOREACH(a, link->addresses, i)
|
|
|
|
if (!address_is_ready(a))
|
|
|
|
return;
|
|
|
|
|
2014-08-14 14:13:36 +02:00
|
|
|
if (link->state != LINK_STATE_CONFIGURED)
|
|
|
|
link_enter_configured(link);
|
2014-08-08 12:12:17 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
2014-07-01 10:09:52 +02:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
assert(link->link_messages > 0);
|
2014-05-08 20:50:05 +02:00
|
|
|
assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
|
|
|
|
LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
|
|
|
|
LINK_STATE_LINGER));
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
link->link_messages --;
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-08-06 15:54:25 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2013-11-14 16:22:51 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2013-11-24 23:36:58 +01:00
|
|
|
if (r < 0 && r != -EEXIST)
|
2015-09-30 19:37:52 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not set route: %m");
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
if (link->link_messages == 0) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Routes set");
|
2014-08-08 12:12:17 +02:00
|
|
|
link->static_configured = true;
|
2015-09-28 13:38:43 +02:00
|
|
|
link_check_ready(link);
|
2013-12-03 18:48:20 +01:00
|
|
|
}
|
2013-11-14 16:22:51 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_enter_set_routes(Link *link) {
|
2014-02-04 23:13:52 +01:00
|
|
|
Route *rt;
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
2013-12-14 19:09:04 +01:00
|
|
|
assert(link->state == LINK_STATE_SETTING_ADDRESSES);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
link_set_state(link, LINK_STATE_SETTING_ROUTES);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-05-15 20:10:33 +02:00
|
|
|
LIST_FOREACH(routes, rt, link->network->static_routes) {
|
2014-02-04 23:13:52 +01:00
|
|
|
r = route_configure(rt, link, &route_handler);
|
2013-12-03 18:48:20 +01:00
|
|
|
if (r < 0) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not set routes: %m");
|
2014-08-08 12:12:17 +02:00
|
|
|
link_enter_failed(link);
|
2014-02-04 23:13:52 +01:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
link->link_messages ++;
|
2014-04-29 22:40:38 +02:00
|
|
|
}
|
2014-01-01 15:16:34 +01:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
if (link->link_messages == 0) {
|
|
|
|
link->static_configured = true;
|
2015-09-28 13:38:43 +02:00
|
|
|
link_check_ready(link);
|
2014-08-06 13:48:11 +02:00
|
|
|
} else
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Setting routes");
|
2013-11-14 16:22:51 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-24 15:25:20 +02:00
|
|
|
int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
2014-07-01 10:09:52 +02:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
2014-02-28 16:10:20 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2014-02-28 16:10:20 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2014-05-09 14:23:17 +02:00
|
|
|
if (r < 0 && r != -ESRCH)
|
2015-09-30 19:37:52 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not drop route: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
2014-07-14 11:04:13 +02:00
|
|
|
return 1;
|
2014-02-28 16:10:20 +01:00
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
2014-07-01 10:09:52 +02:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
2014-07-03 22:47:51 +02:00
|
|
|
assert(rtnl);
|
2014-01-01 15:16:34 +01:00
|
|
|
assert(m);
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
2014-08-08 12:12:17 +02:00
|
|
|
assert(link->link_messages > 0);
|
2014-05-08 20:50:05 +02:00
|
|
|
assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
|
|
|
|
LINK_STATE_FAILED, LINK_STATE_LINGER));
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
link->link_messages --;
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2013-11-14 16:22:51 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2013-11-24 23:36:58 +01:00
|
|
|
if (r < 0 && r != -EEXIST)
|
2015-09-30 19:37:52 +02:00
|
|
|
log_link_warning_errno(link, r, "could not set address: %m");
|
2014-12-08 19:54:06 +01:00
|
|
|
else if (r >= 0)
|
2015-09-22 17:18:20 +02:00
|
|
|
manager_rtnl_process_address(rtnl, m, link->manager);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
if (link->link_messages == 0) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Addresses set");
|
2013-12-14 19:09:04 +01:00
|
|
|
link_enter_set_routes(link);
|
2013-12-03 18:48:20 +01:00
|
|
|
}
|
2013-11-14 16:22:51 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-08-27 16:45:24 +02:00
|
|
|
static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
|
|
|
|
_cleanup_free_ struct in_addr *addresses = NULL;
|
|
|
|
size_t n_addresses = 0, n_allocated = 0;
|
|
|
|
char **a;
|
|
|
|
|
|
|
|
log_debug("Copying DNS server information from %s", link->ifname);
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
STRV_FOREACH(a, link->network->dns) {
|
|
|
|
struct in_addr ia;
|
|
|
|
|
|
|
|
/* Only look for IPv4 addresses */
|
|
|
|
if (inet_pton(AF_INET, *a, &ia) <= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
addresses[n_addresses++] = ia;
|
|
|
|
}
|
|
|
|
|
2016-01-25 21:47:02 +01:00
|
|
|
if (link->network->dhcp_use_dns &&
|
2015-08-27 16:45:24 +02:00
|
|
|
link->dhcp_lease) {
|
|
|
|
const struct in_addr *da = NULL;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
n = sd_dhcp_lease_get_dns(link->dhcp_lease, &da);
|
|
|
|
if (n > 0) {
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n))
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
memcpy(addresses + n_addresses, da, n * sizeof(struct in_addr));
|
|
|
|
n_addresses += n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n_addresses <= 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return sd_dhcp_server_set_dns(s, addresses, n_addresses);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_push_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) {
|
|
|
|
_cleanup_free_ struct in_addr *addresses = NULL;
|
|
|
|
size_t n_addresses = 0, n_allocated = 0;
|
|
|
|
char **a;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
log_debug("Copying NTP server information from %s", link->ifname);
|
|
|
|
|
|
|
|
STRV_FOREACH(a, link->network->ntp) {
|
|
|
|
struct in_addr ia;
|
|
|
|
|
|
|
|
/* Only look for IPv4 addresses */
|
|
|
|
if (inet_pton(AF_INET, *a, &ia) <= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
addresses[n_addresses++] = ia;
|
|
|
|
}
|
|
|
|
|
2016-01-25 21:47:02 +01:00
|
|
|
if (link->network->dhcp_use_ntp &&
|
2015-08-27 16:45:24 +02:00
|
|
|
link->dhcp_lease) {
|
|
|
|
const struct in_addr *da = NULL;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
n = sd_dhcp_lease_get_ntp(link->dhcp_lease, &da);
|
|
|
|
if (n > 0) {
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n))
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
memcpy(addresses + n_addresses, da, n * sizeof(struct in_addr));
|
|
|
|
n_addresses += n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n_addresses <= 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return sd_dhcp_server_set_ntp(s, addresses, n_addresses);
|
|
|
|
}
|
|
|
|
|
2013-11-14 16:22:51 +01:00
|
|
|
static int link_enter_set_addresses(Link *link) {
|
2014-02-04 23:13:52 +01:00
|
|
|
Address *ad;
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
2014-01-01 15:16:34 +01:00
|
|
|
assert(link->state != _LINK_STATE_INVALID);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
link_set_state(link, LINK_STATE_SETTING_ADDRESSES);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-05-15 20:10:33 +02:00
|
|
|
LIST_FOREACH(addresses, ad, link->network->static_addresses) {
|
2015-10-01 17:31:14 +02:00
|
|
|
r = address_configure(ad, link, &address_handler, false);
|
2013-12-03 18:48:20 +01:00
|
|
|
if (r < 0) {
|
2015-01-13 13:47:08 +01:00
|
|
|
log_link_warning_errno(link, r, "Could not set addresses: %m");
|
2014-01-01 15:16:34 +01:00
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
link->link_messages ++;
|
2013-11-14 16:22:51 +01:00
|
|
|
}
|
|
|
|
|
2015-01-30 19:54:01 +01:00
|
|
|
/* now that we can figure out a default address for the dhcp server,
|
|
|
|
start it */
|
|
|
|
if (link_dhcp4_server_enabled(link)) {
|
|
|
|
Address *address;
|
2015-08-27 16:45:24 +02:00
|
|
|
Link *uplink = NULL;
|
|
|
|
bool acquired_uplink = false;
|
2015-01-30 19:54:01 +01:00
|
|
|
|
|
|
|
address = link_find_dhcp_server_address(link);
|
|
|
|
if (!address) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_warning(link, "Failed to find suitable address for DHCPv4 server instance.");
|
2015-01-30 19:54:01 +01:00
|
|
|
link_enter_failed(link);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-28 20:37:03 +02:00
|
|
|
/* use the server address' subnet as the pool */
|
2015-08-29 00:18:20 +02:00
|
|
|
r = sd_dhcp_server_configure_pool(link->dhcp_server, &address->in_addr.in, address->prefixlen,
|
|
|
|
link->network->dhcp_server_pool_offset, link->network->dhcp_server_pool_size);
|
2015-01-30 19:54:01 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
/* TODO:
|
|
|
|
r = sd_dhcp_server_set_router(link->dhcp_server,
|
|
|
|
&main_address->in_addr.in);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
*/
|
|
|
|
|
2015-08-27 01:47:42 +02:00
|
|
|
if (link->network->dhcp_server_max_lease_time_usec > 0) {
|
|
|
|
r = sd_dhcp_server_set_max_lease_time(
|
|
|
|
link->dhcp_server,
|
|
|
|
DIV_ROUND_UP(link->network->dhcp_server_max_lease_time_usec, USEC_PER_SEC));
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link->network->dhcp_server_default_lease_time_usec > 0) {
|
|
|
|
r = sd_dhcp_server_set_default_lease_time(
|
|
|
|
link->dhcp_server,
|
|
|
|
DIV_ROUND_UP(link->network->dhcp_server_default_lease_time_usec, USEC_PER_SEC));
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-08-27 14:48:37 +02:00
|
|
|
if (link->network->dhcp_server_emit_dns) {
|
|
|
|
|
2015-08-27 16:45:24 +02:00
|
|
|
if (link->network->n_dhcp_server_dns > 0)
|
2015-08-27 14:48:37 +02:00
|
|
|
r = sd_dhcp_server_set_dns(link->dhcp_server, link->network->dhcp_server_dns, link->network->n_dhcp_server_dns);
|
2015-08-27 16:45:24 +02:00
|
|
|
else {
|
|
|
|
uplink = manager_find_uplink(link->manager, link);
|
|
|
|
acquired_uplink = true;
|
|
|
|
|
|
|
|
if (!uplink) {
|
|
|
|
log_link_debug(link, "Not emitting DNS server information on link, couldn't find suitable uplink.");
|
|
|
|
r = 0;
|
|
|
|
} else
|
|
|
|
r = link_push_dns_to_dhcp_server(uplink, link->dhcp_server);
|
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "Failed to set DNS server for DHCP server, ignoring: %m");
|
2015-08-27 14:48:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (link->network->dhcp_server_emit_ntp) {
|
|
|
|
|
2015-08-27 16:45:24 +02:00
|
|
|
if (link->network->n_dhcp_server_ntp > 0)
|
2015-08-27 14:48:37 +02:00
|
|
|
r = sd_dhcp_server_set_ntp(link->dhcp_server, link->network->dhcp_server_ntp, link->network->n_dhcp_server_ntp);
|
2015-08-27 16:45:24 +02:00
|
|
|
else {
|
|
|
|
if (!acquired_uplink)
|
|
|
|
uplink = manager_find_uplink(link->manager, link);
|
|
|
|
|
|
|
|
if (!uplink) {
|
|
|
|
log_link_debug(link, "Not emitting NTP server information on link, couldn't find suitable uplink.");
|
|
|
|
r = 0;
|
|
|
|
} else
|
|
|
|
r = link_push_ntp_to_dhcp_server(uplink, link->dhcp_server);
|
|
|
|
|
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m");
|
2015-08-27 14:48:37 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 19:19:32 +02:00
|
|
|
if (link->network->dhcp_server_emit_timezone) {
|
|
|
|
_cleanup_free_ char *buffer = NULL;
|
2015-08-30 03:19:25 +02:00
|
|
|
const char *tz = NULL;
|
2015-08-26 19:19:32 +02:00
|
|
|
|
|
|
|
if (link->network->dhcp_server_timezone)
|
|
|
|
tz = link->network->dhcp_server_timezone;
|
|
|
|
else {
|
|
|
|
r = get_timezone(&buffer);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to determine timezone: %m");
|
|
|
|
else
|
|
|
|
tz = buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tz) {
|
|
|
|
r = sd_dhcp_server_set_timezone(link->dhcp_server, tz);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-30 19:54:01 +01:00
|
|
|
r = sd_dhcp_server_start(link->dhcp_server);
|
|
|
|
if (r < 0) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m");
|
2015-01-30 19:54:01 +01:00
|
|
|
|
|
|
|
link_enter_failed(link);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Offering DHCPv4 leases");
|
2015-01-30 19:54:01 +01:00
|
|
|
}
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
if (link->link_messages == 0)
|
2014-08-06 13:48:11 +02:00
|
|
|
link_enter_set_routes(link);
|
2015-04-21 17:40:18 +02:00
|
|
|
else
|
|
|
|
log_link_debug(link, "Setting addresses");
|
2014-08-06 13:48:11 +02:00
|
|
|
|
2013-11-14 16:22:51 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-24 15:25:20 +02:00
|
|
|
int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
2014-07-01 10:09:52 +02:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
2014-01-03 02:07:56 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2014-01-03 02:07:56 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2014-05-09 14:23:17 +02:00
|
|
|
if (r < 0 && r != -EADDRNOTAVAIL)
|
2015-09-30 19:37:52 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not drop address: %m");
|
2014-01-03 02:07:56 +01:00
|
|
|
|
2014-07-14 11:04:13 +02:00
|
|
|
return 1;
|
2014-01-03 02:07:56 +01:00
|
|
|
}
|
|
|
|
|
2015-02-11 13:02:58 +01:00
|
|
|
static int link_set_bridge_fdb(Link *const link) {
|
2014-12-17 16:35:36 +01:00
|
|
|
FdbEntry *fdb_entry;
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) {
|
2015-02-10 20:40:41 +01:00
|
|
|
r = fdb_entry_configure(link, fdb_entry);
|
2014-12-17 16:35:36 +01:00
|
|
|
if(r < 0) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m");
|
2014-12-17 16:35:36 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
2014-11-15 04:17:16 +01:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
|
|
|
int r;
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Set link");
|
2014-11-15 04:17:16 +01:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2014-11-15 04:17:16 +01:00
|
|
|
if (r < 0 && r != -EEXIST) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_link_error_errno(link, r, "Could not join netdev: %m");
|
2014-11-15 04:17:16 +01:00
|
|
|
link_enter_failed(link);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
2014-07-01 10:09:52 +02:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
2015-08-27 02:12:27 +02:00
|
|
|
const sd_bus_error *e;
|
2014-01-13 23:48:28 +01:00
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
assert(m);
|
2014-05-08 19:46:06 +02:00
|
|
|
assert(link);
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2014-05-08 20:50:05 +02:00
|
|
|
return 1;
|
|
|
|
|
2015-08-27 02:12:27 +02:00
|
|
|
e = sd_bus_message_get_error(m);
|
|
|
|
if (e)
|
|
|
|
log_link_warning_errno(link, sd_bus_error_get_errno(e), "Could not set hostname: %s", e->message);
|
2014-01-13 23:48:28 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
int link_set_hostname(Link *link, const char *hostname) {
|
2015-08-27 02:12:27 +02:00
|
|
|
int r;
|
2014-01-13 23:48:28 +01:00
|
|
|
|
2014-05-08 19:46:06 +02:00
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
2014-01-13 23:48:28 +01:00
|
|
|
|
2015-08-27 12:53:43 +02:00
|
|
|
log_link_debug(link, "Setting transient hostname: '%s'", strna(hostname));
|
2014-01-13 23:48:28 +01:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
if (!link->manager->bus) {
|
|
|
|
/* TODO: replace by assert when we can rely on kdbus */
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_info(link, "Not connected to system bus, ignoring transient hostname.");
|
2014-01-18 01:37:35 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-10 13:15:39 +02:00
|
|
|
r = sd_bus_call_method_async(
|
2014-05-08 19:46:06 +02:00
|
|
|
link->manager->bus,
|
2015-06-10 13:15:39 +02:00
|
|
|
NULL,
|
2014-01-13 23:48:28 +01:00
|
|
|
"org.freedesktop.hostname1",
|
|
|
|
"/org/freedesktop/hostname1",
|
|
|
|
"org.freedesktop.hostname1",
|
2015-06-10 13:15:39 +02:00
|
|
|
"SetHostname",
|
|
|
|
set_hostname_handler,
|
|
|
|
link,
|
|
|
|
"sb",
|
|
|
|
hostname,
|
|
|
|
false);
|
2014-01-13 23:48:28 +01:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set transient hostname: %m");
|
2014-05-08 19:46:06 +02:00
|
|
|
|
|
|
|
link_ref(link);
|
2014-01-13 23:48:28 +01:00
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
return 0;
|
2014-01-13 23:48:28 +01:00
|
|
|
}
|
|
|
|
|
2015-08-27 02:12:27 +02:00
|
|
|
static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
|
|
|
const sd_bus_error *e;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
e = sd_bus_message_get_error(m);
|
|
|
|
if (e)
|
|
|
|
log_link_warning_errno(link, sd_bus_error_get_errno(e), "Could not set timezone: %s", e->message);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-08-30 03:18:33 +02:00
|
|
|
int link_set_timezone(Link *link, const char *tz) {
|
2015-08-27 02:12:27 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
2015-08-30 03:18:33 +02:00
|
|
|
assert(tz);
|
2015-08-27 02:12:27 +02:00
|
|
|
|
2015-08-30 03:18:33 +02:00
|
|
|
log_link_debug(link, "Setting system timezone: '%s'", tz);
|
2015-08-27 02:12:27 +02:00
|
|
|
|
|
|
|
if (!link->manager->bus) {
|
|
|
|
log_link_info(link, "Not connected to system bus, ignoring timezone.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_call_method_async(
|
|
|
|
link->manager->bus,
|
|
|
|
NULL,
|
|
|
|
"org.freedesktop.timedate1",
|
|
|
|
"/org/freedesktop/timedate1",
|
|
|
|
"org.freedesktop.timedate1",
|
|
|
|
"SetTimezone",
|
|
|
|
set_timezone_handler,
|
|
|
|
link,
|
|
|
|
"sb",
|
2015-08-30 03:18:33 +02:00
|
|
|
tz,
|
2015-08-27 02:12:27 +02:00
|
|
|
false);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set timezone: %m");
|
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
2014-07-01 10:09:52 +02:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
2014-01-13 23:07:59 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2014-01-13 23:07:59 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2014-01-25 11:39:22 +01:00
|
|
|
if (r < 0)
|
2015-09-30 19:37:52 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not set MTU: %m");
|
2014-01-13 23:07:59 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
int link_set_mtu(Link *link, uint32_t mtu) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2014-01-13 23:07:59 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Setting MTU: %" PRIu32, mtu);
|
2014-01-13 23:07:59 +01:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
2014-01-13 23:07:59 +01:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_append_u32(req, IFLA_MTU, mtu);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append MTU: %m");
|
2014-01-13 23:07:59 +01:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
2014-01-13 23:07:59 +01:00
|
|
|
|
2014-06-19 19:41:57 +02:00
|
|
|
link_ref(link);
|
2014-05-08 19:46:06 +02:00
|
|
|
|
2014-01-13 23:07:59 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-15 04:17:16 +01:00
|
|
|
static int link_set_bridge(Link *link) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2014-11-15 04:17:16 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
2014-11-15 04:17:16 +01:00
|
|
|
|
|
|
|
r = sd_rtnl_message_link_set_family(req, PF_BRIDGE);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set message family: %m");
|
2014-11-15 04:17:16 +01:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_open_container(req, IFLA_PROTINFO);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m");
|
2014-11-15 04:17:16 +01:00
|
|
|
|
2015-07-25 04:52:26 +02:00
|
|
|
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, !link->network->use_bpdu);
|
2015-07-23 20:01:58 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_GUARD attribute: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MODE, link->network->hairpin);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MODE attribute: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_FAST_LEAVE, link->network->fast_leave);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_FAST_LEAVE attribute: %m");
|
|
|
|
|
2015-07-25 05:12:20 +02:00
|
|
|
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, !link->network->allow_port_to_be_root);
|
2015-07-23 20:01:58 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
|
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
if (link->network->cost != 0) {
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
|
2014-11-15 04:17:16 +01:00
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_close_container(req);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
|
2014-11-15 04:17:16 +01:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call_async(link->manager->rtnl, req, link_set_handler, link, 0, NULL);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
2014-11-15 04:17:16 +01:00
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
static int link_lldp_save(Link *link) {
|
|
|
|
_cleanup_free_ char *temp_path = NULL;
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
sd_lldp_neighbor **l = NULL;
|
|
|
|
int n = 0, r, i;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
|
|
|
assert(link);
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
assert(link->lldp_file);
|
|
|
|
|
|
|
|
if (!link->lldp) {
|
|
|
|
(void) unlink(link->lldp_file);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_lldp_get_neighbors(link->lldp, &l);
|
|
|
|
if (r < 0)
|
|
|
|
goto finish;
|
|
|
|
if (r == 0) {
|
|
|
|
(void) unlink(link->lldp_file);
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = r;
|
|
|
|
|
|
|
|
r = fopen_temporary(link->lldp_file, &f, &temp_path);
|
|
|
|
if (r < 0)
|
|
|
|
goto finish;
|
|
|
|
|
|
|
|
fchmod(fileno(f), 0644);
|
2014-12-11 05:29:55 +01:00
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
const void *p;
|
|
|
|
le64_t u;
|
|
|
|
size_t sz;
|
|
|
|
|
|
|
|
r = sd_lldp_neighbor_get_raw(l[i], &p, &sz);
|
2015-09-22 15:19:42 +02:00
|
|
|
if (r < 0)
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
goto finish;
|
|
|
|
|
|
|
|
u = htole64(sz);
|
|
|
|
(void) fwrite(&u, 1, sizeof(u), f);
|
|
|
|
(void) fwrite(p, 1, sz, f);
|
|
|
|
}
|
2014-12-11 05:29:55 +01:00
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
r = fflush_and_check(f);
|
|
|
|
if (r < 0)
|
|
|
|
goto finish;
|
|
|
|
|
|
|
|
if (rename(temp_path, link->lldp_file) < 0) {
|
|
|
|
r = -errno;
|
|
|
|
goto finish;
|
2015-09-22 15:19:42 +02:00
|
|
|
}
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
|
|
|
|
finish:
|
|
|
|
if (r < 0) {
|
|
|
|
(void) unlink(link->lldp_file);
|
|
|
|
if (temp_path)
|
|
|
|
(void) unlink(temp_path);
|
|
|
|
|
|
|
|
log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l) {
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
sd_lldp_neighbor_unref(l[i]);
|
|
|
|
free(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lldp_handler(sd_lldp *lldp, void *userdata) {
|
|
|
|
Link *link = userdata;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
(void) link_lldp_save(link);
|
2014-12-11 05:29:55 +01:00
|
|
|
}
|
|
|
|
|
2015-11-10 21:30:59 +01:00
|
|
|
static int link_acquire_ipv6_conf(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (link_dhcp6_enabled(link)) {
|
|
|
|
assert(link->dhcp6_client);
|
2015-11-16 17:43:08 +01:00
|
|
|
assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
|
2015-11-10 21:30:59 +01:00
|
|
|
|
|
|
|
log_link_debug(link, "Acquiring DHCPv6 lease");
|
|
|
|
|
2015-11-16 17:43:08 +01:00
|
|
|
r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address);
|
|
|
|
if (r < 0 && r != -EBUSY)
|
|
|
|
return log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m");
|
|
|
|
|
2015-11-10 21:30:59 +01:00
|
|
|
r = sd_dhcp6_client_start(link->dhcp6_client);
|
2015-11-16 16:46:14 +01:00
|
|
|
if (r < 0 && r != -EBUSY)
|
2015-11-10 21:30:59 +01:00
|
|
|
return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link_ipv6_accept_ra_enabled(link)) {
|
|
|
|
assert(link->ndisc_router_discovery);
|
|
|
|
|
|
|
|
log_link_debug(link, "Discovering IPv6 routers");
|
|
|
|
|
|
|
|
r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery);
|
2015-11-16 16:46:14 +01:00
|
|
|
if (r < 0 && r != -EBUSY)
|
2015-11-10 21:30:59 +01:00
|
|
|
return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-03 02:07:56 +01:00
|
|
|
static int link_acquire_conf(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->event);
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link_ipv4ll_enabled(link)) {
|
2014-03-20 19:57:19 +01:00
|
|
|
assert(link->ipv4ll);
|
2014-01-03 02:07:56 +01:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Acquiring IPv4 link-local address");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
|
|
|
r = sd_ipv4ll_start(link->ipv4ll);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
}
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link_dhcp4_enabled(link)) {
|
2014-03-20 19:57:19 +01:00
|
|
|
assert(link->dhcp_client);
|
2014-01-03 02:07:56 +01:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Acquiring DHCPv4 lease");
|
2014-01-12 15:24:11 +01:00
|
|
|
|
2014-02-28 16:10:20 +01:00
|
|
|
r = sd_dhcp_client_start(link->dhcp_client);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
}
|
2014-01-03 02:07:56 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-04 14:05:54 +02:00
|
|
|
bool link_has_carrier(Link *link) {
|
2014-05-07 16:35:05 +02:00
|
|
|
/* see Documentation/networking/operstates.txt in the kernel sources */
|
|
|
|
|
2014-09-04 14:05:54 +02:00
|
|
|
if (link->kernel_operstate == IF_OPER_UP)
|
2014-05-07 16:35:05 +02:00
|
|
|
return true;
|
|
|
|
|
2014-09-04 14:05:54 +02:00
|
|
|
if (link->kernel_operstate == IF_OPER_UNKNOWN)
|
2014-05-07 16:35:05 +02:00
|
|
|
/* operstate may not be implemented, so fall back to flags */
|
2014-09-04 14:05:54 +02:00
|
|
|
if ((link->flags & IFF_LOWER_UP) && !(link->flags & IFF_DORMANT))
|
2014-05-07 16:35:05 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
2014-07-01 10:09:52 +02:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
2013-12-03 18:48:20 +01:00
|
|
|
int r;
|
|
|
|
|
2014-01-03 00:55:09 +01:00
|
|
|
assert(link);
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2014-01-03 00:55:09 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
/* we warn but don't fail the link, as it may be
|
|
|
|
brought up later */
|
2015-09-30 19:37:52 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not bring up interface: %m");
|
2014-04-22 19:36:40 +02:00
|
|
|
|
2013-11-14 16:22:51 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_up(Link *link) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2015-02-12 14:15:41 +01:00
|
|
|
uint8_t ipv6ll_mode;
|
2013-10-17 03:18:36 +02:00
|
|
|
int r;
|
|
|
|
|
2013-11-14 16:22:51 +01:00
|
|
|
assert(link);
|
2014-12-04 21:57:13 +01:00
|
|
|
assert(link->network);
|
2013-11-14 16:22:51 +01:00
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Bringing link up");
|
2014-01-02 15:30:46 +01:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2014-01-21 15:20:42 +01:00
|
|
|
r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set link flags: %m");
|
2013-12-06 18:16:16 +01:00
|
|
|
|
2014-12-04 21:57:13 +01:00
|
|
|
if (link->network->mac) {
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set MAC address: %m");
|
2014-12-04 21:57:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (link->network->mtu) {
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_append_u32(req, IFLA_MTU, link->network->mtu);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set MTU: %m");
|
2014-12-04 21:57:13 +01:00
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
|
2015-02-08 22:27:15 +01:00
|
|
|
|
2015-05-25 17:34:47 +02:00
|
|
|
if (socket_ipv6_is_supported()) {
|
|
|
|
/* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_open_container(req, AF_INET6);
|
2015-05-25 17:34:47 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m");
|
2015-02-08 22:27:15 +01:00
|
|
|
|
2015-05-25 17:34:47 +02:00
|
|
|
ipv6ll_mode = link_ipv6ll_enabled(link) ? IN6_ADDR_GEN_MODE_EUI64 : IN6_ADDR_GEN_MODE_NONE;
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode);
|
2015-05-25 17:34:47 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m");
|
2015-02-08 22:27:15 +01:00
|
|
|
|
2015-05-25 17:34:47 +02:00
|
|
|
if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) {
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6);
|
2015-05-25 17:34:47 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_INET6_TOKEN: %m");
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_close_container(req);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
2015-05-25 17:34:47 +02:00
|
|
|
return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m");
|
2015-02-08 23:20:56 +01:00
|
|
|
}
|
2015-02-08 22:27:15 +01:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_close_container(req);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
|
2015-02-08 22:27:15 +01:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2014-05-08 19:46:06 +02:00
|
|
|
link_ref(link);
|
|
|
|
|
2013-11-14 16:22:51 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
2015-02-17 13:06:57 +01:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2015-02-17 13:06:57 +01:00
|
|
|
if (r < 0)
|
2015-09-30 19:37:52 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not bring down interface: %m");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_down(Link *link) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2015-02-17 13:06:57 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Bringing link down");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
|
|
|
|
RTM_SETLINK, link->ifindex);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set link flags: %m");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call_async(link->manager->rtnl, req, link_down_handler, link, 0, NULL);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_handle_bound_to_list(Link *link) {
|
|
|
|
Link *l;
|
|
|
|
Iterator i;
|
|
|
|
int r;
|
|
|
|
bool required_up = false;
|
|
|
|
bool link_is_up = false;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (hashmap_isempty(link->bound_to_links))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags & IFF_UP)
|
|
|
|
link_is_up = true;
|
|
|
|
|
|
|
|
HASHMAP_FOREACH (l, link->bound_to_links, i)
|
|
|
|
if (link_has_carrier(l)) {
|
|
|
|
required_up = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!required_up && link_is_up) {
|
|
|
|
r = link_down(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (required_up && !link_is_up) {
|
|
|
|
r = link_up(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_handle_bound_by_list(Link *link) {
|
|
|
|
Iterator i;
|
|
|
|
Link *l;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (hashmap_isempty(link->bound_by_links))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
HASHMAP_FOREACH (l, link->bound_by_links, i) {
|
|
|
|
r = link_handle_bound_to_list(l);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_put_carrier(Link *link, Link *carrier, Hashmap **h) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(carrier);
|
|
|
|
|
|
|
|
if (link == carrier)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (hashmap_get(*h, INT_TO_PTR(carrier->ifindex)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = hashmap_ensure_allocated(h, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = hashmap_put(*h, INT_TO_PTR(carrier->ifindex), carrier);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_new_bound_by_list(Link *link) {
|
|
|
|
Manager *m;
|
|
|
|
Link *carrier;
|
|
|
|
Iterator i;
|
|
|
|
int r;
|
|
|
|
bool list_updated = false;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
|
|
|
|
m = link->manager;
|
|
|
|
|
2016-02-19 20:43:03 +01:00
|
|
|
HASHMAP_FOREACH(carrier, m->links, i) {
|
2015-02-17 13:06:57 +01:00
|
|
|
if (!carrier->network)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (strv_isempty(carrier->network->bind_carrier))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (strv_fnmatch(carrier->network->bind_carrier, link->ifname, 0)) {
|
|
|
|
r = link_put_carrier(link, carrier, &link->bound_by_links);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
list_updated = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (list_updated)
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2016-02-19 20:43:03 +01:00
|
|
|
HASHMAP_FOREACH(carrier, link->bound_by_links, i) {
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_put_carrier(carrier, link, &carrier->bound_to_links);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(carrier);
|
2015-02-17 13:06:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_new_bound_to_list(Link *link) {
|
|
|
|
Manager *m;
|
|
|
|
Link *carrier;
|
|
|
|
Iterator i;
|
|
|
|
int r;
|
|
|
|
bool list_updated = false;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (strv_isempty(link->network->bind_carrier))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
m = link->manager;
|
|
|
|
|
|
|
|
HASHMAP_FOREACH (carrier, m->links, i) {
|
|
|
|
if (strv_fnmatch(link->network->bind_carrier, carrier->ifname, 0)) {
|
|
|
|
r = link_put_carrier(link, carrier, &link->bound_to_links);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
list_updated = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (list_updated)
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
HASHMAP_FOREACH (carrier, link->bound_to_links, i) {
|
|
|
|
r = link_put_carrier(carrier, link, &carrier->bound_by_links);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(carrier);
|
2015-02-17 13:06:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_new_carrier_maps(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = link_new_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_handle_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_new_bound_to_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_handle_bound_to_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_free_bound_to_list(Link *link) {
|
|
|
|
Link *bound_to;
|
|
|
|
Iterator i;
|
|
|
|
|
|
|
|
HASHMAP_FOREACH (bound_to, link->bound_to_links, i) {
|
|
|
|
hashmap_remove(link->bound_to_links, INT_TO_PTR(bound_to->ifindex));
|
|
|
|
|
|
|
|
if (hashmap_remove(bound_to->bound_by_links, INT_TO_PTR(link->ifindex)))
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(bound_to);
|
2015-02-17 13:06:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_free_bound_by_list(Link *link) {
|
|
|
|
Link *bound_by;
|
|
|
|
Iterator i;
|
|
|
|
|
|
|
|
HASHMAP_FOREACH (bound_by, link->bound_by_links, i) {
|
|
|
|
hashmap_remove(link->bound_by_links, INT_TO_PTR(bound_by->ifindex));
|
|
|
|
|
|
|
|
if (hashmap_remove(bound_by->bound_to_links, INT_TO_PTR(link->ifindex))) {
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(bound_by);
|
2015-02-17 13:06:57 +01:00
|
|
|
link_handle_bound_to_list(bound_by);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_free_carrier_maps(Link *link) {
|
|
|
|
bool list_updated = false;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (!hashmap_isempty(link->bound_to_links)) {
|
|
|
|
link_free_bound_to_list(link);
|
|
|
|
list_updated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hashmap_isempty(link->bound_by_links)) {
|
|
|
|
link_free_bound_by_list(link);
|
|
|
|
list_updated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (list_updated)
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void link_drop(Link *link) {
|
|
|
|
if (!link || link->state == LINK_STATE_LINGER)
|
|
|
|
return;
|
|
|
|
|
|
|
|
link_set_state(link, LINK_STATE_LINGER);
|
|
|
|
|
|
|
|
link_free_carrier_maps(link);
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Link removed");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
(void)unlink(link->state_file);
|
2015-02-17 13:06:57 +01:00
|
|
|
link_unref(link);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-05 14:53:54 +02:00
|
|
|
static int link_joined(Link *link) {
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
2013-12-14 19:09:04 +01:00
|
|
|
assert(link);
|
2014-01-01 15:16:34 +01:00
|
|
|
assert(link->network);
|
2013-12-03 18:48:20 +01:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
if (!hashmap_isempty(link->bound_to_links)) {
|
|
|
|
r = link_handle_bound_to_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (!(link->flags & IFF_UP)) {
|
2014-04-15 14:21:44 +02:00
|
|
|
r = link_up(link);
|
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
2013-12-14 19:09:04 +01:00
|
|
|
}
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-11-15 04:17:16 +01:00
|
|
|
if(link->network->bridge) {
|
|
|
|
r = link_set_bridge(link);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
log_link_error_errno(link, r, "Could not set bridge message: %m");
|
2014-11-15 04:17:16 +01:00
|
|
|
}
|
|
|
|
|
2014-06-28 16:21:58 +02:00
|
|
|
return link_enter_set_addresses(link);
|
2013-11-24 23:37:56 +01:00
|
|
|
}
|
|
|
|
|
2015-06-29 14:24:40 +02:00
|
|
|
static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
2014-07-01 10:09:52 +02:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
2013-11-24 23:37:56 +01:00
|
|
|
int r;
|
|
|
|
|
2014-01-03 00:55:09 +01:00
|
|
|
assert(link);
|
2013-12-14 19:09:04 +01:00
|
|
|
assert(link->network);
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2014-01-21 21:58:08 +01:00
|
|
|
link->enslaving --;
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2013-11-24 23:37:56 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2014-07-01 13:30:23 +02:00
|
|
|
if (r < 0 && r != -EEXIST) {
|
2015-09-30 19:37:52 +02:00
|
|
|
log_link_error_errno(link, r, "Could not join netdev: %m");
|
2013-12-14 19:09:04 +01:00
|
|
|
link_enter_failed(link);
|
|
|
|
return 1;
|
2014-07-25 01:13:47 +02:00
|
|
|
} else
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Joined netdev");
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2014-07-01 13:30:23 +02:00
|
|
|
if (link->enslaving <= 0)
|
2014-07-05 14:53:54 +02:00
|
|
|
link_joined(link);
|
2013-11-24 23:37:56 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-07-05 14:53:54 +02:00
|
|
|
static int link_enter_join_netdev(Link *link) {
|
2014-07-28 12:10:37 +02:00
|
|
|
NetDev *netdev;
|
2014-02-10 18:41:54 +01:00
|
|
|
Iterator i;
|
2013-11-24 23:37:56 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
2014-08-13 15:34:27 +02:00
|
|
|
assert(link->state == LINK_STATE_PENDING);
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
link_set_state(link, LINK_STATE_ENSLAVING);
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2014-05-12 07:18:24 +02:00
|
|
|
if (!link->network->bridge &&
|
|
|
|
!link->network->bond &&
|
2014-07-28 12:10:37 +02:00
|
|
|
hashmap_isempty(link->network->stacked_netdevs))
|
2014-07-05 14:53:54 +02:00
|
|
|
return link_joined(link);
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2014-05-09 12:20:21 +02:00
|
|
|
if (link->network->bond) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct(LOG_DEBUG,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(link->network->bond),
|
|
|
|
LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->bond->ifname),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
r = netdev_join(link->network->bond, link, netdev_join_handler);
|
2014-01-21 21:58:08 +01:00
|
|
|
if (r < 0) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct_errno(LOG_WARNING, r,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(link->network->bond),
|
|
|
|
LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->bond->ifname),
|
|
|
|
NULL);
|
|
|
|
|
2014-01-21 21:58:08 +01:00
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-03-05 10:41:13 +01:00
|
|
|
link->enslaving ++;
|
|
|
|
}
|
|
|
|
|
2014-05-09 12:20:21 +02:00
|
|
|
if (link->network->bridge) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct(LOG_DEBUG,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(link->network->bridge),
|
|
|
|
LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->bridge->ifname),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
r = netdev_join(link->network->bridge, link, netdev_join_handler);
|
2014-03-05 10:41:13 +01:00
|
|
|
if (r < 0) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct_errno(LOG_WARNING, r,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(link->network->bridge),
|
|
|
|
LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->bridge->ifname),
|
|
|
|
NULL),
|
2014-03-05 10:41:13 +01:00
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-01-21 21:58:08 +01:00
|
|
|
link->enslaving ++;
|
|
|
|
}
|
|
|
|
|
2014-07-28 12:10:37 +02:00
|
|
|
HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) {
|
2014-05-12 07:18:24 +02:00
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct(LOG_DEBUG,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(netdev),
|
|
|
|
LOG_LINK_MESSAGE(link, "Enslaving by '%s'", netdev->ifname),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
r = netdev_join(netdev, link, netdev_join_handler);
|
2014-05-12 07:18:24 +02:00
|
|
|
if (r < 0) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct_errno(LOG_WARNING, r,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(netdev),
|
|
|
|
LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", netdev->ifname),
|
|
|
|
NULL);
|
2014-06-16 08:24:33 +02:00
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
link->enslaving ++;
|
|
|
|
}
|
|
|
|
|
2013-12-14 19:09:04 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-13 20:07:13 +01:00
|
|
|
static int link_set_ipv4_forward(Link *link) {
|
2015-01-13 13:47:08 +01:00
|
|
|
int r;
|
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
if (!link_ipv4_forward_enabled(link))
|
2015-07-06 13:38:47 +02:00
|
|
|
return 0;
|
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
/* We propagate the forwarding flag from one interface to the
|
|
|
|
* global setting one way. This means: as long as at least one
|
|
|
|
* interface was configured at any time that had IP forwarding
|
|
|
|
* enabled the setting will stay on for good. We do this
|
|
|
|
* primarily to keep IPv4 and IPv6 packet forwarding behaviour
|
|
|
|
* somewhat in sync (see below). */
|
2015-07-06 13:38:47 +02:00
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
r = write_string_file("/proc/sys/net/ipv4/ip_forward", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
|
2015-11-13 00:54:56 +01:00
|
|
|
if (r < 0)
|
2015-11-13 12:49:15 +01:00
|
|
|
log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
|
2015-01-13 20:50:46 +01:00
|
|
|
|
2015-01-13 20:07:13 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_set_ipv6_forward(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
if (!link_ipv6_forward_enabled(link))
|
2015-05-01 20:48:08 +02:00
|
|
|
return 0;
|
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
/* On Linux, the IPv6 stack does not not know a per-interface
|
|
|
|
* packet forwarding setting: either packet forwarding is on
|
|
|
|
* for all, or off for all. We hence don't bother with a
|
|
|
|
* per-interface setting, but simply propagate the interface
|
|
|
|
* flag, if it is set, to the global flag, one-way. Note that
|
|
|
|
* while IPv4 would allow a per-interface flag, we expose the
|
|
|
|
* same behaviour there and also propagate the setting from
|
|
|
|
* one to all, to keep things simple (see above). */
|
2015-07-06 13:38:47 +02:00
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
r = write_string_file("/proc/sys/net/ipv6/conf/all/forwarding", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
|
2015-11-13 00:54:56 +01:00
|
|
|
if (r < 0)
|
2015-11-13 12:49:15 +01:00
|
|
|
log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");
|
2015-01-13 13:47:08 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-05 07:54:31 +02:00
|
|
|
static int link_set_ipv6_privacy_extensions(Link *link) {
|
2015-07-06 20:29:33 +02:00
|
|
|
char buf[DECIMAL_STR_MAX(unsigned) + 1];
|
|
|
|
IPv6PrivacyExtensions s;
|
2015-07-05 07:54:31 +02:00
|
|
|
const char *p = NULL;
|
|
|
|
int r;
|
|
|
|
|
2015-07-06 20:29:33 +02:00
|
|
|
s = link_ipv6_privacy_extensions(link);
|
2015-11-13 12:30:57 +01:00
|
|
|
if (s < 0)
|
2015-07-05 07:54:31 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr");
|
2015-11-13 12:30:57 +01:00
|
|
|
xsprintf(buf, "%u", (unsigned) link->network->ipv6_privacy_extensions);
|
2015-07-05 07:54:31 +02:00
|
|
|
|
2015-11-13 00:54:56 +01:00
|
|
|
r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
|
|
|
|
if (r < 0)
|
2015-07-05 07:54:31 +02:00
|
|
|
log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-12 04:48:06 +02:00
|
|
|
static int link_set_ipv6_accept_ra(Link *link) {
|
networkd: ndisc - handle router advertisement in userspace
Router Discovery is a core part of IPv6, which by default is handled by the kernel.
However, the kernel implementation is meant as a fall-back, and to fully support
the protocol a userspace implementation is desired.
The protocol essentially listens for Router Advertisement packets from routers
on the local link and use these to configure the client automatically. The four
main pieces of information are: what kind (if any) of DHCPv6 configuration should
be performed; a default gateway; the prefixes that should be considered to be on
the local link; and the prefixes with which we can preform SLAAC in order to pick
a global IPv6 address.
A lot of additional information is also available, which we do not yet fully
support, but which will eventually allow us to avoid the need for DHCPv6 in the
common case.
Short-term, the reason for wanting this is in userspace was the desire to fully
track all the addresses on links we manage, and that is not possible for addresses
managed by the kernel (as the kernel does not expose to us the fact that it
manages these addresses). Moreover, we would like to support stable privacy
addresses, which will soon be mandated and the legacy MAC-based global addresses
deprecated, to do this well we need to handle the generation in userspace. Lastly,
more long-term we wish to support more RA options than what the kernel exposes.
2015-11-03 13:02:16 +01:00
|
|
|
const char *p = NULL;
|
2015-09-12 04:48:06 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Make this a NOP if IPv6 is not available */
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return 0;
|
|
|
|
|
2015-11-13 12:32:38 +01:00
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
2015-09-12 04:48:06 +02:00
|
|
|
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra");
|
|
|
|
|
2015-11-18 21:32:43 +01:00
|
|
|
/* We handle router advertisments ourselves, tell the kernel to GTFO */
|
|
|
|
r = write_string_file(p, "0", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
|
2015-11-13 00:54:56 +01:00
|
|
|
if (r < 0)
|
2015-11-18 21:32:43 +01:00
|
|
|
log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface: %m");
|
2015-09-12 04:48:06 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-12 11:01:10 +02:00
|
|
|
static int link_set_ipv6_dad_transmits(Link *link) {
|
2015-11-13 12:30:57 +01:00
|
|
|
char buf[DECIMAL_STR_MAX(int) + 1];
|
2015-10-12 11:01:10 +02:00
|
|
|
const char *p = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Make this a NOP if IPv6 is not available */
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return 0;
|
|
|
|
|
2015-11-13 12:32:38 +01:00
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
2015-10-12 11:01:10 +02:00
|
|
|
if (link->network->ipv6_dad_transmits < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/dad_transmits");
|
2015-11-13 12:30:57 +01:00
|
|
|
xsprintf(buf, "%i", link->network->ipv6_dad_transmits);
|
2015-10-12 11:01:10 +02:00
|
|
|
|
2015-11-13 00:54:56 +01:00
|
|
|
r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
|
|
|
|
if (r < 0)
|
2015-10-12 11:01:10 +02:00
|
|
|
log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-10 04:56:38 +01:00
|
|
|
static int link_set_ipv6_hop_limit(Link *link) {
|
2015-11-13 12:30:57 +01:00
|
|
|
char buf[DECIMAL_STR_MAX(int) + 1];
|
2015-11-10 04:56:38 +01:00
|
|
|
const char *p = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Make this a NOP if IPv6 is not available */
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return 0;
|
|
|
|
|
2015-11-13 12:32:38 +01:00
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
2015-11-10 04:56:38 +01:00
|
|
|
if (link->network->ipv6_hop_limit < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/hop_limit");
|
2015-11-13 12:30:57 +01:00
|
|
|
xsprintf(buf, "%i", link->network->ipv6_hop_limit);
|
2015-11-10 04:56:38 +01:00
|
|
|
|
2015-11-13 00:54:56 +01:00
|
|
|
r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
|
|
|
|
if (r < 0)
|
2015-11-10 04:56:38 +01:00
|
|
|
log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-02 16:52:49 +02:00
|
|
|
static int link_drop_foreign_config(Link *link) {
|
|
|
|
Address *address;
|
|
|
|
Route *route;
|
|
|
|
Iterator i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
SET_FOREACH(address, link->addresses_foreign, i) {
|
2015-11-18 21:32:43 +01:00
|
|
|
/* we consider IPv6LL addresses to be managed by the kernel */
|
2015-10-02 16:52:49 +02:00
|
|
|
if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = address_remove(address, link, link_address_remove_handler);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
SET_FOREACH(route, link->routes_foreign, i) {
|
2015-11-18 21:32:43 +01:00
|
|
|
/* do not touch routes managed by the kernel */
|
2015-10-02 16:52:49 +02:00
|
|
|
if (route->protocol == RTPROT_KERNEL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = route_remove(route, link, link_address_remove_handler);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-20 22:35:02 +01:00
|
|
|
static int link_update_lldp(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (!link->lldp)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags & IFF_UP) {
|
|
|
|
r = sd_lldp_start(link->lldp);
|
|
|
|
if (r > 0)
|
|
|
|
log_link_debug(link, "Started LLDP.");
|
|
|
|
} else {
|
|
|
|
r = sd_lldp_stop(link->lldp);
|
|
|
|
if (r > 0)
|
|
|
|
log_link_debug(link, "Stopped LLDP.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-03-09 14:43:37 +01:00
|
|
|
static int link_configure(Link *link) {
|
2013-11-24 23:37:56 +01:00
|
|
|
int r;
|
|
|
|
|
2013-12-14 19:09:04 +01:00
|
|
|
assert(link);
|
2014-08-06 15:54:03 +02:00
|
|
|
assert(link->network);
|
2014-08-13 15:34:27 +02:00
|
|
|
assert(link->state == LINK_STATE_PENDING);
|
2014-03-09 14:43:37 +01:00
|
|
|
|
2016-01-04 22:04:17 +01:00
|
|
|
/* Drop foreign config, but ignore loopback or critical devices.
|
|
|
|
* We do not want to remove loopback address or addresses used for root NFS. */
|
|
|
|
if (!(link->flags & IFF_LOOPBACK) && !(link->network->dhcp_critical)) {
|
2015-11-25 08:46:43 +01:00
|
|
|
r = link_drop_foreign_config(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2015-10-02 16:52:49 +02:00
|
|
|
|
2014-12-17 16:35:36 +01:00
|
|
|
r = link_set_bridge_fdb(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-01-13 20:07:13 +01:00
|
|
|
r = link_set_ipv4_forward(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_set_ipv6_forward(link);
|
2015-01-13 13:47:08 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-07-05 07:54:31 +02:00
|
|
|
r = link_set_ipv6_privacy_extensions(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-09-12 04:48:06 +02:00
|
|
|
r = link_set_ipv6_accept_ra(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-10-12 11:01:10 +02:00
|
|
|
r = link_set_ipv6_dad_transmits(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-11-10 04:56:38 +01:00
|
|
|
|
|
|
|
r = link_set_ipv6_hop_limit(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-10-12 11:01:10 +02:00
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link_ipv4ll_enabled(link)) {
|
2014-08-06 15:54:03 +02:00
|
|
|
r = ipv4ll_configure(link);
|
2014-03-20 19:57:19 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link_dhcp4_enabled(link)) {
|
2014-08-08 12:12:17 +02:00
|
|
|
r = dhcp4_configure(link);
|
2014-03-20 19:57:19 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link_dhcp4_server_enabled(link)) {
|
2014-03-05 08:13:30 +01:00
|
|
|
r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_dhcp_server_attach_event(link->dhcp_server, NULL, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-11-16 16:47:18 +01:00
|
|
|
if (link_dhcp6_enabled(link) ||
|
|
|
|
link_ipv6_accept_ra_enabled(link)) {
|
networkd: IPv6 router discovery - follow IPv6AcceptRouterAdvertisemnt=
The previous behavior:
When DHCPv6 was enabled, router discover was performed first, and then DHCPv6 was
enabled only if the relevant flags were passed in the Router Advertisement message.
Moreover, router discovery was performed even if AcceptRouterAdvertisements=false,
moreover, even if router advertisements were accepted (by the kernel) the flags
indicating that DHCPv6 should be performed were ignored.
New behavior:
If RouterAdvertisements are accepted, and either no routers are found, or an
advertisement is received indicating DHCPv6 should be performed, the DHCPv6
client is started. Moreover, the DHCP option now truly enables the DHCPv6
client regardless of router discovery (though it will probably not be
very useful to get a lease withotu any routes, this seems the more consistent
approach).
The recommended default setting should be to set DHCP=ipv4 and to leave
IPv6AcceptRouterAdvertisements unset.
2015-10-18 18:25:58 +02:00
|
|
|
r = dhcp6_configure(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link_ipv6_accept_ra_enabled(link)) {
|
2015-10-16 17:34:58 +02:00
|
|
|
r = ndisc_configure(link);
|
2014-06-19 14:40:01 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-11-23 05:26:14 +01:00
|
|
|
if (link_lldp_enabled(link)) {
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
r = sd_lldp_new(&link->lldp, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_lldp_match_capabilities(link->lldp,
|
|
|
|
link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ?
|
|
|
|
_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS :
|
|
|
|
_LLDP_SYSTEM_CAPABILITIES_ALL);
|
2014-11-23 05:26:14 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_lldp_attach_event(link->lldp, NULL, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
2016-02-16 19:26:40 +01:00
|
|
|
r = sd_lldp_set_callback(link->lldp, lldp_handler, link);
|
2014-12-11 05:29:55 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-20 22:35:02 +01:00
|
|
|
|
|
|
|
r = link_update_lldp(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-11-23 05:26:14 +01:00
|
|
|
}
|
|
|
|
|
2014-09-04 14:05:54 +02:00
|
|
|
if (link_has_carrier(link)) {
|
2014-04-22 19:40:05 +02:00
|
|
|
r = link_acquire_conf(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-11-10 21:30:59 +01:00
|
|
|
|
2015-11-16 17:43:08 +01:00
|
|
|
if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) {
|
2015-11-10 21:30:59 +01:00
|
|
|
r = link_acquire_ipv6_conf(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2014-04-22 21:45:17 +02:00
|
|
|
}
|
2014-04-22 19:40:05 +02:00
|
|
|
|
2014-07-05 14:53:54 +02:00
|
|
|
return link_enter_join_netdev(link);
|
2014-04-15 14:21:44 +02:00
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
|
2014-08-08 12:12:17 +02:00
|
|
|
void *userdata) {
|
2014-07-01 10:09:52 +02:00
|
|
|
_cleanup_link_unref_ Link *link = userdata;
|
2014-04-15 14:21:44 +02:00
|
|
|
Network *network;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
|
|
|
assert(link->manager);
|
|
|
|
|
2014-08-13 15:34:27 +02:00
|
|
|
if (link->state != LINK_STATE_PENDING)
|
2014-07-01 10:09:52 +02:00
|
|
|
return 1;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Link state is up-to-date");
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_new_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_handle_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
if (!link->network) {
|
|
|
|
r = network_get(link->manager, link->udev_device, link->ifname,
|
|
|
|
&link->mac, &network);
|
|
|
|
if (r == -ENOENT) {
|
|
|
|
link_enter_unmanaged(link);
|
|
|
|
return 1;
|
|
|
|
} else if (r < 0)
|
|
|
|
return r;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK) {
|
|
|
|
if (network->link_local != ADDRESS_FAMILY_NO)
|
|
|
|
log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
|
2014-09-04 20:54:08 +02:00
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
if (network->dhcp != ADDRESS_FAMILY_NO)
|
|
|
|
log_link_debug(link, "Ignoring DHCP clients for loopback link");
|
2014-09-04 20:54:08 +02:00
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
if (network->dhcp_server)
|
|
|
|
log_link_debug(link, "Ignoring DHCP server for loopback link");
|
|
|
|
}
|
2014-09-04 13:40:24 +02:00
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
r = network_apply(link->manager, network, link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_new_bound_to_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2014-03-09 14:43:37 +01:00
|
|
|
r = link_configure(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
return 1;
|
2014-04-15 14:21:44 +02:00
|
|
|
}
|
|
|
|
|
2014-06-14 18:52:46 +02:00
|
|
|
int link_initialized(Link *link, struct udev_device *device) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2014-06-14 18:52:46 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
assert(device);
|
|
|
|
|
2014-08-13 15:34:27 +02:00
|
|
|
if (link->state != LINK_STATE_PENDING)
|
2014-06-14 18:52:46 +02:00
|
|
|
return 0;
|
|
|
|
|
2014-07-13 01:11:52 +02:00
|
|
|
if (link->udev_device)
|
|
|
|
return 0;
|
|
|
|
|
2014-11-27 20:20:23 +01:00
|
|
|
log_link_debug(link, "udev initialized link");
|
2014-06-14 18:52:46 +02:00
|
|
|
|
|
|
|
link->udev_device = udev_device_ref(device);
|
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
/* udev has initialized the link, but we don't know if we have yet
|
|
|
|
* processed the NEWLINK messages with the latest state. Do a GETLINK,
|
|
|
|
* when it returns we know that the pending NEWLINKs have already been
|
|
|
|
* processed and that we are up-to-date */
|
2014-06-14 18:52:46 +02:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK,
|
|
|
|
link->ifindex);
|
2014-06-14 18:52:46 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call_async(link->manager->rtnl, req,
|
2014-08-08 12:12:17 +02:00
|
|
|
link_initialized_and_synced, link, 0, NULL);
|
2014-06-14 18:52:46 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
link_ref(link);
|
|
|
|
|
2014-06-14 18:52:46 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
static int link_load(Link *link) {
|
2015-10-01 22:29:50 +02:00
|
|
|
_cleanup_free_ char *network_file = NULL,
|
|
|
|
*addresses = NULL,
|
2015-10-25 14:45:53 +01:00
|
|
|
*routes = NULL,
|
2015-10-01 22:29:50 +02:00
|
|
|
*dhcp4_address = NULL,
|
|
|
|
*ipv4ll_address = NULL;
|
|
|
|
union in_addr_union address;
|
2015-10-25 14:45:53 +01:00
|
|
|
union in_addr_union route_dst;
|
2015-10-27 17:37:42 +01:00
|
|
|
const char *p;
|
2015-10-01 21:14:06 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
r = parse_env_file(link->state_file, NEWLINE,
|
|
|
|
"NETWORK_FILE", &network_file,
|
|
|
|
"ADDRESSES", &addresses,
|
2015-10-25 14:45:53 +01:00
|
|
|
"ROUTES", &routes,
|
2015-10-01 22:29:50 +02:00
|
|
|
"DHCP4_ADDRESS", &dhcp4_address,
|
|
|
|
"IPV4LL_ADDRESS", &ipv4ll_address,
|
2015-10-01 21:14:06 +02:00
|
|
|
NULL);
|
|
|
|
if (r < 0 && r != -ENOENT)
|
|
|
|
return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file);
|
|
|
|
|
|
|
|
if (network_file) {
|
|
|
|
Network *network;
|
|
|
|
char *suffix;
|
|
|
|
|
|
|
|
/* drop suffix */
|
|
|
|
suffix = strrchr(network_file, '.');
|
|
|
|
if (!suffix) {
|
|
|
|
log_link_debug(link, "Failed to get network name from %s", network_file);
|
|
|
|
goto network_file_fail;
|
|
|
|
}
|
|
|
|
*suffix = '\0';
|
|
|
|
|
|
|
|
r = network_get_by_name(link->manager, basename(network_file), &network);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(link, r, "Failed to get network %s: %m", basename(network_file));
|
|
|
|
goto network_file_fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = network_apply(link->manager, network, link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to apply network %s: %m", basename(network_file));
|
|
|
|
}
|
|
|
|
|
|
|
|
network_file_fail:
|
|
|
|
|
|
|
|
if (addresses) {
|
2015-10-27 17:37:42 +01:00
|
|
|
p = addresses;
|
2015-10-01 21:14:06 +02:00
|
|
|
|
2015-10-27 17:37:42 +01:00
|
|
|
for (;;) {
|
|
|
|
_cleanup_free_ char *address_str = NULL;
|
2015-10-01 21:14:06 +02:00
|
|
|
char *prefixlen_str;
|
|
|
|
int family;
|
|
|
|
unsigned char prefixlen;
|
|
|
|
|
2015-10-27 17:37:42 +01:00
|
|
|
r = extract_first_word(&p, &address_str, NULL, 0);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(link, r, "Failed to extract next address string: %m");
|
|
|
|
continue;
|
2015-11-18 19:08:44 +01:00
|
|
|
}
|
|
|
|
if (r == 0)
|
2015-10-27 17:37:42 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
prefixlen_str = strchr(address_str, '/');
|
2015-10-01 21:14:06 +02:00
|
|
|
if (!prefixlen_str) {
|
2015-10-27 17:37:42 +01:00
|
|
|
log_link_debug(link, "Failed to parse address and prefix length %s", address_str);
|
2015-10-01 21:14:06 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*prefixlen_str ++ = '\0';
|
|
|
|
|
|
|
|
r = sscanf(prefixlen_str, "%hhu", &prefixlen);
|
|
|
|
if (r != 1) {
|
|
|
|
log_link_error(link, "Failed to parse prefixlen %s", prefixlen_str);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-10-27 17:37:42 +01:00
|
|
|
r = in_addr_from_string_auto(address_str, &family, &address);
|
2015-10-01 21:14:06 +02:00
|
|
|
if (r < 0) {
|
2015-10-27 17:37:42 +01:00
|
|
|
log_link_debug_errno(link, r, "Failed to parse address %s: %m", address_str);
|
2015-10-01 21:14:06 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = address_add(link, family, &address, prefixlen, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to add address: %m");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-25 14:45:53 +01:00
|
|
|
if (routes) {
|
2015-11-22 18:37:58 +01:00
|
|
|
p = routes;
|
|
|
|
|
2015-10-27 17:37:42 +01:00
|
|
|
for (;;) {
|
2015-10-26 12:29:37 +01:00
|
|
|
Route *route;
|
2015-10-27 17:37:42 +01:00
|
|
|
_cleanup_free_ char *route_str = NULL;
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
|
2015-10-26 12:29:37 +01:00
|
|
|
usec_t lifetime;
|
2015-10-25 14:45:53 +01:00
|
|
|
char *prefixlen_str;
|
|
|
|
int family;
|
|
|
|
unsigned char prefixlen, tos, table;
|
|
|
|
uint32_t priority;
|
|
|
|
|
2015-10-27 17:37:42 +01:00
|
|
|
r = extract_first_word(&p, &route_str, NULL, 0);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(link, r, "Failed to extract next route string: %m");
|
|
|
|
continue;
|
2015-11-18 19:08:44 +01:00
|
|
|
}
|
|
|
|
if (r == 0)
|
2015-10-27 17:37:42 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
prefixlen_str = strchr(route_str, '/');
|
2015-10-25 14:45:53 +01:00
|
|
|
if (!prefixlen_str) {
|
2015-10-27 17:37:42 +01:00
|
|
|
log_link_debug(link, "Failed to parse route %s", route_str);
|
2015-10-25 14:45:53 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*prefixlen_str ++ = '\0';
|
|
|
|
|
2015-10-26 12:29:37 +01:00
|
|
|
r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime);
|
|
|
|
if (r != 5) {
|
|
|
|
log_link_debug(link,
|
|
|
|
"Failed to parse destination prefix length, tos, priority, table or expiration %s",
|
|
|
|
prefixlen_str);
|
2015-10-25 14:45:53 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-10-27 17:37:42 +01:00
|
|
|
r = in_addr_from_string_auto(route_str, &family, &route_dst);
|
2015-10-25 14:45:53 +01:00
|
|
|
if (r < 0) {
|
2015-10-27 17:37:42 +01:00
|
|
|
log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
|
2015-10-25 14:45:53 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-10-26 12:29:37 +01:00
|
|
|
r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, &route);
|
2015-10-25 14:45:53 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to add route: %m");
|
2015-10-26 12:29:37 +01:00
|
|
|
|
|
|
|
if (lifetime != USEC_INFINITY) {
|
|
|
|
r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), lifetime,
|
|
|
|
0, route_expire_handler, route);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "Could not arm route expiration handler: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
route->lifetime = lifetime;
|
|
|
|
sd_event_source_unref(route->expire);
|
|
|
|
route->expire = expire;
|
|
|
|
expire = NULL;
|
2015-10-25 14:45:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-01 22:29:50 +02:00
|
|
|
if (dhcp4_address) {
|
|
|
|
r = in_addr_from_string(AF_INET, dhcp4_address, &address);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(link, r, "Falied to parse DHCPv4 address %s: %m", dhcp4_address);
|
|
|
|
goto dhcp4_address_fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_dhcp_client_new(&link->dhcp_client);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Falied to create DHCPv4 client: %m");
|
|
|
|
|
|
|
|
r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Falied to set inital DHCPv4 address %s: %m", dhcp4_address);
|
|
|
|
}
|
|
|
|
|
|
|
|
dhcp4_address_fail:
|
|
|
|
|
|
|
|
if (ipv4ll_address) {
|
|
|
|
r = in_addr_from_string(AF_INET, ipv4ll_address, &address);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(link, r, "Falied to parse IPv4LL address %s: %m", ipv4ll_address);
|
|
|
|
goto ipv4ll_address_fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_ipv4ll_new(&link->ipv4ll);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Falied to create IPv4LL client: %m");
|
|
|
|
|
|
|
|
r = sd_ipv4ll_set_address(link->ipv4ll, &address.in);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Falied to set inital IPv4LL address %s: %m", ipv4ll_address);
|
|
|
|
}
|
|
|
|
|
|
|
|
ipv4ll_address_fail:
|
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
|
2014-04-15 14:21:44 +02:00
|
|
|
Link *link;
|
|
|
|
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
|
|
|
|
char ifindex_str[2 + DECIMAL_STR_MAX(int)];
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
2014-05-11 13:58:18 +02:00
|
|
|
assert(m->rtnl);
|
2014-04-15 14:21:44 +02:00
|
|
|
assert(message);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
r = link_new(m, message, ret);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
link = *ret;
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Link %d added", link->ifindex);
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
r = link_load(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
if (detect_container() <= 0) {
|
2014-04-15 14:21:44 +02:00
|
|
|
/* not in a container, udev will be around */
|
2014-07-28 11:39:37 +02:00
|
|
|
sprintf(ifindex_str, "n%d", link->ifindex);
|
2014-04-15 14:21:44 +02:00
|
|
|
device = udev_device_new_from_device_id(m->udev, ifindex_str);
|
2015-10-09 17:21:15 +02:00
|
|
|
if (!device) {
|
|
|
|
r = log_link_warning_errno(link, errno, "Could not find udev device: %m");
|
|
|
|
goto failed;
|
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2014-05-16 14:47:43 +02:00
|
|
|
if (udev_device_get_is_initialized(device) <= 0) {
|
2014-04-15 14:21:44 +02:00
|
|
|
/* not yet ready */
|
2014-11-27 20:20:23 +01:00
|
|
|
log_link_debug(link, "link pending udev initialization...");
|
2014-04-15 14:21:44 +02:00
|
|
|
return 0;
|
2014-05-16 14:47:43 +02:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2014-06-14 18:52:46 +02:00
|
|
|
r = link_initialized(link, device);
|
|
|
|
if (r < 0)
|
2015-10-09 17:21:15 +02:00
|
|
|
goto failed;
|
2014-06-14 18:52:46 +02:00
|
|
|
} else {
|
2014-07-01 10:09:52 +02:00
|
|
|
/* we are calling a callback directly, so must take a ref */
|
|
|
|
link_ref(link);
|
|
|
|
|
2014-06-14 18:52:46 +02:00
|
|
|
r = link_initialized_and_synced(m->rtnl, NULL, link);
|
|
|
|
if (r < 0)
|
2015-10-09 17:21:15 +02:00
|
|
|
goto failed;
|
2014-06-14 18:52:46 +02:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2014-03-09 14:43:37 +01:00
|
|
|
return 0;
|
2015-10-09 17:21:15 +02:00
|
|
|
failed:
|
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
2014-03-09 14:43:37 +01:00
|
|
|
}
|
|
|
|
|
2015-11-16 17:43:08 +01:00
|
|
|
int link_ipv6ll_gained(Link *link, const struct in6_addr *address) {
|
2015-11-10 21:30:59 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
log_link_info(link, "Gained IPv6LL");
|
|
|
|
|
2015-11-16 17:43:08 +01:00
|
|
|
link->ipv6ll_address = *address;
|
2015-11-10 21:30:59 +01:00
|
|
|
link_check_ready(link);
|
|
|
|
|
2016-01-10 18:10:08 +01:00
|
|
|
if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) {
|
2015-11-10 21:30:59 +01:00
|
|
|
r = link_acquire_ipv6_conf(link);
|
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
static int link_carrier_gained(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
2016-01-10 18:10:08 +01:00
|
|
|
if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) {
|
2015-02-03 15:44:12 +01:00
|
|
|
r = link_acquire_conf(link);
|
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_handle_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_carrier_lost(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
r = link_stop_clients(link);
|
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_handle_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int link_carrier_reset(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (link_has_carrier(link)) {
|
|
|
|
r = link_carrier_lost(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_carrier_gained(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_info(link, "Reset carrier");
|
2015-02-03 15:44:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
int link_update(Link *link, sd_netlink_message *m) {
|
2014-03-20 19:20:55 +01:00
|
|
|
struct ether_addr mac;
|
2014-07-18 02:35:16 +02:00
|
|
|
const char *ifname;
|
2014-08-01 15:42:08 +02:00
|
|
|
uint32_t mtu;
|
2014-09-04 14:05:54 +02:00
|
|
|
bool had_carrier, carrier_gained, carrier_lost;
|
2013-12-17 18:36:09 +01:00
|
|
|
int r;
|
|
|
|
|
2013-12-03 18:48:20 +01:00
|
|
|
assert(link);
|
2014-04-19 20:39:17 +02:00
|
|
|
assert(link->ifname);
|
2013-12-17 18:36:09 +01:00
|
|
|
assert(m);
|
|
|
|
|
2014-05-09 12:11:15 +02:00
|
|
|
if (link->state == LINK_STATE_LINGER) {
|
|
|
|
link_ref(link);
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_info(link, "Link readded");
|
2015-02-04 11:44:37 +01:00
|
|
|
link_set_state(link, LINK_STATE_ENSLAVING);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
r = link_new_carrier_maps(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-05-09 12:11:15 +02:00
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_string(m, IFLA_IFNAME, &ifname);
|
2014-04-19 20:39:17 +02:00
|
|
|
if (r >= 0 && !streq(ifname, link->ifname)) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_info(link, "Renamed to %s", ifname);
|
2014-04-19 20:39:17 +02:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
link_free_carrier_maps(link);
|
|
|
|
|
2015-07-29 20:25:57 +02:00
|
|
|
r = free_and_strdup(&link->ifname, ifname);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
r = link_new_carrier_maps(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-04-19 20:39:17 +02:00
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_u32(m, IFLA_MTU, &mtu);
|
2014-08-01 15:42:08 +02:00
|
|
|
if (r >= 0 && mtu > 0) {
|
|
|
|
link->mtu = mtu;
|
|
|
|
if (!link->original_mtu) {
|
|
|
|
link->original_mtu = mtu;
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Saved original MTU: %" PRIu32, link->original_mtu);
|
2014-08-01 15:42:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (link->dhcp_client) {
|
2014-08-08 12:12:17 +02:00
|
|
|
r = sd_dhcp_client_set_mtu(link->dhcp_client,
|
|
|
|
link->mtu);
|
2014-08-01 15:42:08 +02:00
|
|
|
if (r < 0) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not update MTU in DHCP client: %m");
|
2014-08-01 15:42:08 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
2014-03-07 17:34:38 +01:00
|
|
|
}
|
2014-03-05 11:53:26 +01:00
|
|
|
|
2014-04-13 22:10:34 +02:00
|
|
|
/* The kernel may broadcast NEWLINK messages without the MAC address
|
|
|
|
set, simply ignore them. */
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
|
2014-04-13 22:10:34 +02:00
|
|
|
if (r >= 0) {
|
2014-08-08 12:12:17 +02:00
|
|
|
if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet,
|
|
|
|
ETH_ALEN)) {
|
2014-03-20 19:20:55 +01:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet,
|
|
|
|
ETH_ALEN);
|
2014-03-20 19:20:55 +01:00
|
|
|
|
2014-11-27 20:20:23 +01:00
|
|
|
log_link_debug(link, "MAC address: "
|
2014-03-31 17:17:56 +02:00
|
|
|
"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
|
|
|
mac.ether_addr_octet[0],
|
|
|
|
mac.ether_addr_octet[1],
|
|
|
|
mac.ether_addr_octet[2],
|
|
|
|
mac.ether_addr_octet[3],
|
|
|
|
mac.ether_addr_octet[4],
|
|
|
|
mac.ether_addr_octet[5]);
|
2014-03-20 19:20:55 +01:00
|
|
|
|
2014-03-31 17:17:56 +02:00
|
|
|
if (link->ipv4ll) {
|
|
|
|
r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not update MAC address in IPv4LL client: %m");
|
2014-03-20 19:20:55 +01:00
|
|
|
}
|
|
|
|
|
2014-03-31 17:17:56 +02:00
|
|
|
if (link->dhcp_client) {
|
2014-08-08 12:12:17 +02:00
|
|
|
r = sd_dhcp_client_set_mac(link->dhcp_client,
|
2014-10-08 21:15:45 +02:00
|
|
|
(const uint8_t *) &link->mac,
|
|
|
|
sizeof (link->mac),
|
|
|
|
ARPHRD_ETHER);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
|
2014-03-20 19:20:55 +01:00
|
|
|
}
|
2014-06-19 14:40:01 +02:00
|
|
|
|
|
|
|
if (link->dhcp6_client) {
|
|
|
|
r = sd_dhcp6_client_set_mac(link->dhcp6_client,
|
2014-10-08 21:15:45 +02:00
|
|
|
(const uint8_t *) &link->mac,
|
|
|
|
sizeof (link->mac),
|
|
|
|
ARPHRD_ETHER);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
|
2014-06-19 14:40:01 +02:00
|
|
|
}
|
2014-03-20 19:20:55 +01:00
|
|
|
}
|
2014-01-13 23:07:59 +01:00
|
|
|
}
|
|
|
|
|
2014-09-04 14:05:54 +02:00
|
|
|
had_carrier = link_has_carrier(link);
|
|
|
|
|
|
|
|
r = link_update_flags(link, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-02-20 22:35:02 +01:00
|
|
|
r = link_update_lldp(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2014-09-04 14:05:54 +02:00
|
|
|
carrier_gained = !had_carrier && link_has_carrier(link);
|
|
|
|
carrier_lost = had_carrier && !link_has_carrier(link);
|
|
|
|
|
|
|
|
if (carrier_gained) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_info(link, "Gained carrier");
|
2014-09-04 14:05:54 +02:00
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
r = link_carrier_gained(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-09-04 14:05:54 +02:00
|
|
|
} else if (carrier_lost) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_info(link, "Lost carrier");
|
2014-09-04 14:05:54 +02:00
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
r = link_carrier_lost(link);
|
|
|
|
if (r < 0)
|
2014-09-04 14:05:54 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2013-12-03 18:48:20 +01:00
|
|
|
}
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2016-02-19 20:43:03 +01:00
|
|
|
static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
|
|
|
|
bool space = false;
|
|
|
|
Iterator i;
|
|
|
|
Link *link;
|
|
|
|
|
|
|
|
assert(f);
|
|
|
|
assert(prefix);
|
|
|
|
|
|
|
|
if (hashmap_isempty(h))
|
|
|
|
return;
|
|
|
|
|
|
|
|
fputs(prefix, f);
|
|
|
|
HASHMAP_FOREACH(link, h, i) {
|
|
|
|
if (space)
|
|
|
|
fputc(' ', f);
|
|
|
|
|
|
|
|
fprintf(f, "%i", link->ifindex);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
fputc('\n', f);
|
|
|
|
}
|
|
|
|
|
2014-02-27 01:24:05 +01:00
|
|
|
int link_save(Link *link) {
|
2014-05-08 18:53:32 +02:00
|
|
|
_cleanup_free_ char *temp_path = NULL;
|
2014-02-27 01:24:05 +01:00
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
2014-05-19 20:44:21 +02:00
|
|
|
const char *admin_state, *oper_state;
|
2015-09-30 15:32:16 +02:00
|
|
|
Address *a;
|
2015-10-12 17:54:41 +02:00
|
|
|
Route *route;
|
2015-09-30 15:32:16 +02:00
|
|
|
Iterator i;
|
2014-02-27 01:24:05 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->state_file);
|
2014-05-08 18:53:32 +02:00
|
|
|
assert(link->lease_file);
|
2014-05-08 17:21:37 +02:00
|
|
|
assert(link->manager);
|
|
|
|
|
2014-05-08 20:50:05 +02:00
|
|
|
if (link->state == LINK_STATE_LINGER) {
|
|
|
|
unlink(link->state_file);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
link_lldp_save(link);
|
|
|
|
|
2014-05-07 16:35:05 +02:00
|
|
|
admin_state = link_state_to_string(link->state);
|
|
|
|
assert(admin_state);
|
|
|
|
|
2014-05-19 20:44:21 +02:00
|
|
|
oper_state = link_operstate_to_string(link->operstate);
|
|
|
|
assert(oper_state);
|
2014-05-07 16:35:05 +02:00
|
|
|
|
2014-02-27 01:24:05 +01:00
|
|
|
r = fopen_temporary(link->state_file, &f, &temp_path);
|
|
|
|
if (r < 0)
|
2015-04-21 17:40:18 +02:00
|
|
|
goto fail;
|
2014-02-27 01:24:05 +01:00
|
|
|
|
|
|
|
fchmod(fileno(f), 0644);
|
|
|
|
|
|
|
|
fprintf(f,
|
|
|
|
"# This is private data. Do not parse.\n"
|
2014-05-07 16:35:05 +02:00
|
|
|
"ADMIN_STATE=%s\n"
|
2014-07-16 11:05:25 +02:00
|
|
|
"OPER_STATE=%s\n",
|
|
|
|
admin_state, oper_state);
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2014-05-19 18:42:14 +02:00
|
|
|
if (link->network) {
|
2014-08-18 18:59:48 +02:00
|
|
|
bool space;
|
2015-07-06 14:00:12 +02:00
|
|
|
sd_dhcp6_lease *dhcp6_lease = NULL;
|
2016-01-25 22:27:01 +01:00
|
|
|
const char *dhcp_domainname = NULL;
|
|
|
|
char **dhcp6_domains = NULL;
|
2015-07-06 14:00:12 +02:00
|
|
|
|
|
|
|
if (link->dhcp6_client) {
|
2015-11-10 21:45:41 +01:00
|
|
|
r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease);
|
|
|
|
if (r < 0 && r != -ENOMSG)
|
2015-07-06 14:00:12 +02:00
|
|
|
log_link_debug(link, "No DHCPv6 lease");
|
|
|
|
}
|
2014-07-23 13:48:18 +02:00
|
|
|
|
2014-09-08 13:50:52 +02:00
|
|
|
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
|
|
|
|
|
2014-07-23 13:48:18 +02:00
|
|
|
fputs("DNS=", f);
|
2014-08-18 18:59:48 +02:00
|
|
|
space = false;
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
fputstrv(f, link->network->dns, NULL, &space);
|
2014-08-15 15:42:56 +02:00
|
|
|
|
2016-01-25 21:47:02 +01:00
|
|
|
if (link->network->dhcp_use_dns &&
|
2014-07-23 13:48:18 +02:00
|
|
|
link->dhcp_lease) {
|
|
|
|
const struct in_addr *addresses;
|
|
|
|
|
|
|
|
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
|
|
|
|
if (r > 0) {
|
2014-08-18 18:59:48 +02:00
|
|
|
if (space)
|
|
|
|
fputc(' ', f);
|
2014-07-23 13:48:18 +02:00
|
|
|
serialize_in_addrs(f, addresses, r);
|
2015-07-06 14:00:12 +02:00
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-25 21:47:02 +01:00
|
|
|
if (link->network->dhcp_use_dns && dhcp6_lease) {
|
2015-07-06 14:00:12 +02:00
|
|
|
struct in6_addr *in6_addrs;
|
|
|
|
|
|
|
|
r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs);
|
|
|
|
if (r > 0) {
|
|
|
|
if (space)
|
|
|
|
fputc(' ', f);
|
|
|
|
serialize_in6_addrs(f, in6_addrs, r);
|
2014-07-23 13:48:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-25 15:09:40 +01:00
|
|
|
fputc('\n', f);
|
2014-07-23 13:48:18 +02:00
|
|
|
|
2015-10-25 15:09:40 +01:00
|
|
|
fputs("NTP=", f);
|
2014-08-18 18:59:48 +02:00
|
|
|
space = false;
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
fputstrv(f, link->network->ntp, NULL, &space);
|
2014-08-15 15:42:56 +02:00
|
|
|
|
2016-01-25 21:47:02 +01:00
|
|
|
if (link->network->dhcp_use_ntp &&
|
2014-07-23 13:48:18 +02:00
|
|
|
link->dhcp_lease) {
|
|
|
|
const struct in_addr *addresses;
|
|
|
|
|
|
|
|
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
|
|
|
|
if (r > 0) {
|
2014-08-18 18:59:48 +02:00
|
|
|
if (space)
|
|
|
|
fputc(' ', f);
|
2014-07-23 13:48:18 +02:00
|
|
|
serialize_in_addrs(f, addresses, r);
|
2015-07-06 14:00:12 +02:00
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-25 21:47:02 +01:00
|
|
|
if (link->network->dhcp_use_ntp && dhcp6_lease) {
|
2015-07-06 14:00:12 +02:00
|
|
|
struct in6_addr *in6_addrs;
|
|
|
|
char **hosts;
|
|
|
|
|
|
|
|
r = sd_dhcp6_lease_get_ntp_addrs(dhcp6_lease,
|
|
|
|
&in6_addrs);
|
|
|
|
if (r > 0) {
|
|
|
|
if (space)
|
|
|
|
fputc(' ', f);
|
|
|
|
serialize_in6_addrs(f, in6_addrs, r);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_dhcp6_lease_get_ntp_fqdn(dhcp6_lease, &hosts);
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
if (r > 0)
|
|
|
|
fputstrv(f, hosts, NULL, &space);
|
2014-07-23 13:48:18 +02:00
|
|
|
}
|
|
|
|
|
2015-10-25 15:09:40 +01:00
|
|
|
fputc('\n', f);
|
2014-08-03 18:45:07 +02:00
|
|
|
|
2016-01-25 22:27:01 +01:00
|
|
|
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
|
|
|
|
if (link->dhcp_lease)
|
|
|
|
(void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
|
2014-08-14 20:35:37 +02:00
|
|
|
|
2016-01-25 22:27:01 +01:00
|
|
|
if (dhcp6_lease)
|
|
|
|
(void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains);
|
2015-07-06 14:00:12 +02:00
|
|
|
}
|
|
|
|
|
2016-01-25 22:27:01 +01:00
|
|
|
fputs("DOMAINS=", f);
|
|
|
|
fputstrv(f, link->network->search_domains, NULL, &space);
|
2015-07-06 14:00:12 +02:00
|
|
|
|
2016-01-25 22:42:36 +01:00
|
|
|
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp_domainname)
|
|
|
|
fputs_with_space(f, dhcp_domainname, NULL, &space);
|
2014-08-14 20:35:37 +02:00
|
|
|
|
2016-01-25 22:27:01 +01:00
|
|
|
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp6_domains)
|
|
|
|
fputstrv(f, dhcp6_domains, NULL, &space);
|
|
|
|
|
2015-10-25 15:09:40 +01:00
|
|
|
fputc('\n', f);
|
2014-08-15 14:21:08 +02:00
|
|
|
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
fputs("ROUTE_DOMAINS=", f);
|
|
|
|
fputstrv(f, link->network->route_domains, NULL, NULL);
|
2016-01-25 22:27:01 +01:00
|
|
|
|
2016-01-25 22:42:36 +01:00
|
|
|
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp_domainname)
|
|
|
|
fputs_with_space(f, dhcp_domainname, NULL, &space);
|
2016-01-25 22:27:01 +01:00
|
|
|
|
|
|
|
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp6_domains)
|
|
|
|
fputstrv(f, dhcp6_domains, NULL, &space);
|
|
|
|
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
fputc('\n', f);
|
2014-08-15 14:49:31 +02:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
fprintf(f, "LLMNR=%s\n",
|
2015-07-28 15:00:59 +02:00
|
|
|
resolve_support_to_string(link->network->llmnr));
|
2016-01-05 17:32:25 +01:00
|
|
|
fprintf(f, "MDNS=%s\n",
|
|
|
|
resolve_support_to_string(link->network->mdns));
|
2015-09-30 15:32:16 +02:00
|
|
|
|
2016-01-05 19:57:33 +01:00
|
|
|
if (link->network->dnssec_mode != _DNSSEC_MODE_INVALID)
|
|
|
|
fprintf(f, "DNSSEC=%s\n",
|
|
|
|
dnssec_mode_to_string(link->network->dnssec_mode));
|
|
|
|
|
2016-01-06 18:36:32 +01:00
|
|
|
if (!set_isempty(link->network->dnssec_negative_trust_anchors)) {
|
|
|
|
const char *n;
|
|
|
|
|
|
|
|
fputs("DNSSEC_NTA=", f);
|
|
|
|
space = false;
|
2016-01-25 22:42:36 +01:00
|
|
|
SET_FOREACH(n, link->network->dnssec_negative_trust_anchors, i)
|
|
|
|
fputs_with_space(f, n, NULL, &space);
|
2016-01-06 18:36:32 +01:00
|
|
|
fputc('\n', f);
|
|
|
|
}
|
|
|
|
|
2015-10-25 15:09:40 +01:00
|
|
|
fputs("ADDRESSES=", f);
|
2015-09-30 15:32:16 +02:00
|
|
|
space = false;
|
|
|
|
SET_FOREACH(a, link->addresses, i) {
|
|
|
|
_cleanup_free_ char *address_str = NULL;
|
|
|
|
|
|
|
|
r = in_addr_to_string(a->family, &a->in_addr, &address_str);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
|
|
|
|
space = true;
|
|
|
|
}
|
2015-10-25 15:09:40 +01:00
|
|
|
fputc('\n', f);
|
2015-10-12 17:54:41 +02:00
|
|
|
|
|
|
|
fputs("ROUTES=", f);
|
|
|
|
space = false;
|
|
|
|
SET_FOREACH(route, link->routes, i) {
|
|
|
|
_cleanup_free_ char *route_str = NULL;
|
|
|
|
|
|
|
|
r = in_addr_to_string(route->family, &route->dst, &route_str);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
2015-10-26 12:29:37 +01:00
|
|
|
fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu/"USEC_FMT, space ? " " : "", route_str,
|
|
|
|
route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
|
2015-10-12 17:54:41 +02:00
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
fputc('\n', f);
|
2014-05-19 18:42:14 +02:00
|
|
|
}
|
2014-05-18 22:04:14 +02:00
|
|
|
|
2016-02-19 20:43:03 +01:00
|
|
|
print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
|
|
|
|
print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2015-08-26 19:19:32 +02:00
|
|
|
if (link->dhcp_lease) {
|
2015-10-01 22:29:50 +02:00
|
|
|
struct in_addr address;
|
2015-08-26 19:19:32 +02:00
|
|
|
const char *tz = NULL;
|
|
|
|
|
2015-10-01 22:29:50 +02:00
|
|
|
assert(link->network);
|
|
|
|
|
2015-08-26 19:19:32 +02:00
|
|
|
r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
|
|
|
|
if (r >= 0)
|
|
|
|
fprintf(f, "TIMEZONE=%s\n", tz);
|
|
|
|
|
2015-10-01 22:29:50 +02:00
|
|
|
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
|
|
|
|
if (r >= 0) {
|
|
|
|
fputs("DHCP4_ADDRESS=", f);
|
|
|
|
serialize_in_addrs(f, &address, 1);
|
|
|
|
fputc('\n', f);
|
|
|
|
}
|
2014-06-14 15:03:56 +02:00
|
|
|
|
2015-08-26 20:48:21 +02:00
|
|
|
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
|
2014-02-27 01:24:05 +01:00
|
|
|
if (r < 0)
|
2014-08-12 11:55:06 +02:00
|
|
|
goto fail;
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2014-05-18 22:04:14 +02:00
|
|
|
fprintf(f,
|
2014-07-23 13:48:18 +02:00
|
|
|
"DHCP_LEASE=%s\n",
|
|
|
|
link->lease_file);
|
2014-05-07 16:35:05 +02:00
|
|
|
} else
|
2014-05-08 18:53:32 +02:00
|
|
|
unlink(link->lease_file);
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2015-10-01 22:29:50 +02:00
|
|
|
if (link->ipv4ll) {
|
|
|
|
struct in_addr address;
|
|
|
|
|
|
|
|
r = sd_ipv4ll_get_address(link->ipv4ll, &address);
|
|
|
|
if (r >= 0) {
|
|
|
|
fputs("IPV4LL_ADDRESS=", f);
|
|
|
|
serialize_in_addrs(f, &address, 1);
|
|
|
|
fputc('\n', f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-12 11:55:06 +02:00
|
|
|
r = fflush_and_check(f);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2014-08-12 11:55:06 +02:00
|
|
|
if (rename(temp_path, link->state_file) < 0) {
|
2014-02-27 01:24:05 +01:00
|
|
|
r = -errno;
|
2014-08-12 11:55:06 +02:00
|
|
|
goto fail;
|
2014-02-27 01:24:05 +01:00
|
|
|
}
|
|
|
|
|
2014-08-12 11:55:06 +02:00
|
|
|
return 0;
|
2015-07-29 20:31:07 +02:00
|
|
|
|
2014-08-12 11:55:06 +02:00
|
|
|
fail:
|
2015-04-21 17:40:18 +02:00
|
|
|
(void) unlink(link->state_file);
|
|
|
|
if (temp_path)
|
|
|
|
(void) unlink(temp_path);
|
|
|
|
|
2015-07-29 20:31:07 +02:00
|
|
|
return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file);
|
2014-02-27 01:24:05 +01:00
|
|
|
}
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
/* The serialized state in /run is no longer up-to-date. */
|
|
|
|
void link_dirty(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
r = set_ensure_allocated(&link->manager->dirty_links, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
/* allocation errors are ignored */
|
|
|
|
return;
|
|
|
|
|
|
|
|
r = set_put(link->manager->dirty_links, link);
|
|
|
|
if (r < 0)
|
|
|
|
/* allocation errors are ignored */
|
|
|
|
return;
|
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The serialized state in /run is up-to-date */
|
|
|
|
void link_clean(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
|
|
|
|
set_remove(link->manager->dirty_links, link);
|
|
|
|
link_unref(link);
|
|
|
|
}
|
|
|
|
|
2014-02-27 01:24:05 +01:00
|
|
|
static const char* const link_state_table[_LINK_STATE_MAX] = {
|
2014-08-13 15:34:27 +02:00
|
|
|
[LINK_STATE_PENDING] = "pending",
|
2014-02-27 01:24:05 +01:00
|
|
|
[LINK_STATE_ENSLAVING] = "configuring",
|
|
|
|
[LINK_STATE_SETTING_ADDRESSES] = "configuring",
|
|
|
|
[LINK_STATE_SETTING_ROUTES] = "configuring",
|
|
|
|
[LINK_STATE_CONFIGURED] = "configured",
|
2014-04-20 19:49:00 +02:00
|
|
|
[LINK_STATE_UNMANAGED] = "unmanaged",
|
2014-02-27 01:24:05 +01:00
|
|
|
[LINK_STATE_FAILED] = "failed",
|
2014-05-08 20:50:05 +02:00
|
|
|
[LINK_STATE_LINGER] = "linger",
|
2014-02-27 01:24:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
|
2014-05-19 20:44:21 +02:00
|
|
|
|
|
|
|
static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
|
2014-08-13 22:44:35 +02:00
|
|
|
[LINK_OPERSTATE_OFF] = "off",
|
|
|
|
[LINK_OPERSTATE_NO_CARRIER] = "no-carrier",
|
2014-05-19 20:44:21 +02:00
|
|
|
[LINK_OPERSTATE_DORMANT] = "dormant",
|
|
|
|
[LINK_OPERSTATE_CARRIER] = "carrier",
|
|
|
|
[LINK_OPERSTATE_DEGRADED] = "degraded",
|
|
|
|
[LINK_OPERSTATE_ROUTABLE] = "routable",
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);
|