Skip to content

Commit 7d8dab4

Browse files
author
Arto Kinnunen
authored
IPv6 routing cache configuration update (#2056)
Add new API to allow IPv6 routing and destination cache to be configured separately.
1 parent f701d39 commit 7d8dab4

File tree

8 files changed

+257
-38
lines changed

8 files changed

+257
-38
lines changed

nanostack/net_ipv6_api.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,40 @@ int8_t arm_nwk_ipv6_frag_mru(uint16_t frag_mru);
5151
*/
5252
int8_t arm_nwk_ipv6_max_cache_entries(uint16_t max_entries);
5353

54+
/**
55+
* \brief Configure destination cache.
56+
*
57+
* Set destination cache maximum entry count, thresholds where amount of entries is kept during operation and lifetime.
58+
*
59+
* Note: This must be called before arm_nwk_interface_lowpan_init()
60+
*
61+
* \param max_entries Maximum number of entries allowed in destination cache at any time.
62+
* \param short_term_threshold Amount of cache entries kept in memory in short term. Must be less than max_entries.
63+
* \param long_term_threshold Amount of entries kept in memory over long period of time. Must be less than short_term_threshold.
64+
* \param lifetime Lifetime of cache entry, must be over 120 seconds
65+
*
66+
* \return 0 Change OK.
67+
* \return <0 Change invalid - unable to change the maximum for cache.
68+
*/
69+
int8_t arm_nwk_ipv6_destination_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime);
70+
71+
/**
72+
* \brief Configure neighbour cache.
73+
*
74+
* Set neighbour cache maximum entry count, thresholds where amount of entries is kept during operation and lifetime.
75+
*
76+
* Note: This must be called before arm_nwk_interface_lowpan_init()
77+
*
78+
* \param max_entries Maximum number of entries allowed in neighbour cache at any time.
79+
* \param short_term_threshold Amount of cache entries kept in memory in short term. Must be less than max_entries.
80+
* \param long_term_threshold Amount of entries kept in memory over long period of time. Must be less than short_term_threshold.
81+
* \param lifetime Lifetime of cache entry, must be over 120 seconds
82+
*
83+
* \return 0 Change OK.
84+
* \return <0 Change invalid - unable to change the maximum for cache.
85+
*/
86+
int8_t arm_nwk_ipv6_neighbour_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime);
87+
5488
/**
5589
* \brief Configure automatic flow label calculation.
5690
*

source/ipv6_stack/ipv6_routing_table.c

Lines changed: 91 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,40 @@
5252
#define NCACHE_GC_PERIOD 20 /* seconds */
5353
#define DCACHE_GC_PERIOD 20 /* seconds */
5454

55-
static uint16_t current_max_cache = 64;
55+
/* Neighbour Cache garbage collection parameters (per interface) */
56+
/* Parameters only for garbage-collectible entries; registered entries counted separately */
57+
#define NCACHE_MAX_LONG_TERM 8 /* Target for basic GC - expire old entries if more than this */
58+
#define NCACHE_MAX_SHORT_TERM 32 /* Expire stale entries if more than this */
59+
#define NCACHE_MAX_ABSOLUTE 64 /* Never have more than this */
60+
#define NCACHE_GC_AGE 600 /* 10 minutes (1s units - decremented every slow timer call) */
61+
62+
/* Destination Cache garbage collection parameters (system-wide) */
63+
#define DCACHE_MAX_LONG_TERM 16
64+
#define DCACHE_MAX_SHORT_TERM 40
65+
#define DCACHE_MAX_ABSOLUTE 64 /* Never have more than this */
66+
#define DCACHE_GC_AGE (30 * DCACHE_GC_PERIOD) /* 10 minutes */
67+
68+
typedef struct destination_cache_configuration_s {
69+
uint16_t max_entries; // Never have more than this
70+
uint16_t short_term_entries; // Expire stale entries if more than this
71+
uint16_t long_term_entries; // Target for basic GC - expire old entries if more than this
72+
uint16_t entry_lifetime; // 20s units - decremented once per periodic GC
73+
} destination_cache_config_t;
74+
75+
typedef struct neighbour_cache_configuration_s {
76+
uint16_t max_entries; // Never have more than this
77+
uint16_t short_term_entries; // Expire stale entries if more than this
78+
uint16_t long_term_entries; // Target for basic GC - expire old entries if more than this
79+
uint16_t entry_lifetime; // 1s units - decremented every slow timer call
80+
} neighbour_cache_config_t;
81+
82+
static destination_cache_config_t destination_cache_config = {DCACHE_MAX_ABSOLUTE, DCACHE_MAX_SHORT_TERM, DCACHE_MAX_LONG_TERM, DCACHE_GC_AGE};
83+
static neighbour_cache_config_t neighbour_cache_config = {NCACHE_MAX_ABSOLUTE, NCACHE_MAX_SHORT_TERM, NCACHE_MAX_LONG_TERM, NCACHE_GC_AGE};
5684

5785
/* We track "lifetime" of garbage-collectible entries, resetting
5886
* when used. Entries with lifetime 0 are favoured
5987
* for garbage-collection. */
60-
#define NCACHE_GC_AGE 600 /* 10 minutes (1s units - decremented every slow timer call) */
61-
#define DCACHE_GC_AGE 30 /* 10 minutes (20s units - decremented once per periodic GC) */
62-
#define DCACHE_GC_AGE_LL 6 /* 2 minutes for link-local destinations */
88+
#define DCACHE_GC_AGE_LL (120 / DCACHE_GC_PERIOD) /* 2 minutes for link-local destinations, in DCACHE_GC_PERIOD intervals */
6389

6490
/* For probable routers, consider them unreachable if ETX is greater than this */
6591
#define ETX_REACHABILITY_THRESHOLD 0x200 /* 8.8 fixed-point, so 2 */
@@ -79,27 +105,6 @@ static uint8_t ipv6_route_table_get_max_entries(int8_t interface_id, ipv6_route_
79105

80106
static uint16_t dcache_gc_timer;
81107

82-
static uint16_t cache_long_term(bool is_destination)
83-
{
84-
uint16_t value = current_max_cache / 8;
85-
if (is_destination) {
86-
value *= 2;
87-
}
88-
if (value < 4) {
89-
value = 4;
90-
}
91-
return value;
92-
}
93-
94-
static uint16_t cache_short_term(bool is_destination)
95-
{
96-
uint16_t value = current_max_cache / 2;
97-
if (value < cache_long_term(is_destination)) {
98-
return cache_long_term(is_destination);
99-
}
100-
return value;
101-
}
102-
103108
static uint32_t next_probe_time(ipv6_neighbour_cache_t *cache, uint_fast8_t retrans_num)
104109
{
105110
uint32_t t = cache->retrans_timer;
@@ -120,7 +125,57 @@ int8_t ipv6_neighbour_set_current_max_cache(uint16_t max_cache)
120125
if (max_cache < 4) {
121126
return -1;
122127
}
123-
current_max_cache = max_cache;
128+
129+
// adjust destination cache
130+
destination_cache_config.max_entries = max_cache;
131+
destination_cache_config.long_term_entries = max_cache / 4;
132+
if (destination_cache_config.long_term_entries < 4) {
133+
destination_cache_config.long_term_entries = 4;
134+
}
135+
destination_cache_config.short_term_entries = max_cache / 2;
136+
if (destination_cache_config.short_term_entries < destination_cache_config.long_term_entries) {
137+
destination_cache_config.short_term_entries = destination_cache_config.long_term_entries;
138+
}
139+
140+
// adjust neighbour cache
141+
neighbour_cache_config.max_entries = max_cache;
142+
neighbour_cache_config.long_term_entries = max_cache / 8;
143+
if (neighbour_cache_config.long_term_entries < 4) {
144+
neighbour_cache_config.long_term_entries = 4;
145+
}
146+
neighbour_cache_config.short_term_entries = max_cache / 4;
147+
if (neighbour_cache_config.short_term_entries < neighbour_cache_config.long_term_entries) {
148+
neighbour_cache_config.short_term_entries = neighbour_cache_config.long_term_entries;
149+
}
150+
151+
return 0;
152+
}
153+
154+
int8_t ipv6_destination_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime)
155+
{
156+
if ((max_entries < 4) || (short_term_threshold >= max_entries) || (long_term_threshold >= short_term_threshold) || (lifetime < 120)) {
157+
return -1;
158+
}
159+
160+
destination_cache_config.max_entries = max_entries;
161+
destination_cache_config.short_term_entries = short_term_threshold;
162+
destination_cache_config.long_term_entries = long_term_threshold;
163+
destination_cache_config.entry_lifetime = lifetime;
164+
165+
return 0;
166+
}
167+
168+
int8_t ipv6_neighbour_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime)
169+
{
170+
if ((max_entries < 4) || (short_term_threshold >= max_entries) || (long_term_threshold >= short_term_threshold) || (lifetime < 120)) {
171+
return -1;
172+
}
173+
174+
neighbour_cache_config.max_entries = max_entries;
175+
neighbour_cache_config.short_term_entries = short_term_threshold;
176+
neighbour_cache_config.long_term_entries = long_term_threshold;
177+
neighbour_cache_config.entry_lifetime = lifetime;
178+
124179
return 0;
125180
}
126181

@@ -260,7 +315,7 @@ ipv6_neighbour_t *ipv6_neighbour_lookup_or_create(ipv6_neighbour_cache_t *cache,
260315
}
261316
}
262317

263-
if (count >= current_max_cache) {
318+
if (count >= neighbour_cache_config.max_entries) {
264319
entry = ns_list_get_last(&cache->list);
265320
ipv6_neighbour_entry_remove(cache, entry);
266321
}
@@ -311,7 +366,7 @@ ipv6_neighbour_t *ipv6_neighbour_used(ipv6_neighbour_cache_t *cache, ipv6_neighb
311366
{
312367
/* Reset the GC life, if it's a GC entry */
313368
if (entry->type == IP_NEIGHBOUR_GARBAGE_COLLECTIBLE) {
314-
entry->lifetime = NCACHE_GC_AGE;
369+
entry->lifetime = neighbour_cache_config.entry_lifetime;
315370
}
316371

317372
/* Move it to the front of the list */
@@ -653,7 +708,7 @@ static void ipv6_neighbour_cache_gc_periodic(ipv6_neighbour_cache_t *cache)
653708
}
654709
}
655710

656-
if (gc_count <= cache_long_term(false)) {
711+
if (gc_count <= neighbour_cache_config.long_term_entries) {
657712
return;
658713
}
659714

@@ -669,9 +724,9 @@ static void ipv6_neighbour_cache_gc_periodic(ipv6_neighbour_cache_t *cache)
669724
continue;
670725
}
671726

672-
if (entry->lifetime == 0 || gc_count > cache_short_term(false)) {
727+
if (entry->lifetime == 0 || gc_count > neighbour_cache_config.short_term_entries) {
673728
ipv6_neighbour_entry_remove(cache, entry);
674-
if (--gc_count <= cache_long_term(false)) {
729+
if (--gc_count <= neighbour_cache_config.long_term_entries) {
675730
break;
676731
}
677732
}
@@ -876,7 +931,7 @@ ipv6_destination_t *ipv6_destination_lookup_or_create(const uint8_t *address, in
876931

877932

878933
if (!entry) {
879-
if (count > current_max_cache) {
934+
if (count > destination_cache_config.max_entries) {
880935
entry = ns_list_get_last(&ipv6_destination_cache);
881936
ns_list_remove(&ipv6_destination_cache, entry);
882937
ipv6_destination_release(entry);
@@ -915,7 +970,7 @@ ipv6_destination_t *ipv6_destination_lookup_or_create(const uint8_t *address, in
915970
if (addr_ipv6_scope(address, NULL) <= IPV6_SCOPE_LINK_LOCAL) {
916971
entry->lifetime = DCACHE_GC_AGE_LL;
917972
} else {
918-
entry->lifetime = DCACHE_GC_AGE;
973+
entry->lifetime = destination_cache_config.entry_lifetime / DCACHE_GC_PERIOD;
919974
}
920975

921976
return entry;
@@ -1048,7 +1103,7 @@ static void ipv6_destination_cache_gc_periodic(void)
10481103
#endif
10491104
}
10501105

1051-
if (gc_count <= cache_long_term(true)) {
1106+
if (gc_count <= destination_cache_config.long_term_entries) {
10521107
return;
10531108
}
10541109

@@ -1058,10 +1113,10 @@ static void ipv6_destination_cache_gc_periodic(void)
10581113
* MAX_LONG_TERM.
10591114
*/
10601115
ns_list_foreach_reverse_safe(ipv6_destination_t, entry, &ipv6_destination_cache) {
1061-
if (entry->lifetime == 0 || gc_count > cache_short_term(true)) {
1116+
if (entry->lifetime == 0 || gc_count > destination_cache_config.short_term_entries) {
10621117
ns_list_remove(&ipv6_destination_cache, entry);
10631118
ipv6_destination_release(entry);
1064-
if (--gc_count <= cache_long_term(true)) {
1119+
if (--gc_count <= destination_cache_config.long_term_entries) {
10651120
break;
10661121
}
10671122
}

source/ipv6_stack/ipv6_routing_table.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,9 @@ extern void ipv6_neighbour_cache_fast_timer(ipv6_neighbour_cache_t *cache, uint1
171171
extern void ipv6_neighbour_cache_slow_timer(ipv6_neighbour_cache_t *cache, uint8_t seconds);
172172
extern void ipv6_neighbour_cache_print(const ipv6_neighbour_cache_t *cache, route_print_fn_t *print_fn);
173173
extern void ipv6_router_gone(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry);
174-
175174
extern int8_t ipv6_neighbour_set_current_max_cache(uint16_t max_cache);
175+
extern int8_t ipv6_destination_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime);
176+
extern int8_t ipv6_neighbour_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime);
176177

177178
/* Backwards compatibility with test app */
178179
#define ROUTE_RPL_UP ROUTE_RPL_DIO

source/libNET/src/net_ipv6.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ int8_t arm_nwk_ipv6_max_cache_entries(uint16_t max_entries)
4343
return ipv6_neighbour_set_current_max_cache(max_entries);
4444
}
4545

46+
int8_t arm_nwk_ipv6_destination_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime)
47+
{
48+
return ipv6_destination_cache_configure(max_entries, short_term_threshold, long_term_threshold, lifetime);
49+
}
50+
51+
int8_t arm_nwk_ipv6_neighbour_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime)
52+
{
53+
return ipv6_neighbour_cache_configure(max_entries, short_term_threshold, long_term_threshold, lifetime);
54+
}
55+
4656
void arm_nwk_ipv6_auto_flow_label(bool auto_flow_label)
4757
{
4858
ipv6_flow_auto_label = auto_flow_label;

test/nanostack/unittest/ipv6_stack/ipv6_routing_table/ipv6_routing_tabletest.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,18 @@ TEST(ipv6_routing_table, test_ipv6_route_table_set_max_entries)
3535
{
3636
CHECK(test_ipv6_route_table_set_max_entries());
3737
}
38+
39+
TEST(ipv6_routing_table, test_ipv6_neighbour_set_current_max_cache)
40+
{
41+
CHECK(test_ipv6_neighbour_set_current_max_cache());
42+
}
43+
44+
TEST(ipv6_routing_table, test_ipv6_destination_cache_configure)
45+
{
46+
CHECK(test_ipv6_destination_cache_configure());
47+
}
48+
49+
TEST(ipv6_routing_table, test_ipv6_neighbour_cache_configure)
50+
{
51+
CHECK(test_ipv6_neighbour_cache_configure());
52+
}

test/nanostack/unittest/ipv6_stack/ipv6_routing_table/test_ipv6_routing_table.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,96 @@ bool test_ipv6_route_table_set_max_entries()
7070

7171
return true;
7272
}
73+
74+
bool test_ipv6_neighbour_set_current_max_cache()
75+
{
76+
int8_t ret_val;
77+
78+
// max_cache invalid
79+
ret_val = ipv6_neighbour_set_current_max_cache(0);
80+
if (ret_val == 0) {
81+
return false;
82+
}
83+
84+
ret_val = ipv6_neighbour_set_current_max_cache(4);
85+
if (ret_val != 0) {
86+
return false;
87+
}
88+
89+
return true;
90+
}
91+
92+
bool test_ipv6_destination_cache_configure()
93+
{
94+
int8_t ret_val;
95+
96+
// max_entries invalid
97+
ret_val = ipv6_destination_cache_configure(0, 20, 10, 200);
98+
if (ret_val == 0) {
99+
return false;
100+
}
101+
102+
// short term > max_entries
103+
ret_val = ipv6_destination_cache_configure(100, 120, 10, 200);
104+
if (ret_val == 0) {
105+
return false;
106+
}
107+
108+
// long_term > short term
109+
ret_val = ipv6_destination_cache_configure(100, 20, 30, 200);
110+
if (ret_val == 0) {
111+
return false;
112+
}
113+
114+
// invalid lifetime
115+
ret_val = ipv6_destination_cache_configure(100, 20, 10, 0);
116+
if (ret_val == 0) {
117+
return false;
118+
}
119+
120+
// OK case
121+
ret_val = ipv6_destination_cache_configure(100, 20, 10, 600);
122+
if (ret_val != 0) {
123+
return false;
124+
}
125+
126+
return true;
127+
}
128+
129+
bool test_ipv6_neighbour_cache_configure()
130+
{
131+
int8_t ret_val;
132+
133+
// max_entries invalid
134+
ret_val = ipv6_neighbour_cache_configure(0, 20, 10, 200);
135+
if (ret_val == 0) {
136+
return false;
137+
}
138+
139+
// short term > max_entries
140+
ret_val = ipv6_destination_cache_configure(100, 120, 10, 200);
141+
if (ret_val == 0) {
142+
return false;
143+
}
144+
145+
// long_term > short term
146+
ret_val = ipv6_neighbour_cache_configure(100, 20, 30, 200);
147+
if (ret_val == 0) {
148+
return false;
149+
}
150+
151+
// invalid lifetime
152+
ret_val = ipv6_neighbour_cache_configure(100, 20, 10, 0);
153+
if (ret_val == 0) {
154+
return false;
155+
}
156+
157+
// OK case
158+
ret_val = ipv6_neighbour_cache_configure(100, 20, 10, 600);
159+
if (ret_val != 0) {
160+
return false;
161+
}
162+
163+
return true;
164+
}
165+

0 commit comments

Comments
 (0)