/* * Copyright (c) 2012, 2014-2019, 2021, Pelion and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * ipv6_routing_table.h * * Implements Neighbour Cache */ #ifndef IPV6_ROUTING_TABLE_H_ #define IPV6_ROUTING_TABLE_H_ #include "ns_list.h" #include "Core/include/ns_address_internal.h" /* Address Resolution and Neighbour Unreachablity Detection constants from * RFC 4861, updated by RFC 7048. */ #define MAX_MULTICAST_SOLICIT 3 #define MAX_UNICAST_SOLICIT 5 #define MARK_UNREACHABLE 3 #define MAX_RETRANS_TIMER 60000 /* ms */ #define DELAY_FIRST_PROBE_TIME 5000 /* ms */ #define BACKOFF_MULTIPLE 3 /* RFC 6775 parameters */ #define TENTATIVE_NCE_LIFETIME 20 /* s */ #define IPV6_ROUTE_DEFAULT_METRIC 128 /* XXX in the process of renaming this - it's really specifically the * IP Neighbour Cache but was initially called a routing table */ typedef enum ip_neighbour_cache_state { IP_NEIGHBOUR_NEW, /* Not yet used; no LL addr, no NS sent */ IP_NEIGHBOUR_INCOMPLETE, IP_NEIGHBOUR_REACHABLE, IP_NEIGHBOUR_STALE, IP_NEIGHBOUR_DELAY, IP_NEIGHBOUR_PROBE, IP_NEIGHBOUR_UNREACHABLE } ip_neighbour_cache_state_t; /* RFC 6775 types */ typedef enum ip_neighbour_cache_type { IP_NEIGHBOUR_GARBAGE_COLLECTIBLE, IP_NEIGHBOUR_REGISTERED, IP_NEIGHBOUR_TENTATIVE } ip_neighbour_cache_type_t; typedef enum ipv6_route_src { ROUTE_ANY, /* Unspecified - use in lookups */ ROUTE_NONE, /* Only occurs in incomplete destination cache entries */ ROUTE_STATIC, ROUTE_LOOPBACK, ROUTE_USER, ROUTE_ARO, ROUTE_RADV, ROUTE_RPL_DIO, /* Explicitly advertised in DIO RIO */ ROUTE_RPL_DAO, /* Explicitly advertised in DAO, Storing mode */ ROUTE_RPL_DAO_SR, /* Explicitly advertised in DAO, Root Source Routes in Non-Storing mode */ ROUTE_RPL_SRH, /* Not in routing table - used in buffers to represent on-link inferred from SRH */ ROUTE_RPL_ROOT, /* Implicit route to DODAG root */ ROUTE_RPL_INSTANCE, /* Implicit instance-specific default upward route (not for general search) */ ROUTE_RPL_FWD_ERROR, /* Not in routing table - used in buffers to represent Forwarding-Error bounce */ ROUTE_MULTICAST, /* Not in routing table - used to represent multicast interface selection */ ROUTE_MPL, ROUTE_RIP, ROUTE_THREAD, ROUTE_THREAD_BORDER_ROUTER, ROUTE_THREAD_PROXIED_HOST, ROUTE_THREAD_PROXIED_DUA_HOST, ROUTE_THREAD_BBR, ROUTE_REDIRECT, /* Only occurs in destination cache */ ROUTE_MAX, } ipv6_route_src_t; struct buffer; typedef struct ipv6_neighbour { uint8_t ip_address[16]; /*!< neighbour IP address */ bool is_router: 1; bool from_redirect: 1; uint8_t retrans_count; ip_neighbour_cache_state_t state; ip_neighbour_cache_type_t type; addrtype_t ll_type; uint32_t timer; /* 100ms ticks */ uint32_t lifetime; /* seconds */ ns_list_link_t link; /*!< List link */ NS_LIST_HEAD_INCOMPLETE(struct buffer) queue; uint8_t ll_address[]; } ipv6_neighbour_t; /* Neighbour Cache entries also store EUI-64 after ll_address if "recv_addr_reg" * is set for the cache. This is ADDR_EUI64_ZERO if unknown. */ #define ipv6_neighbour_eui64(ncache, entry) ((entry)->ll_address + (ncache)->max_ll_len) typedef struct ipv6_route_info_cache { uint16_t metric; // interface metric uint8_t sources[ROUTE_MAX]; } ipv6_route_interface_info_t; typedef struct ipv6_neighbour_cache { bool send_addr_reg : 1; bool recv_addr_reg : 1; bool send_nud_probes : 1; bool probe_avoided_routers : 1; bool recv_ns_aro : 1; bool recv_na_aro : 1; bool use_eui64_as_slla_in_aro : 1; bool omit_na_aro_success : 1; bool omit_na : 1; // except for ARO successes which have a separate flag int8_t interface_id; uint8_t max_ll_len; uint8_t gc_timer; uint16_t link_mtu; uint32_t retrans_timer; uint32_t reachable_time; // Interface specific information for route ipv6_route_interface_info_t route_if_info; //uint8_t num_entries; NS_LIST_HEAD(ipv6_neighbour_t, link) list; } ipv6_neighbour_cache_t; /* Macros for formatting ipv6 addresses into strings for route printing. */ /* Initialize a string buffer for the ipv6 address */ #define ROUTE_PRINT_ADDR_STR_BUFFER_INIT(str) char str[41] = "<null>" /* Format and store ipv6 'addr' into 'str', and evaluate 'str' */ #define ROUTE_PRINT_ADDR_STR_FORMAT(str, addr) (ip6tos(addr, str), str) /* Callback type for route print */ typedef void (route_print_fn_t)(const char *fmt, ...); extern void ipv6_neighbour_cache_init(ipv6_neighbour_cache_t *cache, int8_t interface_id); extern void ipv6_neighbour_cache_flush(ipv6_neighbour_cache_t *cache); extern ipv6_neighbour_t *ipv6_neighbour_update(ipv6_neighbour_cache_t *cache, const uint8_t *address, bool solicited); extern void ipv6_neighbour_set_state(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry, ip_neighbour_cache_state_t state); extern ipv6_neighbour_t *ipv6_neighbour_used(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry); extern ipv6_neighbour_t *ipv6_neighbour_lookup(ipv6_neighbour_cache_t *cache, const uint8_t *address); extern ipv6_neighbour_t *ipv6_neighbour_lookup_by_interface_id(int8_t interface_id, const uint8_t *address); extern ipv6_neighbour_t *ipv6_neighbour_lookup_or_create(ipv6_neighbour_cache_t *cache, const uint8_t *address); extern ipv6_neighbour_t *ipv6_neighbour_lookup_or_create_by_interface_id(int8_t interface_id, const uint8_t *address); extern void ipv6_neighbour_entry_remove(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry); extern bool ipv6_neighbour_is_probably_reachable(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *n); extern bool ipv6_neighbour_addr_is_probably_reachable(ipv6_neighbour_cache_t *cache, const uint8_t *address); extern bool ipv6_neighbour_ll_addr_match(const ipv6_neighbour_t *entry, addrtype_t ll_type, const uint8_t *ll_address); extern void ipv6_neighbour_invalidate_ll_addr(ipv6_neighbour_cache_t *cache, addrtype_t ll_type, const uint8_t *ll_address); extern void ipv6_neighbour_delete_registered_by_eui64(ipv6_neighbour_cache_t *cache, const uint8_t *eui64); extern bool ipv6_neighbour_has_registered_by_eui64(ipv6_neighbour_cache_t *cache, const uint8_t *eui64); extern ipv6_neighbour_t *ipv6_neighbour_get_registered_by_eui64(ipv6_neighbour_cache_t *cache, const uint8_t *eui64); extern void ipv6_neighbour_entry_update_unsolicited(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry, addrtype_t type, const uint8_t *ll_address/*, bool tentative*/); extern ipv6_neighbour_t *ipv6_neighbour_update_unsolicited(ipv6_neighbour_cache_t *cache, const uint8_t *ip_address, addrtype_t ll_type, const uint8_t *ll_address); extern void ipv6_neighbour_reachability_confirmation(const uint8_t ip_address[__static 16], int8_t interface_id); extern void ipv6_neighbour_reachability_problem(const uint8_t ip_address[__static 16], int8_t interface_id); extern void ipv6_neighbour_update_from_na(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry, uint8_t flags, addrtype_t ll_type, const uint8_t *ll_address); extern void ipv6_neighbour_cache_fast_timer(ipv6_neighbour_cache_t *cache, uint16_t ticks); extern void ipv6_neighbour_cache_slow_timer(ipv6_neighbour_cache_t *cache, uint8_t seconds); extern void ipv6_neighbour_cache_print(const ipv6_neighbour_cache_t *cache, route_print_fn_t *print_fn); extern void ipv6_router_gone(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry); extern int8_t ipv6_neighbour_set_current_max_cache(uint16_t max_cache); extern int8_t ipv6_destination_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime); extern int8_t ipv6_neighbour_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime); /* Backwards compatibility with test app */ #define ROUTE_RPL_UP ROUTE_RPL_DIO #define ROUTE_RPL_DOWN ROUTE_RPL_DAO typedef struct ipv6_route_info { ipv6_route_src_t source; uint8_t source_id; int8_t interface_id; uint16_t pmtu; void *info; // pointer to route provider's info uint8_t next_hop_addr[16]; } ipv6_route_info_t; typedef struct ipv6_destination { /* Destination/path information */ uint8_t destination[16]; #ifdef HAVE_IPV6_ND uint8_t redirect_addr[16]; bool redirected; // we have a redirect in force #endif int8_t interface_id; // fixed if link-local destination, else variable and gets set from redirect interface and/or last_neighbour interface uint16_t refcount; uint16_t lifetime; // Life in GC calls, so 20s units #ifndef NO_IPV6_PMTUD uint16_t pmtu; // note this may be less than 1280 - upper layers may choose to send smaller based on this uint16_t pmtu_lifetime; // seconds #endif #ifndef NO_IP_FRAGMENT_TX uint32_t fragment_id; #endif ipv6_neighbour_t *last_neighbour; // last neighbour used (only for reachability confirmation) ns_list_link_t link; } ipv6_destination_t; #ifndef NO_IPV6_PMTUD #define ipv6_destination_pmtu(d) ((d)->pmtu) #else #define ipv6_destination_pmtu(d) IPV6_MIN_LINK_MTU #endif void ipv6_destination_cache_print(route_print_fn_t *print_fn); ipv6_destination_t *ipv6_destination_lookup_or_create(const uint8_t *address, int8_t interface_id); ipv6_destination_t *ipv6_destination_lookup_or_create_with_route(const uint8_t *address, int8_t interface_id, ipv6_route_info_t *route_out); void ipv6_destination_cache_timer(uint8_t ticks); #ifdef HAVE_IPV6_ND void ipv6_destination_redirect(const uint8_t *dest_addr, const uint8_t *sender_addr, const uint8_t *redirect_addr, int8_t interface_id, addrtype_t ll_type, const uint8_t *ll_address); #endif void ipv6_destination_cache_forced_gc(bool full_gc); void ipv6_destination_cache_clean(int8_t interface_id); /* Combined Routing Table (RFC 4191) and Prefix List (RFC 4861) */ /* On-link prefixes have the on_link flag set and next_hop is unset */ typedef struct ipv6_route { uint8_t prefix_len; bool on_link: 1; bool search_skip: 1; bool probe: 1; bool info_autofree: 1; uint8_t metric; // 0x40 = RFC 4191 pref high, 0x80 = default, 0xC0 = RFC 4191 pref low ipv6_route_info_t info; uint32_t lifetime; // (seconds); 0xFFFFFFFF means permanent uint16_t probe_timer; ns_list_link_t link; uint8_t prefix[]; // variable length } ipv6_route_t; /* Callback type for route predicate */ typedef bool ipv6_route_predicate_fn_t(const ipv6_route_info_t *route, bool valid); /* Callbacks for route providers that dynamically compute next hop */ typedef bool ipv6_route_next_hop_fn_t(const uint8_t *dest, ipv6_route_info_t *route_info); uint8_t ipv6_route_pref_to_metric(int_fast8_t pref); ipv6_route_t *ipv6_route_add(const uint8_t *prefix, uint8_t prefix_len, int8_t interface_id, const uint8_t *next_hop, ipv6_route_src_t source, uint32_t lifetime, int_fast8_t pref); ipv6_route_t *ipv6_route_add_with_info(const uint8_t *prefix, uint8_t prefix_len, int8_t interface_id, const uint8_t *next_hop, ipv6_route_src_t source, void *info, uint8_t source_id, uint32_t lifetime, int_fast8_t pref); ipv6_route_t *ipv6_route_add_metric(const uint8_t *prefix, uint8_t prefix_len, int8_t interface_id, const uint8_t *next_hop, ipv6_route_src_t source, void *info, uint8_t source_id, uint32_t lifetime, uint8_t metric); ipv6_route_t *ipv6_route_lookup_with_info(const uint8_t *prefix, uint8_t prefix_len, int8_t interface_id, const uint8_t *next_hop, ipv6_route_src_t source, void *info, int_fast16_t source_id); int_fast8_t ipv6_route_delete(const uint8_t *prefix, uint8_t prefix_len, int8_t interface_id, const uint8_t *next_hop, ipv6_route_src_t source); int_fast8_t ipv6_route_delete_with_info(const uint8_t *prefix, uint8_t prefix_len, int8_t interface_id, const uint8_t *next_hop, ipv6_route_src_t source, void *info, int_fast16_t source_id); ipv6_route_t *ipv6_route_choose_next_hop(const uint8_t *dest, int8_t interface_id, ipv6_route_predicate_fn_t *predicate); void ipv6_route_table_change_next_hop_for_info(int8_t interface_id, const uint8_t *next_hop, ipv6_route_src_t source, void *info); void ipv6_route_table_remove_interface(int8_t interface_id); void ipv6_route_table_modify_router_metric(int8_t interface_id, const uint8_t *addr, ipv6_route_src_t source, uint8_t keep, uint8_t toggle); void ipv6_route_table_remove_info(int8_t interface_id, ipv6_route_src_t source, void *info); void ipv6_route_table_set_predicate_fn(ipv6_route_src_t src, ipv6_route_predicate_fn_t *fn); void ipv6_route_table_set_next_hop_fn(ipv6_route_src_t src, ipv6_route_next_hop_fn_t *fn); void ipv6_route_table_ttl_update(uint16_t seconds); void ipv6_route_table_print(route_print_fn_t *print_fn); void ipv6_route_table_set_max_entries(int8_t interface_id, ipv6_route_src_t source, uint8_t max_entries); bool ipv6_route_table_source_was_invalidated(ipv6_route_src_t src); void ipv6_route_table_source_invalidated_reset(void); #endif /* IPV6_ROUTING_TABLE_H_ */