diff options
Diffstat (limited to 'src')
30 files changed, 617 insertions, 188 deletions
diff --git a/src/systemd/src/basic/hashmap.c b/src/systemd/src/basic/hashmap.c index 49a0479592..50fefb0b54 100644 --- a/src/systemd/src/basic/hashmap.c +++ b/src/systemd/src/basic/hashmap.c @@ -1764,6 +1764,9 @@ void *ordered_hashmap_next(OrderedHashmap *h, const void *key) { int set_consume(Set *s, void *value) { int r; + assert(s); + assert(value); + r = set_put(s, value); if (r <= 0) free(value); @@ -1791,6 +1794,8 @@ int set_put_strdupv(Set *s, char **l) { int n = 0, r; char **i; + assert(s); + STRV_FOREACH(i, l) { r = set_put_strdup(s, *i); if (r < 0) @@ -1801,3 +1806,23 @@ int set_put_strdupv(Set *s, char **l) { return n; } + +int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) { + const char *p = v; + int r; + + assert(s); + assert(v); + + for (;;) { + char *word; + + r = extract_first_word(&p, &word, separators, flags); + if (r <= 0) + return r; + + r = set_consume(s, word); + if (r < 0) + return r; + } +} diff --git a/src/systemd/src/basic/in-addr-util.c b/src/systemd/src/basic/in-addr-util.c index 245107ebb8..aa7ccd1afd 100644 --- a/src/systemd/src/basic/in-addr-util.c +++ b/src/systemd/src/basic/in-addr-util.c @@ -20,26 +20,36 @@ #include <arpa/inet.h> #include <endian.h> #include <errno.h> +#include <net/if.h> #include <stdint.h> #include <stdlib.h> #include "alloc-util.h" #include "in-addr-util.h" #include "macro.h" +#include "parse-util.h" #include "util.h" +bool in4_addr_is_null(const struct in_addr *a) { + return a->s_addr == 0; +} + +bool in6_addr_is_null(const struct in6_addr *a) { + return + a->s6_addr32[0] == 0 && + a->s6_addr32[1] == 0 && + a->s6_addr32[2] == 0 && + a->s6_addr32[3] == 0; +} + int in_addr_is_null(int family, const union in_addr_union *u) { assert(u); if (family == AF_INET) - return u->in.s_addr == 0; + return in4_addr_is_null(&u->in); if (family == AF_INET6) - return - u->in6.s6_addr32[0] == 0 && - u->in6.s6_addr32[1] == 0 && - u->in6.s6_addr32[2] == 0 && - u->in6.s6_addr32[3] == 0; + return in6_addr_is_null(&u->in6); return -EAFNOSUPPORT; } @@ -224,6 +234,48 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { return 0; } +int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) { + size_t l; + char *x; + int r; + + assert(u); + assert(ret); + + /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly + * handle IPv6 link-local addresses. */ + + if (family != AF_INET6) + goto fallback; + if (ifindex <= 0) + goto fallback; + + r = in_addr_is_link_local(family, u); + if (r < 0) + return r; + if (r == 0) + goto fallback; + + l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1; + x = new(char, l); + if (!x) + return -ENOMEM; + + errno = 0; + if (!inet_ntop(family, u, x, l)) { + free(x); + return errno > 0 ? -errno : -EINVAL; + } + + sprintf(strchr(x, 0), "%%%i", ifindex); + *ret = x; + + return 0; + +fallback: + return in_addr_to_string(family, u, ret); +} + int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { assert(s); @@ -261,6 +313,47 @@ int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *re return -EINVAL; } +int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) { + const char *suffix; + int r, ifi = 0; + + assert(s); + assert(family); + assert(ret); + + /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id") + * if one is found. */ + + suffix = strchr(s, '%'); + if (suffix) { + + if (ifindex) { + /* If we shall return the interface index, try to parse it */ + r = parse_ifindex(suffix + 1, &ifi); + if (r < 0) { + unsigned u; + + u = if_nametoindex(suffix + 1); + if (u <= 0) + return -errno; + + ifi = (int) u; + } + } + + s = strndupa(s, suffix - s); + } + + r = in_addr_from_string_auto(s, family, ret); + if (r < 0) + return r; + + if (ifindex) + *ifindex = ifi; + + return r; +} + unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) { assert(addr); diff --git a/src/systemd/src/basic/in-addr-util.h b/src/systemd/src/basic/in-addr-util.h index 17798ce816..d60064aef8 100644 --- a/src/systemd/src/basic/in-addr-util.h +++ b/src/systemd/src/basic/in-addr-util.h @@ -36,6 +36,9 @@ struct in_addr_data { union in_addr_union address; }; +bool in4_addr_is_null(const struct in_addr *a); +bool in6_addr_is_null(const struct in6_addr *a); + int in_addr_is_null(int family, const union in_addr_union *u); int in_addr_is_link_local(int family, const union in_addr_union *u); int in_addr_is_localhost(int family, const union in_addr_union *u); @@ -43,8 +46,10 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_ int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen); int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen); int in_addr_to_string(int family, const union in_addr_union *u, char **ret); +int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret); int in_addr_from_string(int family, const char *s, union in_addr_union *ret); int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret); +int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex); unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr); struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen); int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen); diff --git a/src/systemd/src/basic/macro.h b/src/systemd/src/basic/macro.h index e41aa4260f..6b2aeb933f 100644 --- a/src/systemd/src/basic/macro.h +++ b/src/systemd/src/basic/macro.h @@ -89,6 +89,15 @@ #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) #define UNIQ __COUNTER__ +/* builtins */ +#if __SIZEOF_INT__ == 4 +#define BUILTIN_FFS_U32(x) __builtin_ffs(x); +#elif __SIZEOF_LONG__ == 4 +#define BUILTIN_FFS_U32(x) __builtin_ffsl(x); +#else +#error "neither int nor long are four bytes long?!?" +#endif + /* Rounds up */ #define ALIGN4(l) (((l) + 3) & ~3) diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c index 6c11b605a9..503a895731 100644 --- a/src/systemd/src/basic/parse-util.c +++ b/src/systemd/src/basic/parse-util.c @@ -532,3 +532,22 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { return 0; } + +int parse_percent(const char *p) { + const char *pc, *n; + unsigned v; + int r; + + pc = endswith(p, "%"); + if (!pc) + return -EINVAL; + + n = strndupa(p, pc - p); + r = safe_atou(n, &v); + if (r < 0) + return r; + if (v > 100) + return -ERANGE; + + return (int) v; +} diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h index 7dc579a159..73441bb6fd 100644 --- a/src/systemd/src/basic/parse-util.h +++ b/src/systemd/src/basic/parse-util.h @@ -105,3 +105,5 @@ static inline int safe_atozu(const char *s, size_t *ret_u) { int safe_atod(const char *s, double *ret_d); int parse_fractional_part_u(const char **s, size_t digits, unsigned *res); + +int parse_percent(const char *p); diff --git a/src/systemd/src/basic/random-util.c b/src/systemd/src/basic/random-util.c index 2f468db770..ad7b3eedf2 100644 --- a/src/systemd/src/basic/random-util.c +++ b/src/systemd/src/basic/random-util.c @@ -46,7 +46,7 @@ int dev_urandom(void *p, size_t n) { * never block, and will always return some data from the * kernel, regardless if the random pool is fully initialized * or not. It thus makes no guarantee for the quality of the - * returned entropy, but is good enough for or usual usecases + * returned entropy, but is good enough for our usual usecases * of seeding the hash functions for hashtable */ /* Use the getrandom() syscall unless we know we don't have diff --git a/src/systemd/src/basic/set.h b/src/systemd/src/basic/set.h index e0d9dd001c..12f64a8c57 100644 --- a/src/systemd/src/basic/set.h +++ b/src/systemd/src/basic/set.h @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "extract-word.h" #include "hashmap.h" #include "macro.h" @@ -122,6 +123,7 @@ static inline char **set_get_strv(Set *s) { int set_consume(Set *s, void *value); int set_put_strdup(Set *s, const char *p); int set_put_strdupv(Set *s, char **l); +int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags); #define SET_FOREACH(e, s, i) \ for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); ) diff --git a/src/systemd/src/basic/siphash24.c b/src/systemd/src/basic/siphash24.c index 060e8ba387..8c1cdc3db6 100644 --- a/src/systemd/src/basic/siphash24.c +++ b/src/systemd/src/basic/siphash24.c @@ -17,6 +17,8 @@ coding style) */ +#include <stdio.h> + #include "macro.h" #include "siphash24.h" #include "unaligned.h" diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c index c8769a54f4..385c3e4df3 100644 --- a/src/systemd/src/basic/socket-util.c +++ b/src/systemd/src/basic/socket-util.c @@ -85,7 +85,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { return -EINVAL; a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->size = sizeof(struct sockaddr_in6); } else if (*s == '/') { @@ -133,7 +133,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (r > 0) { /* Gotcha, it's a traditional IPv4 address */ a->sockaddr.in.sin_family = AF_INET; - a->sockaddr.in.sin_port = htons((uint16_t) u); + a->sockaddr.in.sin_port = htobe16((uint16_t)u); a->size = sizeof(struct sockaddr_in); } else { unsigned idx; @@ -147,7 +147,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { return -EINVAL; a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->sockaddr.in6.sin6_scope_id = idx; a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); @@ -164,12 +164,12 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (socket_ipv6_is_supported()) { a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); } else { a->sockaddr.in.sin_family = AF_INET; - a->sockaddr.in.sin_port = htons((uint16_t) u); + a->sockaddr.in.sin_port = htobe16((uint16_t)u); a->sockaddr.in.sin_addr.s_addr = INADDR_ANY; a->size = sizeof(struct sockaddr_in); } @@ -488,9 +488,7 @@ int sockaddr_port(const struct sockaddr *_sa) { if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6)) return -EAFNOSUPPORT; - return ntohs(sa->sa.sa_family == AF_INET6 ? - sa->in6.sin6_port : - sa->in.sin_port); + return be16toh(sa->sa.sa_family == AF_INET6 ? sa->in6.sin6_port : sa->in.sin_port); } int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) { @@ -506,13 +504,13 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ case AF_INET: { uint32_t a; - a = ntohl(sa->in.sin_addr.s_addr); + a = be32toh(sa->in.sin_addr.s_addr); if (include_port) r = asprintf(&p, "%u.%u.%u.%u:%u", a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, - ntohs(sa->in.sin_port)); + be16toh(sa->in.sin_port)); else r = asprintf(&p, "%u.%u.%u.%u", @@ -534,7 +532,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ r = asprintf(&p, "%u.%u.%u.%u:%u", a[0], a[1], a[2], a[3], - ntohs(sa->in6.sin6_port)); + be16toh(sa->in6.sin6_port)); else r = asprintf(&p, "%u.%u.%u.%u", @@ -550,7 +548,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ r = asprintf(&p, "[%s]:%u", a, - ntohs(sa->in6.sin6_port)); + be16toh(sa->in6.sin6_port)); if (r < 0) return -ENOMEM; } else { @@ -988,7 +986,7 @@ ssize_t next_datagram_size_fd(int fd) { l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC); if (l < 0) { - if (errno == EOPNOTSUPP) + if (errno == EOPNOTSUPP || errno == EFAULT) goto fallback; return -errno; diff --git a/src/systemd/src/basic/string-table.h b/src/systemd/src/basic/string-table.h index d88625fca7..369610efc8 100644 --- a/src/systemd/src/basic/string-table.h +++ b/src/systemd/src/basic/string-table.h @@ -48,6 +48,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ scope type name##_from_string(const char *s) { \ int b; \ + if (!s) \ + return -1; \ b = parse_boolean(s); \ if (b == 0) \ return (type) 0; \ diff --git a/src/systemd/src/basic/string-util.h b/src/systemd/src/basic/string-util.h index 139cc8c91b..1209e1e2e1 100644 --- a/src/systemd/src/basic/string-util.h +++ b/src/systemd/src/basic/string-util.h @@ -66,6 +66,10 @@ static inline bool isempty(const char *p) { return !p || !p[0]; } +static inline const char *empty_to_null(const char *p) { + return isempty(p) ? NULL : p; +} + static inline char *startswith(const char *s, const char *prefix) { size_t l; diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c index 97a96e5762..53298268f4 100644 --- a/src/systemd/src/basic/strv.c +++ b/src/systemd/src/basic/strv.c @@ -139,16 +139,16 @@ char **strv_new_ap(const char *x, va_list ap) { va_list aq; /* As a special trick we ignore all listed strings that equal - * (const char*) -1. This is supposed to be used with the + * STRV_IGNORE. This is supposed to be used with the * STRV_IFNOTNULL() macro to include possibly NULL strings in * the string list. */ if (x) { - n = x == (const char*) -1 ? 0 : 1; + n = x == STRV_IGNORE ? 0 : 1; va_copy(aq, ap); while ((s = va_arg(aq, const char*))) { - if (s == (const char*) -1) + if (s == STRV_IGNORE) continue; n++; @@ -162,7 +162,7 @@ char **strv_new_ap(const char *x, va_list ap) { return NULL; if (x) { - if (x != (const char*) -1) { + if (x != STRV_IGNORE) { a[i] = strdup(x); if (!a[i]) goto fail; @@ -171,7 +171,7 @@ char **strv_new_ap(const char *x, va_list ap) { while ((s = va_arg(ap, const char*))) { - if (s == (const char*) -1) + if (s == STRV_IGNORE) continue; a[i] = strdup(s); @@ -804,11 +804,7 @@ char **strv_reverse(char **l) { return l; for (i = 0; i < n / 2; i++) { - char *t; - - t = l[i]; - l[i] = l[n-1-i]; - l[n-1-i] = t; + SWAP_TWO(l[i], l[n-1-i]); } return l; @@ -838,7 +834,7 @@ bool strv_fnmatch(char* const* patterns, const char *s, int flags) { char* const* p; STRV_FOREACH(p, patterns) - if (fnmatch(*p, s, 0) == 0) + if (fnmatch(*p, s, flags) == 0) return true; return false; diff --git a/src/systemd/src/basic/strv.h b/src/systemd/src/basic/strv.h index f61bbb5386..683ce83a2a 100644 --- a/src/systemd/src/basic/strv.h +++ b/src/systemd/src/basic/strv.h @@ -69,8 +69,10 @@ bool strv_equal(char **a, char **b); char **strv_new(const char *x, ...) _sentinel_; char **strv_new_ap(const char *x, va_list ap); +#define STRV_IGNORE ((const char *) -1) + static inline const char* STRV_IFNOTNULL(const char *x) { - return x ? x : (const char *) -1; + return x ? x : STRV_IGNORE; } static inline bool strv_isempty(char * const *l) { diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index edd9179cb8..24e681bf85 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -87,6 +87,16 @@ dual_timestamp* dual_timestamp_get(dual_timestamp *ts) { return ts; } +triple_timestamp* triple_timestamp_get(triple_timestamp *ts) { + assert(ts); + + ts->realtime = now(CLOCK_REALTIME); + ts->monotonic = now(CLOCK_MONOTONIC); + ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY; + + return ts; +} + dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { int64_t delta; assert(ts); @@ -104,6 +114,24 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { return ts; } +triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) { + int64_t delta; + + assert(ts); + + if (u == USEC_INFINITY || u <= 0) { + ts->realtime = ts->monotonic = ts->boottime = u; + return ts; + } + + ts->realtime = u; + delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; + ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta); + ts->boottime = clock_boottime_supported() ? usec_sub(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY; + + return ts; +} + dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { int64_t delta; assert(ts); @@ -136,6 +164,26 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us return ts; } +usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) { + + switch (clock) { + + case CLOCK_REALTIME: + case CLOCK_REALTIME_ALARM: + return ts->realtime; + + case CLOCK_MONOTONIC: + return ts->monotonic; + + case CLOCK_BOOTTIME: + case CLOCK_BOOTTIME_ALARM: + return ts->boottime; + + default: + return USEC_INFINITY; + } +} + usec_t timespec_load(const struct timespec *ts) { assert(ts); @@ -1107,6 +1155,30 @@ clockid_t clock_boottime_or_monotonic(void) { return CLOCK_MONOTONIC; } +bool clock_supported(clockid_t clock) { + struct timespec ts; + + switch (clock) { + + case CLOCK_MONOTONIC: + case CLOCK_REALTIME: + return true; + + case CLOCK_BOOTTIME: + return clock_boottime_supported(); + + case CLOCK_BOOTTIME_ALARM: + if (!clock_boottime_supported()) + return false; + + /* fall through, after checking the cached value for CLOCK_BOOTTIME. */ + + default: + /* For everything else, check properly */ + return clock_gettime(clock, &ts) >= 0; + } +} + int get_timezone(char **tz) { _cleanup_free_ char *t = NULL; const char *e; diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h index a5e3f567ec..1b058f0e49 100644 --- a/src/systemd/src/basic/time-util.h +++ b/src/systemd/src/basic/time-util.h @@ -39,6 +39,12 @@ typedef struct dual_timestamp { usec_t monotonic; } dual_timestamp; +typedef struct triple_timestamp { + usec_t realtime; + usec_t monotonic; + usec_t boottime; +} triple_timestamp; + #define USEC_INFINITY ((usec_t) -1) #define NSEC_INFINITY ((nsec_t) -1) @@ -69,7 +75,8 @@ typedef struct dual_timestamp { #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1) -#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL }) +#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) {}) +#define TRIPLE_TIMESTAMP_NULL ((struct triple_timestamp) {}) usec_t now(clockid_t clock); nsec_t now_nsec(clockid_t clock); @@ -79,11 +86,28 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u); dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u); +triple_timestamp* triple_timestamp_get(triple_timestamp *ts); +triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u); + +#define DUAL_TIMESTAMP_HAS_CLOCK(clock) \ + IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC) + +#define TRIPLE_TIMESTAMP_HAS_CLOCK(clock) \ + IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) + static inline bool dual_timestamp_is_set(dual_timestamp *ts) { return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY)); } +static inline bool triple_timestamp_is_set(triple_timestamp *ts) { + return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || + (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY) || + (ts->boottime > 0 && ts->boottime != USEC_INFINITY)); +} + +usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock); + usec_t timespec_load(const struct timespec *ts) _pure_; struct timespec *timespec_store(struct timespec *ts, usec_t u); @@ -113,6 +137,7 @@ int get_timezones(char ***l); bool timezone_is_valid(const char *name); bool clock_boottime_supported(void); +bool clock_supported(clockid_t clock); clockid_t clock_boottime_or_monotonic(void); #define xstrftime(buf, fmt, tm) \ diff --git a/src/systemd/src/basic/unaligned.h b/src/systemd/src/basic/unaligned.h index 79be645bed..7c847a3ccb 100644 --- a/src/systemd/src/basic/unaligned.h +++ b/src/systemd/src/basic/unaligned.h @@ -109,3 +109,21 @@ static inline void unaligned_write_le64(void *_u, uint64_t a) { unaligned_write_le32(u, (uint32_t) a); unaligned_write_le32(u + 4, (uint32_t) (a >> 32)); } + +#if __BYTE_ORDER == __BIG_ENDIAN +#define unaligned_read_ne16 unaligned_read_be16 +#define unaligned_read_ne32 unaligned_read_be32 +#define unaligned_read_ne64 unaligned_read_be64 + +#define unaligned_write_ne16 unaligned_write_be16 +#define unaligned_write_ne32 unaligned_write_be32 +#define unaligned_write_ne64 unaligned_write_be64 +#else +#define unaligned_read_ne16 unaligned_read_le16 +#define unaligned_read_ne32 unaligned_read_le32 +#define unaligned_read_ne64 unaligned_read_le64 + +#define unaligned_write_ne16 unaligned_write_le16 +#define unaligned_write_ne32 unaligned_write_le32 +#define unaligned_write_ne64 unaligned_write_le64 +#endif diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index 756c663be4..09d16697b7 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -36,6 +36,7 @@ #include "alloc-util.h" #include "build.h" +#include "cgroup-util.h" #include "def.h" #include "dirent-util.h" #include "fd-util.h" @@ -64,6 +65,7 @@ assert_cc(EAGAIN == EWOULDBLOCK); int saved_argc = 0; char **saved_argv = NULL; +static int saved_in_initrd = -1; size_t page_size(void) { static thread_local size_t pgsz = 0; @@ -454,11 +456,10 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa } bool in_initrd(void) { - static int saved = -1; struct statfs s; - if (saved >= 0) - return saved; + if (saved_in_initrd >= 0) + return saved_in_initrd; /* We make two checks here: * @@ -470,11 +471,15 @@ bool in_initrd(void) { * emptying when transititioning to the main systemd. */ - saved = access("/etc/initrd-release", F_OK) >= 0 && - statfs("/", &s) >= 0 && - is_temporary_fs(&s); + saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 && + statfs("/", &s) >= 0 && + is_temporary_fs(&s); - return saved; + return saved_in_initrd; +} + +void in_initrd_force(bool value) { + saved_in_initrd = value; } /* hey glibc, APIs with callbacks without a user pointer are so useless */ @@ -767,15 +772,64 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int } uint64_t physical_memory(void) { - long mem; + _cleanup_free_ char *root = NULL, *value = NULL; + uint64_t mem, lim; + size_t ps; + long sc; + + /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of + * memory. + * + * In order to support containers nicely that have a configured memory limit we'll take the minimum of the + * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */ + + sc = sysconf(_SC_PHYS_PAGES); + assert(sc > 0); + + ps = page_size(); + mem = (uint64_t) sc * (uint64_t) ps; + + if (cg_get_root_path(&root) < 0) + return mem; + + if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value)) + return mem; + + if (safe_atou64(value, &lim) < 0) + return mem; + + /* Make sure the limit is a multiple of our own page size */ + lim /= ps; + lim *= ps; + + return MIN(mem, lim); +} + +uint64_t physical_memory_scale(uint64_t v, uint64_t max) { + uint64_t p, m, ps, r; + + assert(max > 0); + + /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success + * the result is a multiple of the page size (rounds down). */ + + ps = page_size(); + assert(ps > 0); + + p = physical_memory() / ps; + assert(p > 0); + + m = p * v; + if (m / p != v) + return UINT64_MAX; - /* We return this as uint64_t in case we are running as 32bit - * process on a 64bit kernel with huge amounts of memory */ + m /= max; - mem = sysconf(_SC_PHYS_PAGES); - assert(mem > 0); + r = m * ps; + if (r / ps != m) + return UINT64_MAX; - return (uint64_t) mem * (uint64_t) page_size(); + return r; } int update_reboot_parameter_and_warn(const char *param) { diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h index 1c032c15c9..db105197e8 100644 --- a/src/systemd/src/basic/util.h +++ b/src/systemd/src/basic/util.h @@ -86,6 +86,7 @@ int prot_from_flags(int flags) _const_; int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); bool in_initrd(void); +void in_initrd_force(bool value); void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *, void *), @@ -183,6 +184,7 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int * int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); uint64_t physical_memory(void); +uint64_t physical_memory_scale(uint64_t v, uint64_t max); int update_reboot_parameter_and_warn(const char *param); diff --git a/src/systemd/src/libsystemd-network/arp-util.c b/src/systemd/src/libsystemd-network/arp-util.c index 4660c7ea09..02028bf28a 100644 --- a/src/systemd/src/libsystemd-network/arp-util.c +++ b/src/systemd/src/libsystemd-network/arp-util.c @@ -79,7 +79,7 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_ }; union sockaddr_union link = { .ll.sll_family = AF_PACKET, - .ll.sll_protocol = htons(ETH_P_ARP), + .ll.sll_protocol = htobe16(ETH_P_ARP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, @@ -112,17 +112,17 @@ static int arp_send_packet(int fd, int ifindex, bool announce) { union sockaddr_union link = { .ll.sll_family = AF_PACKET, - .ll.sll_protocol = htons(ETH_P_ARP), + .ll.sll_protocol = htobe16(ETH_P_ARP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }; struct ether_arp arp = { - .ea_hdr.ar_hrd = htons(ARPHRD_ETHER), /* HTYPE */ - .ea_hdr.ar_pro = htons(ETHERTYPE_IP), /* PTYPE */ + .ea_hdr.ar_hrd = htobe16(ARPHRD_ETHER), /* HTYPE */ + .ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */ .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */ .ea_hdr.ar_pln = sizeof(be32_t), /* PLEN */ - .ea_hdr.ar_op = htons(ARPOP_REQUEST), /* REQUEST */ + .ea_hdr.ar_op = htobe16(ARPOP_REQUEST), /* REQUEST */ }; int r; diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index fac25e0fa2..a9f5a0a5de 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -107,9 +107,9 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, return -errno; link->ll.sll_family = AF_PACKET; - link->ll.sll_protocol = htons(ETH_P_IP); + link->ll.sll_protocol = htobe16(ETH_P_IP); link->ll.sll_ifindex = ifindex; - link->ll.sll_hatype = htons(arp_type); + link->ll.sll_hatype = htobe16(arp_type); link->ll.sll_halen = mac_addr_len; memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len); diff --git a/src/systemd/src/libsystemd-network/lldp-internal.h b/src/systemd/src/libsystemd-network/lldp-internal.h index 7592bc4305..becc162fab 100644 --- a/src/systemd/src/libsystemd-network/lldp-internal.h +++ b/src/systemd/src/libsystemd-network/lldp-internal.h @@ -28,6 +28,8 @@ #include "prioq.h" struct sd_lldp { + unsigned n_ref; + int ifindex; int fd; diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c index 6a716430e3..88f7e329b0 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.c +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c @@ -360,9 +360,16 @@ end_marker: void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) { assert(n); - if (n->ttl > 0) - n->until = usec_add(now(clock_boottime_or_monotonic()), n->ttl * USEC_PER_SEC); - else + if (n->ttl > 0) { + usec_t base; + + /* Use the packet's timestamp if there is one known */ + base = triple_timestamp_by_clock(&n->timestamp, clock_boottime_or_monotonic()); + if (base <= 0 || base == USEC_INFINITY) + base = now(clock_boottime_or_monotonic()); /* Otherwise, take the current time */ + + n->until = usec_add(base, n->ttl * USEC_PER_SEC); + } else n->until = 0; if (n->lldp) @@ -588,11 +595,11 @@ done: return 0; } -_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret) { +_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) { assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); + assert_return(ret_sec, -EINVAL); - *ret = n->ttl; + *ret_sec = n->ttl; return 0; } @@ -651,7 +658,7 @@ _public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint return 0; } -int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) { +_public_ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) { _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; int r; @@ -668,7 +675,7 @@ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t ra return r; *ret = n; - n = 0; + n = NULL; return r; } @@ -679,7 +686,7 @@ _public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) { assert(n->raw_size >= sizeof(struct ether_header)); n->rindex = sizeof(struct ether_header); - return 0; + return n->rindex < n->raw_size; } _public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) { @@ -693,7 +700,7 @@ _public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) { if (n->rindex + 2 > n->raw_size) /* Truncated message */ return -EBADMSG; - length = LLDP_NEIGHBOR_LENGTH(n); + length = LLDP_NEIGHBOR_TLV_LENGTH(n); if (n->rindex + 2 + length > n->raw_size) return -EBADMSG; @@ -711,7 +718,7 @@ _public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) { if (n->rindex + 2 > n->raw_size) return -EBADMSG; - *type = LLDP_NEIGHBOR_TYPE(n); + *type = LLDP_NEIGHBOR_TLV_TYPE(n); return 0; } @@ -743,14 +750,14 @@ _public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], u if (r == 0) return -ENXIO; - length = LLDP_NEIGHBOR_LENGTH(n); + length = LLDP_NEIGHBOR_TLV_LENGTH(n); if (length < 4) return -EBADMSG; if (n->rindex + 2 + length > n->raw_size) return -EBADMSG; - d = LLDP_NEIGHBOR_DATA(n); + d = LLDP_NEIGHBOR_TLV_DATA(n); memcpy(oui, d, 3); *subtype = d[3]; @@ -782,8 +789,7 @@ _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, if (n->rindex + 2 > n->raw_size) return -EBADMSG; - length = LLDP_NEIGHBOR_LENGTH(n); - + length = LLDP_NEIGHBOR_TLV_LENGTH(n); if (n->rindex + 2 + length > n->raw_size) return -EBADMSG; @@ -792,3 +798,16 @@ _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, return 0; } + +_public_ int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) { + assert_return(n, -EINVAL); + assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP); + assert_return(clock_supported(clock), -EOPNOTSUPP); + assert_return(ret, -EINVAL); + + if (!triple_timestamp_is_set(&n->timestamp)) + return -ENODATA; + + *ret = triple_timestamp_by_clock(&n->timestamp, clock); + return 0; +} diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.h b/src/systemd/src/libsystemd-network/lldp-neighbor.h index f203bfa604..c1a7606d06 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.h +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.h @@ -43,6 +43,8 @@ struct sd_lldp_neighbor { sd_lldp *lldp; unsigned n_ref; + triple_timestamp timestamp; + usec_t until; unsigned prioq_idx; @@ -81,18 +83,18 @@ static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) { return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor)); } -static inline uint8_t LLDP_NEIGHBOR_TYPE(const sd_lldp_neighbor *n) { +static inline uint8_t LLDP_NEIGHBOR_TLV_TYPE(const sd_lldp_neighbor *n) { return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1; } -static inline size_t LLDP_NEIGHBOR_LENGTH(const sd_lldp_neighbor *n) { +static inline size_t LLDP_NEIGHBOR_TLV_LENGTH(const sd_lldp_neighbor *n) { uint8_t *p; p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex; return p[1] + (((size_t) (p[0] & 1)) << 8); } -static inline void* LLDP_NEIGHBOR_DATA(const sd_lldp_neighbor *n) { +static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) { return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2; } diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c index f031760351..59c25598e9 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.c +++ b/src/systemd/src/libsystemd-network/lldp-network.c @@ -57,7 +57,8 @@ int lldp_network_bind_raw_socket(int ifindex) { assert(ifindex > 0); - fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, htons(ETHERTYPE_LLDP)); + fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, + htobe16(ETHERTYPE_LLDP)); if (fd < 0) return -errno; diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index 046b0f9393..ce30b7fc25 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -27,7 +27,7 @@ #include "condition.h" #include "conf-parser.h" #include "dhcp-lease-internal.h" -#include "ether-addr-util.c" +#include "ether-addr-util.h" #include "hexdecoct.h" #include "log.h" #include "network-internal.h" @@ -380,18 +380,21 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { return size; } -void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, - size_t size) { +void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) { unsigned i; assert(f); assert(addresses); assert(size); - for (i = 0; i < size; i++) - fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s", - SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]), - (i < (size - 1)) ? " ": ""); + for (i = 0; i < size; i++) { + char buffer[INET6_ADDRSTRLEN]; + + fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f); + + if (i < size - 1) + fputc(' ', f); + } } int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c index 9d4587c80e..0bd1e66aa0 100644 --- a/src/systemd/src/libsystemd-network/sd-lldp.c +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -43,7 +43,6 @@ static void lldp_flush_neighbors(sd_lldp *lldp) { static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) { assert(lldp); - assert(n); log_lldp("Invoking callback for '%c'.", event); @@ -138,6 +137,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { if (lldp_neighbor_equal(n, old)) { /* Is this equal, then restart the TTL counter, but don't do anyting else. */ + old->timestamp = n->timestamp; lldp_start_timer(lldp, old); lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old); return 0; @@ -171,7 +171,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { finish: if (old) - lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n); + lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old); return r; } @@ -202,6 +202,7 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; ssize_t space, length; sd_lldp *lldp = userdata; + struct timespec ts; assert(fd >= 0); assert(lldp); @@ -215,21 +216,41 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v return -ENOMEM; length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT); - if (length < 0) + if (length < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + return log_lldp_errno(errno, "Failed to read LLDP datagram: %m"); + } if ((size_t) length != n->raw_size) { log_lldp("Packet size mismatch."); return -EINVAL; } + /* Try to get the timestamp of this packet if it is known */ + if (ioctl(fd, SIOCGSTAMPNS, &ts) >= 0) + triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts)); + else + triple_timestamp_get(&n->timestamp); + return lldp_handle_datagram(lldp, n); } +static void lldp_reset(sd_lldp *lldp) { + assert(lldp); + + lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); + lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); + lldp->fd = safe_close(lldp->fd); +} + _public_ int sd_lldp_start(sd_lldp *lldp) { int r; assert_return(lldp, -EINVAL); + assert_return(lldp->event, -EINVAL); + assert_return(lldp->ifindex > 0, -EINVAL); if (lldp->fd >= 0) return 0; @@ -240,24 +261,21 @@ _public_ int sd_lldp_start(sd_lldp *lldp) { if (lldp->fd < 0) return lldp->fd; - if (lldp->event) { - r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp); - if (r < 0) - goto fail; + r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp); + if (r < 0) + goto fail; - r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority); - if (r < 0) - goto fail; + r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority); + if (r < 0) + goto fail; - (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io"); - } + (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io"); + log_lldp("Started LLDP client"); return 1; fail: - lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); - lldp->fd = safe_close(lldp->fd); - + lldp_reset(lldp); return r; } @@ -267,10 +285,9 @@ _public_ int sd_lldp_stop(sd_lldp *lldp) { if (lldp->fd < 0) return 0; - lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); - lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); - lldp->fd = safe_close(lldp->fd); + log_lldp("Stopping LLDP client"); + lldp_reset(lldp); lldp_flush_neighbors(lldp); return 1; @@ -305,6 +322,12 @@ _public_ int sd_lldp_detach_event(sd_lldp *lldp) { return 0; } +_public_ sd_event* sd_lldp_get_event(sd_lldp *lldp) { + assert_return(lldp, NULL); + + return lldp->event; +} + _public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { assert_return(lldp, -EINVAL); @@ -314,39 +337,60 @@ _public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *us return 0; } +_public_ int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) { + assert_return(lldp, -EINVAL); + assert_return(ifindex > 0, -EINVAL); + assert_return(lldp->fd < 0, -EBUSY); + + lldp->ifindex = ifindex; + return 0; +} + +_public_ sd_lldp* sd_lldp_ref(sd_lldp *lldp) { + + if (!lldp) + return NULL; + + assert(lldp->n_ref > 0); + lldp->n_ref++; + + return lldp; +} + _public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) { if (!lldp) return NULL; + assert(lldp->n_ref > 0); + lldp->n_ref --; + + if (lldp->n_ref > 0) + return NULL; + + lldp_reset(lldp); + sd_lldp_detach_event(lldp); lldp_flush_neighbors(lldp); hashmap_free(lldp->neighbor_by_id); prioq_free(lldp->neighbor_by_expiry); - - sd_event_source_unref(lldp->io_event_source); - sd_event_source_unref(lldp->timer_event_source); - sd_event_unref(lldp->event); - safe_close(lldp->fd); - free(lldp); return NULL; } -_public_ int sd_lldp_new(sd_lldp **ret, int ifindex) { +_public_ int sd_lldp_new(sd_lldp **ret) { _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; int r; assert_return(ret, -EINVAL); - assert_return(ifindex > 0, -EINVAL); lldp = new0(sd_lldp, 1); if (!lldp) return -ENOMEM; + lldp->n_ref = 1; lldp->fd = -1; - lldp->ifindex = ifindex; lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX; lldp->capability_mask = (uint16_t) -1; @@ -486,11 +530,10 @@ _public_ int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr * /* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so * that our own can be filtered out here. */ - if (!addr) { + if (addr) + lldp->filter_address = *addr; + else zero(lldp->filter_address); - return 0; - } - lldp->filter_address = *addr; return 0; } diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 7ba6527f63..f364b54b50 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -216,8 +216,7 @@ struct sd_event { pid_t original_pid; unsigned iteration; - dual_timestamp timestamp; - usec_t timestamp_boottime; + triple_timestamp timestamp; int state; bool exit_requested:1; @@ -1072,16 +1071,16 @@ _public_ int sd_event_add_time( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); - if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && - !clock_boottime_supported()) + if (!clock_supported(clock)) /* Checks whether the kernel supports the clock */ + return -EOPNOTSUPP; + + type = clock_to_event_source_type(clock); /* checks whether sd-event supports this clock */ + if (type < 0) return -EOPNOTSUPP; if (!callback) callback = time_exit_callback; - type = clock_to_event_source_type(clock); - assert_return(type >= 0, -EOPNOTSUPP); - d = event_get_clock_data(e, type); assert(d); @@ -2530,9 +2529,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { goto finish; } - dual_timestamp_get(&e->timestamp); - if (clock_boottime_supported()) - e->timestamp_boottime = now(CLOCK_BOOTTIME); + triple_timestamp_get(&e->timestamp); for (i = 0; i < m; i++) { @@ -2573,7 +2570,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { if (r < 0) goto finish; - r = process_timer(e, e->timestamp_boottime, &e->boottime); + r = process_timer(e, e->timestamp.boottime, &e->boottime); if (r < 0) goto finish; @@ -2585,7 +2582,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { if (r < 0) goto finish; - r = process_timer(e, e->timestamp_boottime, &e->boottime_alarm); + r = process_timer(e, e->timestamp.boottime, &e->boottime_alarm); if (r < 0) goto finish; @@ -2759,43 +2756,24 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { assert_return(e, -EINVAL); assert_return(usec, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); - assert_return(IN_SET(clock, - CLOCK_REALTIME, - CLOCK_REALTIME_ALARM, - CLOCK_MONOTONIC, - CLOCK_BOOTTIME, - CLOCK_BOOTTIME_ALARM), -EOPNOTSUPP); + if (!TRIPLE_TIMESTAMP_HAS_CLOCK(clock)) + return -EOPNOTSUPP; + + /* Generate a clean error in case CLOCK_BOOTTIME is not available. Note that don't use clock_supported() here, + * for a reason: there are systems where CLOCK_BOOTTIME is supported, but CLOCK_BOOTTIME_ALARM is not, but for + * the purpose of getting the time this doesn't matter. */ if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported()) return -EOPNOTSUPP; - if (!dual_timestamp_is_set(&e->timestamp)) { + if (!triple_timestamp_is_set(&e->timestamp)) { /* Implicitly fall back to now() if we never ran * before and thus have no cached time. */ *usec = now(clock); return 1; } - switch (clock) { - - case CLOCK_REALTIME: - case CLOCK_REALTIME_ALARM: - *usec = e->timestamp.realtime; - break; - - case CLOCK_MONOTONIC: - *usec = e->timestamp.monotonic; - break; - - case CLOCK_BOOTTIME: - case CLOCK_BOOTTIME_ALARM: - *usec = e->timestamp_boottime; - break; - - default: - assert_not_reached("Unknown clock?"); - } - + *usec = triple_timestamp_by_clock(&e->timestamp, clock); return 0; } diff --git a/src/systemd/src/systemd/sd-lldp.h b/src/systemd/src/systemd/sd-lldp.h index 5772d5794a..3f35eebea3 100644 --- a/src/systemd/src/systemd/sd-lldp.h +++ b/src/systemd/src/systemd/sd-lldp.h @@ -23,6 +23,7 @@ #include <inttypes.h> #include <net/ethernet.h> +#include <sys/types.h> #include "sd-event.h" @@ -30,9 +31,6 @@ _SD_BEGIN_DECLARATIONS; -typedef struct sd_lldp sd_lldp; -typedef struct sd_lldp_neighbor sd_lldp_neighbor; - /* IEEE 802.3AB Clause 9: TLV Types */ enum { SD_LLDP_TYPE_END = 0, @@ -111,6 +109,9 @@ enum { SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, }; +typedef struct sd_lldp sd_lldp; +typedef struct sd_lldp_neighbor sd_lldp_neighbor; + typedef enum sd_lldp_event { SD_LLDP_EVENT_ADDED = 'a', SD_LLDP_EVENT_REMOVED = 'r', @@ -120,7 +121,8 @@ typedef enum sd_lldp_event { typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata); -int sd_lldp_new(sd_lldp **ret, int ifindex); +int sd_lldp_new(sd_lldp **ret); +sd_lldp* sd_lldp_ref(sd_lldp *lldp); sd_lldp* sd_lldp_unref(sd_lldp *lldp); int sd_lldp_start(sd_lldp *lldp); @@ -128,8 +130,10 @@ int sd_lldp_stop(sd_lldp *lldp); int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority); int sd_lldp_detach_event(sd_lldp *lldp); +sd_event *sd_lldp_get_event(sd_lldp *lldp); int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata); +int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex); /* Controls how much and what to store in the neighbors database */ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n); @@ -145,6 +149,7 @@ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n); /* Access to LLDP frame metadata */ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address); int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address); +int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret); int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); /* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */ @@ -152,7 +157,7 @@ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const vo int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret); int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size); int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret); -int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret); +int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec); int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret); int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret); int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret); diff --git a/src/systemd/src/systemd/sd-ndisc.h b/src/systemd/src/systemd/sd-ndisc.h index 2b774233b8..9f7d4ef71a 100644 --- a/src/systemd/src/systemd/sd-ndisc.h +++ b/src/systemd/src/systemd/sd-ndisc.h @@ -22,6 +22,8 @@ #include <inttypes.h> #include <net/ethernet.h> +#include <netinet/in.h> +#include <sys/types.h> #include "sd-event.h" @@ -29,55 +31,99 @@ _SD_BEGIN_DECLARATIONS; +/* Neightbor Discovery Options, RFC 4861, Section 4.6 and + * https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */ enum { - SD_NDISC_EVENT_STOP = 0, - SD_NDISC_EVENT_TIMEOUT = 1, + SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1, + SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2, + SD_NDISC_OPTION_PREFIX_INFORMATION = 3, + SD_NDISC_OPTION_MTU = 5, + SD_NDISC_OPTION_ROUTE_INFORMATION = 24, + SD_NDISC_OPTION_RDNSS = 25, + SD_NDISC_OPTION_FLAGS_EXTENSION = 26, + SD_NDISC_OPTION_DNSSL = 31, + SD_NDISC_OPTION_CAPTIVE_PORTAL = 37, +}; + +/* Route preference, RFC 4191, Section 2.1 */ +enum { + SD_NDISC_PREFERENCE_LOW = 3U, + SD_NDISC_PREFERENCE_MEDIUM = 0U, + SD_NDISC_PREFERENCE_HIGH = 1U, }; typedef struct sd_ndisc sd_ndisc; +typedef struct sd_ndisc_router sd_ndisc_router; -typedef void(*sd_ndisc_router_callback_t)(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata); -typedef void(*sd_ndisc_prefix_onlink_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, - unsigned lifetime, void *userdata); -typedef void(*sd_ndisc_prefix_autonomous_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, - unsigned lifetime_prefered, unsigned lifetime_valid, void *userdata); -typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event, void *userdata); - -int sd_ndisc_set_callback(sd_ndisc *nd, - sd_ndisc_router_callback_t rcb, - sd_ndisc_prefix_onlink_callback_t plcb, - sd_ndisc_prefix_autonomous_callback_t pacb, - sd_ndisc_callback_t cb, - void *userdata); -int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index); -int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); +typedef enum sd_ndisc_event { + SD_NDISC_EVENT_TIMEOUT = 't', + SD_NDISC_EVENT_ROUTER = 'r', +} sd_ndisc_event; -int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); -int sd_ndisc_detach_event(sd_ndisc *nd); -sd_event *sd_ndisc_get_event(sd_ndisc *nd); +typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata); +int sd_ndisc_new(sd_ndisc **ret); sd_ndisc *sd_ndisc_ref(sd_ndisc *nd); sd_ndisc *sd_ndisc_unref(sd_ndisc *nd); -int sd_ndisc_new(sd_ndisc **ret); - -int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu); +int sd_ndisc_start(sd_ndisc *nd); int sd_ndisc_stop(sd_ndisc *nd); -int sd_ndisc_router_discovery_start(sd_ndisc *nd); -#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); +int sd_ndisc_detach_event(sd_ndisc *nd); +sd_event *sd_ndisc_get_event(sd_ndisc *nd); + +int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb, void *userdata); +int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index); +int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); -#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \ - be16toh((address).s6_addr16[0]), \ - be16toh((address).s6_addr16[1]), \ - be16toh((address).s6_addr16[2]), \ - be16toh((address).s6_addr16[3]), \ - be16toh((address).s6_addr16[4]), \ - be16toh((address).s6_addr16[5]), \ - be16toh((address).s6_addr16[6]), \ - be16toh((address).s6_addr16[7]) +int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *ret); +int sd_ndisc_get_hop_limit(sd_ndisc *nd, uint8_t *ret); + +int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size); +sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt); +sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt); + +int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); +int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); +int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size); + +int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags); +int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret); +int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime); +int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret); + +/* Generic option access */ +int sd_ndisc_router_option_rewind(sd_ndisc_router *rt); +int sd_ndisc_router_option_next(sd_ndisc_router *rt); +int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type); +int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size); + +/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */ +int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret); +int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret); +int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); +int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen); + +/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */ +int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); +int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); +int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen); +int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret); + +/* Specific option access: SD_NDISC_OPTION_RDNSS */ +int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret); +int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); + +/* Specific option access: SD_NDISC_OPTION_DNSSL */ +int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret); +int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref); _SD_END_DECLARATIONS; |