Changeset View
Standalone View
sys/net/route/route_cache.h
- This file was added.
/*- | |||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||||
* | |||||
* Copyright (c) 2022 Zhenlei Huang | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* | |||||
* $FreeBSD$ | |||||
*/ | |||||
#ifndef _NET_ROUTE_ROUTE_CACHE_H_ | |||||
#define _NET_ROUTE_ROUTE_CACHE_H_ | |||||
struct route_cache_pcpu { | |||||
struct mtx mtx; | |||||
union { | |||||
struct route ro; | |||||
#ifdef INET | |||||
melifaro: Different `struct route` differ only by the tail `struct sockaddr_XX`.
I'd consider having a… | |||||
Done Inline ActionsMy previous version is exactly struct route_cache_pcpu { struct mtx mtx; union { #ifdef INET struct route ro; #endif #ifdef INET6 struct route_in6 ro6; #endif } } I worried about future change of struct route_in6 then route_cache_pcpu may occupy extra unused cache line then it will punish dual stacked host. Indeed I'm planning to embed rt_cookie into struct route[_in6] so that route cache can be asynchronously revalidated without waiting on lock ( if trylock fails just ignore and continue, the lock is held by hot data path and will be validated ). Embedding rt_cookie into struct route_in6 then struct route_cache_pcpu will need one more cache line on 64bit systems. zlei: My previous version is exactly
```
struct route_cache_pcpu {
struct mtx mtx;
union {
#ifdef… | |||||
struct route_in ro4; | |||||
#endif | |||||
#ifdef INET6 | |||||
struct route_in6 ro6; | |||||
#endif | |||||
}; | |||||
} __aligned(CACHE_LINE_SIZE); | |||||
struct route_cache { | |||||
struct route_cache_pcpu *pcpu; | |||||
struct rib_subscription *rs; | |||||
}; | |||||
void route_cache_init(struct route_cache *); | |||||
void route_cache_uninit(struct route_cache *); | |||||
void route_cache_invalidate(struct route_cache *); | |||||
void route_cache_subscribe_rib_event(struct route_cache *, int, uint32_t); | |||||
void route_cache_unsubscribe_rib_event(struct route_cache *); | |||||
static inline struct route * | |||||
route_cache_acquire(struct route_cache *rc) | |||||
{ | |||||
struct route_cache_pcpu *pcpu; | |||||
Done Inline ActionsA second thought that if embed family and fibnum into struct route_cache then the implementation will be more simple (and also the usage of APIs). zlei: A second thought that if embed `family` and `fibnum` into `struct route_cache` then the… | |||||
struct route *ro = NULL; | |||||
pcpu = zpcpu_get(rc->pcpu); | |||||
if (mtx_trylock(&pcpu->mtx)) | |||||
ro = &pcpu->ro; | |||||
return ro; | |||||
Done Inline ActionsThese per AF method indeed can be turned into internal then consumers will use unified APIs listed above. zlei: These per AF method indeed can be turned into internal then consumers will use unified APIs… | |||||
} | |||||
static inline void | |||||
route_cache_release(struct route *ro) | |||||
{ | |||||
struct route_cache_pcpu *pcpu; | |||||
if (ro != NULL) { | |||||
pcpu = __containerof(ro, struct route_cache_pcpu, ro); | |||||
mtx_assert(&pcpu->mtx, MA_OWNED); | |||||
mtx_unlock(&pcpu->mtx); | |||||
} | |||||
Done Inline ActionsThis is important as if the lock of PCPU route cache is held by other thread, then we never block and fallback to no route caching. zlei: This is important as if the lock of PCPU route cache is held by other thread, then we never… | |||||
} | |||||
#ifdef INET6 | |||||
static inline struct route_in6 * | |||||
route_cache_acquire6(struct route_cache *rc) | |||||
{ | |||||
struct route_cache_pcpu *pcpu; | |||||
struct route_in6 *ro = NULL; | |||||
pcpu = zpcpu_get(rc->pcpu); | |||||
if (mtx_trylock(&pcpu->mtx)) | |||||
ro = &pcpu->ro6; | |||||
return ro; | |||||
} | |||||
static inline void | |||||
route_cache_release6(struct route_in6 *ro) | |||||
{ | |||||
struct route_cache_pcpu *pcpu; | |||||
if (ro != NULL) { | |||||
pcpu = __containerof(ro, struct route_cache_pcpu, ro6); | |||||
mtx_assert(&pcpu->mtx, MA_OWNED); | |||||
mtx_unlock(&pcpu->mtx); | |||||
} | |||||
} | |||||
#endif | |||||
#endif |
Different struct route differ only by the tail struct sockaddr_XX.
I'd consider having a unified structure of everything, sufficient to hold any supported/compiled family.
Union inside can be struct route, struct route_in and struct route_in6, with the latter two being conditionally enabled. The former one can be used in most of the internal code, as it doesn't care about the actual sockaddr.