mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-29 06:50:10 +01:00
ndisc: track expiry of Router Advertisements in milliseconds
Elements of RAs have a lifetime. Previously we would track both the timestamp (when we received the RA) and the lifetime. However, we are mainly interested in the expiry time. So tracking the expiry in form of timestamp and lifetime is redundant and cumbersome to use. Consider also the cases nm_ndisc_add_address() were we mangle the expiry. In that case, the timestamp becomes meaningless or it's not clear what the timestamp should be. Also, there are no real cases where we actually need the receive timestamp. Note that when we convert the times to NMPlatformIP6Address, we again need to synthesize a base time stamp. But here too, it's NMPlatformIP6Address fault of doing this pointless split of timestamp and lifetime. While at it, increase the precision to milliseconds. As we receive lifetimes with seconds precision, one might think that seconds precision is enough for tracking the timeouts. However it just leads to ugly uncertainty about rounding, when we can track times with sufficient precision without downside. For example, before configuring an address in kernel, we also need to calculate a remaining lifetime with a lower precision. By having the exact values, we can do so more accurately. At least, in theory. Of course NMPlatformIP6Address itself has only precision of seconds, we already loose the information before. However, NMNDisc no longer has that problem.
This commit is contained in:
parent
03c6d8280c
commit
4c2035347e
9 changed files with 910 additions and 666 deletions
|
|
@ -5148,26 +5148,26 @@ device_recheck_slave_status(NMDevice *self, const NMPlatformLink *plink)
|
|||
static void
|
||||
ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
gint32 now;
|
||||
GArray * addresses, *dns_servers, *dns_domains;
|
||||
guint len, i;
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
gs_unref_array GArray *addresses = NULL;
|
||||
gs_unref_array GArray *dns_servers = NULL;
|
||||
gs_unref_array GArray * dns_domains = NULL;
|
||||
guint len;
|
||||
guint i;
|
||||
const NMDedupMultiHeadEntry *head_entry;
|
||||
NMDedupMultiIter ipconf_iter;
|
||||
|
||||
if (nm_ndisc_get_node_type(ndisc) != NM_NDISC_NODE_TYPE_ROUTER)
|
||||
return;
|
||||
|
||||
now = nm_utils_get_monotonic_timestamp_sec();
|
||||
|
||||
head_entry = nm_ip6_config_lookup_addresses(priv->ip_config_6);
|
||||
addresses =
|
||||
g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscAddress), head_entry ? head_entry->len : 0);
|
||||
nm_dedup_multi_iter_for_each (&ipconf_iter, head_entry) {
|
||||
const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(ipconf_iter.current->obj);
|
||||
NMNDiscAddress * ndisc_addr;
|
||||
guint32 lifetime, preferred;
|
||||
gint32 base;
|
||||
guint32 lifetime;
|
||||
guint32 preferred;
|
||||
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&addr->address) || IN6_IS_ADDR_LINKLOCAL(&addr->address))
|
||||
continue;
|
||||
|
|
@ -5178,31 +5178,21 @@ ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self)
|
|||
if (addr->plen != 64)
|
||||
continue;
|
||||
|
||||
/* resolve the timestamps relative to a new base.
|
||||
*
|
||||
* Note that for convenience, platform @addr might have timestamp and/or
|
||||
* lifetime unset. We don't allow that flexibility for ndisc and require
|
||||
* well defined timestamps. */
|
||||
if (addr->timestamp) {
|
||||
nm_assert(addr->timestamp < G_MAXINT32);
|
||||
base = addr->timestamp;
|
||||
} else
|
||||
base = now;
|
||||
|
||||
lifetime = nm_utils_lifetime_get(addr->timestamp,
|
||||
addr->lifetime,
|
||||
addr->preferred,
|
||||
base,
|
||||
NM_NDISC_EXPIRY_BASE_TIMESTAMP / 1000,
|
||||
&preferred);
|
||||
if (!lifetime)
|
||||
continue;
|
||||
|
||||
g_array_set_size(addresses, addresses->len + 1);
|
||||
ndisc_addr = &g_array_index(addresses, NMNDiscAddress, addresses->len - 1);
|
||||
ndisc_addr->address = addr->address;
|
||||
ndisc_addr->timestamp = base;
|
||||
ndisc_addr->lifetime = lifetime;
|
||||
ndisc_addr->preferred = preferred;
|
||||
ndisc_addr = &g_array_index(addresses, NMNDiscAddress, addresses->len - 1);
|
||||
ndisc_addr->address = addr->address;
|
||||
ndisc_addr->expiry_msec =
|
||||
_nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, lifetime);
|
||||
ndisc_addr->expiry_preferred_msec =
|
||||
_nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, preferred);
|
||||
}
|
||||
|
||||
len = nm_ip6_config_get_num_nameservers(priv->ip_config_6);
|
||||
|
|
@ -5212,10 +5202,10 @@ ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self)
|
|||
const struct in6_addr *nameserver = nm_ip6_config_get_nameserver(priv->ip_config_6, i);
|
||||
NMNDiscDNSServer * ndisc_nameserver;
|
||||
|
||||
ndisc_nameserver = &g_array_index(dns_servers, NMNDiscDNSServer, i);
|
||||
ndisc_nameserver->address = *nameserver;
|
||||
ndisc_nameserver->timestamp = now;
|
||||
ndisc_nameserver->lifetime = NM_NDISC_ROUTER_LIFETIME;
|
||||
ndisc_nameserver = &g_array_index(dns_servers, NMNDiscDNSServer, i);
|
||||
ndisc_nameserver->address = *nameserver;
|
||||
ndisc_nameserver->expiry_msec =
|
||||
_nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, NM_NDISC_ROUTER_LIFETIME);
|
||||
}
|
||||
|
||||
len = nm_ip6_config_get_num_searches(priv->ip_config_6);
|
||||
|
|
@ -5225,16 +5215,13 @@ ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self)
|
|||
const char * search = nm_ip6_config_get_search(priv->ip_config_6, i);
|
||||
NMNDiscDNSDomain *ndisc_search;
|
||||
|
||||
ndisc_search = &g_array_index(dns_domains, NMNDiscDNSDomain, i);
|
||||
ndisc_search->domain = (char *) search;
|
||||
ndisc_search->timestamp = now;
|
||||
ndisc_search->lifetime = NM_NDISC_ROUTER_LIFETIME;
|
||||
ndisc_search = &g_array_index(dns_domains, NMNDiscDNSDomain, i);
|
||||
ndisc_search->domain = (char *) search;
|
||||
ndisc_search->expiry_msec =
|
||||
_nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, NM_NDISC_ROUTER_LIFETIME);
|
||||
}
|
||||
|
||||
nm_ndisc_set_config(ndisc, addresses, dns_servers, dns_domains);
|
||||
g_array_unref(addresses);
|
||||
g_array_unref(dns_servers);
|
||||
g_array_unref(dns_domains);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -30,11 +30,10 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
struct in6_addr network;
|
||||
int plen;
|
||||
struct in6_addr gateway;
|
||||
guint32 timestamp;
|
||||
guint32 lifetime;
|
||||
guint32 preferred;
|
||||
gint64 expiry_msec;
|
||||
gint64 expiry_preferred_msec;
|
||||
int plen;
|
||||
NMIcmpv6RouterPref preference;
|
||||
} FakePrefix;
|
||||
|
||||
|
|
@ -128,8 +127,7 @@ void
|
|||
nm_fake_ndisc_add_gateway(NMFakeNDisc * self,
|
||||
guint ra_id,
|
||||
const char * addr,
|
||||
guint32 timestamp,
|
||||
guint32 lifetime,
|
||||
gint64 expiry_msec,
|
||||
NMIcmpv6RouterPref preference)
|
||||
{
|
||||
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||
|
|
@ -137,12 +135,12 @@ nm_fake_ndisc_add_gateway(NMFakeNDisc * self,
|
|||
NMNDiscGateway * gw;
|
||||
|
||||
g_assert(ra);
|
||||
g_array_set_size(ra->gateways, ra->gateways->len + 1);
|
||||
gw = &g_array_index(ra->gateways, NMNDiscGateway, ra->gateways->len - 1);
|
||||
g_assert(inet_pton(AF_INET6, addr, &gw->address) == 1);
|
||||
gw->timestamp = timestamp;
|
||||
gw->lifetime = lifetime;
|
||||
gw->preference = preference;
|
||||
|
||||
gw = nm_g_array_append_new(ra->gateways, NMNDiscGateway);
|
||||
if (inet_pton(AF_INET6, addr, &gw->address) != 1)
|
||||
g_assert_not_reached();
|
||||
gw->expiry_msec = expiry_msec;
|
||||
gw->preference = preference;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -151,9 +149,8 @@ nm_fake_ndisc_add_prefix(NMFakeNDisc * self,
|
|||
const char * network,
|
||||
guint plen,
|
||||
const char * gateway,
|
||||
guint32 timestamp,
|
||||
guint32 lifetime,
|
||||
guint32 preferred,
|
||||
gint64 expiry_msec,
|
||||
gint64 expiry_preferred_msec,
|
||||
NMIcmpv6RouterPref preference)
|
||||
{
|
||||
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||
|
|
@ -161,54 +158,52 @@ nm_fake_ndisc_add_prefix(NMFakeNDisc * self,
|
|||
FakePrefix * prefix;
|
||||
|
||||
g_assert(ra);
|
||||
g_array_set_size(ra->prefixes, ra->prefixes->len + 1);
|
||||
prefix = &g_array_index(ra->prefixes, FakePrefix, ra->prefixes->len - 1);
|
||||
memset(prefix, 0, sizeof(*prefix));
|
||||
g_assert(inet_pton(AF_INET6, network, &prefix->network) == 1);
|
||||
g_assert(inet_pton(AF_INET6, gateway, &prefix->gateway) == 1);
|
||||
prefix->plen = plen;
|
||||
prefix->timestamp = timestamp;
|
||||
prefix->lifetime = lifetime;
|
||||
prefix->preferred = preferred;
|
||||
prefix->preference = preference;
|
||||
|
||||
prefix = nm_g_array_append_new(ra->prefixes, FakePrefix);
|
||||
*prefix = (FakePrefix){
|
||||
.plen = plen,
|
||||
.expiry_msec = expiry_msec,
|
||||
.expiry_preferred_msec = expiry_preferred_msec,
|
||||
.preference = preference,
|
||||
};
|
||||
if (inet_pton(AF_INET6, network, &prefix->network) != 1)
|
||||
g_assert_not_reached();
|
||||
if (inet_pton(AF_INET6, gateway, &prefix->gateway) != 1)
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
void
|
||||
nm_fake_ndisc_add_dns_server(NMFakeNDisc *self,
|
||||
guint ra_id,
|
||||
const char * address,
|
||||
guint32 timestamp,
|
||||
guint32 lifetime)
|
||||
gint64 expiry_msec)
|
||||
{
|
||||
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||
FakeRa * ra = find_ra(priv->ras, ra_id);
|
||||
NMNDiscDNSServer * dns;
|
||||
|
||||
g_assert(ra);
|
||||
g_array_set_size(ra->dns_servers, ra->dns_servers->len + 1);
|
||||
dns = &g_array_index(ra->dns_servers, NMNDiscDNSServer, ra->dns_servers->len - 1);
|
||||
g_assert(inet_pton(AF_INET6, address, &dns->address) == 1);
|
||||
dns->timestamp = timestamp;
|
||||
dns->lifetime = lifetime;
|
||||
|
||||
dns = nm_g_array_append_new(ra->dns_servers, NMNDiscDNSServer);
|
||||
|
||||
dns->expiry_msec = expiry_msec;
|
||||
if (inet_pton(AF_INET6, address, &dns->address) != 1)
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
void
|
||||
nm_fake_ndisc_add_dns_domain(NMFakeNDisc *self,
|
||||
guint ra_id,
|
||||
const char * domain,
|
||||
guint32 timestamp,
|
||||
guint32 lifetime)
|
||||
nm_fake_ndisc_add_dns_domain(NMFakeNDisc *self, guint ra_id, const char *domain, gint64 expiry_msec)
|
||||
{
|
||||
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||
FakeRa * ra = find_ra(priv->ras, ra_id);
|
||||
NMNDiscDNSDomain * dns;
|
||||
|
||||
g_assert(ra);
|
||||
g_array_set_size(ra->dns_domains, ra->dns_domains->len + 1);
|
||||
dns = &g_array_index(ra->dns_domains, NMNDiscDNSDomain, ra->dns_domains->len - 1);
|
||||
dns->domain = g_strdup(domain);
|
||||
dns->timestamp = timestamp;
|
||||
dns->lifetime = lifetime;
|
||||
|
||||
dns = nm_g_array_append_new(ra->dns_domains, NMNDiscDNSDomain);
|
||||
|
||||
dns->domain = g_strdup(domain);
|
||||
dns->expiry_msec = expiry_msec;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -230,13 +225,13 @@ send_rs(NMNDisc *ndisc, GError **error)
|
|||
static gboolean
|
||||
receive_ra(gpointer user_data)
|
||||
{
|
||||
NMFakeNDisc * self = user_data;
|
||||
NMFakeNDiscPrivate * priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||
NMNDisc * ndisc = NM_NDISC(self);
|
||||
NMNDiscDataInternal *rdata = ndisc->rdata;
|
||||
FakeRa * ra = priv->ras->data;
|
||||
NMNDiscConfigMap changed = 0;
|
||||
gint32 now = nm_utils_get_monotonic_timestamp_sec();
|
||||
NMFakeNDisc * self = user_data;
|
||||
NMFakeNDiscPrivate * priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||
NMNDisc * ndisc = NM_NDISC(self);
|
||||
NMNDiscDataInternal *rdata = ndisc->rdata;
|
||||
FakeRa * ra = priv->ras->data;
|
||||
NMNDiscConfigMap changed = 0;
|
||||
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
guint i;
|
||||
NMNDiscDHCPLevel dhcp_level;
|
||||
|
||||
|
|
@ -251,53 +246,51 @@ receive_ra(gpointer user_data)
|
|||
}
|
||||
|
||||
for (i = 0; i < ra->gateways->len; i++) {
|
||||
NMNDiscGateway *item = &g_array_index(ra->gateways, NMNDiscGateway, i);
|
||||
const NMNDiscGateway *item = &g_array_index(ra->gateways, NMNDiscGateway, i);
|
||||
|
||||
if (nm_ndisc_add_gateway(ndisc, item))
|
||||
if (nm_ndisc_add_gateway(ndisc, item, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_GATEWAYS;
|
||||
}
|
||||
|
||||
for (i = 0; i < ra->prefixes->len; i++) {
|
||||
FakePrefix * item = &g_array_index(ra->prefixes, FakePrefix, i);
|
||||
NMNDiscRoute route = {
|
||||
.network = item->network,
|
||||
.plen = item->plen,
|
||||
.gateway = item->gateway,
|
||||
.timestamp = item->timestamp,
|
||||
.lifetime = item->lifetime,
|
||||
.preference = item->preference,
|
||||
FakePrefix * item = &g_array_index(ra->prefixes, FakePrefix, i);
|
||||
const NMNDiscRoute route = {
|
||||
.network = item->network,
|
||||
.plen = item->plen,
|
||||
.gateway = item->gateway,
|
||||
.expiry_msec = item->expiry_msec,
|
||||
.preference = item->preference,
|
||||
};
|
||||
|
||||
g_assert(route.plen > 0 && route.plen <= 128);
|
||||
|
||||
if (nm_ndisc_add_route(ndisc, &route))
|
||||
if (nm_ndisc_add_route(ndisc, &route, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_ROUTES;
|
||||
|
||||
if (item->plen == 64) {
|
||||
NMNDiscAddress address = {
|
||||
.address = item->network,
|
||||
.timestamp = item->timestamp,
|
||||
.lifetime = item->lifetime,
|
||||
.preferred = item->preferred,
|
||||
.dad_counter = 0,
|
||||
const NMNDiscAddress address = {
|
||||
.address = item->network,
|
||||
.expiry_msec = item->expiry_msec,
|
||||
.expiry_preferred_msec = item->expiry_preferred_msec,
|
||||
.dad_counter = 0,
|
||||
};
|
||||
|
||||
if (nm_ndisc_complete_and_add_address(ndisc, &address, now))
|
||||
if (nm_ndisc_complete_and_add_address(ndisc, &address, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_ADDRESSES;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ra->dns_servers->len; i++) {
|
||||
NMNDiscDNSServer *item = &g_array_index(ra->dns_servers, NMNDiscDNSServer, i);
|
||||
const NMNDiscDNSServer *item = &g_array_index(ra->dns_servers, NMNDiscDNSServer, i);
|
||||
|
||||
if (nm_ndisc_add_dns_server(ndisc, item))
|
||||
if (nm_ndisc_add_dns_server(ndisc, item, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_DNS_SERVERS;
|
||||
}
|
||||
|
||||
for (i = 0; i < ra->dns_domains->len; i++) {
|
||||
NMNDiscDNSDomain *item = &g_array_index(ra->dns_domains, NMNDiscDNSDomain, i);
|
||||
const NMNDiscDNSDomain *item = &g_array_index(ra->dns_domains, NMNDiscDNSDomain, i);
|
||||
|
||||
if (nm_ndisc_add_dns_domain(ndisc, item))
|
||||
if (nm_ndisc_add_dns_domain(ndisc, item, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_DNS_DOMAINS;
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +307,7 @@ receive_ra(gpointer user_data)
|
|||
priv->ras = g_slist_remove(priv->ras, priv->ras->data);
|
||||
fake_ra_free(ra);
|
||||
|
||||
nm_ndisc_ra_received(NM_NDISC(self), now, changed);
|
||||
nm_ndisc_ra_received(NM_NDISC(self), now_msec, changed);
|
||||
|
||||
/* Schedule next RA */
|
||||
if (priv->ras) {
|
||||
|
|
|
|||
|
|
@ -35,8 +35,7 @@ guint nm_fake_ndisc_add_ra(NMFakeNDisc * self,
|
|||
void nm_fake_ndisc_add_gateway(NMFakeNDisc * self,
|
||||
guint ra_id,
|
||||
const char * addr,
|
||||
guint32 timestamp,
|
||||
guint32 lifetime,
|
||||
gint64 expiry_msec,
|
||||
NMIcmpv6RouterPref preference);
|
||||
|
||||
void nm_fake_ndisc_add_prefix(NMFakeNDisc * self,
|
||||
|
|
@ -44,22 +43,19 @@ void nm_fake_ndisc_add_prefix(NMFakeNDisc * self,
|
|||
const char * network,
|
||||
guint plen,
|
||||
const char * gateway,
|
||||
guint32 timestamp,
|
||||
guint32 lifetime,
|
||||
guint32 preferred,
|
||||
gint64 expiry_msec,
|
||||
gint64 expiry_preferred_msec,
|
||||
NMIcmpv6RouterPref preference);
|
||||
|
||||
void nm_fake_ndisc_add_dns_server(NMFakeNDisc *self,
|
||||
guint ra_id,
|
||||
const char * address,
|
||||
guint32 timestamp,
|
||||
guint32 lifetime);
|
||||
gint64 expiry_msec);
|
||||
|
||||
void nm_fake_ndisc_add_dns_domain(NMFakeNDisc *self,
|
||||
guint ra_id,
|
||||
const char * domain,
|
||||
guint32 timestamp,
|
||||
guint32 lifetime);
|
||||
gint64 expiry_msec);
|
||||
|
||||
void nm_fake_ndisc_emit_new_ras(NMFakeNDisc *self);
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
|
|||
NMNDiscConfigMap changed = 0;
|
||||
struct ndp_msgra * msgra = ndp_msgra(msg);
|
||||
struct in6_addr gateway_addr;
|
||||
gint32 now = nm_utils_get_monotonic_timestamp_sec();
|
||||
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
int offset;
|
||||
int hop_limit;
|
||||
guint32 val;
|
||||
|
|
@ -133,7 +133,9 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
|
|||
* single time when the configuration is finished and updates can
|
||||
* come at any time.
|
||||
*/
|
||||
_LOGD("received router advertisement at %d", (int) now);
|
||||
_LOGD("received router advertisement at timestamp %" G_GINT64_FORMAT ".%03d seconds",
|
||||
now_msec / 1000,
|
||||
(int) (now_msec % 1000));
|
||||
|
||||
gateway_addr = *ndp_msg_addrto(msg);
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&gateway_addr))
|
||||
|
|
@ -175,13 +177,18 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
|
|||
*/
|
||||
{
|
||||
const NMNDiscGateway gateway = {
|
||||
.address = gateway_addr,
|
||||
.timestamp = now,
|
||||
.lifetime = ndp_msgra_router_lifetime(msgra),
|
||||
.preference = _route_preference_coerce(ndp_msgra_route_preference(msgra)),
|
||||
.address = gateway_addr,
|
||||
.expiry_msec = _nm_ndisc_lifetime_to_expiry(now_msec, ndp_msgra_router_lifetime(msgra)),
|
||||
.preference = _route_preference_coerce(ndp_msgra_route_preference(msgra)),
|
||||
};
|
||||
|
||||
if (nm_ndisc_add_gateway(ndisc, &gateway))
|
||||
/* https://tools.ietf.org/html/rfc2461#section-4.2
|
||||
* > A Lifetime of 0 indicates that the router is not a
|
||||
* > default router and SHOULD NOT appear on the default
|
||||
* > router list.
|
||||
* We handle that by tracking a gateway that expires right now. */
|
||||
|
||||
if (nm_ndisc_add_gateway(ndisc, &gateway, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_GATEWAYS;
|
||||
}
|
||||
|
||||
|
|
@ -204,64 +211,71 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
|
|||
|
||||
if (ndp_msg_opt_prefix_flag_on_link(msg, offset)) {
|
||||
const NMNDiscRoute route = {
|
||||
.network = r_network,
|
||||
.plen = r_plen,
|
||||
.timestamp = now,
|
||||
.lifetime = ndp_msg_opt_prefix_valid_time(msg, offset),
|
||||
.network = r_network,
|
||||
.plen = r_plen,
|
||||
.expiry_msec =
|
||||
_nm_ndisc_lifetime_to_expiry(now_msec,
|
||||
ndp_msg_opt_prefix_valid_time(msg, offset)),
|
||||
};
|
||||
|
||||
if (nm_ndisc_add_route(ndisc, &route))
|
||||
if (nm_ndisc_add_route(ndisc, &route, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_ROUTES;
|
||||
}
|
||||
|
||||
/* Address */
|
||||
if (r_plen == 64 && ndp_msg_opt_prefix_flag_auto_addr_conf(msg, offset)) {
|
||||
NMNDiscAddress address = {
|
||||
.address = r_network,
|
||||
.timestamp = now,
|
||||
.lifetime = ndp_msg_opt_prefix_valid_time(msg, offset),
|
||||
.preferred = ndp_msg_opt_prefix_preferred_time(msg, offset),
|
||||
const guint32 valid_time = ndp_msg_opt_prefix_valid_time(msg, offset);
|
||||
const guint32 preferred_time =
|
||||
NM_MIN(ndp_msg_opt_prefix_preferred_time(msg, offset), valid_time);
|
||||
const NMNDiscAddress address = {
|
||||
.address = r_network,
|
||||
.expiry_msec = _nm_ndisc_lifetime_to_expiry(now_msec, valid_time),
|
||||
.expiry_preferred_msec = _nm_ndisc_lifetime_to_expiry(now_msec, preferred_time),
|
||||
};
|
||||
|
||||
if (address.preferred <= address.lifetime) {
|
||||
if (nm_ndisc_complete_and_add_address(ndisc, &address, now))
|
||||
changed |= NM_NDISC_CONFIG_ADDRESSES;
|
||||
}
|
||||
if (nm_ndisc_complete_and_add_address(ndisc, &address, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_ADDRESSES;
|
||||
}
|
||||
}
|
||||
ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_ROUTE) {
|
||||
NMNDiscRoute route = {
|
||||
.gateway = gateway_addr,
|
||||
.plen = ndp_msg_opt_route_prefix_len(msg, offset),
|
||||
.timestamp = now,
|
||||
.lifetime = ndp_msg_opt_route_lifetime(msg, offset),
|
||||
.preference = _route_preference_coerce(ndp_msg_opt_route_preference(msg, offset)),
|
||||
};
|
||||
guint8 plen = ndp_msg_opt_route_prefix_len(msg, offset);
|
||||
struct in6_addr network;
|
||||
|
||||
if (route.plen == 0 || route.plen > 128)
|
||||
if (plen == 0 || plen > 128)
|
||||
continue;
|
||||
|
||||
/* Routers through this particular gateway */
|
||||
nm_utils_ip6_address_clear_host_address(&route.network,
|
||||
nm_utils_ip6_address_clear_host_address(&network,
|
||||
ndp_msg_opt_route_prefix(msg, offset),
|
||||
route.plen);
|
||||
if (nm_ndisc_add_route(ndisc, &route))
|
||||
changed |= NM_NDISC_CONFIG_ROUTES;
|
||||
plen);
|
||||
|
||||
{
|
||||
const NMNDiscRoute route = {
|
||||
.network = network,
|
||||
.gateway = gateway_addr,
|
||||
.plen = plen,
|
||||
.expiry_msec =
|
||||
_nm_ndisc_lifetime_to_expiry(now_msec, ndp_msg_opt_route_lifetime(msg, offset)),
|
||||
.preference = _route_preference_coerce(ndp_msg_opt_route_preference(msg, offset)),
|
||||
};
|
||||
|
||||
/* Routers through this particular gateway */
|
||||
if (nm_ndisc_add_route(ndisc, &route, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_ROUTES;
|
||||
}
|
||||
}
|
||||
|
||||
/* DNS information */
|
||||
ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_RDNSS) {
|
||||
struct in6_addr *addr;
|
||||
int addr_index;
|
||||
|
||||
ndp_msg_opt_rdnss_for_each_addr (addr, addr_index, msg, offset) {
|
||||
NMNDiscDNSServer dns_server = {
|
||||
.address = *addr,
|
||||
.timestamp = now,
|
||||
.lifetime = ndp_msg_opt_rdnss_lifetime(msg, offset),
|
||||
const NMNDiscDNSServer dns_server = {
|
||||
.address = *addr,
|
||||
.expiry_msec =
|
||||
_nm_ndisc_lifetime_to_expiry(now_msec, ndp_msg_opt_rdnss_lifetime(msg, offset)),
|
||||
};
|
||||
|
||||
if (nm_ndisc_add_dns_server(ndisc, &dns_server))
|
||||
if (nm_ndisc_add_dns_server(ndisc, &dns_server, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_DNS_SERVERS;
|
||||
}
|
||||
}
|
||||
|
|
@ -270,13 +284,13 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
|
|||
int domain_index;
|
||||
|
||||
ndp_msg_opt_dnssl_for_each_domain (domain, domain_index, msg, offset) {
|
||||
NMNDiscDNSDomain dns_domain = {
|
||||
.domain = domain,
|
||||
.timestamp = now,
|
||||
.lifetime = ndp_msg_opt_dnssl_lifetime(msg, offset),
|
||||
const NMNDiscDNSDomain dns_domain = {
|
||||
.domain = domain,
|
||||
.expiry_msec =
|
||||
_nm_ndisc_lifetime_to_expiry(now_msec, ndp_msg_opt_dnssl_lifetime(msg, offset)),
|
||||
};
|
||||
|
||||
if (nm_ndisc_add_dns_domain(ndisc, &dns_domain))
|
||||
if (nm_ndisc_add_dns_domain(ndisc, &dns_domain, now_msec))
|
||||
changed |= NM_NDISC_CONFIG_DNS_DOMAINS;
|
||||
}
|
||||
}
|
||||
|
|
@ -316,7 +330,7 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
|
|||
}
|
||||
}
|
||||
|
||||
nm_ndisc_ra_received(ndisc, now, changed);
|
||||
nm_ndisc_ra_received(ndisc, now_msec, changed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -374,7 +388,6 @@ send_ra(NMNDisc *ndisc, GError **error)
|
|||
{
|
||||
NMLndpNDiscPrivate * priv = NM_LNDP_NDISC_GET_PRIVATE(ndisc);
|
||||
NMNDiscDataInternal * rdata = ndisc->rdata;
|
||||
gint32 now = nm_utils_get_monotonic_timestamp_sec();
|
||||
int errsv;
|
||||
struct in6_addr * addr;
|
||||
struct ndp_msg * msg;
|
||||
|
|
@ -404,18 +417,9 @@ send_ra(NMNDisc *ndisc, GError **error)
|
|||
/* The device let us know about all addresses that the device got
|
||||
* whose prefixes are suitable for delegating. Let's announce them. */
|
||||
for (i = 0; i < rdata->addresses->len; i++) {
|
||||
const NMNDiscAddress *address = &g_array_index(rdata->addresses, NMNDiscAddress, i);
|
||||
guint32 age = NM_CLAMP((gint64) now - (gint64) address->timestamp, 0, G_MAXUINT32 - 1);
|
||||
guint32 lifetime = address->lifetime;
|
||||
guint32 preferred = address->preferred;
|
||||
const NMNDiscAddress * address = &g_array_index(rdata->addresses, NMNDiscAddress, i);
|
||||
struct nd_opt_prefix_info *prefix;
|
||||
|
||||
/* Clamp the life times if they're not forever. */
|
||||
if (lifetime != NM_NDISC_INFINITY)
|
||||
lifetime = lifetime > age ? lifetime - age : 0;
|
||||
if (preferred != NM_NDISC_INFINITY)
|
||||
preferred = preferred > age ? preferred - age : 0;
|
||||
|
||||
prefix = _ndp_msg_add_option(msg, sizeof(*prefix));
|
||||
if (!prefix) {
|
||||
/* Maybe we could sent separate RAs, but why bother... */
|
||||
|
|
@ -428,8 +432,14 @@ send_ra(NMNDisc *ndisc, GError **error)
|
|||
prefix->nd_opt_pi_prefix_len = 64;
|
||||
prefix->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
|
||||
prefix->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
|
||||
prefix->nd_opt_pi_valid_time = htonl(lifetime);
|
||||
prefix->nd_opt_pi_preferred_time = htonl(preferred);
|
||||
prefix->nd_opt_pi_valid_time =
|
||||
htonl(_nm_ndisc_lifetime_from_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP,
|
||||
address->expiry_msec,
|
||||
TRUE));
|
||||
prefix->nd_opt_pi_preferred_time =
|
||||
htonl(_nm_ndisc_lifetime_from_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP,
|
||||
address->expiry_preferred_msec,
|
||||
TRUE));
|
||||
prefix->nd_opt_pi_prefix.s6_addr32[0] = address->address.s6_addr32[0];
|
||||
prefix->nd_opt_pi_prefix.s6_addr32[1] = address->address.s6_addr32[1];
|
||||
prefix->nd_opt_pi_prefix.s6_addr32[2] = 0;
|
||||
|
|
|
|||
|
|
@ -21,14 +21,15 @@ struct _NMNDiscDataInternal {
|
|||
|
||||
typedef struct _NMNDiscDataInternal NMNDiscDataInternal;
|
||||
|
||||
void nm_ndisc_ra_received(NMNDisc *ndisc, gint32 now, NMNDiscConfigMap changed);
|
||||
void nm_ndisc_ra_received(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap changed);
|
||||
void nm_ndisc_rs_received(NMNDisc *ndisc);
|
||||
|
||||
gboolean nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *new);
|
||||
gboolean nm_ndisc_complete_and_add_address(NMNDisc *ndisc, const NMNDiscAddress *new, gint32 now_s);
|
||||
gboolean nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new);
|
||||
gboolean nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new);
|
||||
gboolean nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new);
|
||||
gboolean nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *new_item, gint64 now_msec);
|
||||
gboolean
|
||||
nm_ndisc_complete_and_add_address(NMNDisc *ndisc, const NMNDiscAddress *new_item, gint64 now_msec);
|
||||
gboolean nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new_item, gint64 now_msec);
|
||||
gboolean nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new_item, gint64 now_msec);
|
||||
gboolean nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new_item, gint64 now_msec);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ struct _NMNDiscPrivate {
|
|||
gint32 last_rs;
|
||||
gint32 last_ra;
|
||||
};
|
||||
guint timeout_id; /* prefix/dns/etc lifetime timeout */
|
||||
|
||||
GSource *timeout_expire_source;
|
||||
|
||||
NMUtilsIPv6IfaceId iid;
|
||||
|
||||
/* immutable values: */
|
||||
|
|
@ -84,7 +86,8 @@ G_DEFINE_TYPE(NMNDisc, nm_ndisc, G_TYPE_OBJECT)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed);
|
||||
static void _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed);
|
||||
static gboolean timeout_expire_cb(gpointer user_data);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -102,6 +105,7 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx,
|
|||
guint32 ifa_flags;
|
||||
guint8 plen;
|
||||
guint i;
|
||||
const gint32 now_sec = nm_utils_get_monotonic_timestamp_sec();
|
||||
|
||||
l3cd = nm_l3_config_data_new(multi_idx, ifindex);
|
||||
|
||||
|
|
@ -129,12 +133,17 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx,
|
|||
NMPlatformIP6Address a;
|
||||
|
||||
a = (NMPlatformIP6Address){
|
||||
.ifindex = ifindex,
|
||||
.address = ndisc_addr->address,
|
||||
.plen = plen,
|
||||
.timestamp = ndisc_addr->timestamp,
|
||||
.lifetime = ndisc_addr->lifetime,
|
||||
.preferred = MIN(ndisc_addr->lifetime, ndisc_addr->preferred),
|
||||
.ifindex = ifindex,
|
||||
.address = ndisc_addr->address,
|
||||
.plen = plen,
|
||||
.timestamp = now_sec,
|
||||
.lifetime = _nm_ndisc_lifetime_from_expiry(((gint64) now_sec) * 1000,
|
||||
ndisc_addr->expiry_msec,
|
||||
TRUE),
|
||||
.preferred = _nm_ndisc_lifetime_from_expiry(
|
||||
((gint64) now_sec) * 1000,
|
||||
NM_MIN(ndisc_addr->expiry_msec, ndisc_addr->expiry_preferred_msec),
|
||||
TRUE),
|
||||
.addr_source = NM_IP_CONFIG_SOURCE_NDISC,
|
||||
.n_ifa_flags = ifa_flags,
|
||||
};
|
||||
|
|
@ -220,68 +229,40 @@ _preference_to_priority(NMIcmpv6RouterPref pref)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* we rely on the fact, that _EXPIRY_INFINITY > any other valid gint64 timestamps. */
|
||||
#define _EXPIRY_INFINITY G_MAXINT64
|
||||
|
||||
static gint64
|
||||
get_expiry_time(guint32 timestamp, guint32 lifetime)
|
||||
{
|
||||
nm_assert(timestamp > 0);
|
||||
nm_assert(timestamp <= G_MAXINT32);
|
||||
|
||||
if (lifetime == NM_NDISC_INFINITY)
|
||||
return _EXPIRY_INFINITY;
|
||||
return ((gint64) timestamp) + ((gint64) lifetime);
|
||||
}
|
||||
|
||||
#define get_expiry(item) \
|
||||
({ \
|
||||
typeof(item) _item = (item); \
|
||||
nm_assert(_item); \
|
||||
get_expiry_time(_item->timestamp, _item->lifetime); \
|
||||
})
|
||||
|
||||
#define get_expiry_preferred(item) \
|
||||
({ \
|
||||
typeof(item) _item = (item); \
|
||||
nm_assert(_item); \
|
||||
get_expiry_time(_item->timestamp, _item->preferred); \
|
||||
})
|
||||
|
||||
static gboolean
|
||||
expiry_next(gint32 now_s, gint64 expiry_timestamp, gint32 *nextevent)
|
||||
expiry_next(gint64 now_msec, gint64 expiry_msec, gint64 *next_msec)
|
||||
{
|
||||
gint32 e;
|
||||
|
||||
if (expiry_timestamp == _EXPIRY_INFINITY)
|
||||
if (expiry_msec == NM_NDISC_EXPIRY_INFINITY)
|
||||
return TRUE;
|
||||
e = MIN(expiry_timestamp, ((gint64)(G_MAXINT32 - 1)));
|
||||
if (now_s >= e)
|
||||
|
||||
if (expiry_msec <= now_msec) {
|
||||
/* expired. */
|
||||
return FALSE;
|
||||
if (nextevent) {
|
||||
if (*nextevent > e)
|
||||
*nextevent = e;
|
||||
}
|
||||
|
||||
if (next_msec) {
|
||||
if (*next_msec > expiry_msec)
|
||||
*next_msec = expiry_msec;
|
||||
}
|
||||
|
||||
/* the timestamp is good (not yet expired) */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
_get_exp(char *buf, gsize buf_size, gint64 now_ns, gint64 expiry_time)
|
||||
_get_exp(char *buf, gsize buf_size, gint64 now_msec, gint64 expiry_time)
|
||||
{
|
||||
int l;
|
||||
|
||||
if (expiry_time == _EXPIRY_INFINITY)
|
||||
if (expiry_time == NM_NDISC_EXPIRY_INFINITY)
|
||||
return "permanent";
|
||||
l = g_snprintf(buf,
|
||||
buf_size,
|
||||
"%.4f",
|
||||
((double) ((expiry_time * NM_UTILS_NSEC_PER_SEC) - now_ns))
|
||||
/ ((double) NM_UTILS_NSEC_PER_SEC));
|
||||
l = g_snprintf(buf, buf_size, "%.3f", ((double) (expiry_time - now_msec)) / 1000);
|
||||
nm_assert(l < buf_size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define get_exp(buf, now_ns, item) _get_exp((buf), G_N_ELEMENTS(buf), (now_ns), (get_expiry(item)))
|
||||
#define get_exp(buf, now_msec, item) \
|
||||
_get_exp((buf), G_N_ELEMENTS(buf), (now_msec), (item)->expiry_msec)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -352,17 +333,16 @@ _ASSERT_data_gateways(const NMNDiscDataInternal *data)
|
|||
const NMNDiscGateway *item = &g_array_index(data->gateways, NMNDiscGateway, i);
|
||||
|
||||
nm_assert(!IN6_IS_ADDR_UNSPECIFIED(&item->address));
|
||||
nm_assert(item->timestamp > 0 && item->timestamp <= G_MAXINT32);
|
||||
for (j = 0; j < i; j++) {
|
||||
const NMNDiscGateway *item2 = &g_array_index(data->gateways, NMNDiscGateway, j);
|
||||
|
||||
nm_assert(!IN6_ARE_ADDR_EQUAL(&item->address, &item2->address));
|
||||
}
|
||||
|
||||
nm_assert(item->lifetime > 0);
|
||||
if (i > 0)
|
||||
if (i > 0) {
|
||||
nm_assert(_preference_to_priority(item_prev->preference)
|
||||
>= _preference_to_priority(item->preference));
|
||||
}
|
||||
|
||||
item_prev = item;
|
||||
}
|
||||
|
|
@ -408,7 +388,7 @@ nm_ndisc_emit_config_change(NMNDisc *self, NMNDiscConfigMap changed)
|
|||
/*****************************************************************************/
|
||||
|
||||
gboolean
|
||||
nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *new)
|
||||
nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *new_item, gint64 now_msec)
|
||||
{
|
||||
NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
guint i;
|
||||
|
|
@ -417,41 +397,43 @@ nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *new)
|
|||
for (i = 0; i < rdata->gateways->len;) {
|
||||
NMNDiscGateway *item = &g_array_index(rdata->gateways, NMNDiscGateway, i);
|
||||
|
||||
if (IN6_ARE_ADDR_EQUAL(&item->address, &new->address)) {
|
||||
if (new->lifetime == 0) {
|
||||
if (IN6_ARE_ADDR_EQUAL(&item->address, &new_item->address)) {
|
||||
if (new_item->expiry_msec <= now_msec) {
|
||||
g_array_remove_index(rdata->gateways, i);
|
||||
_ASSERT_data_gateways(rdata);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (item->preference != new->preference) {
|
||||
if (item->preference != new_item->preference) {
|
||||
g_array_remove_index(rdata->gateways, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (get_expiry(item) == get_expiry(new))
|
||||
if (item->expiry_msec == new_item->expiry_msec)
|
||||
return FALSE;
|
||||
|
||||
*item = *new;
|
||||
item->expiry_msec = new_item->expiry_msec;
|
||||
_ASSERT_data_gateways(rdata);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Put before less preferable gateways. */
|
||||
if (_preference_to_priority(item->preference) < _preference_to_priority(new->preference)
|
||||
if (_preference_to_priority(item->preference)
|
||||
< _preference_to_priority(new_item->preference)
|
||||
&& insert_idx == G_MAXUINT)
|
||||
insert_idx = i;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (new->lifetime) {
|
||||
g_array_insert_val(rdata->gateways,
|
||||
insert_idx == G_MAXUINT ? rdata->gateways->len : insert_idx,
|
||||
*new);
|
||||
}
|
||||
if (new_item->expiry_msec <= now_msec)
|
||||
return FALSE;
|
||||
|
||||
g_array_insert_val(rdata->gateways,
|
||||
insert_idx == G_MAXUINT ? rdata->gateways->len : insert_idx,
|
||||
*new_item);
|
||||
_ASSERT_data_gateways(rdata);
|
||||
return !!new->lifetime;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -504,25 +486,27 @@ complete_address(NMNDisc *ndisc, NMNDiscAddress *addr)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
_LOGW("complete-address: can't generate a new EUI-64 address");
|
||||
_LOGW("complete-address: can't generate a new_item EUI-64 address");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
nm_ndisc_add_address(NMNDisc *ndisc, const NMNDiscAddress *new, gint32 now_s, gboolean from_ra)
|
||||
nm_ndisc_add_address(NMNDisc * ndisc,
|
||||
const NMNDiscAddress *new_item,
|
||||
gint64 now_msec,
|
||||
gboolean from_ra)
|
||||
{
|
||||
NMNDiscPrivate * priv = NM_NDISC_GET_PRIVATE(ndisc);
|
||||
NMNDiscDataInternal *rdata = &priv->rdata;
|
||||
NMNDiscAddress new2;
|
||||
NMNDiscAddress * new2;
|
||||
NMNDiscAddress * existing = NULL;
|
||||
guint i;
|
||||
|
||||
nm_assert(new);
|
||||
nm_assert(new->timestamp > 0 && new->timestamp < G_MAXINT32);
|
||||
nm_assert(!IN6_IS_ADDR_UNSPECIFIED(&new->address));
|
||||
nm_assert(!IN6_IS_ADDR_LINKLOCAL(&new->address));
|
||||
nm_assert(new->preferred <= new->lifetime);
|
||||
nm_assert(!from_ra || now_s > 0);
|
||||
nm_assert(new_item);
|
||||
nm_assert(!IN6_IS_ADDR_UNSPECIFIED(&new_item->address));
|
||||
nm_assert(!IN6_IS_ADDR_LINKLOCAL(&new_item->address));
|
||||
nm_assert(new_item->expiry_preferred_msec <= new_item->expiry_msec);
|
||||
nm_assert((!!from_ra) == (now_msec > 0));
|
||||
|
||||
for (i = 0; i < rdata->addresses->len; i++) {
|
||||
NMNDiscAddress *item = &g_array_index(rdata->addresses, NMNDiscAddress, i);
|
||||
|
|
@ -530,12 +514,12 @@ nm_ndisc_add_address(NMNDisc *ndisc, const NMNDiscAddress *new, gint32 now_s, gb
|
|||
if (from_ra) {
|
||||
/* RFC4862 5.5.3.d, we find an existing address with the same prefix.
|
||||
* (note that all prefixes at this point have implicitly length /64). */
|
||||
if (memcmp(&item->address, &new->address, 8) == 0) {
|
||||
if (memcmp(&item->address, &new_item->address, 8) == 0) {
|
||||
existing = item;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (IN6_ARE_ADDR_EQUAL(&item->address, &new->address)) {
|
||||
if (IN6_ARE_ADDR_EQUAL(&item->address, &new_item->address)) {
|
||||
existing = item;
|
||||
break;
|
||||
}
|
||||
|
|
@ -543,67 +527,60 @@ nm_ndisc_add_address(NMNDisc *ndisc, const NMNDiscAddress *new, gint32 now_s, gb
|
|||
}
|
||||
|
||||
if (existing) {
|
||||
gint64 new_expiry_preferred_msec;
|
||||
gint64 new_expiry_msec;
|
||||
|
||||
if (from_ra) {
|
||||
const gint32 NM_NDISC_PREFIX_LFT_MIN = 7200; /* seconds, RFC4862 5.5.3.e */
|
||||
gint64 old_expiry_lifetime, old_expiry_preferred;
|
||||
|
||||
old_expiry_lifetime = get_expiry(existing);
|
||||
old_expiry_preferred = get_expiry_preferred(existing);
|
||||
|
||||
if (new->lifetime == NM_NDISC_INFINITY)
|
||||
existing->lifetime = NM_NDISC_INFINITY;
|
||||
if (new_item->expiry_msec == NM_NDISC_EXPIRY_INFINITY)
|
||||
new_expiry_msec = NM_NDISC_EXPIRY_INFINITY;
|
||||
else {
|
||||
gint64 new_lifetime, remaining_lifetime;
|
||||
const gint64 NDISC_PREFIX_LFT_MIN_MSEC = 7200 * 1000; /* RFC4862 5.5.3.e */
|
||||
gint64 new_lifetime;
|
||||
gint64 existing_lifetime;
|
||||
|
||||
new_lifetime = new_item->expiry_msec - now_msec;
|
||||
if (existing->expiry_msec == NM_NDISC_EXPIRY_INFINITY)
|
||||
existing_lifetime = G_MAXINT64;
|
||||
else
|
||||
existing_lifetime = existing->expiry_msec - now_msec;
|
||||
|
||||
/* see RFC4862 5.5.3.e */
|
||||
if (existing->lifetime == NM_NDISC_INFINITY)
|
||||
remaining_lifetime = G_MAXINT64;
|
||||
else
|
||||
remaining_lifetime = ((gint64) existing->timestamp)
|
||||
+ ((gint64) existing->lifetime) - ((gint64) now_s);
|
||||
new_lifetime =
|
||||
((gint64) new->timestamp) + ((gint64) new->lifetime) - ((gint64) now_s);
|
||||
|
||||
if (new_lifetime > (gint64) NM_NDISC_PREFIX_LFT_MIN
|
||||
|| new_lifetime > remaining_lifetime) {
|
||||
existing->timestamp = now_s;
|
||||
existing->lifetime = CLAMP(new_lifetime, (gint64) 0, (gint64)(G_MAXUINT32 - 1));
|
||||
} else if (remaining_lifetime <= (gint64) NM_NDISC_PREFIX_LFT_MIN) {
|
||||
if (new_lifetime >= NDISC_PREFIX_LFT_MIN_MSEC
|
||||
|| new_lifetime >= existing_lifetime) {
|
||||
/* either extend the lifetime of the new_item lifetime is longer than
|
||||
* NDISC_PREFIX_LFT_MIN_MSEC. */
|
||||
new_expiry_msec = new_item->expiry_msec;
|
||||
} else if (existing_lifetime <= NDISC_PREFIX_LFT_MIN_MSEC) {
|
||||
/* keep the current lifetime. */
|
||||
new_expiry_msec = existing->expiry_msec;
|
||||
} else {
|
||||
existing->timestamp = now_s;
|
||||
existing->lifetime = NM_NDISC_PREFIX_LFT_MIN;
|
||||
/* trim the current lifetime to NDISC_PREFIX_LFT_MIN_MSEC. */
|
||||
new_expiry_msec = now_msec + NDISC_PREFIX_LFT_MIN_MSEC;
|
||||
}
|
||||
}
|
||||
|
||||
if (new->preferred == NM_NDISC_INFINITY) {
|
||||
nm_assert(existing->lifetime == NM_NDISC_INFINITY);
|
||||
existing->preferred = new->preferred;
|
||||
} else {
|
||||
existing->preferred = NM_CLAMP(((gint64) new->timestamp) + ((gint64) new->preferred)
|
||||
- ((gint64) existing->timestamp),
|
||||
0,
|
||||
G_MAXUINT32 - 1);
|
||||
if (existing->lifetime != NM_NDISC_INFINITY)
|
||||
existing->preferred = MIN(existing->preferred, existing->lifetime);
|
||||
new_expiry_preferred_msec =
|
||||
NM_MIN(new_item->expiry_preferred_msec, new_item->expiry_msec);
|
||||
new_expiry_preferred_msec = NM_MIN(new_expiry_preferred_msec, new_expiry_msec);
|
||||
} else {
|
||||
if (new_item->expiry_msec <= now_msec) {
|
||||
g_array_remove_index(rdata->addresses, i);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return old_expiry_lifetime != get_expiry(existing)
|
||||
|| old_expiry_preferred != get_expiry_preferred(existing);
|
||||
new_expiry_msec = new_item->expiry_msec;
|
||||
new_expiry_preferred_msec =
|
||||
NM_MIN(new_item->expiry_preferred_msec, new_item->expiry_msec);
|
||||
}
|
||||
|
||||
if (new->lifetime == 0) {
|
||||
g_array_remove_index(rdata->addresses, i);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (get_expiry(existing) == get_expiry(new)
|
||||
&& get_expiry_preferred(existing) == get_expiry_preferred(new))
|
||||
/* the dad_counter does not get modified. */
|
||||
if (new_expiry_msec == existing->expiry_msec
|
||||
&& new_expiry_preferred_msec == existing->expiry_preferred_msec) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
existing->timestamp = new->timestamp;
|
||||
existing->lifetime = new->lifetime;
|
||||
existing->preferred = new->preferred;
|
||||
existing->expiry_msec = new_expiry_msec;
|
||||
existing->expiry_preferred_msec = new_expiry_preferred_msec;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -614,36 +591,42 @@ nm_ndisc_add_address(NMNDisc *ndisc, const NMNDiscAddress *new, gint32 now_s, gb
|
|||
if (priv->max_addresses && rdata->addresses->len >= priv->max_addresses)
|
||||
return FALSE;
|
||||
|
||||
if (new->lifetime == 0)
|
||||
if (new_item->expiry_msec <= now_msec)
|
||||
return FALSE;
|
||||
|
||||
new2 = nm_g_array_append_new(rdata->addresses, NMNDiscAddress);
|
||||
|
||||
*new2 = *new_item;
|
||||
|
||||
new2->expiry_preferred_msec = NM_MIN(new2->expiry_preferred_msec, new2->expiry_msec);
|
||||
|
||||
if (from_ra) {
|
||||
new2 = *new;
|
||||
new2.dad_counter = 0;
|
||||
if (!complete_address(ndisc, &new2))
|
||||
new2->dad_counter = 0;
|
||||
if (!complete_address(ndisc, new2)) {
|
||||
g_array_set_size(rdata->addresses, rdata->addresses->len - 1);
|
||||
return FALSE;
|
||||
new = &new2;
|
||||
}
|
||||
}
|
||||
|
||||
g_array_append_val(rdata->addresses, *new);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_ndisc_complete_and_add_address(NMNDisc *ndisc, const NMNDiscAddress *new, gint32 now_s)
|
||||
nm_ndisc_complete_and_add_address(NMNDisc *ndisc, const NMNDiscAddress *new_item, gint64 now_msec)
|
||||
{
|
||||
return nm_ndisc_add_address(ndisc, new, now_s, TRUE);
|
||||
return nm_ndisc_add_address(ndisc, new_item, now_msec, TRUE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new)
|
||||
nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new_item, gint64 now_msec)
|
||||
{
|
||||
NMNDiscPrivate * priv;
|
||||
NMNDiscDataInternal *rdata;
|
||||
guint i;
|
||||
guint insert_idx = G_MAXUINT;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
if (new->plen == 0 || new->plen > 128) {
|
||||
if (new_item->plen == 0 || new_item->plen > 128) {
|
||||
/* Only expect non-default routes. The router has no idea what the
|
||||
* local configuration or user preferences are, so sending routes
|
||||
* with a prefix length of 0 must be ignored by NMNDisc.
|
||||
|
|
@ -660,41 +643,48 @@ nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new)
|
|||
for (i = 0; i < rdata->routes->len;) {
|
||||
NMNDiscRoute *item = &g_array_index(rdata->routes, NMNDiscRoute, i);
|
||||
|
||||
if (IN6_ARE_ADDR_EQUAL(&item->network, &new->network) && item->plen == new->plen) {
|
||||
if (new->lifetime == 0) {
|
||||
if (IN6_ARE_ADDR_EQUAL(&item->network, &new_item->network)
|
||||
&& item->plen == new_item->plen) {
|
||||
if (new_item->expiry_msec <= now_msec) {
|
||||
g_array_remove_index(rdata->routes, i);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (item->preference != new->preference) {
|
||||
if (item->preference != new_item->preference) {
|
||||
g_array_remove_index(rdata->routes, i);
|
||||
changed = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (get_expiry(item) == get_expiry(new)
|
||||
&& IN6_ARE_ADDR_EQUAL(&item->gateway, &new->gateway))
|
||||
if (item->expiry_msec == new_item->expiry_msec
|
||||
&& IN6_ARE_ADDR_EQUAL(&item->gateway, &new_item->gateway))
|
||||
return FALSE;
|
||||
|
||||
*item = *new;
|
||||
item->expiry_msec = new_item->expiry_msec;
|
||||
item->gateway = new_item->gateway;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Put before less preferable routes. */
|
||||
if (_preference_to_priority(item->preference) < _preference_to_priority(new->preference)
|
||||
if (_preference_to_priority(item->preference)
|
||||
< _preference_to_priority(new_item->preference)
|
||||
&& insert_idx == G_MAXUINT)
|
||||
insert_idx = i;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (new->lifetime) {
|
||||
g_array_insert_val(rdata->routes, insert_idx == G_MAXUINT ? 0u : insert_idx, *new);
|
||||
if (new_item->expiry_msec <= now_msec) {
|
||||
nm_assert(!changed);
|
||||
return FALSE;
|
||||
}
|
||||
return !!new->lifetime;
|
||||
|
||||
g_array_insert_val(rdata->routes, insert_idx == G_MAXUINT ? 0u : insert_idx, *new_item);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new)
|
||||
nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new_item, gint64 now_msec)
|
||||
{
|
||||
NMNDiscPrivate * priv;
|
||||
NMNDiscDataInternal *rdata;
|
||||
|
|
@ -706,28 +696,30 @@ nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new)
|
|||
for (i = 0; i < rdata->dns_servers->len; i++) {
|
||||
NMNDiscDNSServer *item = &g_array_index(rdata->dns_servers, NMNDiscDNSServer, i);
|
||||
|
||||
if (IN6_ARE_ADDR_EQUAL(&item->address, &new->address)) {
|
||||
if (new->lifetime == 0) {
|
||||
if (IN6_ARE_ADDR_EQUAL(&item->address, &new_item->address)) {
|
||||
if (new_item->expiry_msec <= now_msec) {
|
||||
g_array_remove_index(rdata->dns_servers, i);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (get_expiry(item) == get_expiry(new))
|
||||
if (item->expiry_msec == new_item->expiry_msec)
|
||||
return FALSE;
|
||||
|
||||
*item = *new;
|
||||
item->expiry_msec = new_item->expiry_msec;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (new->lifetime)
|
||||
g_array_append_val(rdata->dns_servers, *new);
|
||||
return !!new->lifetime;
|
||||
if (new_item->expiry_msec <= now_msec)
|
||||
return FALSE;
|
||||
|
||||
g_array_append_val(rdata->dns_servers, *new_item);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Copies new->domain if 'new' is added to the dns_domains list */
|
||||
/* Copies new_item->domain if 'new_item' is added to the dns_domains list */
|
||||
gboolean
|
||||
nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new)
|
||||
nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new_item, gint64 now_msec)
|
||||
{
|
||||
NMNDiscPrivate * priv;
|
||||
NMNDiscDataInternal *rdata;
|
||||
|
|
@ -740,43 +732,45 @@ nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new)
|
|||
for (i = 0; i < rdata->dns_domains->len; i++) {
|
||||
item = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i);
|
||||
|
||||
if (!g_strcmp0(item->domain, new->domain)) {
|
||||
if (new->lifetime == 0) {
|
||||
if (nm_streq(item->domain, new_item->domain)) {
|
||||
if (new_item->expiry_msec <= now_msec) {
|
||||
g_array_remove_index(rdata->dns_domains, i);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (get_expiry(item) == get_expiry(new))
|
||||
if (item->expiry_msec == new_item->expiry_msec)
|
||||
return FALSE;
|
||||
|
||||
item->timestamp = new->timestamp;
|
||||
item->lifetime = new->lifetime;
|
||||
item->expiry_msec = new_item->expiry_msec;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (new->lifetime) {
|
||||
g_array_append_val(rdata->dns_domains, *new);
|
||||
item = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, rdata->dns_domains->len - 1);
|
||||
item->domain = g_strdup(new->domain);
|
||||
}
|
||||
return !!new->lifetime;
|
||||
if (new_item->expiry_msec <= now_msec)
|
||||
return FALSE;
|
||||
|
||||
item = nm_g_array_append_new(rdata->dns_domains, NMNDiscDNSDomain);
|
||||
*item = (NMNDiscDNSDomain){
|
||||
.domain = g_strdup(new_item->domain),
|
||||
.expiry_msec = new_item->expiry_msec,
|
||||
};
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define _MAYBE_WARN(...) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
gboolean _different_message; \
|
||||
\
|
||||
_different_message = g_strcmp0(priv->last_error, error->message) != 0; \
|
||||
_NMLOG(_different_message ? LOGL_WARN : LOGL_DEBUG, __VA_ARGS__); \
|
||||
if (_different_message) { \
|
||||
nm_clear_g_free(&priv->last_error); \
|
||||
priv->last_error = g_strdup(error->message); \
|
||||
} \
|
||||
} \
|
||||
#define _MAYBE_WARN(...) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
gboolean _different_message; \
|
||||
\
|
||||
_different_message = !nm_streq0(priv->last_error, error->message); \
|
||||
_NMLOG(_different_message ? LOGL_WARN : LOGL_DEBUG, __VA_ARGS__); \
|
||||
if (_different_message) { \
|
||||
nm_clear_g_free(&priv->last_error); \
|
||||
priv->last_error = g_strdup(error->message); \
|
||||
} \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
static gboolean
|
||||
|
|
@ -937,12 +931,16 @@ nm_ndisc_set_config(NMNDisc * ndisc,
|
|||
}
|
||||
|
||||
for (i = 0; i < dns_servers->len; i++) {
|
||||
if (nm_ndisc_add_dns_server(ndisc, &g_array_index(dns_servers, NMNDiscDNSServer, i)))
|
||||
if (nm_ndisc_add_dns_server(ndisc,
|
||||
&g_array_index(dns_servers, NMNDiscDNSServer, i),
|
||||
G_MININT64))
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < dns_domains->len; i++) {
|
||||
if (nm_ndisc_add_dns_domain(ndisc, &g_array_index(dns_domains, NMNDiscDNSDomain, i)))
|
||||
if (nm_ndisc_add_dns_domain(ndisc,
|
||||
&g_array_index(dns_domains, NMNDiscDNSDomain, i),
|
||||
G_MININT64))
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1098,7 +1096,7 @@ nm_ndisc_stop(NMNDisc *ndisc)
|
|||
nm_clear_g_source(&priv->send_rs_id);
|
||||
nm_clear_g_source(&priv->send_ra_id);
|
||||
nm_clear_g_free(&priv->last_error);
|
||||
nm_clear_g_source(&priv->timeout_id);
|
||||
nm_clear_g_source_inst(&priv->timeout_expire_source);
|
||||
|
||||
priv->solicitations_left = 0;
|
||||
priv->announcements_left = 0;
|
||||
|
|
@ -1180,15 +1178,15 @@ _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed)
|
|||
NMNDiscDataInternal *rdata;
|
||||
guint i;
|
||||
char changedstr[CONFIG_MAP_MAX_STR];
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
char addrstr[NM_UTILS_INET_ADDRSTRLEN];
|
||||
char str_pref[35];
|
||||
char str_exp[100];
|
||||
gint64 now_ns;
|
||||
gint64 now_msec;
|
||||
|
||||
if (!_LOGD_ENABLED())
|
||||
return;
|
||||
|
||||
now_ns = nm_utils_get_monotonic_timestamp_nsec();
|
||||
now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
|
||||
priv = NM_NDISC_GET_PRIVATE(ndisc);
|
||||
rdata = &priv->rdata;
|
||||
|
|
@ -1205,199 +1203,245 @@ _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed)
|
|||
_LOGD(" retrans timer : %u", (guint) rdata->public.retrans_timer_ms);
|
||||
|
||||
for (i = 0; i < rdata->gateways->len; i++) {
|
||||
NMNDiscGateway *gateway = &g_array_index(rdata->gateways, NMNDiscGateway, i);
|
||||
const NMNDiscGateway *gateway = &g_array_index(rdata->gateways, NMNDiscGateway, i);
|
||||
|
||||
inet_ntop(AF_INET6, &gateway->address, addrstr, sizeof(addrstr));
|
||||
_LOGD(" gateway %s pref %s exp %s",
|
||||
addrstr,
|
||||
_nm_utils_inet6_ntop(&gateway->address, addrstr),
|
||||
nm_icmpv6_router_pref_to_string(gateway->preference, str_pref, sizeof(str_pref)),
|
||||
get_exp(str_exp, now_ns, gateway));
|
||||
get_exp(str_exp, now_msec, gateway));
|
||||
}
|
||||
for (i = 0; i < rdata->addresses->len; i++) {
|
||||
const NMNDiscAddress *address = &g_array_index(rdata->addresses, NMNDiscAddress, i);
|
||||
|
||||
inet_ntop(AF_INET6, &address->address, addrstr, sizeof(addrstr));
|
||||
_LOGD(" address %s exp %s", addrstr, get_exp(str_exp, now_ns, address));
|
||||
_LOGD(" address %s exp %s",
|
||||
_nm_utils_inet6_ntop(&address->address, addrstr),
|
||||
get_exp(str_exp, now_msec, address));
|
||||
}
|
||||
for (i = 0; i < rdata->routes->len; i++) {
|
||||
NMNDiscRoute *route = &g_array_index(rdata->routes, NMNDiscRoute, i);
|
||||
char sbuf[NM_UTILS_INET_ADDRSTRLEN];
|
||||
const NMNDiscRoute *route = &g_array_index(rdata->routes, NMNDiscRoute, i);
|
||||
char sbuf[NM_UTILS_INET_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET6, &route->network, addrstr, sizeof(addrstr));
|
||||
_LOGD(" route %s/%u via %s pref %s exp %s",
|
||||
addrstr,
|
||||
_nm_utils_inet6_ntop(&route->network, addrstr),
|
||||
(guint) route->plen,
|
||||
_nm_utils_inet6_ntop(&route->gateway, sbuf),
|
||||
nm_icmpv6_router_pref_to_string(route->preference, str_pref, sizeof(str_pref)),
|
||||
get_exp(str_exp, now_ns, route));
|
||||
get_exp(str_exp, now_msec, route));
|
||||
}
|
||||
for (i = 0; i < rdata->dns_servers->len; i++) {
|
||||
NMNDiscDNSServer *dns_server = &g_array_index(rdata->dns_servers, NMNDiscDNSServer, i);
|
||||
const NMNDiscDNSServer *dns_server =
|
||||
&g_array_index(rdata->dns_servers, NMNDiscDNSServer, i);
|
||||
|
||||
inet_ntop(AF_INET6, &dns_server->address, addrstr, sizeof(addrstr));
|
||||
_LOGD(" dns_server %s exp %s", addrstr, get_exp(str_exp, now_ns, dns_server));
|
||||
_LOGD(" dns_server %s exp %s",
|
||||
_nm_utils_inet6_ntop(&dns_server->address, addrstr),
|
||||
get_exp(str_exp, now_msec, dns_server));
|
||||
}
|
||||
for (i = 0; i < rdata->dns_domains->len; i++) {
|
||||
NMNDiscDNSDomain *dns_domain = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i);
|
||||
const NMNDiscDNSDomain *dns_domain =
|
||||
&g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i);
|
||||
|
||||
_LOGD(" dns_domain %s exp %s", dns_domain->domain, get_exp(str_exp, now_ns, dns_domain));
|
||||
_LOGD(" dns_domain %s exp %s", dns_domain->domain, get_exp(str_exp, now_msec, dns_domain));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
clean_gateways(NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 *nextevent)
|
||||
clean_gateways(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec)
|
||||
{
|
||||
NMNDiscDataInternal *rdata;
|
||||
NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
NMNDiscGateway * arr;
|
||||
guint i;
|
||||
guint j;
|
||||
|
||||
rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
if (rdata->gateways->len == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < rdata->gateways->len;) {
|
||||
NMNDiscGateway *item = &g_array_index(rdata->gateways, NMNDiscGateway, i);
|
||||
arr = &g_array_index(rdata->gateways, NMNDiscGateway, 0);
|
||||
|
||||
if (!expiry_next(now, get_expiry(item), nextevent)) {
|
||||
g_array_remove_index(rdata->gateways, i);
|
||||
*changed |= NM_NDISC_CONFIG_GATEWAYS;
|
||||
for (i = 0, j = 0; i < rdata->gateways->len; i++) {
|
||||
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec))
|
||||
continue;
|
||||
}
|
||||
if (i != j)
|
||||
arr[j] = arr[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
i++;
|
||||
if (i != j) {
|
||||
*changed |= NM_NDISC_CONFIG_GATEWAYS;
|
||||
g_array_set_size(rdata->gateways, j);
|
||||
}
|
||||
|
||||
_ASSERT_data_gateways(rdata);
|
||||
}
|
||||
|
||||
static void
|
||||
clean_addresses(NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 *nextevent)
|
||||
clean_addresses(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec)
|
||||
{
|
||||
NMNDiscDataInternal *rdata;
|
||||
NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
NMNDiscAddress * arr;
|
||||
guint i;
|
||||
guint j;
|
||||
|
||||
rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
if (rdata->addresses->len == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < rdata->addresses->len;) {
|
||||
const NMNDiscAddress *item = &g_array_index(rdata->addresses, NMNDiscAddress, i);
|
||||
arr = &g_array_index(rdata->addresses, NMNDiscAddress, 0);
|
||||
|
||||
if (!expiry_next(now, get_expiry(item), nextevent)) {
|
||||
g_array_remove_index(rdata->addresses, i);
|
||||
*changed |= NM_NDISC_CONFIG_ADDRESSES;
|
||||
for (i = 0, j = 0; i < rdata->addresses->len; i++) {
|
||||
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec))
|
||||
continue;
|
||||
}
|
||||
if (i != j)
|
||||
arr[j] = arr[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
i++;
|
||||
if (i != j) {
|
||||
*changed = NM_NDISC_CONFIG_ADDRESSES;
|
||||
g_array_set_size(rdata->addresses, j);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clean_routes(NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 *nextevent)
|
||||
clean_routes(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec)
|
||||
{
|
||||
NMNDiscDataInternal *rdata;
|
||||
NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
NMNDiscRoute * arr;
|
||||
guint i;
|
||||
guint j;
|
||||
|
||||
rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
if (rdata->routes->len == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < rdata->routes->len;) {
|
||||
NMNDiscRoute *item = &g_array_index(rdata->routes, NMNDiscRoute, i);
|
||||
arr = &g_array_index(rdata->routes, NMNDiscRoute, 0);
|
||||
|
||||
if (!expiry_next(now, get_expiry(item), nextevent)) {
|
||||
g_array_remove_index(rdata->routes, i);
|
||||
*changed |= NM_NDISC_CONFIG_ROUTES;
|
||||
for (i = 0, j = 0; i < rdata->routes->len; i++) {
|
||||
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec))
|
||||
continue;
|
||||
}
|
||||
if (i != j)
|
||||
arr[j] = arr[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
i++;
|
||||
if (i != j) {
|
||||
*changed |= NM_NDISC_CONFIG_ROUTES;
|
||||
g_array_set_size(rdata->routes, j);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clean_dns_servers(NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 *nextevent)
|
||||
clean_dns_servers(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec)
|
||||
{
|
||||
NMNDiscDataInternal *rdata;
|
||||
NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
NMNDiscDNSServer * arr;
|
||||
guint i;
|
||||
guint j;
|
||||
|
||||
rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
if (rdata->dns_servers->len == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < rdata->dns_servers->len;) {
|
||||
NMNDiscDNSServer *item = &g_array_index(rdata->dns_servers, NMNDiscDNSServer, i);
|
||||
arr = &g_array_index(rdata->dns_servers, NMNDiscDNSServer, 0);
|
||||
|
||||
if (!expiry_next(now, get_expiry(item), nextevent)) {
|
||||
g_array_remove_index(rdata->dns_servers, i);
|
||||
*changed |= NM_NDISC_CONFIG_DNS_SERVERS;
|
||||
for (i = 0, j = 0; i < rdata->dns_servers->len; i++) {
|
||||
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec))
|
||||
continue;
|
||||
}
|
||||
if (i != j)
|
||||
arr[j] = arr[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
i++;
|
||||
if (i != j) {
|
||||
*changed |= NM_NDISC_CONFIG_DNS_SERVERS;
|
||||
g_array_set_size(rdata->dns_servers, j);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clean_dns_domains(NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 *nextevent)
|
||||
clean_dns_domains(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec)
|
||||
{
|
||||
NMNDiscDataInternal *rdata;
|
||||
NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
NMNDiscDNSDomain * arr;
|
||||
guint i;
|
||||
guint j;
|
||||
|
||||
rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
if (rdata->dns_domains->len == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < rdata->dns_domains->len;) {
|
||||
NMNDiscDNSDomain *item = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i);
|
||||
arr = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, 0);
|
||||
|
||||
if (!expiry_next(now, get_expiry(item), nextevent)) {
|
||||
g_array_remove_index(rdata->dns_domains, i);
|
||||
*changed |= NM_NDISC_CONFIG_DNS_DOMAINS;
|
||||
for (i = 0, j = 0; i < rdata->dns_domains->len; i++) {
|
||||
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec))
|
||||
continue;
|
||||
|
||||
if (i != j) {
|
||||
g_free(arr[j].domain);
|
||||
arr[j] = arr[i];
|
||||
arr[i].domain = NULL;
|
||||
}
|
||||
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
*changed |= NM_NDISC_CONFIG_DNS_DOMAINS;
|
||||
g_array_set_size(rdata->dns_domains, j);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean timeout_cb(gpointer user_data);
|
||||
|
||||
static void
|
||||
check_timestamps(NMNDisc *ndisc, gint32 now, NMNDiscConfigMap changed)
|
||||
check_timestamps(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap changed)
|
||||
{
|
||||
NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc);
|
||||
/* Use a magic date in the distant future (~68 years) */
|
||||
gint32 nextevent = G_MAXINT32;
|
||||
NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc);
|
||||
gint64 next_msec = G_MAXINT64;
|
||||
|
||||
nm_clear_g_source(&priv->timeout_id);
|
||||
_LOGT("router-data: check for changed router advertisement data");
|
||||
|
||||
clean_gateways(ndisc, now, &changed, &nextevent);
|
||||
clean_addresses(ndisc, now, &changed, &nextevent);
|
||||
clean_routes(ndisc, now, &changed, &nextevent);
|
||||
clean_dns_servers(ndisc, now, &changed, &nextevent);
|
||||
clean_dns_domains(ndisc, now, &changed, &nextevent);
|
||||
clean_gateways(ndisc, now_msec, &changed, &next_msec);
|
||||
clean_addresses(ndisc, now_msec, &changed, &next_msec);
|
||||
clean_routes(ndisc, now_msec, &changed, &next_msec);
|
||||
clean_dns_servers(ndisc, now_msec, &changed, &next_msec);
|
||||
clean_dns_domains(ndisc, now_msec, &changed, &next_msec);
|
||||
|
||||
if (nextevent != G_MAXINT32) {
|
||||
if (nextevent <= now)
|
||||
g_return_if_reached();
|
||||
_LOGD("scheduling next now/lifetime check: %d seconds", (int) (nextevent - now));
|
||||
priv->timeout_id = g_timeout_add_seconds(nextevent - now, timeout_cb, ndisc);
|
||||
nm_assert(next_msec > now_msec);
|
||||
|
||||
nm_clear_g_source_inst(&priv->timeout_expire_source);
|
||||
|
||||
if (next_msec == NM_NDISC_EXPIRY_INFINITY)
|
||||
_LOGD("router-data: next lifetime expiration will happen: never");
|
||||
else {
|
||||
const gint64 timeout_msec = NM_MIN(next_msec - now_msec, ((gint64) G_MAXINT32));
|
||||
const guint TIMEOUT_APPROX_THRESHOLD_SEC = 10000;
|
||||
|
||||
_LOGD("router-data: next lifetime expiration will happen: in %s%.3f seconds",
|
||||
(timeout_msec / 1000) >= TIMEOUT_APPROX_THRESHOLD_SEC ? " about" : "",
|
||||
((double) timeout_msec) / 1000);
|
||||
|
||||
priv->timeout_expire_source = nm_g_timeout_add_source_approx(timeout_msec,
|
||||
TIMEOUT_APPROX_THRESHOLD_SEC,
|
||||
timeout_expire_cb,
|
||||
ndisc);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
if (changed != NM_NDISC_CONFIG_NONE)
|
||||
nm_ndisc_emit_config_change(ndisc, changed);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
timeout_cb(gpointer user_data)
|
||||
timeout_expire_cb(gpointer user_data)
|
||||
{
|
||||
NMNDisc *self = user_data;
|
||||
|
||||
NM_NDISC_GET_PRIVATE(self)->timeout_id = 0;
|
||||
check_timestamps(self, nm_utils_get_monotonic_timestamp_sec(), 0);
|
||||
return G_SOURCE_REMOVE;
|
||||
check_timestamps(user_data, nm_utils_get_monotonic_timestamp_msec(), NM_NDISC_CONFIG_NONE);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
void
|
||||
nm_ndisc_ra_received(NMNDisc *ndisc, gint32 now, NMNDiscConfigMap changed)
|
||||
nm_ndisc_ra_received(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap changed)
|
||||
{
|
||||
NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc);
|
||||
|
||||
nm_clear_g_source_inst(&priv->ra_timeout_source);
|
||||
nm_clear_g_source(&priv->send_rs_id);
|
||||
nm_clear_g_free(&priv->last_error);
|
||||
check_timestamps(ndisc, now, changed);
|
||||
check_timestamps(ndisc, now_msec, changed);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1525,7 +1569,7 @@ dispose(GObject *object)
|
|||
nm_clear_g_source(&priv->send_ra_id);
|
||||
nm_clear_g_free(&priv->last_error);
|
||||
|
||||
nm_clear_g_source(&priv->timeout_id);
|
||||
nm_clear_g_source_inst(&priv->timeout_expire_source);
|
||||
|
||||
G_OBJECT_CLASS(nm_ndisc_parent_class)->dispose(object);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,48 +48,91 @@ typedef enum {
|
|||
NM_NDISC_DHCP_LEVEL_MANAGED
|
||||
} NMNDiscDHCPLevel;
|
||||
|
||||
/* we rely on the fact that NM_NDISC_INFINITY is the largest possible
|
||||
* time duration (G_MAXUINT32) and that the range of finite values
|
||||
* goes from 0 to G_MAXUINT32-1. */
|
||||
#define NM_NDISC_INFINITY G_MAXUINT32
|
||||
#define NM_NDISC_INFINITY_U32 ((uint32_t) -1)
|
||||
|
||||
struct _NMNDiscGateway {
|
||||
/* It's important that this is G_MAXINT64, so that we can meaningfully do
|
||||
* MIN(e1, e2) to find the minimum expiry time (and properly handle if any
|
||||
* of them is infinity).
|
||||
*
|
||||
* While usually you assign this to "expiry_msec", you might say the
|
||||
* unit of it is milliseconds. But of course, infinity has not really a unit. */
|
||||
#define NM_NDISC_EXPIRY_INFINITY G_MAXINT64
|
||||
|
||||
/* in common cases, the expiry_msec tracks the timestamp in nm_utils_get_monotonic_timestamp_mses()
|
||||
* timestamp when the item expires.
|
||||
*
|
||||
* When we configure an NMNDiscAddress to be announced via the router advertisement,
|
||||
* then that address does not have a fixed expiry point in time, instead, the expiry
|
||||
* really contains the lifetime from the moment when we send the router advertisement.
|
||||
* In that case, the expiry_msec is more a "lifetime" that starts counting at timestamp
|
||||
* zero.
|
||||
*
|
||||
* The unit is milliseconds (but of course, the timestamp is zero, so it doesn't really matter). */
|
||||
#define NM_NDISC_EXPIRY_BASE_TIMESTAMP ((gint64) 0)
|
||||
|
||||
static inline gint64
|
||||
_nm_ndisc_lifetime_to_expiry(gint64 now_msec, guint32 lifetime)
|
||||
{
|
||||
if (lifetime == NM_NDISC_INFINITY_U32)
|
||||
return NM_NDISC_EXPIRY_INFINITY;
|
||||
return now_msec + (((gint64) lifetime) * 1000);
|
||||
}
|
||||
|
||||
static inline gint64
|
||||
_nm_ndisc_lifetime_from_expiry(gint64 now_msec, gint64 expiry_msec, gboolean ceil)
|
||||
{
|
||||
gint64 diff;
|
||||
|
||||
if (expiry_msec == NM_NDISC_EXPIRY_INFINITY)
|
||||
return NM_NDISC_INFINITY_U32;
|
||||
|
||||
/* we don't expect nor handle integer overflow. The time stamp and expiry
|
||||
* should be reasonably small so that it cannot happen. */
|
||||
|
||||
diff = expiry_msec - now_msec;
|
||||
|
||||
if (diff <= 0)
|
||||
return 0;
|
||||
|
||||
if (ceil) {
|
||||
/* we ceil() towards the next full second (instead of floor()). */
|
||||
diff += 999;
|
||||
}
|
||||
|
||||
return NM_MIN(diff / 1000, (gint64)(G_MAXUINT32 - 1));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct _NMNDiscGateway {
|
||||
struct in6_addr address;
|
||||
guint32 timestamp;
|
||||
guint32 lifetime;
|
||||
gint64 expiry_msec;
|
||||
NMIcmpv6RouterPref preference;
|
||||
};
|
||||
typedef struct _NMNDiscGateway NMNDiscGateway;
|
||||
} NMNDiscGateway;
|
||||
|
||||
struct _NMNDiscAddress {
|
||||
typedef struct _NMNDiscAddress {
|
||||
struct in6_addr address;
|
||||
gint64 expiry_msec;
|
||||
gint64 expiry_preferred_msec;
|
||||
guint8 dad_counter;
|
||||
guint32 timestamp;
|
||||
guint32 lifetime;
|
||||
guint32 preferred;
|
||||
};
|
||||
typedef struct _NMNDiscAddress NMNDiscAddress;
|
||||
} NMNDiscAddress;
|
||||
|
||||
struct _NMNDiscRoute {
|
||||
typedef struct _NMNDiscRoute {
|
||||
struct in6_addr network;
|
||||
guint8 plen;
|
||||
struct in6_addr gateway;
|
||||
guint32 timestamp;
|
||||
guint32 lifetime;
|
||||
gint64 expiry_msec;
|
||||
NMIcmpv6RouterPref preference;
|
||||
};
|
||||
typedef struct _NMNDiscRoute NMNDiscRoute;
|
||||
guint8 plen;
|
||||
} NMNDiscRoute;
|
||||
|
||||
typedef struct {
|
||||
struct in6_addr address;
|
||||
guint32 timestamp;
|
||||
guint32 lifetime;
|
||||
gint64 expiry_msec;
|
||||
} NMNDiscDNSServer;
|
||||
|
||||
typedef struct {
|
||||
char * domain;
|
||||
guint32 timestamp;
|
||||
guint32 lifetime;
|
||||
char * domain;
|
||||
gint64 expiry_msec;
|
||||
} NMNDiscDNSDomain;
|
||||
|
||||
typedef enum {
|
||||
|
|
@ -113,6 +156,7 @@ typedef enum {
|
|||
} NMNDiscNodeType;
|
||||
|
||||
#define NM_NDISC_MAX_ADDRESSES_DEFAULT 16
|
||||
#define NM_NDISC_MAX_RTR_SOLICITATION_DELAY 1 /* RFC4861 MAX_RTR_SOLICITATION_DELAY */
|
||||
#define NM_NDISC_ROUTER_SOLICITATIONS_DEFAULT 3 /* RFC4861 MAX_RTR_SOLICITATIONS */
|
||||
#define NM_NDISC_ROUTER_SOLICITATION_INTERVAL_DEFAULT 4 /* RFC4861 RTR_SOLICITATION_INTERVAL */
|
||||
#define NM_NDISC_ROUTER_ADVERTISEMENTS_DEFAULT 3 /* RFC4861 MAX_INITIAL_RTR_ADVERTISEMENTS */
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "nm-test-utils-core.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static NMFakeNDisc *
|
||||
ndisc_new(void)
|
||||
{
|
||||
|
|
@ -26,19 +28,20 @@ ndisc_new(void)
|
|||
iid.id_u8[7] = 1;
|
||||
nm_ndisc_set_iid(ndisc, iid);
|
||||
g_assert(ndisc);
|
||||
|
||||
return NM_FAKE_NDISC(ndisc);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
match_gateway(const NMNDiscData *rdata,
|
||||
guint idx,
|
||||
const char * addr,
|
||||
guint32 ts,
|
||||
guint32 lt,
|
||||
gint64 expiry_msec,
|
||||
NMIcmpv6RouterPref pref)
|
||||
{
|
||||
const NMNDiscGateway *gw;
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
g_assert(rdata);
|
||||
g_assert_cmpint(idx, <, rdata->gateways_n);
|
||||
|
|
@ -46,63 +49,57 @@ match_gateway(const NMNDiscData *rdata,
|
|||
|
||||
gw = &rdata->gateways[idx];
|
||||
|
||||
g_assert_cmpstr(inet_ntop(AF_INET6, &gw->address, buf, sizeof(buf)), ==, addr);
|
||||
g_assert_cmpint(gw->timestamp, ==, ts);
|
||||
g_assert_cmpint(gw->lifetime, ==, lt);
|
||||
nmtst_assert_ip6_address(&gw->address, addr);
|
||||
g_assert_cmpint(gw->expiry_msec, ==, expiry_msec);
|
||||
g_assert_cmpint(gw->preference, ==, pref);
|
||||
}
|
||||
|
||||
#define match_address(rdata, idx, addr, ts, lt, pref) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
const NMNDiscData * _rdata = (rdata); \
|
||||
guint _idx = (idx); \
|
||||
const NMNDiscAddress *_a; \
|
||||
guint _ts = (ts); \
|
||||
\
|
||||
g_assert(_rdata); \
|
||||
g_assert_cmpint(_idx, <, _rdata->addresses_n); \
|
||||
g_assert(_rdata->addresses); \
|
||||
\
|
||||
_a = &_rdata->addresses[_idx]; \
|
||||
\
|
||||
nmtst_assert_ip6_address(&_a->address, (addr)); \
|
||||
g_assert_cmpint(_a->timestamp, <=, _ts + 1); \
|
||||
g_assert_cmpint((int) _a->timestamp, >=, (int) _ts - 1); \
|
||||
g_assert_cmpint(_a->timestamp + _a->lifetime, ==, _ts + (lt)); \
|
||||
g_assert_cmpint(_a->timestamp + _a->preferred, ==, _ts + (pref)); \
|
||||
} \
|
||||
#define match_address(rdata, idx, addr, _expiry_msec, _expiry_preferred_msec) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
const NMNDiscData * _rdata = (rdata); \
|
||||
guint _idx = (idx); \
|
||||
const NMNDiscAddress *_a; \
|
||||
\
|
||||
g_assert(_rdata); \
|
||||
g_assert_cmpint(_idx, <, _rdata->addresses_n); \
|
||||
g_assert(_rdata->addresses); \
|
||||
\
|
||||
_a = &_rdata->addresses[_idx]; \
|
||||
\
|
||||
nmtst_assert_ip6_address(&_a->address, (addr)); \
|
||||
g_assert_cmpint(_a->expiry_msec, ==, (_expiry_msec)); \
|
||||
g_assert_cmpint(_a->expiry_preferred_msec, ==, (_expiry_preferred_msec)); \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
#define match_route(rdata, idx, nw, pl, gw, ts, lt, pref) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
const NMNDiscData * _rdata = (rdata); \
|
||||
guint _idx = (idx); \
|
||||
const NMNDiscRoute *_r; \
|
||||
int _plen = (pl); \
|
||||
\
|
||||
g_assert(_rdata); \
|
||||
g_assert_cmpint(_idx, <, _rdata->routes_n); \
|
||||
g_assert(_rdata->routes); \
|
||||
g_assert(_plen > 0 && _plen <= 128); \
|
||||
\
|
||||
_r = &_rdata->routes[idx]; \
|
||||
\
|
||||
nmtst_assert_ip6_address(&_r->network, (nw)); \
|
||||
g_assert_cmpint((int) _r->plen, ==, _plen); \
|
||||
nmtst_assert_ip6_address(&_r->gateway, (gw)); \
|
||||
g_assert_cmpint(_r->timestamp, ==, (ts)); \
|
||||
g_assert_cmpint(_r->lifetime, ==, (lt)); \
|
||||
g_assert_cmpint(_r->preference, ==, (pref)); \
|
||||
} \
|
||||
#define match_route(rdata, idx, nw, pl, gw, _expiry_msec, pref) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
const NMNDiscData * _rdata = (rdata); \
|
||||
guint _idx = (idx); \
|
||||
const NMNDiscRoute *_r; \
|
||||
int _plen = (pl); \
|
||||
\
|
||||
g_assert(_rdata); \
|
||||
g_assert_cmpint(_idx, <, _rdata->routes_n); \
|
||||
g_assert(_rdata->routes); \
|
||||
g_assert(_plen > 0 && _plen <= 128); \
|
||||
\
|
||||
_r = &_rdata->routes[idx]; \
|
||||
\
|
||||
nmtst_assert_ip6_address(&_r->network, (nw)); \
|
||||
g_assert_cmpint((int) _r->plen, ==, _plen); \
|
||||
nmtst_assert_ip6_address(&_r->gateway, (gw)); \
|
||||
g_assert_cmpint(_r->expiry_msec, ==, (_expiry_msec)); \
|
||||
g_assert_cmpint(_r->preference, ==, (pref)); \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
static void
|
||||
match_dns_server(const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt)
|
||||
match_dns_server(const NMNDiscData *rdata, guint idx, const char *addr, gint64 expiry_msec)
|
||||
{
|
||||
const NMNDiscDNSServer *dns;
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
g_assert(rdata);
|
||||
g_assert_cmpint(idx, <, rdata->dns_servers_n);
|
||||
|
|
@ -110,13 +107,12 @@ match_dns_server(const NMNDiscData *rdata, guint idx, const char *addr, guint32
|
|||
|
||||
dns = &rdata->dns_servers[idx];
|
||||
|
||||
g_assert_cmpstr(inet_ntop(AF_INET6, &dns->address, buf, sizeof(buf)), ==, addr);
|
||||
g_assert_cmpint(dns->timestamp, ==, ts);
|
||||
g_assert_cmpint(dns->lifetime, ==, lt);
|
||||
nmtst_assert_ip6_address(&dns->address, addr);
|
||||
g_assert_cmpint(dns->expiry_msec, ==, expiry_msec);
|
||||
}
|
||||
|
||||
static void
|
||||
match_dns_domain(const NMNDiscData *rdata, guint idx, const char *domain, guint32 ts, guint32 lt)
|
||||
match_dns_domain(const NMNDiscData *rdata, guint idx, const char *domain, gint64 expiry_msec)
|
||||
{
|
||||
const NMNDiscDNSDomain *dns;
|
||||
|
||||
|
|
@ -127,67 +123,96 @@ match_dns_domain(const NMNDiscData *rdata, guint idx, const char *domain, guint3
|
|||
dns = &rdata->dns_domains[idx];
|
||||
|
||||
g_assert_cmpstr(dns->domain, ==, domain);
|
||||
g_assert_cmpint(dns->timestamp, ==, ts);
|
||||
g_assert_cmpint(dns->lifetime, ==, lt);
|
||||
g_assert_cmpint(dns->expiry_msec, ==, expiry_msec);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
GMainLoop *loop;
|
||||
gint64 timestamp_msec_1;
|
||||
guint counter;
|
||||
guint rs_counter;
|
||||
guint32 timestamp1;
|
||||
guint32 first_solicit;
|
||||
gint64 first_solicit_msec;
|
||||
guint32 timeout_id;
|
||||
} TestData;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_simple_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, TestData *data)
|
||||
{
|
||||
NMNDiscConfigMap changed = changed_int;
|
||||
|
||||
g_assert_cmpint(changed,
|
||||
==,
|
||||
NM_NDISC_CONFIG_DHCP_LEVEL | NM_NDISC_CONFIG_GATEWAYS
|
||||
| NM_NDISC_CONFIG_ADDRESSES | NM_NDISC_CONFIG_ROUTES
|
||||
| NM_NDISC_CONFIG_DNS_SERVERS | NM_NDISC_CONFIG_DNS_DOMAINS
|
||||
| NM_NDISC_CONFIG_HOP_LIMIT | NM_NDISC_CONFIG_MTU);
|
||||
g_assert_cmpint(rdata->dhcp_level, ==, NM_NDISC_DHCP_LEVEL_OTHERCONF);
|
||||
match_gateway(rdata, 0, "fe80::1", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
|
||||
match_route(rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 10);
|
||||
match_dns_server(rdata, 0, "2001:db8:c:c::1", data->timestamp1, 10);
|
||||
match_dns_domain(rdata, 0, "foobar.com", data->timestamp1, 10);
|
||||
switch (data->counter++) {
|
||||
case 0:
|
||||
g_assert_cmpint(changed,
|
||||
==,
|
||||
NM_NDISC_CONFIG_DHCP_LEVEL | NM_NDISC_CONFIG_GATEWAYS
|
||||
| NM_NDISC_CONFIG_ADDRESSES | NM_NDISC_CONFIG_ROUTES
|
||||
| NM_NDISC_CONFIG_DNS_SERVERS | NM_NDISC_CONFIG_DNS_DOMAINS
|
||||
| NM_NDISC_CONFIG_HOP_LIMIT | NM_NDISC_CONFIG_MTU);
|
||||
g_assert_cmpint(rdata->dhcp_level, ==, NM_NDISC_DHCP_LEVEL_OTHERCONF);
|
||||
match_gateway(rdata,
|
||||
0,
|
||||
"fe80::1",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
match_address(rdata,
|
||||
0,
|
||||
"2001:db8:a:a::1",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
data->timestamp_msec_1 + 10000);
|
||||
match_route(rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp_msec_1 + 10000, 10);
|
||||
match_dns_server(rdata, 0, "2001:db8:c:c::1", data->timestamp_msec_1 + 10000);
|
||||
match_dns_domain(rdata, 0, "foobar.com", data->timestamp_msec_1 + 3500);
|
||||
|
||||
g_assert(nm_fake_ndisc_done(NM_FAKE_NDISC(ndisc)));
|
||||
data->counter++;
|
||||
g_main_loop_quit(data->loop);
|
||||
g_assert(nm_fake_ndisc_done(NM_FAKE_NDISC(ndisc)));
|
||||
break;
|
||||
case 1:
|
||||
g_main_loop_quit(data->loop);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_simple(void)
|
||||
{
|
||||
NMFakeNDisc *ndisc = ndisc_new();
|
||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
||||
TestData data = {g_main_loop_new(NULL, FALSE), 0, 0, now};
|
||||
guint id;
|
||||
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
gs_unref_object NMFakeNDisc *ndisc = ndisc_new();
|
||||
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
TestData data = {
|
||||
.loop = loop,
|
||||
.timestamp_msec_1 = now_msec,
|
||||
};
|
||||
guint id;
|
||||
|
||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_OTHERCONF, 4, 1500);
|
||||
g_assert(id);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_prefix(ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 10);
|
||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now, 10);
|
||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar.com", now, 10);
|
||||
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now_msec + 10000, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_prefix(ndisc,
|
||||
id,
|
||||
"2001:db8:a:a::",
|
||||
64,
|
||||
"fe80::1",
|
||||
now_msec + 10000,
|
||||
now_msec + 10000,
|
||||
10);
|
||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now_msec + 10000);
|
||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar.com", now_msec + 3500);
|
||||
|
||||
g_signal_connect(ndisc, NM_NDISC_CONFIG_RECEIVED, G_CALLBACK(test_simple_changed), &data);
|
||||
|
||||
nm_ndisc_start(NM_NDISC(ndisc));
|
||||
nmtst_main_loop_run_assert(data.loop, 15000);
|
||||
g_assert_cmpint(data.counter, ==, 1);
|
||||
|
||||
g_object_unref(ndisc);
|
||||
g_main_loop_unref(data.loop);
|
||||
g_assert_cmpint(data.counter, ==, 2);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_everything_rs_sent(NMNDisc *ndisc, TestData *data)
|
||||
{
|
||||
|
|
@ -208,11 +233,19 @@ test_everything_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_
|
|||
| NM_NDISC_CONFIG_ADDRESSES | NM_NDISC_CONFIG_ROUTES
|
||||
| NM_NDISC_CONFIG_DNS_SERVERS | NM_NDISC_CONFIG_DNS_DOMAINS
|
||||
| NM_NDISC_CONFIG_HOP_LIMIT | NM_NDISC_CONFIG_MTU);
|
||||
match_gateway(rdata, 0, "fe80::1", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
|
||||
match_route(rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 10);
|
||||
match_dns_server(rdata, 0, "2001:db8:c:c::1", data->timestamp1, 10);
|
||||
match_dns_domain(rdata, 0, "foobar.com", data->timestamp1, 10);
|
||||
match_gateway(rdata,
|
||||
0,
|
||||
"fe80::1",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
match_address(rdata,
|
||||
0,
|
||||
"2001:db8:a:a::1",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
data->timestamp_msec_1 + 10000);
|
||||
match_route(rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp_msec_1 + 10000, 10);
|
||||
match_dns_server(rdata, 0, "2001:db8:c:c::1", data->timestamp_msec_1 + 10000);
|
||||
match_dns_domain(rdata, 0, "foobar.com", data->timestamp_msec_1 + 10000);
|
||||
} else if (data->counter == 1) {
|
||||
g_assert_cmpint(changed,
|
||||
==,
|
||||
|
|
@ -221,16 +254,28 @@ test_everything_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_
|
|||
| NM_NDISC_CONFIG_DNS_DOMAINS);
|
||||
|
||||
g_assert_cmpint(rdata->gateways_n, ==, 1);
|
||||
match_gateway(rdata, 0, "fe80::2", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
match_gateway(rdata,
|
||||
0,
|
||||
"fe80::2",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
g_assert_cmpint(rdata->addresses_n, ==, 2);
|
||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 0);
|
||||
match_address(rdata, 1, "2001:db8:a:b::1", data->timestamp1, 10, 10);
|
||||
match_address(rdata,
|
||||
0,
|
||||
"2001:db8:a:a::1",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
data->timestamp_msec_1);
|
||||
match_address(rdata,
|
||||
1,
|
||||
"2001:db8:a:b::1",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
data->timestamp_msec_1 + 10000);
|
||||
g_assert_cmpint(rdata->routes_n, ==, 1);
|
||||
match_route(rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1, 10, 10);
|
||||
match_route(rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp_msec_1 + 10000, 10);
|
||||
g_assert_cmpint(rdata->dns_servers_n, ==, 1);
|
||||
match_dns_server(rdata, 0, "2001:db8:c:c::2", data->timestamp1, 10);
|
||||
match_dns_server(rdata, 0, "2001:db8:c:c::2", data->timestamp_msec_1 + 10000);
|
||||
g_assert_cmpint(rdata->dns_domains_n, ==, 1);
|
||||
match_dns_domain(rdata, 0, "foobar2.com", data->timestamp1, 10);
|
||||
match_dns_domain(rdata, 0, "foobar2.com", data->timestamp_msec_1 + 10000);
|
||||
|
||||
g_assert(nm_fake_ndisc_done(NM_FAKE_NDISC(ndisc)));
|
||||
g_main_loop_quit(data->loop);
|
||||
|
|
@ -243,31 +288,49 @@ test_everything_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_
|
|||
static void
|
||||
test_everything(void)
|
||||
{
|
||||
NMFakeNDisc *ndisc = ndisc_new();
|
||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
||||
TestData data = {g_main_loop_new(NULL, FALSE), 0, 0, now};
|
||||
guint id;
|
||||
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
gs_unref_object NMFakeNDisc *ndisc = ndisc_new();
|
||||
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
TestData data = {
|
||||
.loop = loop,
|
||||
.timestamp_msec_1 = now_msec,
|
||||
};
|
||||
guint id;
|
||||
|
||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||
g_assert(id);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_prefix(ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 10);
|
||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now, 10);
|
||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar.com", now, 10);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now_msec + 10000, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_prefix(ndisc,
|
||||
id,
|
||||
"2001:db8:a:a::",
|
||||
64,
|
||||
"fe80::1",
|
||||
now_msec + 10000,
|
||||
now_msec + 10000,
|
||||
10);
|
||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now_msec + 10000);
|
||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar.com", now_msec + 10000);
|
||||
|
||||
/* expire everything from the first RA in the second */
|
||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||
g_assert(id);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 0, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_prefix(ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 0, 0, 0);
|
||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now, 0);
|
||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar.com", now, 0);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now_msec, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_prefix(ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now_msec, now_msec, 0);
|
||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now_msec);
|
||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar.com", now_msec);
|
||||
|
||||
/* and add some new stuff */
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::2", now, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_prefix(ndisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10, 10);
|
||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::2", now, 10);
|
||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar2.com", now, 10);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::2", now_msec + 10000, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_prefix(ndisc,
|
||||
id,
|
||||
"2001:db8:a:b::",
|
||||
64,
|
||||
"fe80::2",
|
||||
now_msec + 10000,
|
||||
now_msec + 10000,
|
||||
10);
|
||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::2", now_msec + 10000);
|
||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar2.com", now_msec + 10000);
|
||||
|
||||
g_signal_connect(ndisc, NM_NDISC_CONFIG_RECEIVED, G_CALLBACK(test_everything_changed), &data);
|
||||
g_signal_connect(ndisc, NM_FAKE_NDISC_RS_SENT, G_CALLBACK(test_everything_rs_sent), &data);
|
||||
|
|
@ -276,9 +339,6 @@ test_everything(void)
|
|||
nmtst_main_loop_run_assert(data.loop, 15000);
|
||||
g_assert_cmpint(data.counter, ==, 2);
|
||||
g_assert_cmpint(data.rs_counter, ==, 1);
|
||||
|
||||
g_object_unref(ndisc);
|
||||
g_main_loop_unref(data.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -296,14 +356,30 @@ test_preference_order_cb(NMNDisc * ndisc,
|
|||
| NM_NDISC_CONFIG_ROUTES);
|
||||
|
||||
g_assert_cmpint(rdata->gateways_n, ==, 2);
|
||||
match_gateway(rdata, 0, "fe80::1", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_HIGH);
|
||||
match_gateway(rdata, 1, "fe80::2", data->timestamp1 + 1, 10, NM_ICMPV6_ROUTER_PREF_LOW);
|
||||
match_gateway(rdata,
|
||||
0,
|
||||
"fe80::1",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
NM_ICMPV6_ROUTER_PREF_HIGH);
|
||||
match_gateway(rdata,
|
||||
1,
|
||||
"fe80::2",
|
||||
data->timestamp_msec_1 + 11000,
|
||||
NM_ICMPV6_ROUTER_PREF_LOW);
|
||||
g_assert_cmpint(rdata->addresses_n, ==, 2);
|
||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
|
||||
match_address(rdata, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10);
|
||||
match_address(rdata,
|
||||
0,
|
||||
"2001:db8:a:a::1",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
data->timestamp_msec_1 + 10000);
|
||||
match_address(rdata,
|
||||
1,
|
||||
"2001:db8:a:b::1",
|
||||
data->timestamp_msec_1 + 11000,
|
||||
data->timestamp_msec_1 + 10000);
|
||||
g_assert_cmpint(rdata->routes_n, ==, 2);
|
||||
match_route(rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10);
|
||||
match_route(rdata, 1, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 5);
|
||||
match_route(rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp_msec_1 + 11000, 10);
|
||||
match_route(rdata, 1, "2001:db8:a:a::", 64, "fe80::1", data->timestamp_msec_1 + 10000, 5);
|
||||
|
||||
g_assert(nm_fake_ndisc_done(NM_FAKE_NDISC(ndisc)));
|
||||
g_main_loop_quit(data->loop);
|
||||
|
|
@ -315,31 +391,46 @@ test_preference_order_cb(NMNDisc * ndisc,
|
|||
static void
|
||||
test_preference_order(void)
|
||||
{
|
||||
NMFakeNDisc *ndisc = ndisc_new();
|
||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
||||
TestData data = {g_main_loop_new(NULL, FALSE), 0, 0, now};
|
||||
guint id;
|
||||
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
gs_unref_object NMFakeNDisc *ndisc = ndisc_new();
|
||||
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
TestData data = {
|
||||
.loop = loop,
|
||||
.timestamp_msec_1 = now_msec,
|
||||
};
|
||||
guint id;
|
||||
|
||||
/* Test insertion order of gateways */
|
||||
|
||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||
g_assert(id);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 10, NM_ICMPV6_ROUTER_PREF_HIGH);
|
||||
nm_fake_ndisc_add_prefix(ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 5);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now_msec + 10000, NM_ICMPV6_ROUTER_PREF_HIGH);
|
||||
nm_fake_ndisc_add_prefix(ndisc,
|
||||
id,
|
||||
"2001:db8:a:a::",
|
||||
64,
|
||||
"fe80::1",
|
||||
now_msec + 10000,
|
||||
now_msec + 10000,
|
||||
5);
|
||||
|
||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||
g_assert(id);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::2", ++now, 10, NM_ICMPV6_ROUTER_PREF_LOW);
|
||||
nm_fake_ndisc_add_prefix(ndisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10, 10);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::2", now_msec + 11000, NM_ICMPV6_ROUTER_PREF_LOW);
|
||||
nm_fake_ndisc_add_prefix(ndisc,
|
||||
id,
|
||||
"2001:db8:a:b::",
|
||||
64,
|
||||
"fe80::2",
|
||||
now_msec + 11000,
|
||||
now_msec + 10000,
|
||||
10);
|
||||
|
||||
g_signal_connect(ndisc, NM_NDISC_CONFIG_RECEIVED, G_CALLBACK(test_preference_order_cb), &data);
|
||||
|
||||
nm_ndisc_start(NM_NDISC(ndisc));
|
||||
nmtst_main_loop_run_assert(data.loop, 15000);
|
||||
g_assert_cmpint(data.counter, ==, 2);
|
||||
|
||||
g_object_unref(ndisc);
|
||||
g_main_loop_unref(data.loop);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -356,14 +447,30 @@ test_preference_changed_cb(NMNDisc * ndisc,
|
|||
NM_NDISC_CONFIG_GATEWAYS | NM_NDISC_CONFIG_ADDRESSES
|
||||
| NM_NDISC_CONFIG_ROUTES);
|
||||
g_assert_cmpint(rdata->gateways_n, ==, 2);
|
||||
match_gateway(rdata, 0, "fe80::2", data->timestamp1 + 1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
match_gateway(rdata, 1, "fe80::1", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_LOW);
|
||||
match_gateway(rdata,
|
||||
0,
|
||||
"fe80::2",
|
||||
data->timestamp_msec_1 + 11000,
|
||||
NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
match_gateway(rdata,
|
||||
1,
|
||||
"fe80::1",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
NM_ICMPV6_ROUTER_PREF_LOW);
|
||||
g_assert_cmpint(rdata->addresses_n, ==, 2);
|
||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
|
||||
match_address(rdata, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10);
|
||||
match_address(rdata,
|
||||
0,
|
||||
"2001:db8:a:a::1",
|
||||
data->timestamp_msec_1 + 10000,
|
||||
data->timestamp_msec_1 + 10000);
|
||||
match_address(rdata,
|
||||
1,
|
||||
"2001:db8:a:b::1",
|
||||
data->timestamp_msec_1 + 11000,
|
||||
data->timestamp_msec_1 + 11000);
|
||||
g_assert_cmpint(rdata->routes_n, ==, 2);
|
||||
match_route(rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10);
|
||||
match_route(rdata, 1, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 5);
|
||||
match_route(rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp_msec_1 + 11000, 10);
|
||||
match_route(rdata, 1, "2001:db8:a:a::", 64, "fe80::1", data->timestamp_msec_1 + 10000, 5);
|
||||
} else if (data->counter == 2) {
|
||||
g_assert_cmpint(changed,
|
||||
==,
|
||||
|
|
@ -371,14 +478,30 @@ test_preference_changed_cb(NMNDisc * ndisc,
|
|||
| NM_NDISC_CONFIG_ROUTES);
|
||||
|
||||
g_assert_cmpint(rdata->gateways_n, ==, 2);
|
||||
match_gateway(rdata, 0, "fe80::1", data->timestamp1 + 2, 10, NM_ICMPV6_ROUTER_PREF_HIGH);
|
||||
match_gateway(rdata, 1, "fe80::2", data->timestamp1 + 1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
match_gateway(rdata,
|
||||
0,
|
||||
"fe80::1",
|
||||
data->timestamp_msec_1 + 12000,
|
||||
NM_ICMPV6_ROUTER_PREF_HIGH);
|
||||
match_gateway(rdata,
|
||||
1,
|
||||
"fe80::2",
|
||||
data->timestamp_msec_1 + 11000,
|
||||
NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
g_assert_cmpint(rdata->addresses_n, ==, 2);
|
||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1 + 3, 9, 9);
|
||||
match_address(rdata, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10);
|
||||
match_address(rdata,
|
||||
0,
|
||||
"2001:db8:a:a::1",
|
||||
data->timestamp_msec_1 + 12000,
|
||||
data->timestamp_msec_1 + 12000);
|
||||
match_address(rdata,
|
||||
1,
|
||||
"2001:db8:a:b::1",
|
||||
data->timestamp_msec_1 + 11000,
|
||||
data->timestamp_msec_1 + 11000);
|
||||
g_assert_cmpint(rdata->routes_n, ==, 2);
|
||||
match_route(rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1 + 2, 10, 15);
|
||||
match_route(rdata, 1, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10);
|
||||
match_route(rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp_msec_1 + 12000, 15);
|
||||
match_route(rdata, 1, "2001:db8:a:b::", 64, "fe80::2", data->timestamp_msec_1 + 11000, 10);
|
||||
|
||||
g_assert(nm_fake_ndisc_done(NM_FAKE_NDISC(ndisc)));
|
||||
g_main_loop_quit(data->loop);
|
||||
|
|
@ -390,10 +513,14 @@ test_preference_changed_cb(NMNDisc * ndisc,
|
|||
static void
|
||||
test_preference_changed(void)
|
||||
{
|
||||
NMFakeNDisc *ndisc = ndisc_new();
|
||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
||||
TestData data = {g_main_loop_new(NULL, FALSE), 0, 0, now};
|
||||
guint id;
|
||||
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
gs_unref_object NMFakeNDisc *ndisc = ndisc_new();
|
||||
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
TestData data = {
|
||||
.loop = loop,
|
||||
.timestamp_msec_1 = now_msec,
|
||||
};
|
||||
guint id;
|
||||
|
||||
/* Test that when a low-preference and medium gateway send advertisements,
|
||||
* that if the low-preference gateway switches to high-preference, we do
|
||||
|
|
@ -402,18 +529,39 @@ test_preference_changed(void)
|
|||
|
||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||
g_assert(id);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 10, NM_ICMPV6_ROUTER_PREF_LOW);
|
||||
nm_fake_ndisc_add_prefix(ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 5);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now_msec + 10000, NM_ICMPV6_ROUTER_PREF_LOW);
|
||||
nm_fake_ndisc_add_prefix(ndisc,
|
||||
id,
|
||||
"2001:db8:a:a::",
|
||||
64,
|
||||
"fe80::1",
|
||||
now_msec + 10000,
|
||||
now_msec + 10000,
|
||||
5);
|
||||
|
||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||
g_assert(id);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::2", ++now, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_prefix(ndisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10, 10);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::2", now_msec + 11000, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_prefix(ndisc,
|
||||
id,
|
||||
"2001:db8:a:b::",
|
||||
64,
|
||||
"fe80::2",
|
||||
now_msec + 11000,
|
||||
now_msec + 11000,
|
||||
10);
|
||||
|
||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||
g_assert(id);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", ++now, 10, NM_ICMPV6_ROUTER_PREF_HIGH);
|
||||
nm_fake_ndisc_add_prefix(ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 15);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now_msec + 12000, NM_ICMPV6_ROUTER_PREF_HIGH);
|
||||
nm_fake_ndisc_add_prefix(ndisc,
|
||||
id,
|
||||
"2001:db8:a:a::",
|
||||
64,
|
||||
"fe80::1",
|
||||
now_msec + 12000,
|
||||
now_msec + 12000,
|
||||
15);
|
||||
|
||||
g_signal_connect(ndisc,
|
||||
NM_NDISC_CONFIG_RECEIVED,
|
||||
|
|
@ -423,16 +571,15 @@ test_preference_changed(void)
|
|||
nm_ndisc_start(NM_NDISC(ndisc));
|
||||
nmtst_main_loop_run_assert(data.loop, 15000);
|
||||
g_assert_cmpint(data.counter, ==, 3);
|
||||
|
||||
g_object_unref(ndisc);
|
||||
g_main_loop_unref(data.loop);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_dns_solicit_loop_changed(NMNDisc * ndisc,
|
||||
const NMNDiscData *rdata,
|
||||
guint changed_int,
|
||||
TestData * data)
|
||||
_test_dns_solicit_loop_changed(NMNDisc * ndisc,
|
||||
const NMNDiscData *rdata,
|
||||
guint changed_int,
|
||||
TestData * data)
|
||||
{
|
||||
data->counter++;
|
||||
}
|
||||
|
|
@ -446,14 +593,14 @@ success_timeout(TestData *data)
|
|||
}
|
||||
|
||||
static void
|
||||
test_dns_solicit_loop_rs_sent(NMFakeNDisc *ndisc, TestData *data)
|
||||
_test_dns_solicit_loop_rs_sent(NMFakeNDisc *ndisc, TestData *data)
|
||||
{
|
||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
||||
guint id;
|
||||
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
guint id;
|
||||
|
||||
if (data->rs_counter > 0 && data->rs_counter < 6) {
|
||||
if (data->rs_counter == 1) {
|
||||
data->first_solicit = now;
|
||||
data->first_solicit_msec = now_msec;
|
||||
/* Kill the test after 10 seconds if it hasn't failed yet */
|
||||
data->timeout_id = g_timeout_add_seconds(10, (GSourceFunc) success_timeout, data);
|
||||
}
|
||||
|
|
@ -464,12 +611,16 @@ test_dns_solicit_loop_rs_sent(NMFakeNDisc *ndisc, TestData *data)
|
|||
*/
|
||||
id = nm_fake_ndisc_add_ra(ndisc, 0, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||
g_assert(id);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
nm_fake_ndisc_add_gateway(ndisc,
|
||||
id,
|
||||
"fe80::1",
|
||||
now_msec + 10000,
|
||||
NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||
|
||||
nm_fake_ndisc_emit_new_ras(ndisc);
|
||||
} else if (data->rs_counter >= 6) {
|
||||
/* Fail if we've sent too many solicitations in the past 4 seconds */
|
||||
g_assert_cmpint(now - data->first_solicit, >, 4);
|
||||
g_assert_cmpint(now_msec - data->first_solicit_msec, >, 4000);
|
||||
g_source_remove(data->timeout_id);
|
||||
g_main_loop_quit(data->loop);
|
||||
}
|
||||
|
|
@ -479,10 +630,14 @@ test_dns_solicit_loop_rs_sent(NMFakeNDisc *ndisc, TestData *data)
|
|||
static void
|
||||
test_dns_solicit_loop(void)
|
||||
{
|
||||
NMFakeNDisc *ndisc = ndisc_new();
|
||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
||||
TestData data = {g_main_loop_new(NULL, FALSE), 0, 0, now, 0};
|
||||
guint id;
|
||||
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
gs_unref_object NMFakeNDisc *ndisc = ndisc_new();
|
||||
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
TestData data = {
|
||||
.loop = loop,
|
||||
.timestamp_msec_1 = now_msec,
|
||||
};
|
||||
guint id;
|
||||
|
||||
g_test_skip("The solicitation behavior is wrong and need fixing. This test is not working too");
|
||||
return;
|
||||
|
|
@ -496,26 +651,25 @@ test_dns_solicit_loop(void)
|
|||
|
||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||
g_assert(id);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 10, NM_ICMPV6_ROUTER_PREF_LOW);
|
||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now, 6);
|
||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now_msec + 10000, NM_ICMPV6_ROUTER_PREF_LOW);
|
||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now_msec + 6000);
|
||||
|
||||
g_signal_connect(ndisc,
|
||||
NM_NDISC_CONFIG_RECEIVED,
|
||||
G_CALLBACK(test_dns_solicit_loop_changed),
|
||||
G_CALLBACK(_test_dns_solicit_loop_changed),
|
||||
&data);
|
||||
g_signal_connect(ndisc,
|
||||
NM_FAKE_NDISC_RS_SENT,
|
||||
G_CALLBACK(test_dns_solicit_loop_rs_sent),
|
||||
G_CALLBACK(_test_dns_solicit_loop_rs_sent),
|
||||
&data);
|
||||
|
||||
nm_ndisc_start(NM_NDISC(ndisc));
|
||||
nmtst_main_loop_run_assert(data.loop, 20000);
|
||||
g_assert_cmpint(data.counter, ==, 3);
|
||||
|
||||
g_object_unref(ndisc);
|
||||
g_main_loop_unref(data.loop);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMTST_DEFINE();
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -1497,6 +1497,7 @@ nm_ip6_config_reset_addresses_ndisc(NMIP6Config * self,
|
|||
NMIP6ConfigPrivate *priv;
|
||||
guint i;
|
||||
gboolean changed = FALSE;
|
||||
gint32 base_time_sec;
|
||||
|
||||
g_return_if_fail(NM_IS_IP6_CONFIG(self));
|
||||
|
||||
|
|
@ -1504,6 +1505,16 @@ nm_ip6_config_reset_addresses_ndisc(NMIP6Config * self,
|
|||
|
||||
g_return_if_fail(priv->ifindex > 0);
|
||||
|
||||
/* the base-timestamp doesn't matter it's only an anchor for the
|
||||
* expiry. However, try to re-use the same base-time for a while
|
||||
* by rounding it to 10000 seconds.
|
||||
*
|
||||
* That is because we deduplicate and NMPlatformIP6Address instances
|
||||
* so using the same timestamps is preferable. */
|
||||
base_time_sec = nm_utils_get_monotonic_timestamp_sec();
|
||||
base_time_sec = (base_time_sec / 10000) * 10000;
|
||||
base_time_sec = NM_MAX(1, base_time_sec);
|
||||
|
||||
nm_dedup_multi_index_dirty_set_idx(priv->multi_idx, &priv->idx_ip6_addresses);
|
||||
|
||||
for (i = 0; i < addresses_n; i++) {
|
||||
|
|
@ -1516,9 +1527,13 @@ nm_ip6_config_reset_addresses_ndisc(NMIP6Config * self,
|
|||
a->ifindex = priv->ifindex;
|
||||
a->address = ndisc_addr->address;
|
||||
a->plen = plen;
|
||||
a->timestamp = ndisc_addr->timestamp;
|
||||
a->lifetime = ndisc_addr->lifetime;
|
||||
a->preferred = MIN(ndisc_addr->lifetime, ndisc_addr->preferred);
|
||||
a->timestamp = base_time_sec,
|
||||
a->lifetime = _nm_ndisc_lifetime_from_expiry(((gint64) base_time_sec) * 1000,
|
||||
ndisc_addr->expiry_msec,
|
||||
TRUE),
|
||||
a->preferred = _nm_ndisc_lifetime_from_expiry(((gint64) base_time_sec) * 1000,
|
||||
ndisc_addr->expiry_preferred_msec,
|
||||
TRUE),
|
||||
a->addr_source = NM_IP_CONFIG_SOURCE_NDISC;
|
||||
a->n_ifa_flags = ifa_flags;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue