Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| projectsroutingproposal:api [2016/01/16 10:57] – AlexanderChernikov | projectsroutingproposal:api [2016/01/17 08:25] (current) – AlexanderChernikov | ||
|---|---|---|---|
| Line 3: | Line 3: | ||
| ===== LLTABLE ===== | ===== LLTABLE ===== | ||
| There are 2 main functions in lltable used to lookup lladdr data by external callers: | There are 2 main functions in lltable used to lookup lladdr data by external callers: | ||
| - | //int arpresolve(ifnet *ifp, int is_gw, mbuf *m, sockaddr *dst, u_char *desten, uint32_t *pflags)// and the corresponding | ||
| - | //int nd6_resolve(ifnet *ifp, int is_gw, mbuf *m, sockaddr *dst, u_char *desten, uint32_t *pflags)// | + | < |
| + | int arpresolve(ifnet *ifp, int is_gw, mbuf *m, sockaddr *dst, u_char *desten, uint32_t *pflags) | ||
| + | </code> | ||
| + | |||
| + | and the corresponding | ||
| + | |||
| + | < | ||
| + | int nd6_resolve(ifnet *ifp, int is_gw, mbuf *m, sockaddr *dst, u_char *desten, uint32_t *pflags) | ||
| + | </code> | ||
| ==== API Problems ==== | ==== API Problems ==== | ||
| Line 17: | Line 24: | ||
| ==== New API ==== | ==== New API ==== | ||
| Given that, set of 2 new lookup functions is proposed: | Given that, set of 2 new lookup functions is proposed: | ||
| - | //int lle4_lookup(ifnet *ifp, mbuf *m, struct in_addr dst, u_char *desten, uint32_t *pflags)// and the corresponding | ||
| - | //int lle6_lookup(ifnet *ifp, mbuf *m, struct in6_addr *dst, u_char *desten, uint32_t *pflags)// | + | < |
| + | int in_resolve_lla(ifnet *ifp, mbuf *m, struct in_addr dst, u_char *desten, uint32_t *pflags) | ||
| + | int in6_resolve_lla(ifnet *ifp, mbuf *m, struct in6_addr *dst, u_char *desten, uint32_t *pflags) | ||
| + | </code> | ||
| - | More details in DXXXX. | + | More details in [[https:// |
| ===== Routing ===== | ===== Routing ===== | ||
| - | There are numerous amount of functions | + | There are numerous amount of functions |
| Two most notable are: | Two most notable are: | ||
| //struct rtentry *rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, u_int fibnum)// | //struct rtentry *rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, u_int fibnum)// | ||
| - | Returns | + | It performs radix lookup, using radix head read lock and returns |
| //void rtalloc_ign_fib(struct route *ro, u_long ignore, u_int fibnum)// | //void rtalloc_ign_fib(struct route *ro, u_long ignore, u_int fibnum)// | ||
| - | This one saves //rtentry// into passed ro-> | + | This one is a (popular) wrapper. After calling rtalloc1_fib() it saves //rtentry// into passed ro-> |
| ==== API problems ==== | ==== API problems ==== | ||
| === Locking rtentry === | === Locking rtentry === | ||
| - | Rte is locked and refcounted to ensure that the caller can safely dereference rtentry fields. The important fact here is that **refcounting rtentry does not protect you from rt_ifp ifnet being destroyed after lookup**. The only refcount that is hold by rtentry is rt_ifa (which, in turn, is just a structure not refcounting anything itself). So, **refcounting rtentry just gives you stable storage, nothing more**. Theoretically, | + | Rte is locked and refcounted to ensure that the caller can safely dereference rtentry fields. The important fact here is that **refcounting rtentry does not protect you from rt_ifp ifnet being destroyed after lookup**. |
| - | === Too complex | + | |
| - | Instead of getting pre-computed result consumer has to alter the results itself: if RTF_GATEWAY is set then.., check which MTU is less: rt_mtu or ifp-> | + | The only refcount that is hold by rtentry is rt_ifa (which, in turn, is just a structure not refcounting anything itself). So, **refcounting rtentry just gives you stable storage, nothing more**. Theoretically, |
| + | === Caller complexity | ||
| + | Instead of getting pre-computed result consumer has to alter the results itself: if RTF_GATEWAY is set then.., check which MTU is less: rt_mtu or ifp-> | ||
| + | Again, since most of callers are af-specific, | ||
| Most consumers need very basic things: check if ifp is " | Most consumers need very basic things: check if ifp is " | ||
| + | === Internal problems === | ||
| + | Having individual rtentries returned binds internal implementation to radix (and particular radix.c code). It also prevents (good) multipath implementation. | ||
| + | In general, exposing all internals makes it really hard to hack routing code. | ||
| ==== New API ==== | ==== New API ==== | ||
| === Goals === | === Goals === | ||
| Line 42: | Line 58: | ||
| * Use compact on-stack structures | * Use compact on-stack structures | ||
| * Provide different functions for different tasks varying in terms of provided information and speed | * Provide different functions for different tasks varying in terms of provided information and speed | ||
| + | * Have per-AF functions and use addresses instead of sockaddr | ||
| * Be multipath-ready from day 1. | * Be multipath-ready from day 1. | ||
| - | === Functions | + | * Hide all of the internals avoiding passing rtentries to any data/ |
| + | === Data path functions | ||
| + | This set of functions return minimal amount of data needed to forward a packet (or verify some basic data), e.g. next-hop data. | ||
| + | Nexthop consists of interface, mtu, flags, data to prepend or next-hop address. Right now next-hop size is 64 bytes (leaving about 40 bytes for pre-calculated prepend data like ethernet header). | ||
| + | |||
| + | Next-hop based approach is a very important conversion step. | ||
| + | - It permits pre-calculating/ | ||
| + | - It permits using different lookup algorithms since the algorithm task is reduced to execute ' | ||
| + | - Different lookup algorithms _are_ required: patricia is not so well suited for long IPv6 keys. Additionally, | ||
| + | |||
| + | Source: [[https:// | ||
| + | |||
| + | Actual functions description: | ||
| + | == fibX_lookup_nh_basic() == | ||
| + | The simplest form of lookup, no references are provided. | ||
| + | |||
| + | < | ||
| + | /* | ||
| + | * Performs IPv4 route table lookup on @dst. Returns 0 on success. | ||
| + | * Stores nexthop info provided @pnh4 structure. | ||
| + | * Note that | ||
| + | * - nh_ifp cannot be safely dereferenced | ||
| + | * - nh_ifp represents logical transmit interface (rt_ifp) (e.g. if | ||
| + | | ||
| + | | ||
| + | * - nh_ifp represents " | ||
| + | * - howewer mtu from " | ||
| + | */ | ||
| + | int fib4_lookup_nh_basic(uint32_t fibnum, struct in_addr dst, uint32_t flags, uint32_t flowid, struct nhop4_basic *pnh4) | ||
| + | |||
| + | struct nhop4_basic { | ||
| + | struct ifnet *nh_ifp; | ||
| + | uint16_t | ||
| + | uint16_t | ||
| + | struct in_addr | ||
| + | }; | ||
| + | |||
| + | /* | ||
| + | * Performs IPv6 route table lookup on @dst. Returns 0 on success. | ||
| + | * Stores basic nexthop info into provided @pnh6 structure. | ||
| + | * Note that | ||
| + | * - nh_ifp represents logical transmit interface (rt_ifp) by default | ||
| + | * - nh_ifp represents " | ||
| + | * - mtu from logical transmit interface will be returned. | ||
| + | * - nh_ifp cannot be safely dereferenced | ||
| + | * - nh_ifp represents rt_ifp (e.g. if looking up address on | ||
| + | | ||
| + | | ||
| + | * - howewer mtu from " | ||
| + | * - scope will be embedded in nh_addr | ||
| + | */ | ||
| + | int fib6_lookup_nh_basic(uint32_t fibnum, const struct in6_addr *dst, uint32_t scopeid, uint32_t flags, uint32_t flowid, struct nhop6_basic *pnh6) | ||
| + | |||
| + | struct nhop6_basic { | ||
| + | struct ifnet *nh_ifp; | ||
| + | uint16_t | ||
| + | uint16_t | ||
| + | uint8_t | ||
| + | struct in6_addr nh_addr; | ||
| + | }; | ||
| + | </ | ||
| + | |||
| + | == fibX_lookup_nh_ext() == | ||
| + | More advanced one: IPv4 source address is returned, some pointers can be referenced if required. Right now internal referencing/ | ||
| + | |||
| + | < | ||
| + | /* | ||
| + | * Performs IPv4 route table lookup on @dst. Returns 0 on success. | ||
| + | * Stores extende nexthop info provided @pnh4 structure. | ||
| + | * Note that | ||
| + | * - nh_ifp cannot be safely dereferenced unless NHR_REF is specified. | ||
| + | * - in that case you need to call fib4_free_nh_ext() | ||
| + | * - nh_ifp represents logical transmit interface (rt_ifp) (e.g. if | ||
| + | | ||
| + | | ||
| + | * - nh_ifp represents " | ||
| + | * - howewer mtu from " | ||
| + | */ | ||
| + | int | ||
| + | fib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst, uint32_t flags, uint32_t flowid, struct nhop4_extended *pnh4) | ||
| + | struct nhop4_extended { | ||
| + | struct ifnet *nh_ifp; | ||
| + | uint16_t | ||
| + | uint16_t | ||
| + | uint8_t | ||
| + | struct in_addr | ||
| + | struct in_addr | ||
| + | uint64_t | ||
| + | }; | ||
| + | void fib4_free_nh_ext(uint32_t fibnum, struct nhop4_extended *pnh4) | ||
| + | |||
| + | /* | ||
| + | * Performs IPv6 route table lookup on @dst. Returns 0 on success. | ||
| + | * Stores extended nexthop info into provided @pnh6 structure. | ||
| + | * Note that | ||
| + | * - nh_ifp cannot be safely dereferenced unless NHR_REF is specified. | ||
| + | * - in that case you need to call fib6_free_nh_ext() | ||
| + | * - nh_ifp represents logical transmit interface (rt_ifp) by default | ||
| + | * - nh_ifp represents " | ||
| + | * - mtu from logical transmit interface will be returned. | ||
| + | * - scope will be embedded in nh_addr | ||
| + | */ | ||
| + | int fib6_lookup_nh_ext(uint32_t fibnum, const struct in6_addr *dst, uint32_t scopeid, uint32_t flags, uint32_t flowid, struct nhop6_extended *pnh6) | ||
| + | |||
| + | struct nhop6_extended { | ||
| + | struct ifnet *nh_ifp; | ||
| + | uint16_t | ||
| + | uint16_t | ||
| + | uint8_t | ||
| + | struct in6_addr nh_addr; | ||
| + | uint64_t | ||
| + | }; | ||
| + | void fib6_free_nh_ext(uint32_t fibnum, struct nhop6_extended *pnh6) | ||
| + | |||
| + | </ | ||
| + | |||
| + | == fibX_lookup_prepend() == | ||
| + | Actual functions used for forwarding. Passing //struct route// permits function to automatically program //ro_len//, // | ||
| + | |||
| + | < | ||
| + | /* | ||
| + | * Performs lookup in IPv4 table fib @fibnum. | ||
| + | * Assumes @ro-> | ||
| + | * In case of successful lookup ro-> | ||
| + | * appropriate interface info and full L2 header to prepend or | ||
| + | * nhop address. If route does not contain gateway, or gateway is unreachable, | ||
| + | * NHF_L2_INCOMPLETE flag and gateway address is stored into nh-> | ||
| + | * If @hh is not NULL, additional nexthop data is stored there. | ||
| + | * | ||
| + | * Returns 0 on success. | ||
| + | */ | ||
| + | int fib4_lookup_prepend(uint32_t fibnum, struct in_addr dst, uint32_t flags, uint32_t flowid, struct route *ro, struct nhop4_helper *hh); | ||
| + | /* Non-recursive nexthop */ | ||
| + | struct nhop_prepend { | ||
| + | uint16_t | ||
| + | uint8_t | ||
| + | uint8_t | ||
| + | uint16_t | ||
| + | struct ifnet *nh_lifp; | ||
| + | struct ifnet *nh_aifp; | ||
| + | union { | ||
| + | char nh_data[MAX_PREPEND_LEN]; | ||
| + | struct in_addr | ||
| + | struct in6_addr nh6_addr;/* IPv4 gw address */ | ||
| + | }; | ||
| + | }; | ||
| + | void fib4_free_prepend(struct nhop_prepend *pnh); | ||
| + | </ | ||
| + | |||
| + | === Control plane functions === | ||
| + | Some consumers want to check if particular prefix exists, or check actual rte flags, which cannot be achieved using fibX functions. Luckily, all(most) there consumers are control-plane ones (arp/nd code). | ||
| + | |||
| + | == rib_lookup() == | ||
| + | The goal is to provide real per-rte information and, if possible, avoid direct rte access. This is accomplished by using //struct rt_addrinfo// | ||
| + | |||
| + | < | ||
| + | /* | ||
| + | * Lookups up route entry for @dst in RIB database for fib @fibnum. | ||
| + | * Exports entry data to @info using rt_exportinfo(). | ||
| + | * | ||
| + | * if @flags contains NHR_REF, refcouting is performed on rt_ifp. | ||
| + | | ||
| + | * | ||
| + | * Returns 0 on success. | ||
| + | * Returns ENOENT for lookup failure, ENOMEM for export failure. | ||
| + | */ | ||
| + | int rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags, uint32_t flowid, struct rt_addrinfo *info) | ||
| + | void rib_free_info(struct rt_addrinfo *info) | ||
| + | </ | ||