mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-06-11 11:58:23 +02: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
|
static void
|
||||||
ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self)
|
ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self)
|
||||||
{
|
{
|
||||||
NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||||
gint32 now;
|
gs_unref_array GArray *addresses = NULL;
|
||||||
GArray * addresses, *dns_servers, *dns_domains;
|
gs_unref_array GArray *dns_servers = NULL;
|
||||||
guint len, i;
|
gs_unref_array GArray * dns_domains = NULL;
|
||||||
|
guint len;
|
||||||
|
guint i;
|
||||||
const NMDedupMultiHeadEntry *head_entry;
|
const NMDedupMultiHeadEntry *head_entry;
|
||||||
NMDedupMultiIter ipconf_iter;
|
NMDedupMultiIter ipconf_iter;
|
||||||
|
|
||||||
if (nm_ndisc_get_node_type(ndisc) != NM_NDISC_NODE_TYPE_ROUTER)
|
if (nm_ndisc_get_node_type(ndisc) != NM_NDISC_NODE_TYPE_ROUTER)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
now = nm_utils_get_monotonic_timestamp_sec();
|
|
||||||
|
|
||||||
head_entry = nm_ip6_config_lookup_addresses(priv->ip_config_6);
|
head_entry = nm_ip6_config_lookup_addresses(priv->ip_config_6);
|
||||||
addresses =
|
addresses =
|
||||||
g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscAddress), head_entry ? head_entry->len : 0);
|
g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscAddress), head_entry ? head_entry->len : 0);
|
||||||
nm_dedup_multi_iter_for_each (&ipconf_iter, head_entry) {
|
nm_dedup_multi_iter_for_each (&ipconf_iter, head_entry) {
|
||||||
const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(ipconf_iter.current->obj);
|
const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(ipconf_iter.current->obj);
|
||||||
NMNDiscAddress * ndisc_addr;
|
NMNDiscAddress * ndisc_addr;
|
||||||
guint32 lifetime, preferred;
|
guint32 lifetime;
|
||||||
gint32 base;
|
guint32 preferred;
|
||||||
|
|
||||||
if (IN6_IS_ADDR_UNSPECIFIED(&addr->address) || IN6_IS_ADDR_LINKLOCAL(&addr->address))
|
if (IN6_IS_ADDR_UNSPECIFIED(&addr->address) || IN6_IS_ADDR_LINKLOCAL(&addr->address))
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -5178,31 +5178,21 @@ ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self)
|
||||||
if (addr->plen != 64)
|
if (addr->plen != 64)
|
||||||
continue;
|
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,
|
lifetime = nm_utils_lifetime_get(addr->timestamp,
|
||||||
addr->lifetime,
|
addr->lifetime,
|
||||||
addr->preferred,
|
addr->preferred,
|
||||||
base,
|
NM_NDISC_EXPIRY_BASE_TIMESTAMP / 1000,
|
||||||
&preferred);
|
&preferred);
|
||||||
if (!lifetime)
|
if (!lifetime)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
g_array_set_size(addresses, addresses->len + 1);
|
g_array_set_size(addresses, addresses->len + 1);
|
||||||
ndisc_addr = &g_array_index(addresses, NMNDiscAddress, addresses->len - 1);
|
ndisc_addr = &g_array_index(addresses, NMNDiscAddress, addresses->len - 1);
|
||||||
ndisc_addr->address = addr->address;
|
ndisc_addr->address = addr->address;
|
||||||
ndisc_addr->timestamp = base;
|
ndisc_addr->expiry_msec =
|
||||||
ndisc_addr->lifetime = lifetime;
|
_nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, lifetime);
|
||||||
ndisc_addr->preferred = preferred;
|
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);
|
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);
|
const struct in6_addr *nameserver = nm_ip6_config_get_nameserver(priv->ip_config_6, i);
|
||||||
NMNDiscDNSServer * ndisc_nameserver;
|
NMNDiscDNSServer * ndisc_nameserver;
|
||||||
|
|
||||||
ndisc_nameserver = &g_array_index(dns_servers, NMNDiscDNSServer, i);
|
ndisc_nameserver = &g_array_index(dns_servers, NMNDiscDNSServer, i);
|
||||||
ndisc_nameserver->address = *nameserver;
|
ndisc_nameserver->address = *nameserver;
|
||||||
ndisc_nameserver->timestamp = now;
|
ndisc_nameserver->expiry_msec =
|
||||||
ndisc_nameserver->lifetime = NM_NDISC_ROUTER_LIFETIME;
|
_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);
|
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);
|
const char * search = nm_ip6_config_get_search(priv->ip_config_6, i);
|
||||||
NMNDiscDNSDomain *ndisc_search;
|
NMNDiscDNSDomain *ndisc_search;
|
||||||
|
|
||||||
ndisc_search = &g_array_index(dns_domains, NMNDiscDNSDomain, i);
|
ndisc_search = &g_array_index(dns_domains, NMNDiscDNSDomain, i);
|
||||||
ndisc_search->domain = (char *) search;
|
ndisc_search->domain = (char *) search;
|
||||||
ndisc_search->timestamp = now;
|
ndisc_search->expiry_msec =
|
||||||
ndisc_search->lifetime = NM_NDISC_ROUTER_LIFETIME;
|
_nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, NM_NDISC_ROUTER_LIFETIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
nm_ndisc_set_config(ndisc, addresses, dns_servers, dns_domains);
|
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
|
static void
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,10 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct in6_addr network;
|
struct in6_addr network;
|
||||||
int plen;
|
|
||||||
struct in6_addr gateway;
|
struct in6_addr gateway;
|
||||||
guint32 timestamp;
|
gint64 expiry_msec;
|
||||||
guint32 lifetime;
|
gint64 expiry_preferred_msec;
|
||||||
guint32 preferred;
|
int plen;
|
||||||
NMIcmpv6RouterPref preference;
|
NMIcmpv6RouterPref preference;
|
||||||
} FakePrefix;
|
} FakePrefix;
|
||||||
|
|
||||||
|
|
@ -128,8 +127,7 @@ void
|
||||||
nm_fake_ndisc_add_gateway(NMFakeNDisc * self,
|
nm_fake_ndisc_add_gateway(NMFakeNDisc * self,
|
||||||
guint ra_id,
|
guint ra_id,
|
||||||
const char * addr,
|
const char * addr,
|
||||||
guint32 timestamp,
|
gint64 expiry_msec,
|
||||||
guint32 lifetime,
|
|
||||||
NMIcmpv6RouterPref preference)
|
NMIcmpv6RouterPref preference)
|
||||||
{
|
{
|
||||||
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||||
|
|
@ -137,12 +135,12 @@ nm_fake_ndisc_add_gateway(NMFakeNDisc * self,
|
||||||
NMNDiscGateway * gw;
|
NMNDiscGateway * gw;
|
||||||
|
|
||||||
g_assert(ra);
|
g_assert(ra);
|
||||||
g_array_set_size(ra->gateways, ra->gateways->len + 1);
|
|
||||||
gw = &g_array_index(ra->gateways, NMNDiscGateway, ra->gateways->len - 1);
|
gw = nm_g_array_append_new(ra->gateways, NMNDiscGateway);
|
||||||
g_assert(inet_pton(AF_INET6, addr, &gw->address) == 1);
|
if (inet_pton(AF_INET6, addr, &gw->address) != 1)
|
||||||
gw->timestamp = timestamp;
|
g_assert_not_reached();
|
||||||
gw->lifetime = lifetime;
|
gw->expiry_msec = expiry_msec;
|
||||||
gw->preference = preference;
|
gw->preference = preference;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -151,9 +149,8 @@ nm_fake_ndisc_add_prefix(NMFakeNDisc * self,
|
||||||
const char * network,
|
const char * network,
|
||||||
guint plen,
|
guint plen,
|
||||||
const char * gateway,
|
const char * gateway,
|
||||||
guint32 timestamp,
|
gint64 expiry_msec,
|
||||||
guint32 lifetime,
|
gint64 expiry_preferred_msec,
|
||||||
guint32 preferred,
|
|
||||||
NMIcmpv6RouterPref preference)
|
NMIcmpv6RouterPref preference)
|
||||||
{
|
{
|
||||||
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||||
|
|
@ -161,54 +158,52 @@ nm_fake_ndisc_add_prefix(NMFakeNDisc * self,
|
||||||
FakePrefix * prefix;
|
FakePrefix * prefix;
|
||||||
|
|
||||||
g_assert(ra);
|
g_assert(ra);
|
||||||
g_array_set_size(ra->prefixes, ra->prefixes->len + 1);
|
|
||||||
prefix = &g_array_index(ra->prefixes, FakePrefix, ra->prefixes->len - 1);
|
prefix = nm_g_array_append_new(ra->prefixes, FakePrefix);
|
||||||
memset(prefix, 0, sizeof(*prefix));
|
*prefix = (FakePrefix){
|
||||||
g_assert(inet_pton(AF_INET6, network, &prefix->network) == 1);
|
.plen = plen,
|
||||||
g_assert(inet_pton(AF_INET6, gateway, &prefix->gateway) == 1);
|
.expiry_msec = expiry_msec,
|
||||||
prefix->plen = plen;
|
.expiry_preferred_msec = expiry_preferred_msec,
|
||||||
prefix->timestamp = timestamp;
|
.preference = preference,
|
||||||
prefix->lifetime = lifetime;
|
};
|
||||||
prefix->preferred = preferred;
|
if (inet_pton(AF_INET6, network, &prefix->network) != 1)
|
||||||
prefix->preference = preference;
|
g_assert_not_reached();
|
||||||
|
if (inet_pton(AF_INET6, gateway, &prefix->gateway) != 1)
|
||||||
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nm_fake_ndisc_add_dns_server(NMFakeNDisc *self,
|
nm_fake_ndisc_add_dns_server(NMFakeNDisc *self,
|
||||||
guint ra_id,
|
guint ra_id,
|
||||||
const char * address,
|
const char * address,
|
||||||
guint32 timestamp,
|
gint64 expiry_msec)
|
||||||
guint32 lifetime)
|
|
||||||
{
|
{
|
||||||
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||||
FakeRa * ra = find_ra(priv->ras, ra_id);
|
FakeRa * ra = find_ra(priv->ras, ra_id);
|
||||||
NMNDiscDNSServer * dns;
|
NMNDiscDNSServer * dns;
|
||||||
|
|
||||||
g_assert(ra);
|
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);
|
dns = nm_g_array_append_new(ra->dns_servers, NMNDiscDNSServer);
|
||||||
g_assert(inet_pton(AF_INET6, address, &dns->address) == 1);
|
|
||||||
dns->timestamp = timestamp;
|
dns->expiry_msec = expiry_msec;
|
||||||
dns->lifetime = lifetime;
|
if (inet_pton(AF_INET6, address, &dns->address) != 1)
|
||||||
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nm_fake_ndisc_add_dns_domain(NMFakeNDisc *self,
|
nm_fake_ndisc_add_dns_domain(NMFakeNDisc *self, guint ra_id, const char *domain, gint64 expiry_msec)
|
||||||
guint ra_id,
|
|
||||||
const char * domain,
|
|
||||||
guint32 timestamp,
|
|
||||||
guint32 lifetime)
|
|
||||||
{
|
{
|
||||||
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||||
FakeRa * ra = find_ra(priv->ras, ra_id);
|
FakeRa * ra = find_ra(priv->ras, ra_id);
|
||||||
NMNDiscDNSDomain * dns;
|
NMNDiscDNSDomain * dns;
|
||||||
|
|
||||||
g_assert(ra);
|
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 = nm_g_array_append_new(ra->dns_domains, NMNDiscDNSDomain);
|
||||||
dns->domain = g_strdup(domain);
|
|
||||||
dns->timestamp = timestamp;
|
dns->domain = g_strdup(domain);
|
||||||
dns->lifetime = lifetime;
|
dns->expiry_msec = expiry_msec;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|
@ -230,13 +225,13 @@ send_rs(NMNDisc *ndisc, GError **error)
|
||||||
static gboolean
|
static gboolean
|
||||||
receive_ra(gpointer user_data)
|
receive_ra(gpointer user_data)
|
||||||
{
|
{
|
||||||
NMFakeNDisc * self = user_data;
|
NMFakeNDisc * self = user_data;
|
||||||
NMFakeNDiscPrivate * priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
NMFakeNDiscPrivate * priv = NM_FAKE_NDISC_GET_PRIVATE(self);
|
||||||
NMNDisc * ndisc = NM_NDISC(self);
|
NMNDisc * ndisc = NM_NDISC(self);
|
||||||
NMNDiscDataInternal *rdata = ndisc->rdata;
|
NMNDiscDataInternal *rdata = ndisc->rdata;
|
||||||
FakeRa * ra = priv->ras->data;
|
FakeRa * ra = priv->ras->data;
|
||||||
NMNDiscConfigMap changed = 0;
|
NMNDiscConfigMap changed = 0;
|
||||||
gint32 now = nm_utils_get_monotonic_timestamp_sec();
|
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||||
guint i;
|
guint i;
|
||||||
NMNDiscDHCPLevel dhcp_level;
|
NMNDiscDHCPLevel dhcp_level;
|
||||||
|
|
||||||
|
|
@ -251,53 +246,51 @@ receive_ra(gpointer user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ra->gateways->len; i++) {
|
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;
|
changed |= NM_NDISC_CONFIG_GATEWAYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ra->prefixes->len; i++) {
|
for (i = 0; i < ra->prefixes->len; i++) {
|
||||||
FakePrefix * item = &g_array_index(ra->prefixes, FakePrefix, i);
|
FakePrefix * item = &g_array_index(ra->prefixes, FakePrefix, i);
|
||||||
NMNDiscRoute route = {
|
const NMNDiscRoute route = {
|
||||||
.network = item->network,
|
.network = item->network,
|
||||||
.plen = item->plen,
|
.plen = item->plen,
|
||||||
.gateway = item->gateway,
|
.gateway = item->gateway,
|
||||||
.timestamp = item->timestamp,
|
.expiry_msec = item->expiry_msec,
|
||||||
.lifetime = item->lifetime,
|
.preference = item->preference,
|
||||||
.preference = item->preference,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
g_assert(route.plen > 0 && route.plen <= 128);
|
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;
|
changed |= NM_NDISC_CONFIG_ROUTES;
|
||||||
|
|
||||||
if (item->plen == 64) {
|
if (item->plen == 64) {
|
||||||
NMNDiscAddress address = {
|
const NMNDiscAddress address = {
|
||||||
.address = item->network,
|
.address = item->network,
|
||||||
.timestamp = item->timestamp,
|
.expiry_msec = item->expiry_msec,
|
||||||
.lifetime = item->lifetime,
|
.expiry_preferred_msec = item->expiry_preferred_msec,
|
||||||
.preferred = item->preferred,
|
.dad_counter = 0,
|
||||||
.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;
|
changed |= NM_NDISC_CONFIG_ADDRESSES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ra->dns_servers->len; i++) {
|
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;
|
changed |= NM_NDISC_CONFIG_DNS_SERVERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ra->dns_domains->len; i++) {
|
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;
|
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);
|
priv->ras = g_slist_remove(priv->ras, priv->ras->data);
|
||||||
fake_ra_free(ra);
|
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 */
|
/* Schedule next RA */
|
||||||
if (priv->ras) {
|
if (priv->ras) {
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,7 @@ guint nm_fake_ndisc_add_ra(NMFakeNDisc * self,
|
||||||
void nm_fake_ndisc_add_gateway(NMFakeNDisc * self,
|
void nm_fake_ndisc_add_gateway(NMFakeNDisc * self,
|
||||||
guint ra_id,
|
guint ra_id,
|
||||||
const char * addr,
|
const char * addr,
|
||||||
guint32 timestamp,
|
gint64 expiry_msec,
|
||||||
guint32 lifetime,
|
|
||||||
NMIcmpv6RouterPref preference);
|
NMIcmpv6RouterPref preference);
|
||||||
|
|
||||||
void nm_fake_ndisc_add_prefix(NMFakeNDisc * self,
|
void nm_fake_ndisc_add_prefix(NMFakeNDisc * self,
|
||||||
|
|
@ -44,22 +43,19 @@ void nm_fake_ndisc_add_prefix(NMFakeNDisc * self,
|
||||||
const char * network,
|
const char * network,
|
||||||
guint plen,
|
guint plen,
|
||||||
const char * gateway,
|
const char * gateway,
|
||||||
guint32 timestamp,
|
gint64 expiry_msec,
|
||||||
guint32 lifetime,
|
gint64 expiry_preferred_msec,
|
||||||
guint32 preferred,
|
|
||||||
NMIcmpv6RouterPref preference);
|
NMIcmpv6RouterPref preference);
|
||||||
|
|
||||||
void nm_fake_ndisc_add_dns_server(NMFakeNDisc *self,
|
void nm_fake_ndisc_add_dns_server(NMFakeNDisc *self,
|
||||||
guint ra_id,
|
guint ra_id,
|
||||||
const char * address,
|
const char * address,
|
||||||
guint32 timestamp,
|
gint64 expiry_msec);
|
||||||
guint32 lifetime);
|
|
||||||
|
|
||||||
void nm_fake_ndisc_add_dns_domain(NMFakeNDisc *self,
|
void nm_fake_ndisc_add_dns_domain(NMFakeNDisc *self,
|
||||||
guint ra_id,
|
guint ra_id,
|
||||||
const char * domain,
|
const char * domain,
|
||||||
guint32 timestamp,
|
gint64 expiry_msec);
|
||||||
guint32 lifetime);
|
|
||||||
|
|
||||||
void nm_fake_ndisc_emit_new_ras(NMFakeNDisc *self);
|
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;
|
NMNDiscConfigMap changed = 0;
|
||||||
struct ndp_msgra * msgra = ndp_msgra(msg);
|
struct ndp_msgra * msgra = ndp_msgra(msg);
|
||||||
struct in6_addr gateway_addr;
|
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 offset;
|
||||||
int hop_limit;
|
int hop_limit;
|
||||||
guint32 val;
|
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
|
* single time when the configuration is finished and updates can
|
||||||
* come at any time.
|
* 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);
|
gateway_addr = *ndp_msg_addrto(msg);
|
||||||
if (IN6_IS_ADDR_UNSPECIFIED(&gateway_addr))
|
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 = {
|
const NMNDiscGateway gateway = {
|
||||||
.address = gateway_addr,
|
.address = gateway_addr,
|
||||||
.timestamp = now,
|
.expiry_msec = _nm_ndisc_lifetime_to_expiry(now_msec, ndp_msgra_router_lifetime(msgra)),
|
||||||
.lifetime = ndp_msgra_router_lifetime(msgra),
|
.preference = _route_preference_coerce(ndp_msgra_route_preference(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;
|
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)) {
|
if (ndp_msg_opt_prefix_flag_on_link(msg, offset)) {
|
||||||
const NMNDiscRoute route = {
|
const NMNDiscRoute route = {
|
||||||
.network = r_network,
|
.network = r_network,
|
||||||
.plen = r_plen,
|
.plen = r_plen,
|
||||||
.timestamp = now,
|
.expiry_msec =
|
||||||
.lifetime = ndp_msg_opt_prefix_valid_time(msg, offset),
|
_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;
|
changed |= NM_NDISC_CONFIG_ROUTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Address */
|
/* Address */
|
||||||
if (r_plen == 64 && ndp_msg_opt_prefix_flag_auto_addr_conf(msg, offset)) {
|
if (r_plen == 64 && ndp_msg_opt_prefix_flag_auto_addr_conf(msg, offset)) {
|
||||||
NMNDiscAddress address = {
|
const guint32 valid_time = ndp_msg_opt_prefix_valid_time(msg, offset);
|
||||||
.address = r_network,
|
const guint32 preferred_time =
|
||||||
.timestamp = now,
|
NM_MIN(ndp_msg_opt_prefix_preferred_time(msg, offset), valid_time);
|
||||||
.lifetime = ndp_msg_opt_prefix_valid_time(msg, offset),
|
const NMNDiscAddress address = {
|
||||||
.preferred = ndp_msg_opt_prefix_preferred_time(msg, offset),
|
.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_msec))
|
||||||
if (nm_ndisc_complete_and_add_address(ndisc, &address, now))
|
changed |= NM_NDISC_CONFIG_ADDRESSES;
|
||||||
changed |= NM_NDISC_CONFIG_ADDRESSES;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_ROUTE) {
|
ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_ROUTE) {
|
||||||
NMNDiscRoute route = {
|
guint8 plen = ndp_msg_opt_route_prefix_len(msg, offset);
|
||||||
.gateway = gateway_addr,
|
struct in6_addr network;
|
||||||
.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)),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (route.plen == 0 || route.plen > 128)
|
if (plen == 0 || plen > 128)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Routers through this particular gateway */
|
nm_utils_ip6_address_clear_host_address(&network,
|
||||||
nm_utils_ip6_address_clear_host_address(&route.network,
|
|
||||||
ndp_msg_opt_route_prefix(msg, offset),
|
ndp_msg_opt_route_prefix(msg, offset),
|
||||||
route.plen);
|
plen);
|
||||||
if (nm_ndisc_add_route(ndisc, &route))
|
|
||||||
changed |= NM_NDISC_CONFIG_ROUTES;
|
{
|
||||||
|
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) {
|
ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_RDNSS) {
|
||||||
struct in6_addr *addr;
|
struct in6_addr *addr;
|
||||||
int addr_index;
|
int addr_index;
|
||||||
|
|
||||||
ndp_msg_opt_rdnss_for_each_addr (addr, addr_index, msg, offset) {
|
ndp_msg_opt_rdnss_for_each_addr (addr, addr_index, msg, offset) {
|
||||||
NMNDiscDNSServer dns_server = {
|
const NMNDiscDNSServer dns_server = {
|
||||||
.address = *addr,
|
.address = *addr,
|
||||||
.timestamp = now,
|
.expiry_msec =
|
||||||
.lifetime = ndp_msg_opt_rdnss_lifetime(msg, offset),
|
_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;
|
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;
|
int domain_index;
|
||||||
|
|
||||||
ndp_msg_opt_dnssl_for_each_domain (domain, domain_index, msg, offset) {
|
ndp_msg_opt_dnssl_for_each_domain (domain, domain_index, msg, offset) {
|
||||||
NMNDiscDNSDomain dns_domain = {
|
const NMNDiscDNSDomain dns_domain = {
|
||||||
.domain = domain,
|
.domain = domain,
|
||||||
.timestamp = now,
|
.expiry_msec =
|
||||||
.lifetime = ndp_msg_opt_dnssl_lifetime(msg, offset),
|
_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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -374,7 +388,6 @@ send_ra(NMNDisc *ndisc, GError **error)
|
||||||
{
|
{
|
||||||
NMLndpNDiscPrivate * priv = NM_LNDP_NDISC_GET_PRIVATE(ndisc);
|
NMLndpNDiscPrivate * priv = NM_LNDP_NDISC_GET_PRIVATE(ndisc);
|
||||||
NMNDiscDataInternal * rdata = ndisc->rdata;
|
NMNDiscDataInternal * rdata = ndisc->rdata;
|
||||||
gint32 now = nm_utils_get_monotonic_timestamp_sec();
|
|
||||||
int errsv;
|
int errsv;
|
||||||
struct in6_addr * addr;
|
struct in6_addr * addr;
|
||||||
struct ndp_msg * msg;
|
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
|
/* The device let us know about all addresses that the device got
|
||||||
* whose prefixes are suitable for delegating. Let's announce them. */
|
* whose prefixes are suitable for delegating. Let's announce them. */
|
||||||
for (i = 0; i < rdata->addresses->len; i++) {
|
for (i = 0; i < rdata->addresses->len; i++) {
|
||||||
const NMNDiscAddress *address = &g_array_index(rdata->addresses, NMNDiscAddress, 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;
|
|
||||||
struct nd_opt_prefix_info *prefix;
|
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));
|
prefix = _ndp_msg_add_option(msg, sizeof(*prefix));
|
||||||
if (!prefix) {
|
if (!prefix) {
|
||||||
/* Maybe we could sent separate RAs, but why bother... */
|
/* 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_prefix_len = 64;
|
||||||
prefix->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
|
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_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
|
||||||
prefix->nd_opt_pi_valid_time = htonl(lifetime);
|
prefix->nd_opt_pi_valid_time =
|
||||||
prefix->nd_opt_pi_preferred_time = htonl(preferred);
|
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[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[1] = address->address.s6_addr32[1];
|
||||||
prefix->nd_opt_pi_prefix.s6_addr32[2] = 0;
|
prefix->nd_opt_pi_prefix.s6_addr32[2] = 0;
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,15 @@ struct _NMNDiscDataInternal {
|
||||||
|
|
||||||
typedef struct _NMNDiscDataInternal 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);
|
void nm_ndisc_rs_received(NMNDisc *ndisc);
|
||||||
|
|
||||||
gboolean nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *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, gint32 now_s);
|
gboolean
|
||||||
gboolean nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new);
|
nm_ndisc_complete_and_add_address(NMNDisc *ndisc, const NMNDiscAddress *new_item, gint64 now_msec);
|
||||||
gboolean nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new);
|
gboolean nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new_item, gint64 now_msec);
|
||||||
gboolean nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new);
|
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_rs;
|
||||||
gint32 last_ra;
|
gint32 last_ra;
|
||||||
};
|
};
|
||||||
guint timeout_id; /* prefix/dns/etc lifetime timeout */
|
|
||||||
|
GSource *timeout_expire_source;
|
||||||
|
|
||||||
NMUtilsIPv6IfaceId iid;
|
NMUtilsIPv6IfaceId iid;
|
||||||
|
|
||||||
/* immutable values: */
|
/* 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;
|
guint32 ifa_flags;
|
||||||
guint8 plen;
|
guint8 plen;
|
||||||
guint i;
|
guint i;
|
||||||
|
const gint32 now_sec = nm_utils_get_monotonic_timestamp_sec();
|
||||||
|
|
||||||
l3cd = nm_l3_config_data_new(multi_idx, ifindex);
|
l3cd = nm_l3_config_data_new(multi_idx, ifindex);
|
||||||
|
|
||||||
|
|
@ -129,12 +133,17 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx,
|
||||||
NMPlatformIP6Address a;
|
NMPlatformIP6Address a;
|
||||||
|
|
||||||
a = (NMPlatformIP6Address){
|
a = (NMPlatformIP6Address){
|
||||||
.ifindex = ifindex,
|
.ifindex = ifindex,
|
||||||
.address = ndisc_addr->address,
|
.address = ndisc_addr->address,
|
||||||
.plen = plen,
|
.plen = plen,
|
||||||
.timestamp = ndisc_addr->timestamp,
|
.timestamp = now_sec,
|
||||||
.lifetime = ndisc_addr->lifetime,
|
.lifetime = _nm_ndisc_lifetime_from_expiry(((gint64) now_sec) * 1000,
|
||||||
.preferred = MIN(ndisc_addr->lifetime, ndisc_addr->preferred),
|
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,
|
.addr_source = NM_IP_CONFIG_SOURCE_NDISC,
|
||||||
.n_ifa_flags = ifa_flags,
|
.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
|
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_msec == NM_NDISC_EXPIRY_INFINITY)
|
||||||
|
|
||||||
if (expiry_timestamp == _EXPIRY_INFINITY)
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
e = MIN(expiry_timestamp, ((gint64)(G_MAXINT32 - 1)));
|
|
||||||
if (now_s >= e)
|
if (expiry_msec <= now_msec) {
|
||||||
|
/* expired. */
|
||||||
return FALSE;
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
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;
|
int l;
|
||||||
|
|
||||||
if (expiry_time == _EXPIRY_INFINITY)
|
if (expiry_time == NM_NDISC_EXPIRY_INFINITY)
|
||||||
return "permanent";
|
return "permanent";
|
||||||
l = g_snprintf(buf,
|
l = g_snprintf(buf, buf_size, "%.3f", ((double) (expiry_time - now_msec)) / 1000);
|
||||||
buf_size,
|
|
||||||
"%.4f",
|
|
||||||
((double) ((expiry_time * NM_UTILS_NSEC_PER_SEC) - now_ns))
|
|
||||||
/ ((double) NM_UTILS_NSEC_PER_SEC));
|
|
||||||
nm_assert(l < buf_size);
|
nm_assert(l < buf_size);
|
||||||
return buf;
|
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);
|
const NMNDiscGateway *item = &g_array_index(data->gateways, NMNDiscGateway, i);
|
||||||
|
|
||||||
nm_assert(!IN6_IS_ADDR_UNSPECIFIED(&item->address));
|
nm_assert(!IN6_IS_ADDR_UNSPECIFIED(&item->address));
|
||||||
nm_assert(item->timestamp > 0 && item->timestamp <= G_MAXINT32);
|
|
||||||
for (j = 0; j < i; j++) {
|
for (j = 0; j < i; j++) {
|
||||||
const NMNDiscGateway *item2 = &g_array_index(data->gateways, NMNDiscGateway, j);
|
const NMNDiscGateway *item2 = &g_array_index(data->gateways, NMNDiscGateway, j);
|
||||||
|
|
||||||
nm_assert(!IN6_ARE_ADDR_EQUAL(&item->address, &item2->address));
|
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)
|
nm_assert(_preference_to_priority(item_prev->preference)
|
||||||
>= _preference_to_priority(item->preference));
|
>= _preference_to_priority(item->preference));
|
||||||
|
}
|
||||||
|
|
||||||
item_prev = item;
|
item_prev = item;
|
||||||
}
|
}
|
||||||
|
|
@ -408,7 +388,7 @@ nm_ndisc_emit_config_change(NMNDisc *self, NMNDiscConfigMap changed)
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
gboolean
|
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;
|
NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
@ -417,41 +397,43 @@ nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *new)
|
||||||
for (i = 0; i < rdata->gateways->len;) {
|
for (i = 0; i < rdata->gateways->len;) {
|
||||||
NMNDiscGateway *item = &g_array_index(rdata->gateways, NMNDiscGateway, i);
|
NMNDiscGateway *item = &g_array_index(rdata->gateways, NMNDiscGateway, i);
|
||||||
|
|
||||||
if (IN6_ARE_ADDR_EQUAL(&item->address, &new->address)) {
|
if (IN6_ARE_ADDR_EQUAL(&item->address, &new_item->address)) {
|
||||||
if (new->lifetime == 0) {
|
if (new_item->expiry_msec <= now_msec) {
|
||||||
g_array_remove_index(rdata->gateways, i);
|
g_array_remove_index(rdata->gateways, i);
|
||||||
_ASSERT_data_gateways(rdata);
|
_ASSERT_data_gateways(rdata);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->preference != new->preference) {
|
if (item->preference != new_item->preference) {
|
||||||
g_array_remove_index(rdata->gateways, i);
|
g_array_remove_index(rdata->gateways, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_expiry(item) == get_expiry(new))
|
if (item->expiry_msec == new_item->expiry_msec)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
*item = *new;
|
item->expiry_msec = new_item->expiry_msec;
|
||||||
_ASSERT_data_gateways(rdata);
|
_ASSERT_data_gateways(rdata);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put before less preferable gateways. */
|
/* 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 == G_MAXUINT)
|
||||||
insert_idx = i;
|
insert_idx = i;
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new->lifetime) {
|
if (new_item->expiry_msec <= now_msec)
|
||||||
g_array_insert_val(rdata->gateways,
|
return FALSE;
|
||||||
insert_idx == G_MAXUINT ? rdata->gateways->len : insert_idx,
|
|
||||||
*new);
|
g_array_insert_val(rdata->gateways,
|
||||||
}
|
insert_idx == G_MAXUINT ? rdata->gateways->len : insert_idx,
|
||||||
|
*new_item);
|
||||||
_ASSERT_data_gateways(rdata);
|
_ASSERT_data_gateways(rdata);
|
||||||
return !!new->lifetime;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -504,25 +486,27 @@ complete_address(NMNDisc *ndisc, NMNDiscAddress *addr)
|
||||||
return TRUE;
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
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);
|
NMNDiscPrivate * priv = NM_NDISC_GET_PRIVATE(ndisc);
|
||||||
NMNDiscDataInternal *rdata = &priv->rdata;
|
NMNDiscDataInternal *rdata = &priv->rdata;
|
||||||
NMNDiscAddress new2;
|
NMNDiscAddress * new2;
|
||||||
NMNDiscAddress * existing = NULL;
|
NMNDiscAddress * existing = NULL;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
nm_assert(new);
|
nm_assert(new_item);
|
||||||
nm_assert(new->timestamp > 0 && new->timestamp < G_MAXINT32);
|
nm_assert(!IN6_IS_ADDR_UNSPECIFIED(&new_item->address));
|
||||||
nm_assert(!IN6_IS_ADDR_UNSPECIFIED(&new->address));
|
nm_assert(!IN6_IS_ADDR_LINKLOCAL(&new_item->address));
|
||||||
nm_assert(!IN6_IS_ADDR_LINKLOCAL(&new->address));
|
nm_assert(new_item->expiry_preferred_msec <= new_item->expiry_msec);
|
||||||
nm_assert(new->preferred <= new->lifetime);
|
nm_assert((!!from_ra) == (now_msec > 0));
|
||||||
nm_assert(!from_ra || now_s > 0);
|
|
||||||
|
|
||||||
for (i = 0; i < rdata->addresses->len; i++) {
|
for (i = 0; i < rdata->addresses->len; i++) {
|
||||||
NMNDiscAddress *item = &g_array_index(rdata->addresses, NMNDiscAddress, 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) {
|
if (from_ra) {
|
||||||
/* RFC4862 5.5.3.d, we find an existing address with the same prefix.
|
/* 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). */
|
* (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;
|
existing = item;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (IN6_ARE_ADDR_EQUAL(&item->address, &new->address)) {
|
if (IN6_ARE_ADDR_EQUAL(&item->address, &new_item->address)) {
|
||||||
existing = item;
|
existing = item;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -543,67 +527,60 @@ nm_ndisc_add_address(NMNDisc *ndisc, const NMNDiscAddress *new, gint32 now_s, gb
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
|
gint64 new_expiry_preferred_msec;
|
||||||
|
gint64 new_expiry_msec;
|
||||||
|
|
||||||
if (from_ra) {
|
if (from_ra) {
|
||||||
const gint32 NM_NDISC_PREFIX_LFT_MIN = 7200; /* seconds, RFC4862 5.5.3.e */
|
if (new_item->expiry_msec == NM_NDISC_EXPIRY_INFINITY)
|
||||||
gint64 old_expiry_lifetime, old_expiry_preferred;
|
new_expiry_msec = NM_NDISC_EXPIRY_INFINITY;
|
||||||
|
|
||||||
old_expiry_lifetime = get_expiry(existing);
|
|
||||||
old_expiry_preferred = get_expiry_preferred(existing);
|
|
||||||
|
|
||||||
if (new->lifetime == NM_NDISC_INFINITY)
|
|
||||||
existing->lifetime = NM_NDISC_INFINITY;
|
|
||||||
else {
|
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 */
|
/* see RFC4862 5.5.3.e */
|
||||||
if (existing->lifetime == NM_NDISC_INFINITY)
|
if (new_lifetime >= NDISC_PREFIX_LFT_MIN_MSEC
|
||||||
remaining_lifetime = G_MAXINT64;
|
|| new_lifetime >= existing_lifetime) {
|
||||||
else
|
/* either extend the lifetime of the new_item lifetime is longer than
|
||||||
remaining_lifetime = ((gint64) existing->timestamp)
|
* NDISC_PREFIX_LFT_MIN_MSEC. */
|
||||||
+ ((gint64) existing->lifetime) - ((gint64) now_s);
|
new_expiry_msec = new_item->expiry_msec;
|
||||||
new_lifetime =
|
} else if (existing_lifetime <= NDISC_PREFIX_LFT_MIN_MSEC) {
|
||||||
((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) {
|
|
||||||
/* keep the current lifetime. */
|
/* keep the current lifetime. */
|
||||||
|
new_expiry_msec = existing->expiry_msec;
|
||||||
} else {
|
} else {
|
||||||
existing->timestamp = now_s;
|
/* trim the current lifetime to NDISC_PREFIX_LFT_MIN_MSEC. */
|
||||||
existing->lifetime = NM_NDISC_PREFIX_LFT_MIN;
|
new_expiry_msec = now_msec + NDISC_PREFIX_LFT_MIN_MSEC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new->preferred == NM_NDISC_INFINITY) {
|
new_expiry_preferred_msec =
|
||||||
nm_assert(existing->lifetime == NM_NDISC_INFINITY);
|
NM_MIN(new_item->expiry_preferred_msec, new_item->expiry_msec);
|
||||||
existing->preferred = new->preferred;
|
new_expiry_preferred_msec = NM_MIN(new_expiry_preferred_msec, new_expiry_msec);
|
||||||
} else {
|
} else {
|
||||||
existing->preferred = NM_CLAMP(((gint64) new->timestamp) + ((gint64) new->preferred)
|
if (new_item->expiry_msec <= now_msec) {
|
||||||
- ((gint64) existing->timestamp),
|
g_array_remove_index(rdata->addresses, i);
|
||||||
0,
|
return TRUE;
|
||||||
G_MAXUINT32 - 1);
|
|
||||||
if (existing->lifetime != NM_NDISC_INFINITY)
|
|
||||||
existing->preferred = MIN(existing->preferred, existing->lifetime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return old_expiry_lifetime != get_expiry(existing)
|
new_expiry_msec = new_item->expiry_msec;
|
||||||
|| old_expiry_preferred != get_expiry_preferred(existing);
|
new_expiry_preferred_msec =
|
||||||
|
NM_MIN(new_item->expiry_preferred_msec, new_item->expiry_msec);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new->lifetime == 0) {
|
/* the dad_counter does not get modified. */
|
||||||
g_array_remove_index(rdata->addresses, i);
|
if (new_expiry_msec == existing->expiry_msec
|
||||||
return TRUE;
|
&& new_expiry_preferred_msec == existing->expiry_preferred_msec) {
|
||||||
}
|
|
||||||
|
|
||||||
if (get_expiry(existing) == get_expiry(new)
|
|
||||||
&& get_expiry_preferred(existing) == get_expiry_preferred(new))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
existing->timestamp = new->timestamp;
|
existing->expiry_msec = new_expiry_msec;
|
||||||
existing->lifetime = new->lifetime;
|
existing->expiry_preferred_msec = new_expiry_preferred_msec;
|
||||||
existing->preferred = new->preferred;
|
|
||||||
return TRUE;
|
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)
|
if (priv->max_addresses && rdata->addresses->len >= priv->max_addresses)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (new->lifetime == 0)
|
if (new_item->expiry_msec <= now_msec)
|
||||||
return FALSE;
|
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) {
|
if (from_ra) {
|
||||||
new2 = *new;
|
new2->dad_counter = 0;
|
||||||
new2.dad_counter = 0;
|
if (!complete_address(ndisc, new2)) {
|
||||||
if (!complete_address(ndisc, &new2))
|
g_array_set_size(rdata->addresses, rdata->addresses->len - 1);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
new = &new2;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_array_append_val(rdata->addresses, *new);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
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
|
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;
|
NMNDiscPrivate * priv;
|
||||||
NMNDiscDataInternal *rdata;
|
NMNDiscDataInternal *rdata;
|
||||||
guint i;
|
guint i;
|
||||||
guint insert_idx = G_MAXUINT;
|
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
|
/* Only expect non-default routes. The router has no idea what the
|
||||||
* local configuration or user preferences are, so sending routes
|
* local configuration or user preferences are, so sending routes
|
||||||
* with a prefix length of 0 must be ignored by NMNDisc.
|
* 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;) {
|
for (i = 0; i < rdata->routes->len;) {
|
||||||
NMNDiscRoute *item = &g_array_index(rdata->routes, NMNDiscRoute, i);
|
NMNDiscRoute *item = &g_array_index(rdata->routes, NMNDiscRoute, i);
|
||||||
|
|
||||||
if (IN6_ARE_ADDR_EQUAL(&item->network, &new->network) && item->plen == new->plen) {
|
if (IN6_ARE_ADDR_EQUAL(&item->network, &new_item->network)
|
||||||
if (new->lifetime == 0) {
|
&& item->plen == new_item->plen) {
|
||||||
|
if (new_item->expiry_msec <= now_msec) {
|
||||||
g_array_remove_index(rdata->routes, i);
|
g_array_remove_index(rdata->routes, i);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->preference != new->preference) {
|
if (item->preference != new_item->preference) {
|
||||||
g_array_remove_index(rdata->routes, i);
|
g_array_remove_index(rdata->routes, i);
|
||||||
|
changed = TRUE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_expiry(item) == get_expiry(new)
|
if (item->expiry_msec == new_item->expiry_msec
|
||||||
&& IN6_ARE_ADDR_EQUAL(&item->gateway, &new->gateway))
|
&& IN6_ARE_ADDR_EQUAL(&item->gateway, &new_item->gateway))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
*item = *new;
|
item->expiry_msec = new_item->expiry_msec;
|
||||||
|
item->gateway = new_item->gateway;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put before less preferable routes. */
|
/* 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 == G_MAXUINT)
|
||||||
insert_idx = i;
|
insert_idx = i;
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new->lifetime) {
|
if (new_item->expiry_msec <= now_msec) {
|
||||||
g_array_insert_val(rdata->routes, insert_idx == G_MAXUINT ? 0u : insert_idx, *new);
|
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
|
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;
|
NMNDiscPrivate * priv;
|
||||||
NMNDiscDataInternal *rdata;
|
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++) {
|
for (i = 0; i < rdata->dns_servers->len; i++) {
|
||||||
NMNDiscDNSServer *item = &g_array_index(rdata->dns_servers, NMNDiscDNSServer, i);
|
NMNDiscDNSServer *item = &g_array_index(rdata->dns_servers, NMNDiscDNSServer, i);
|
||||||
|
|
||||||
if (IN6_ARE_ADDR_EQUAL(&item->address, &new->address)) {
|
if (IN6_ARE_ADDR_EQUAL(&item->address, &new_item->address)) {
|
||||||
if (new->lifetime == 0) {
|
if (new_item->expiry_msec <= now_msec) {
|
||||||
g_array_remove_index(rdata->dns_servers, i);
|
g_array_remove_index(rdata->dns_servers, i);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_expiry(item) == get_expiry(new))
|
if (item->expiry_msec == new_item->expiry_msec)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
*item = *new;
|
item->expiry_msec = new_item->expiry_msec;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new->lifetime)
|
if (new_item->expiry_msec <= now_msec)
|
||||||
g_array_append_val(rdata->dns_servers, *new);
|
return FALSE;
|
||||||
return !!new->lifetime;
|
|
||||||
|
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
|
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;
|
NMNDiscPrivate * priv;
|
||||||
NMNDiscDataInternal *rdata;
|
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++) {
|
for (i = 0; i < rdata->dns_domains->len; i++) {
|
||||||
item = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i);
|
item = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i);
|
||||||
|
|
||||||
if (!g_strcmp0(item->domain, new->domain)) {
|
if (nm_streq(item->domain, new_item->domain)) {
|
||||||
if (new->lifetime == 0) {
|
if (new_item->expiry_msec <= now_msec) {
|
||||||
g_array_remove_index(rdata->dns_domains, i);
|
g_array_remove_index(rdata->dns_domains, i);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_expiry(item) == get_expiry(new))
|
if (item->expiry_msec == new_item->expiry_msec)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
item->timestamp = new->timestamp;
|
item->expiry_msec = new_item->expiry_msec;
|
||||||
item->lifetime = new->lifetime;
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new->lifetime) {
|
if (new_item->expiry_msec <= now_msec)
|
||||||
g_array_append_val(rdata->dns_domains, *new);
|
return FALSE;
|
||||||
item = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, rdata->dns_domains->len - 1);
|
|
||||||
item->domain = g_strdup(new->domain);
|
item = nm_g_array_append_new(rdata->dns_domains, NMNDiscDNSDomain);
|
||||||
}
|
*item = (NMNDiscDNSDomain){
|
||||||
return !!new->lifetime;
|
.domain = g_strdup(new_item->domain),
|
||||||
|
.expiry_msec = new_item->expiry_msec,
|
||||||
|
};
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#define _MAYBE_WARN(...) \
|
#define _MAYBE_WARN(...) \
|
||||||
G_STMT_START \
|
G_STMT_START \
|
||||||
{ \
|
{ \
|
||||||
gboolean _different_message; \
|
gboolean _different_message; \
|
||||||
\
|
\
|
||||||
_different_message = g_strcmp0(priv->last_error, error->message) != 0; \
|
_different_message = !nm_streq0(priv->last_error, error->message); \
|
||||||
_NMLOG(_different_message ? LOGL_WARN : LOGL_DEBUG, __VA_ARGS__); \
|
_NMLOG(_different_message ? LOGL_WARN : LOGL_DEBUG, __VA_ARGS__); \
|
||||||
if (_different_message) { \
|
if (_different_message) { \
|
||||||
nm_clear_g_free(&priv->last_error); \
|
nm_clear_g_free(&priv->last_error); \
|
||||||
priv->last_error = g_strdup(error->message); \
|
priv->last_error = g_strdup(error->message); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
G_STMT_END
|
G_STMT_END
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
@ -937,12 +931,16 @@ nm_ndisc_set_config(NMNDisc * ndisc,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < dns_servers->len; i++) {
|
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;
|
changed = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < dns_domains->len; i++) {
|
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;
|
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_rs_id);
|
||||||
nm_clear_g_source(&priv->send_ra_id);
|
nm_clear_g_source(&priv->send_ra_id);
|
||||||
nm_clear_g_free(&priv->last_error);
|
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->solicitations_left = 0;
|
||||||
priv->announcements_left = 0;
|
priv->announcements_left = 0;
|
||||||
|
|
@ -1180,15 +1178,15 @@ _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed)
|
||||||
NMNDiscDataInternal *rdata;
|
NMNDiscDataInternal *rdata;
|
||||||
guint i;
|
guint i;
|
||||||
char changedstr[CONFIG_MAP_MAX_STR];
|
char changedstr[CONFIG_MAP_MAX_STR];
|
||||||
char addrstr[INET6_ADDRSTRLEN];
|
char addrstr[NM_UTILS_INET_ADDRSTRLEN];
|
||||||
char str_pref[35];
|
char str_pref[35];
|
||||||
char str_exp[100];
|
char str_exp[100];
|
||||||
gint64 now_ns;
|
gint64 now_msec;
|
||||||
|
|
||||||
if (!_LOGD_ENABLED())
|
if (!_LOGD_ENABLED())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
now_ns = nm_utils_get_monotonic_timestamp_nsec();
|
now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||||
|
|
||||||
priv = NM_NDISC_GET_PRIVATE(ndisc);
|
priv = NM_NDISC_GET_PRIVATE(ndisc);
|
||||||
rdata = &priv->rdata;
|
rdata = &priv->rdata;
|
||||||
|
|
@ -1205,199 +1203,245 @@ _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed)
|
||||||
_LOGD(" retrans timer : %u", (guint) rdata->public.retrans_timer_ms);
|
_LOGD(" retrans timer : %u", (guint) rdata->public.retrans_timer_ms);
|
||||||
|
|
||||||
for (i = 0; i < rdata->gateways->len; i++) {
|
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",
|
_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)),
|
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++) {
|
for (i = 0; i < rdata->addresses->len; i++) {
|
||||||
const NMNDiscAddress *address = &g_array_index(rdata->addresses, NMNDiscAddress, 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",
|
||||||
_LOGD(" address %s exp %s", addrstr, get_exp(str_exp, now_ns, address));
|
_nm_utils_inet6_ntop(&address->address, addrstr),
|
||||||
|
get_exp(str_exp, now_msec, address));
|
||||||
}
|
}
|
||||||
for (i = 0; i < rdata->routes->len; i++) {
|
for (i = 0; i < rdata->routes->len; i++) {
|
||||||
NMNDiscRoute *route = &g_array_index(rdata->routes, NMNDiscRoute, i);
|
const NMNDiscRoute *route = &g_array_index(rdata->routes, NMNDiscRoute, i);
|
||||||
char sbuf[NM_UTILS_INET_ADDRSTRLEN];
|
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",
|
_LOGD(" route %s/%u via %s pref %s exp %s",
|
||||||
addrstr,
|
_nm_utils_inet6_ntop(&route->network, addrstr),
|
||||||
(guint) route->plen,
|
(guint) route->plen,
|
||||||
_nm_utils_inet6_ntop(&route->gateway, sbuf),
|
_nm_utils_inet6_ntop(&route->gateway, sbuf),
|
||||||
nm_icmpv6_router_pref_to_string(route->preference, str_pref, sizeof(str_pref)),
|
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++) {
|
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",
|
||||||
_LOGD(" dns_server %s exp %s", addrstr, get_exp(str_exp, now_ns, dns_server));
|
_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++) {
|
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
|
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 i;
|
||||||
|
guint j;
|
||||||
|
|
||||||
rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
if (rdata->gateways->len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; i < rdata->gateways->len;) {
|
arr = &g_array_index(rdata->gateways, NMNDiscGateway, 0);
|
||||||
NMNDiscGateway *item = &g_array_index(rdata->gateways, NMNDiscGateway, i);
|
|
||||||
|
|
||||||
if (!expiry_next(now, get_expiry(item), nextevent)) {
|
for (i = 0, j = 0; i < rdata->gateways->len; i++) {
|
||||||
g_array_remove_index(rdata->gateways, i);
|
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec))
|
||||||
*changed |= NM_NDISC_CONFIG_GATEWAYS;
|
|
||||||
continue;
|
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);
|
_ASSERT_data_gateways(rdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 i;
|
||||||
|
guint j;
|
||||||
|
|
||||||
rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
if (rdata->addresses->len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; i < rdata->addresses->len;) {
|
arr = &g_array_index(rdata->addresses, NMNDiscAddress, 0);
|
||||||
const NMNDiscAddress *item = &g_array_index(rdata->addresses, NMNDiscAddress, i);
|
|
||||||
|
|
||||||
if (!expiry_next(now, get_expiry(item), nextevent)) {
|
for (i = 0, j = 0; i < rdata->addresses->len; i++) {
|
||||||
g_array_remove_index(rdata->addresses, i);
|
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec))
|
||||||
*changed |= NM_NDISC_CONFIG_ADDRESSES;
|
|
||||||
continue;
|
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
|
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 i;
|
||||||
|
guint j;
|
||||||
|
|
||||||
rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
if (rdata->routes->len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; i < rdata->routes->len;) {
|
arr = &g_array_index(rdata->routes, NMNDiscRoute, 0);
|
||||||
NMNDiscRoute *item = &g_array_index(rdata->routes, NMNDiscRoute, i);
|
|
||||||
|
|
||||||
if (!expiry_next(now, get_expiry(item), nextevent)) {
|
for (i = 0, j = 0; i < rdata->routes->len; i++) {
|
||||||
g_array_remove_index(rdata->routes, i);
|
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec))
|
||||||
*changed |= NM_NDISC_CONFIG_ROUTES;
|
|
||||||
continue;
|
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
|
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 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;) {
|
arr = &g_array_index(rdata->dns_servers, NMNDiscDNSServer, 0);
|
||||||
NMNDiscDNSServer *item = &g_array_index(rdata->dns_servers, NMNDiscDNSServer, i);
|
|
||||||
|
|
||||||
if (!expiry_next(now, get_expiry(item), nextevent)) {
|
for (i = 0, j = 0; i < rdata->dns_servers->len; i++) {
|
||||||
g_array_remove_index(rdata->dns_servers, i);
|
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec))
|
||||||
*changed |= NM_NDISC_CONFIG_DNS_SERVERS;
|
|
||||||
continue;
|
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
|
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 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;) {
|
arr = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, 0);
|
||||||
NMNDiscDNSDomain *item = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i);
|
|
||||||
|
|
||||||
if (!expiry_next(now, get_expiry(item), nextevent)) {
|
for (i = 0, j = 0; i < rdata->dns_domains->len; i++) {
|
||||||
g_array_remove_index(rdata->dns_domains, i);
|
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec))
|
||||||
*changed |= NM_NDISC_CONFIG_DNS_DOMAINS;
|
|
||||||
continue;
|
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
|
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);
|
NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc);
|
||||||
/* Use a magic date in the distant future (~68 years) */
|
gint64 next_msec = G_MAXINT64;
|
||||||
gint32 nextevent = G_MAXINT32;
|
|
||||||
|
|
||||||
nm_clear_g_source(&priv->timeout_id);
|
_LOGT("router-data: check for changed router advertisement data");
|
||||||
|
|
||||||
clean_gateways(ndisc, now, &changed, &nextevent);
|
clean_gateways(ndisc, now_msec, &changed, &next_msec);
|
||||||
clean_addresses(ndisc, now, &changed, &nextevent);
|
clean_addresses(ndisc, now_msec, &changed, &next_msec);
|
||||||
clean_routes(ndisc, now, &changed, &nextevent);
|
clean_routes(ndisc, now_msec, &changed, &next_msec);
|
||||||
clean_dns_servers(ndisc, now, &changed, &nextevent);
|
clean_dns_servers(ndisc, now_msec, &changed, &next_msec);
|
||||||
clean_dns_domains(ndisc, now, &changed, &nextevent);
|
clean_dns_domains(ndisc, now_msec, &changed, &next_msec);
|
||||||
|
|
||||||
if (nextevent != G_MAXINT32) {
|
nm_assert(next_msec > now_msec);
|
||||||
if (nextevent <= now)
|
|
||||||
g_return_if_reached();
|
nm_clear_g_source_inst(&priv->timeout_expire_source);
|
||||||
_LOGD("scheduling next now/lifetime check: %d seconds", (int) (nextevent - now));
|
|
||||||
priv->timeout_id = g_timeout_add_seconds(nextevent - now, timeout_cb, ndisc);
|
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);
|
nm_ndisc_emit_config_change(ndisc, changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
timeout_cb(gpointer user_data)
|
timeout_expire_cb(gpointer user_data)
|
||||||
{
|
{
|
||||||
NMNDisc *self = user_data;
|
check_timestamps(user_data, nm_utils_get_monotonic_timestamp_msec(), NM_NDISC_CONFIG_NONE);
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
NM_NDISC_GET_PRIVATE(self)->timeout_id = 0;
|
|
||||||
check_timestamps(self, nm_utils_get_monotonic_timestamp_sec(), 0);
|
|
||||||
return G_SOURCE_REMOVE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc);
|
||||||
|
|
||||||
nm_clear_g_source_inst(&priv->ra_timeout_source);
|
nm_clear_g_source_inst(&priv->ra_timeout_source);
|
||||||
nm_clear_g_source(&priv->send_rs_id);
|
nm_clear_g_source(&priv->send_rs_id);
|
||||||
nm_clear_g_free(&priv->last_error);
|
nm_clear_g_free(&priv->last_error);
|
||||||
check_timestamps(ndisc, now, changed);
|
check_timestamps(ndisc, now_msec, changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1525,7 +1569,7 @@ dispose(GObject *object)
|
||||||
nm_clear_g_source(&priv->send_ra_id);
|
nm_clear_g_source(&priv->send_ra_id);
|
||||||
nm_clear_g_free(&priv->last_error);
|
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);
|
G_OBJECT_CLASS(nm_ndisc_parent_class)->dispose(object);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,48 +48,91 @@ typedef enum {
|
||||||
NM_NDISC_DHCP_LEVEL_MANAGED
|
NM_NDISC_DHCP_LEVEL_MANAGED
|
||||||
} NMNDiscDHCPLevel;
|
} NMNDiscDHCPLevel;
|
||||||
|
|
||||||
/* we rely on the fact that NM_NDISC_INFINITY is the largest possible
|
#define NM_NDISC_INFINITY_U32 ((uint32_t) -1)
|
||||||
* time duration (G_MAXUINT32) and that the range of finite values
|
|
||||||
* goes from 0 to G_MAXUINT32-1. */
|
|
||||||
#define NM_NDISC_INFINITY G_MAXUINT32
|
|
||||||
|
|
||||||
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;
|
struct in6_addr address;
|
||||||
guint32 timestamp;
|
gint64 expiry_msec;
|
||||||
guint32 lifetime;
|
|
||||||
NMIcmpv6RouterPref preference;
|
NMIcmpv6RouterPref preference;
|
||||||
};
|
} NMNDiscGateway;
|
||||||
typedef struct _NMNDiscGateway NMNDiscGateway;
|
|
||||||
|
|
||||||
struct _NMNDiscAddress {
|
typedef struct _NMNDiscAddress {
|
||||||
struct in6_addr address;
|
struct in6_addr address;
|
||||||
|
gint64 expiry_msec;
|
||||||
|
gint64 expiry_preferred_msec;
|
||||||
guint8 dad_counter;
|
guint8 dad_counter;
|
||||||
guint32 timestamp;
|
} NMNDiscAddress;
|
||||||
guint32 lifetime;
|
|
||||||
guint32 preferred;
|
|
||||||
};
|
|
||||||
typedef struct _NMNDiscAddress NMNDiscAddress;
|
|
||||||
|
|
||||||
struct _NMNDiscRoute {
|
typedef struct _NMNDiscRoute {
|
||||||
struct in6_addr network;
|
struct in6_addr network;
|
||||||
guint8 plen;
|
|
||||||
struct in6_addr gateway;
|
struct in6_addr gateway;
|
||||||
guint32 timestamp;
|
gint64 expiry_msec;
|
||||||
guint32 lifetime;
|
|
||||||
NMIcmpv6RouterPref preference;
|
NMIcmpv6RouterPref preference;
|
||||||
};
|
guint8 plen;
|
||||||
typedef struct _NMNDiscRoute NMNDiscRoute;
|
} NMNDiscRoute;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct in6_addr address;
|
struct in6_addr address;
|
||||||
guint32 timestamp;
|
gint64 expiry_msec;
|
||||||
guint32 lifetime;
|
|
||||||
} NMNDiscDNSServer;
|
} NMNDiscDNSServer;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char * domain;
|
char * domain;
|
||||||
guint32 timestamp;
|
gint64 expiry_msec;
|
||||||
guint32 lifetime;
|
|
||||||
} NMNDiscDNSDomain;
|
} NMNDiscDNSDomain;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
@ -113,6 +156,7 @@ typedef enum {
|
||||||
} NMNDiscNodeType;
|
} NMNDiscNodeType;
|
||||||
|
|
||||||
#define NM_NDISC_MAX_ADDRESSES_DEFAULT 16
|
#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_SOLICITATIONS_DEFAULT 3 /* RFC4861 MAX_RTR_SOLICITATIONS */
|
||||||
#define NM_NDISC_ROUTER_SOLICITATION_INTERVAL_DEFAULT 4 /* RFC4861 RTR_SOLICITATION_INTERVAL */
|
#define NM_NDISC_ROUTER_SOLICITATION_INTERVAL_DEFAULT 4 /* RFC4861 RTR_SOLICITATION_INTERVAL */
|
||||||
#define NM_NDISC_ROUTER_ADVERTISEMENTS_DEFAULT 3 /* RFC4861 MAX_INITIAL_RTR_ADVERTISEMENTS */
|
#define NM_NDISC_ROUTER_ADVERTISEMENTS_DEFAULT 3 /* RFC4861 MAX_INITIAL_RTR_ADVERTISEMENTS */
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
#include "nm-test-utils-core.h"
|
#include "nm-test-utils-core.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static NMFakeNDisc *
|
static NMFakeNDisc *
|
||||||
ndisc_new(void)
|
ndisc_new(void)
|
||||||
{
|
{
|
||||||
|
|
@ -26,19 +28,20 @@ ndisc_new(void)
|
||||||
iid.id_u8[7] = 1;
|
iid.id_u8[7] = 1;
|
||||||
nm_ndisc_set_iid(ndisc, iid);
|
nm_ndisc_set_iid(ndisc, iid);
|
||||||
g_assert(ndisc);
|
g_assert(ndisc);
|
||||||
|
|
||||||
return NM_FAKE_NDISC(ndisc);
|
return NM_FAKE_NDISC(ndisc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
match_gateway(const NMNDiscData *rdata,
|
match_gateway(const NMNDiscData *rdata,
|
||||||
guint idx,
|
guint idx,
|
||||||
const char * addr,
|
const char * addr,
|
||||||
guint32 ts,
|
gint64 expiry_msec,
|
||||||
guint32 lt,
|
|
||||||
NMIcmpv6RouterPref pref)
|
NMIcmpv6RouterPref pref)
|
||||||
{
|
{
|
||||||
const NMNDiscGateway *gw;
|
const NMNDiscGateway *gw;
|
||||||
char buf[INET6_ADDRSTRLEN];
|
|
||||||
|
|
||||||
g_assert(rdata);
|
g_assert(rdata);
|
||||||
g_assert_cmpint(idx, <, rdata->gateways_n);
|
g_assert_cmpint(idx, <, rdata->gateways_n);
|
||||||
|
|
@ -46,63 +49,57 @@ match_gateway(const NMNDiscData *rdata,
|
||||||
|
|
||||||
gw = &rdata->gateways[idx];
|
gw = &rdata->gateways[idx];
|
||||||
|
|
||||||
g_assert_cmpstr(inet_ntop(AF_INET6, &gw->address, buf, sizeof(buf)), ==, addr);
|
nmtst_assert_ip6_address(&gw->address, addr);
|
||||||
g_assert_cmpint(gw->timestamp, ==, ts);
|
g_assert_cmpint(gw->expiry_msec, ==, expiry_msec);
|
||||||
g_assert_cmpint(gw->lifetime, ==, lt);
|
|
||||||
g_assert_cmpint(gw->preference, ==, pref);
|
g_assert_cmpint(gw->preference, ==, pref);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define match_address(rdata, idx, addr, ts, lt, pref) \
|
#define match_address(rdata, idx, addr, _expiry_msec, _expiry_preferred_msec) \
|
||||||
G_STMT_START \
|
G_STMT_START \
|
||||||
{ \
|
{ \
|
||||||
const NMNDiscData * _rdata = (rdata); \
|
const NMNDiscData * _rdata = (rdata); \
|
||||||
guint _idx = (idx); \
|
guint _idx = (idx); \
|
||||||
const NMNDiscAddress *_a; \
|
const NMNDiscAddress *_a; \
|
||||||
guint _ts = (ts); \
|
\
|
||||||
\
|
g_assert(_rdata); \
|
||||||
g_assert(_rdata); \
|
g_assert_cmpint(_idx, <, _rdata->addresses_n); \
|
||||||
g_assert_cmpint(_idx, <, _rdata->addresses_n); \
|
g_assert(_rdata->addresses); \
|
||||||
g_assert(_rdata->addresses); \
|
\
|
||||||
\
|
_a = &_rdata->addresses[_idx]; \
|
||||||
_a = &_rdata->addresses[_idx]; \
|
\
|
||||||
\
|
nmtst_assert_ip6_address(&_a->address, (addr)); \
|
||||||
nmtst_assert_ip6_address(&_a->address, (addr)); \
|
g_assert_cmpint(_a->expiry_msec, ==, (_expiry_msec)); \
|
||||||
g_assert_cmpint(_a->timestamp, <=, _ts + 1); \
|
g_assert_cmpint(_a->expiry_preferred_msec, ==, (_expiry_preferred_msec)); \
|
||||||
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)); \
|
|
||||||
} \
|
|
||||||
G_STMT_END
|
G_STMT_END
|
||||||
|
|
||||||
#define match_route(rdata, idx, nw, pl, gw, ts, lt, pref) \
|
#define match_route(rdata, idx, nw, pl, gw, _expiry_msec, pref) \
|
||||||
G_STMT_START \
|
G_STMT_START \
|
||||||
{ \
|
{ \
|
||||||
const NMNDiscData * _rdata = (rdata); \
|
const NMNDiscData * _rdata = (rdata); \
|
||||||
guint _idx = (idx); \
|
guint _idx = (idx); \
|
||||||
const NMNDiscRoute *_r; \
|
const NMNDiscRoute *_r; \
|
||||||
int _plen = (pl); \
|
int _plen = (pl); \
|
||||||
\
|
\
|
||||||
g_assert(_rdata); \
|
g_assert(_rdata); \
|
||||||
g_assert_cmpint(_idx, <, _rdata->routes_n); \
|
g_assert_cmpint(_idx, <, _rdata->routes_n); \
|
||||||
g_assert(_rdata->routes); \
|
g_assert(_rdata->routes); \
|
||||||
g_assert(_plen > 0 && _plen <= 128); \
|
g_assert(_plen > 0 && _plen <= 128); \
|
||||||
\
|
\
|
||||||
_r = &_rdata->routes[idx]; \
|
_r = &_rdata->routes[idx]; \
|
||||||
\
|
\
|
||||||
nmtst_assert_ip6_address(&_r->network, (nw)); \
|
nmtst_assert_ip6_address(&_r->network, (nw)); \
|
||||||
g_assert_cmpint((int) _r->plen, ==, _plen); \
|
g_assert_cmpint((int) _r->plen, ==, _plen); \
|
||||||
nmtst_assert_ip6_address(&_r->gateway, (gw)); \
|
nmtst_assert_ip6_address(&_r->gateway, (gw)); \
|
||||||
g_assert_cmpint(_r->timestamp, ==, (ts)); \
|
g_assert_cmpint(_r->expiry_msec, ==, (_expiry_msec)); \
|
||||||
g_assert_cmpint(_r->lifetime, ==, (lt)); \
|
g_assert_cmpint(_r->preference, ==, (pref)); \
|
||||||
g_assert_cmpint(_r->preference, ==, (pref)); \
|
} \
|
||||||
} \
|
|
||||||
G_STMT_END
|
G_STMT_END
|
||||||
|
|
||||||
static void
|
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;
|
const NMNDiscDNSServer *dns;
|
||||||
char buf[INET6_ADDRSTRLEN];
|
|
||||||
|
|
||||||
g_assert(rdata);
|
g_assert(rdata);
|
||||||
g_assert_cmpint(idx, <, rdata->dns_servers_n);
|
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];
|
dns = &rdata->dns_servers[idx];
|
||||||
|
|
||||||
g_assert_cmpstr(inet_ntop(AF_INET6, &dns->address, buf, sizeof(buf)), ==, addr);
|
nmtst_assert_ip6_address(&dns->address, addr);
|
||||||
g_assert_cmpint(dns->timestamp, ==, ts);
|
g_assert_cmpint(dns->expiry_msec, ==, expiry_msec);
|
||||||
g_assert_cmpint(dns->lifetime, ==, lt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
const NMNDiscDNSDomain *dns;
|
||||||
|
|
||||||
|
|
@ -127,67 +123,96 @@ match_dns_domain(const NMNDiscData *rdata, guint idx, const char *domain, guint3
|
||||||
dns = &rdata->dns_domains[idx];
|
dns = &rdata->dns_domains[idx];
|
||||||
|
|
||||||
g_assert_cmpstr(dns->domain, ==, domain);
|
g_assert_cmpstr(dns->domain, ==, domain);
|
||||||
g_assert_cmpint(dns->timestamp, ==, ts);
|
g_assert_cmpint(dns->expiry_msec, ==, expiry_msec);
|
||||||
g_assert_cmpint(dns->lifetime, ==, lt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
|
gint64 timestamp_msec_1;
|
||||||
guint counter;
|
guint counter;
|
||||||
guint rs_counter;
|
guint rs_counter;
|
||||||
guint32 timestamp1;
|
gint64 first_solicit_msec;
|
||||||
guint32 first_solicit;
|
|
||||||
guint32 timeout_id;
|
guint32 timeout_id;
|
||||||
} TestData;
|
} TestData;
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_simple_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, TestData *data)
|
test_simple_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, TestData *data)
|
||||||
{
|
{
|
||||||
NMNDiscConfigMap changed = changed_int;
|
NMNDiscConfigMap changed = changed_int;
|
||||||
|
|
||||||
g_assert_cmpint(changed,
|
switch (data->counter++) {
|
||||||
==,
|
case 0:
|
||||||
NM_NDISC_CONFIG_DHCP_LEVEL | NM_NDISC_CONFIG_GATEWAYS
|
g_assert_cmpint(changed,
|
||||||
| NM_NDISC_CONFIG_ADDRESSES | NM_NDISC_CONFIG_ROUTES
|
==,
|
||||||
| NM_NDISC_CONFIG_DNS_SERVERS | NM_NDISC_CONFIG_DNS_DOMAINS
|
NM_NDISC_CONFIG_DHCP_LEVEL | NM_NDISC_CONFIG_GATEWAYS
|
||||||
| NM_NDISC_CONFIG_HOP_LIMIT | NM_NDISC_CONFIG_MTU);
|
| NM_NDISC_CONFIG_ADDRESSES | NM_NDISC_CONFIG_ROUTES
|
||||||
g_assert_cmpint(rdata->dhcp_level, ==, NM_NDISC_DHCP_LEVEL_OTHERCONF);
|
| NM_NDISC_CONFIG_DNS_SERVERS | NM_NDISC_CONFIG_DNS_DOMAINS
|
||||||
match_gateway(rdata, 0, "fe80::1", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
| NM_NDISC_CONFIG_HOP_LIMIT | NM_NDISC_CONFIG_MTU);
|
||||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
|
g_assert_cmpint(rdata->dhcp_level, ==, NM_NDISC_DHCP_LEVEL_OTHERCONF);
|
||||||
match_route(rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 10);
|
match_gateway(rdata,
|
||||||
match_dns_server(rdata, 0, "2001:db8:c:c::1", data->timestamp1, 10);
|
0,
|
||||||
match_dns_domain(rdata, 0, "foobar.com", data->timestamp1, 10);
|
"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)));
|
g_assert(nm_fake_ndisc_done(NM_FAKE_NDISC(ndisc)));
|
||||||
data->counter++;
|
break;
|
||||||
g_main_loop_quit(data->loop);
|
case 1:
|
||||||
|
g_main_loop_quit(data->loop);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_simple(void)
|
test_simple(void)
|
||||||
{
|
{
|
||||||
NMFakeNDisc *ndisc = ndisc_new();
|
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
gs_unref_object NMFakeNDisc *ndisc = ndisc_new();
|
||||||
TestData data = {g_main_loop_new(NULL, FALSE), 0, 0, now};
|
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||||
guint id;
|
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);
|
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_OTHERCONF, 4, 1500);
|
||||||
g_assert(id);
|
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_gateway(ndisc, id, "fe80::1", now_msec + 10000, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
||||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now, 10);
|
nm_fake_ndisc_add_prefix(ndisc,
|
||||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar.com", now, 10);
|
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);
|
g_signal_connect(ndisc, NM_NDISC_CONFIG_RECEIVED, G_CALLBACK(test_simple_changed), &data);
|
||||||
|
|
||||||
nm_ndisc_start(NM_NDISC(ndisc));
|
nm_ndisc_start(NM_NDISC(ndisc));
|
||||||
nmtst_main_loop_run_assert(data.loop, 15000);
|
nmtst_main_loop_run_assert(data.loop, 15000);
|
||||||
g_assert_cmpint(data.counter, ==, 1);
|
g_assert_cmpint(data.counter, ==, 2);
|
||||||
|
|
||||||
g_object_unref(ndisc);
|
|
||||||
g_main_loop_unref(data.loop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_everything_rs_sent(NMNDisc *ndisc, TestData *data)
|
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_ADDRESSES | NM_NDISC_CONFIG_ROUTES
|
||||||
| NM_NDISC_CONFIG_DNS_SERVERS | NM_NDISC_CONFIG_DNS_DOMAINS
|
| NM_NDISC_CONFIG_DNS_SERVERS | NM_NDISC_CONFIG_DNS_DOMAINS
|
||||||
| NM_NDISC_CONFIG_HOP_LIMIT | NM_NDISC_CONFIG_MTU);
|
| NM_NDISC_CONFIG_HOP_LIMIT | NM_NDISC_CONFIG_MTU);
|
||||||
match_gateway(rdata, 0, "fe80::1", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
match_gateway(rdata,
|
||||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
|
0,
|
||||||
match_route(rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 10);
|
"fe80::1",
|
||||||
match_dns_server(rdata, 0, "2001:db8:c:c::1", data->timestamp1, 10);
|
data->timestamp_msec_1 + 10000,
|
||||||
match_dns_domain(rdata, 0, "foobar.com", data->timestamp1, 10);
|
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) {
|
} else if (data->counter == 1) {
|
||||||
g_assert_cmpint(changed,
|
g_assert_cmpint(changed,
|
||||||
==,
|
==,
|
||||||
|
|
@ -221,16 +254,28 @@ test_everything_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_
|
||||||
| NM_NDISC_CONFIG_DNS_DOMAINS);
|
| NM_NDISC_CONFIG_DNS_DOMAINS);
|
||||||
|
|
||||||
g_assert_cmpint(rdata->gateways_n, ==, 1);
|
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);
|
g_assert_cmpint(rdata->addresses_n, ==, 2);
|
||||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 0);
|
match_address(rdata,
|
||||||
match_address(rdata, 1, "2001:db8:a:b::1", data->timestamp1, 10, 10);
|
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);
|
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);
|
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);
|
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_assert(nm_fake_ndisc_done(NM_FAKE_NDISC(ndisc)));
|
||||||
g_main_loop_quit(data->loop);
|
g_main_loop_quit(data->loop);
|
||||||
|
|
@ -243,31 +288,49 @@ test_everything_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_
|
||||||
static void
|
static void
|
||||||
test_everything(void)
|
test_everything(void)
|
||||||
{
|
{
|
||||||
NMFakeNDisc *ndisc = ndisc_new();
|
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
gs_unref_object NMFakeNDisc *ndisc = ndisc_new();
|
||||||
TestData data = {g_main_loop_new(NULL, FALSE), 0, 0, now};
|
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||||
guint id;
|
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);
|
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||||
g_assert(id);
|
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_add_prefix(ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 10);
|
nm_fake_ndisc_add_prefix(ndisc,
|
||||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now, 10);
|
id,
|
||||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar.com", now, 10);
|
"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 */
|
/* expire everything from the first RA in the second */
|
||||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||||
g_assert(id);
|
g_assert(id);
|
||||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 0, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
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, 0, 0, 0);
|
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, 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, 0);
|
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar.com", now_msec);
|
||||||
|
|
||||||
/* and add some new stuff */
|
/* 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_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, 10, 10, 10);
|
nm_fake_ndisc_add_prefix(ndisc,
|
||||||
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::2", now, 10);
|
id,
|
||||||
nm_fake_ndisc_add_dns_domain(ndisc, id, "foobar2.com", now, 10);
|
"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_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);
|
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);
|
nmtst_main_loop_run_assert(data.loop, 15000);
|
||||||
g_assert_cmpint(data.counter, ==, 2);
|
g_assert_cmpint(data.counter, ==, 2);
|
||||||
g_assert_cmpint(data.rs_counter, ==, 1);
|
g_assert_cmpint(data.rs_counter, ==, 1);
|
||||||
|
|
||||||
g_object_unref(ndisc);
|
|
||||||
g_main_loop_unref(data.loop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -296,14 +356,30 @@ test_preference_order_cb(NMNDisc * ndisc,
|
||||||
| NM_NDISC_CONFIG_ROUTES);
|
| NM_NDISC_CONFIG_ROUTES);
|
||||||
|
|
||||||
g_assert_cmpint(rdata->gateways_n, ==, 2);
|
g_assert_cmpint(rdata->gateways_n, ==, 2);
|
||||||
match_gateway(rdata, 0, "fe80::1", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_HIGH);
|
match_gateway(rdata,
|
||||||
match_gateway(rdata, 1, "fe80::2", data->timestamp1 + 1, 10, NM_ICMPV6_ROUTER_PREF_LOW);
|
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);
|
g_assert_cmpint(rdata->addresses_n, ==, 2);
|
||||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
|
match_address(rdata,
|
||||||
match_address(rdata, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10);
|
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);
|
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, 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->timestamp1, 10, 5);
|
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_assert(nm_fake_ndisc_done(NM_FAKE_NDISC(ndisc)));
|
||||||
g_main_loop_quit(data->loop);
|
g_main_loop_quit(data->loop);
|
||||||
|
|
@ -315,31 +391,46 @@ test_preference_order_cb(NMNDisc * ndisc,
|
||||||
static void
|
static void
|
||||||
test_preference_order(void)
|
test_preference_order(void)
|
||||||
{
|
{
|
||||||
NMFakeNDisc *ndisc = ndisc_new();
|
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
gs_unref_object NMFakeNDisc *ndisc = ndisc_new();
|
||||||
TestData data = {g_main_loop_new(NULL, FALSE), 0, 0, now};
|
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||||
guint id;
|
TestData data = {
|
||||||
|
.loop = loop,
|
||||||
|
.timestamp_msec_1 = now_msec,
|
||||||
|
};
|
||||||
|
guint id;
|
||||||
|
|
||||||
/* Test insertion order of gateways */
|
/* Test insertion order of gateways */
|
||||||
|
|
||||||
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||||
g_assert(id);
|
g_assert(id);
|
||||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 10, NM_ICMPV6_ROUTER_PREF_HIGH);
|
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, 10, 10, 5);
|
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);
|
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||||
g_assert(id);
|
g_assert(id);
|
||||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::2", ++now, 10, NM_ICMPV6_ROUTER_PREF_LOW);
|
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, 10, 10, 10);
|
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);
|
g_signal_connect(ndisc, NM_NDISC_CONFIG_RECEIVED, G_CALLBACK(test_preference_order_cb), &data);
|
||||||
|
|
||||||
nm_ndisc_start(NM_NDISC(ndisc));
|
nm_ndisc_start(NM_NDISC(ndisc));
|
||||||
nmtst_main_loop_run_assert(data.loop, 15000);
|
nmtst_main_loop_run_assert(data.loop, 15000);
|
||||||
g_assert_cmpint(data.counter, ==, 2);
|
g_assert_cmpint(data.counter, ==, 2);
|
||||||
|
|
||||||
g_object_unref(ndisc);
|
|
||||||
g_main_loop_unref(data.loop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -356,14 +447,30 @@ test_preference_changed_cb(NMNDisc * ndisc,
|
||||||
NM_NDISC_CONFIG_GATEWAYS | NM_NDISC_CONFIG_ADDRESSES
|
NM_NDISC_CONFIG_GATEWAYS | NM_NDISC_CONFIG_ADDRESSES
|
||||||
| NM_NDISC_CONFIG_ROUTES);
|
| NM_NDISC_CONFIG_ROUTES);
|
||||||
g_assert_cmpint(rdata->gateways_n, ==, 2);
|
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,
|
||||||
match_gateway(rdata, 1, "fe80::1", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_LOW);
|
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);
|
g_assert_cmpint(rdata->addresses_n, ==, 2);
|
||||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10);
|
match_address(rdata,
|
||||||
match_address(rdata, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10);
|
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);
|
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, 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->timestamp1, 10, 5);
|
match_route(rdata, 1, "2001:db8:a:a::", 64, "fe80::1", data->timestamp_msec_1 + 10000, 5);
|
||||||
} else if (data->counter == 2) {
|
} else if (data->counter == 2) {
|
||||||
g_assert_cmpint(changed,
|
g_assert_cmpint(changed,
|
||||||
==,
|
==,
|
||||||
|
|
@ -371,14 +478,30 @@ test_preference_changed_cb(NMNDisc * ndisc,
|
||||||
| NM_NDISC_CONFIG_ROUTES);
|
| NM_NDISC_CONFIG_ROUTES);
|
||||||
|
|
||||||
g_assert_cmpint(rdata->gateways_n, ==, 2);
|
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,
|
||||||
match_gateway(rdata, 1, "fe80::2", data->timestamp1 + 1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
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);
|
g_assert_cmpint(rdata->addresses_n, ==, 2);
|
||||||
match_address(rdata, 0, "2001:db8:a:a::1", data->timestamp1 + 3, 9, 9);
|
match_address(rdata,
|
||||||
match_address(rdata, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10);
|
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);
|
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, 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->timestamp1 + 1, 10, 10);
|
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_assert(nm_fake_ndisc_done(NM_FAKE_NDISC(ndisc)));
|
||||||
g_main_loop_quit(data->loop);
|
g_main_loop_quit(data->loop);
|
||||||
|
|
@ -390,10 +513,14 @@ test_preference_changed_cb(NMNDisc * ndisc,
|
||||||
static void
|
static void
|
||||||
test_preference_changed(void)
|
test_preference_changed(void)
|
||||||
{
|
{
|
||||||
NMFakeNDisc *ndisc = ndisc_new();
|
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
gs_unref_object NMFakeNDisc *ndisc = ndisc_new();
|
||||||
TestData data = {g_main_loop_new(NULL, FALSE), 0, 0, now};
|
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||||
guint id;
|
TestData data = {
|
||||||
|
.loop = loop,
|
||||||
|
.timestamp_msec_1 = now_msec,
|
||||||
|
};
|
||||||
|
guint id;
|
||||||
|
|
||||||
/* Test that when a low-preference and medium gateway send advertisements,
|
/* Test that when a low-preference and medium gateway send advertisements,
|
||||||
* that if the low-preference gateway switches to high-preference, we do
|
* 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);
|
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||||
g_assert(id);
|
g_assert(id);
|
||||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 10, NM_ICMPV6_ROUTER_PREF_LOW);
|
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, 10, 10, 5);
|
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);
|
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||||
g_assert(id);
|
g_assert(id);
|
||||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::2", ++now, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
|
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, 10, 10, 10);
|
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);
|
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||||
g_assert(id);
|
g_assert(id);
|
||||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", ++now, 10, NM_ICMPV6_ROUTER_PREF_HIGH);
|
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, 10, 10, 15);
|
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,
|
g_signal_connect(ndisc,
|
||||||
NM_NDISC_CONFIG_RECEIVED,
|
NM_NDISC_CONFIG_RECEIVED,
|
||||||
|
|
@ -423,16 +571,15 @@ test_preference_changed(void)
|
||||||
nm_ndisc_start(NM_NDISC(ndisc));
|
nm_ndisc_start(NM_NDISC(ndisc));
|
||||||
nmtst_main_loop_run_assert(data.loop, 15000);
|
nmtst_main_loop_run_assert(data.loop, 15000);
|
||||||
g_assert_cmpint(data.counter, ==, 3);
|
g_assert_cmpint(data.counter, ==, 3);
|
||||||
|
|
||||||
g_object_unref(ndisc);
|
|
||||||
g_main_loop_unref(data.loop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_dns_solicit_loop_changed(NMNDisc * ndisc,
|
_test_dns_solicit_loop_changed(NMNDisc * ndisc,
|
||||||
const NMNDiscData *rdata,
|
const NMNDiscData *rdata,
|
||||||
guint changed_int,
|
guint changed_int,
|
||||||
TestData * data)
|
TestData * data)
|
||||||
{
|
{
|
||||||
data->counter++;
|
data->counter++;
|
||||||
}
|
}
|
||||||
|
|
@ -446,14 +593,14 @@ success_timeout(TestData *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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();
|
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||||
guint id;
|
guint id;
|
||||||
|
|
||||||
if (data->rs_counter > 0 && data->rs_counter < 6) {
|
if (data->rs_counter > 0 && data->rs_counter < 6) {
|
||||||
if (data->rs_counter == 1) {
|
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 */
|
/* Kill the test after 10 seconds if it hasn't failed yet */
|
||||||
data->timeout_id = g_timeout_add_seconds(10, (GSourceFunc) success_timeout, data);
|
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);
|
id = nm_fake_ndisc_add_ra(ndisc, 0, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||||
g_assert(id);
|
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);
|
nm_fake_ndisc_emit_new_ras(ndisc);
|
||||||
} else if (data->rs_counter >= 6) {
|
} else if (data->rs_counter >= 6) {
|
||||||
/* Fail if we've sent too many solicitations in the past 4 seconds */
|
/* 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_source_remove(data->timeout_id);
|
||||||
g_main_loop_quit(data->loop);
|
g_main_loop_quit(data->loop);
|
||||||
}
|
}
|
||||||
|
|
@ -479,10 +630,14 @@ test_dns_solicit_loop_rs_sent(NMFakeNDisc *ndisc, TestData *data)
|
||||||
static void
|
static void
|
||||||
test_dns_solicit_loop(void)
|
test_dns_solicit_loop(void)
|
||||||
{
|
{
|
||||||
NMFakeNDisc *ndisc = ndisc_new();
|
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||||
guint32 now = nm_utils_get_monotonic_timestamp_sec();
|
gs_unref_object NMFakeNDisc *ndisc = ndisc_new();
|
||||||
TestData data = {g_main_loop_new(NULL, FALSE), 0, 0, now, 0};
|
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||||
guint id;
|
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");
|
g_test_skip("The solicitation behavior is wrong and need fixing. This test is not working too");
|
||||||
return;
|
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);
|
id = nm_fake_ndisc_add_ra(ndisc, 1, NM_NDISC_DHCP_LEVEL_NONE, 4, 1500);
|
||||||
g_assert(id);
|
g_assert(id);
|
||||||
nm_fake_ndisc_add_gateway(ndisc, id, "fe80::1", now, 10, NM_ICMPV6_ROUTER_PREF_LOW);
|
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, 6);
|
nm_fake_ndisc_add_dns_server(ndisc, id, "2001:db8:c:c::1", now_msec + 6000);
|
||||||
|
|
||||||
g_signal_connect(ndisc,
|
g_signal_connect(ndisc,
|
||||||
NM_NDISC_CONFIG_RECEIVED,
|
NM_NDISC_CONFIG_RECEIVED,
|
||||||
G_CALLBACK(test_dns_solicit_loop_changed),
|
G_CALLBACK(_test_dns_solicit_loop_changed),
|
||||||
&data);
|
&data);
|
||||||
g_signal_connect(ndisc,
|
g_signal_connect(ndisc,
|
||||||
NM_FAKE_NDISC_RS_SENT,
|
NM_FAKE_NDISC_RS_SENT,
|
||||||
G_CALLBACK(test_dns_solicit_loop_rs_sent),
|
G_CALLBACK(_test_dns_solicit_loop_rs_sent),
|
||||||
&data);
|
&data);
|
||||||
|
|
||||||
nm_ndisc_start(NM_NDISC(ndisc));
|
nm_ndisc_start(NM_NDISC(ndisc));
|
||||||
nmtst_main_loop_run_assert(data.loop, 20000);
|
nmtst_main_loop_run_assert(data.loop, 20000);
|
||||||
g_assert_cmpint(data.counter, ==, 3);
|
g_assert_cmpint(data.counter, ==, 3);
|
||||||
|
|
||||||
g_object_unref(ndisc);
|
|
||||||
g_main_loop_unref(data.loop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
NMTST_DEFINE();
|
NMTST_DEFINE();
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
||||||
|
|
@ -1497,6 +1497,7 @@ nm_ip6_config_reset_addresses_ndisc(NMIP6Config * self,
|
||||||
NMIP6ConfigPrivate *priv;
|
NMIP6ConfigPrivate *priv;
|
||||||
guint i;
|
guint i;
|
||||||
gboolean changed = FALSE;
|
gboolean changed = FALSE;
|
||||||
|
gint32 base_time_sec;
|
||||||
|
|
||||||
g_return_if_fail(NM_IS_IP6_CONFIG(self));
|
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);
|
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);
|
nm_dedup_multi_index_dirty_set_idx(priv->multi_idx, &priv->idx_ip6_addresses);
|
||||||
|
|
||||||
for (i = 0; i < addresses_n; i++) {
|
for (i = 0; i < addresses_n; i++) {
|
||||||
|
|
@ -1516,9 +1527,13 @@ nm_ip6_config_reset_addresses_ndisc(NMIP6Config * self,
|
||||||
a->ifindex = priv->ifindex;
|
a->ifindex = priv->ifindex;
|
||||||
a->address = ndisc_addr->address;
|
a->address = ndisc_addr->address;
|
||||||
a->plen = plen;
|
a->plen = plen;
|
||||||
a->timestamp = ndisc_addr->timestamp;
|
a->timestamp = base_time_sec,
|
||||||
a->lifetime = ndisc_addr->lifetime;
|
a->lifetime = _nm_ndisc_lifetime_from_expiry(((gint64) base_time_sec) * 1000,
|
||||||
a->preferred = MIN(ndisc_addr->lifetime, ndisc_addr->preferred);
|
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->addr_source = NM_IP_CONFIG_SOURCE_NDISC;
|
||||||
a->n_ifa_flags = ifa_flags;
|
a->n_ifa_flags = ifa_flags;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue