M1 progress: engine port compiles except pf.c; AF_DIVERT socket family; ifq framework
- compat layer extended through the full BSD API surface pf_ioctl/pf_lb/ pf_if/pf_norm/pf_table/pf_ruleset/radix/md5/sha2 need (all compile): cpumem/counters model, ifaddr/ifg groups, cred view, endian+in6 names, NAT46/64, SipHash24, mbuf_list, frag6 helpers, ip6 forward/checksum, tcp options/FSM names, taskqueue & sysctl shims (documented in docs/porting-notes.md) - pfsrc/divert_sock.c: real BSD divert(4) as runtime-registered PF_DIVERT=32 socket family inside the module (sock_register; NPROTO=AF_MAX=45 -> zero core patches); divert_packet/divert6_packet wired for pf.c - compat/pfk_ifq.c: OpenBSD 8.0 ifq framework with priq back end; hfsc and fq_codel aliases pending M5 (recorded in feature matrix as pending) - design + plan updated for the divert decision (user-requested) - stage-port.sh: single deterministic rename program for headers and .c
This commit is contained in:
1 parent
a84b2c91f3
commit
1fcd7b3046
77 files changed
+28002
-1114
No files matched your search
@@ -20,8 +20,10 @@ typedef struct {
|
||||
|
||||
void SipHash24_Init(SIPHASH_CTX *ctx, const SIPHASH_KEY *key);
|
||||
void SipHash24_Update(SIPHASH_CTX *ctx, const void *in, __u64 inlen);
|
||||
void SipHash24_Final(SIPHASH_CTX *ctx, unsigned char *out);
|
||||
void SipHash24_Final(void *out, SIPHASH_CTX *ctx);
|
||||
void SipHash24_Generate(const SIPHASH_KEY *key, const void *in, __u64 inlen,
|
||||
unsigned char *out);
|
||||
/* OpenBSD's one-shot helper: returns the 64-bit hash value */
|
||||
__u64 SipHash24(const SIPHASH_KEY *key, const void *in, __u64 inlen);
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,48 @@
|
||||
/* PFLINUX compat: <net/if_var.h> — ifnet view comes from pfk_if.h */
|
||||
/* PFLINUX compat: <net/if_var.h> — the ifnet view comes from pfk_if.h;
|
||||
* the BSD interface-group types are reproduced here (they need the BSD
|
||||
* queue macros and the refcnt type). */
|
||||
#ifndef _PFK_IF_VAR_H
|
||||
#define _PFK_IF_VAR_H
|
||||
/* intentionally minimal; struct pfk_ifnet is the ifnet */
|
||||
|
||||
#include "compat/sys/queue.h"
|
||||
#include "compat/sys/refcnt.h"
|
||||
|
||||
struct ifg_member {
|
||||
TAILQ_ENTRY(ifg_member) ifgm_next; /* [N] all members are chained */
|
||||
struct pfk_ifnet *ifgm_ifp; /* [I] member interface */
|
||||
};
|
||||
|
||||
struct ifg_group {
|
||||
char ifg_group[IFNAMSIZ];
|
||||
u_int ifg_refcnt;
|
||||
caddr_t ifg_pf_kif;
|
||||
int ifg_carp_demoted;
|
||||
TAILQ_HEAD(, ifg_member) ifg_members;
|
||||
TAILQ_ENTRY(ifg_group) ifg_next;
|
||||
struct refcnt ifg_tmprefcnt;
|
||||
TAILQ_ENTRY(ifg_group) ifg_tmplist;
|
||||
};
|
||||
|
||||
/* BSD struct ifaddr (net/if_var.h) — the ported PF code walks interface
|
||||
* addresses through this type. */
|
||||
struct pfk_ifnet;
|
||||
|
||||
struct ifaddr {
|
||||
struct sockaddr *ifa_addr; /* address of interface */
|
||||
struct sockaddr *ifa_dstaddr; /* other end of p-to-p link */
|
||||
#define ifa_broadaddr ifa_dstaddr
|
||||
struct sockaddr *ifa_netmask; /* used to determine subnet */
|
||||
struct pfk_ifnet *ifa_ifp; /* back-pointer to interface */
|
||||
TAILQ_ENTRY(ifaddr) ifa_list; /* [N] list of addresses */
|
||||
TAILQ_ENTRY(ifaddr) ifa_tmplist;/* [T] temporary list */
|
||||
u_int ifa_flags;
|
||||
struct refcnt ifa_refcnt;
|
||||
int ifa_metric;
|
||||
};
|
||||
|
||||
struct ifg_list {
|
||||
struct ifg_group *ifgl_group; /* [I] interface group */
|
||||
TAILQ_ENTRY(ifg_list) ifgl_next; /* [N] all groups are chained */
|
||||
};
|
||||
|
||||
#endif
|
||||
+41
-441
@@ -1,455 +1,81 @@
|
||||
/* $OpenBSD: ifq.h,v 1.44 2025/03/04 01:13:37 dlg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 David Gwynne <dlg@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
/* PFLINUX compat: <net/ifq.h> — OpenBSD 8.0 transmit-queue framework.
|
||||
* Field names follow upstream (ifqop_*) so the ported PF code stays
|
||||
* line-proximate. The framework itself is implemented in compat/pfk_ifq.c
|
||||
* (priq semantics); the HFSC and fq_codel back ends are ported in
|
||||
* milestone M5 and plug into the same ops structures.
|
||||
*/
|
||||
#ifndef _PFK_IFQ_H
|
||||
#define _PFK_IFQ_H
|
||||
|
||||
#ifndef _NET_IFQ_H_
|
||||
#define _NET_IFQ_H_
|
||||
#include <linux/types.h>
|
||||
|
||||
/* struct pfq_ops comes from net/pfvar.h (OpenBSD 8.0) — it is included by
|
||||
* pfk.h before this header. */
|
||||
struct mbuf;
|
||||
struct mbuf_list;
|
||||
struct ifnet;
|
||||
struct kstat;
|
||||
struct pfk_ifnet;
|
||||
struct pf_queuespec;
|
||||
|
||||
struct ifq_ops;
|
||||
#define IFQ_MAXLEN 256
|
||||
|
||||
struct ifqueue {
|
||||
struct ifnet *ifq_if;
|
||||
struct taskq *ifq_softnet;
|
||||
union {
|
||||
void *_ifq_softc;
|
||||
/*
|
||||
* a rings sndq is found by looking up an array of pointers.
|
||||
* by default we only have one sndq and the default drivers
|
||||
* dont use ifq_softc, so we can borrow it for the map until
|
||||
* we need to allocate a proper map.
|
||||
*/
|
||||
struct ifqueue *_ifq_ifqs[1];
|
||||
} _ifq_ptr;
|
||||
#define ifq_softc _ifq_ptr._ifq_softc
|
||||
#define ifq_ifqs _ifq_ptr._ifq_ifqs
|
||||
|
||||
/* mbuf handling */
|
||||
struct mutex ifq_mtx;
|
||||
struct pfk_ifnet *ifq_if;
|
||||
void *ifq_softc;
|
||||
const struct ifq_ops *ifq_ops;
|
||||
void *ifq_q;
|
||||
struct mbuf_list ifq_free;
|
||||
struct mbuf_list *ifq_free; /* free list (unused in the port) */
|
||||
unsigned int ifq_len;
|
||||
unsigned int ifq_oactive;
|
||||
|
||||
/* statistics */
|
||||
uint64_t ifq_packets;
|
||||
uint64_t ifq_bytes;
|
||||
uint64_t ifq_qdrops;
|
||||
uint64_t ifq_errors;
|
||||
uint64_t ifq_mcasts;
|
||||
uint32_t ifq_oactives;
|
||||
u_int64_t ifq_packets;
|
||||
u_int64_t ifq_bytes;
|
||||
u_int64_t ifq_qdrops;
|
||||
u_int64_t ifq_errors;
|
||||
u_int64_t ifq_mcasts;
|
||||
u_int32_t ifq_oactives;
|
||||
|
||||
struct kstat *ifq_kstat;
|
||||
|
||||
/* work serialisation */
|
||||
struct mutex ifq_task_mtx;
|
||||
struct task_list ifq_task_list;
|
||||
void *ifq_serializer;
|
||||
struct task ifq_bundle;
|
||||
|
||||
/* work to be serialised */
|
||||
struct task ifq_start;
|
||||
struct task ifq_restart;
|
||||
void *ifq_kstat;
|
||||
|
||||
/* properties */
|
||||
unsigned int ifq_maxlen;
|
||||
unsigned int ifq_idx;
|
||||
};
|
||||
|
||||
struct ifiqueue {
|
||||
struct ifnet *ifiq_if;
|
||||
caddr_t *ifiq_bpfp;
|
||||
struct taskq *ifiq_softnet;
|
||||
union {
|
||||
void *_ifiq_softc;
|
||||
struct ifiqueue *_ifiq_ifiqs[1];
|
||||
} _ifiq_ptr;
|
||||
#define ifiq_softc _ifiq_ptr._ifiq_softc
|
||||
#define ifiq_ifiqs _ifiq_ptr._ifiq_ifiqs
|
||||
|
||||
struct mutex ifiq_mtx;
|
||||
struct mbuf_list ifiq_ml;
|
||||
struct task ifiq_task;
|
||||
unsigned int ifiq_pressure;
|
||||
|
||||
/* counters */
|
||||
uint64_t ifiq_packets;
|
||||
uint64_t ifiq_bytes;
|
||||
uint64_t ifiq_fdrops;
|
||||
uint64_t ifiq_qdrops;
|
||||
uint64_t ifiq_errors;
|
||||
uint64_t ifiq_mcasts;
|
||||
uint64_t ifiq_noproto;
|
||||
|
||||
/* number of times a list of packets were put on ifiq_ml */
|
||||
uint64_t ifiq_enqueues;
|
||||
/* number of times a list of packets were pulled off ifiq_ml */
|
||||
uint64_t ifiq_dequeues;
|
||||
|
||||
struct kstat *ifiq_kstat;
|
||||
|
||||
/* properties */
|
||||
unsigned int ifiq_idx;
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#define IFQ_MAXLEN 256
|
||||
|
||||
/*
|
||||
*
|
||||
* Interface Send Queues
|
||||
*
|
||||
* struct ifqueue sits between the network stack and a drivers
|
||||
* transmission of packets. The high level view is that when the stack
|
||||
* has finished generating a packet it hands it to a driver for
|
||||
* transmission. It does this by queueing the packet on an ifqueue and
|
||||
* notifying the driver to start transmission of the queued packets.
|
||||
*
|
||||
* A network device may have multiple contexts for the transmission
|
||||
* of packets, ie, independent transmit rings. Such a network device,
|
||||
* represented by a struct ifnet, would then have multiple ifqueue
|
||||
* structures, each of which maps to an independent transmit ring.
|
||||
*
|
||||
* struct ifqueue also provides the point where conditioning of
|
||||
* traffic (ie, priq and hfsc) is implemented, and provides some
|
||||
* infrastructure to assist in the implementation of network drivers.
|
||||
*
|
||||
* = ifq API
|
||||
*
|
||||
* The ifq API provides functions for three distinct consumers:
|
||||
*
|
||||
* 1. The network stack
|
||||
* 2. Traffic QoS/conditioning implementations
|
||||
* 3. Network drivers
|
||||
*
|
||||
* == Network Stack API
|
||||
*
|
||||
* The network stack is responsible for initialising and destroying
|
||||
* the ifqueue structures, changing the traffic conditioner on an
|
||||
* interface, enqueuing packets for transmission, and notifying
|
||||
* the driver to start transmission of a particular ifqueue.
|
||||
*
|
||||
* === ifq_init()
|
||||
*
|
||||
* During if_attach(), the network stack calls ifq_init to initialise
|
||||
* the ifqueue structure. By default it configures the priq traffic
|
||||
* conditioner.
|
||||
*
|
||||
* === ifq_destroy()
|
||||
*
|
||||
* The network stack calls ifq_destroy() during if_detach to tear down
|
||||
* the ifqueue structure. It frees the traffic conditioner state, and
|
||||
* frees any mbufs that were left queued.
|
||||
*
|
||||
* === ifq_attach()
|
||||
*
|
||||
* ifq_attach() is used to replace the current traffic conditioner on
|
||||
* the ifqueue. All the pending mbufs are removed from the previous
|
||||
* conditioner and requeued on the new.
|
||||
*
|
||||
* === ifq_idx()
|
||||
*
|
||||
* ifq_idx() selects a specific ifqueue from the current ifnet
|
||||
* structure for use in the transmission of the mbuf.
|
||||
*
|
||||
* === ifq_enqueue()
|
||||
*
|
||||
* ifq_enqueue() attempts to fit an mbuf onto the ifqueue. The
|
||||
* current traffic conditioner may drop a packet to make space on the
|
||||
* queue.
|
||||
*
|
||||
* === ifq_start()
|
||||
*
|
||||
* Once a packet has been successfully queued with ifq_enqueue(),
|
||||
* the network card is notified with a call to ifq_start().
|
||||
* Calls to ifq_start() run in the ifqueue serialisation context,
|
||||
* guaranteeing that only one instance of ifp->if_qstart() will be
|
||||
* running on behalf of a specific ifqueue in the system at any point
|
||||
* in time.
|
||||
*
|
||||
* == Traffic conditioners API
|
||||
*
|
||||
* The majority of interaction between struct ifqueue and a traffic
|
||||
* conditioner occurs via the callbacks a traffic conditioner provides
|
||||
* in an instance of struct ifq_ops.
|
||||
*
|
||||
* XXX document ifqop_*
|
||||
*
|
||||
* The ifqueue API implements the locking on behalf of the conditioning
|
||||
* implementations so conditioners only have to reject or keep mbufs.
|
||||
* If something needs to inspect a conditioners internals, the queue lock
|
||||
* needs to be taken to allow for a consistent or safe view. The queue
|
||||
* lock may be taken and released with ifq_q_enter() and ifq_q_leave().
|
||||
*
|
||||
* === ifq_q_enter()
|
||||
*
|
||||
* Code wishing to access a conditioners internals may take the queue
|
||||
* lock with ifq_q_enter(). The caller must pass a reference to the
|
||||
* conditioners ifq_ops structure so the infrastructure can ensure the
|
||||
* caller is able to understand the internals. ifq_q_enter() returns
|
||||
* a pointer to the conditioners internal structures, or NULL if the
|
||||
* ifq_ops did not match the current conditioner.
|
||||
*
|
||||
* === ifq_q_leave()
|
||||
*
|
||||
* The queue lock acquired with ifq_q_enter() is released with
|
||||
* ifq_q_leave().
|
||||
*
|
||||
* === ifq_mfreem() and ifq_mfreeml()
|
||||
*
|
||||
* A goal of the API is to avoid freeing an mbuf while mutexes are
|
||||
* held. Because the ifq API manages the lock on behalf of the backend
|
||||
* ifqops, the backend should not directly free mbufs. If a conditioner
|
||||
* backend needs to drop a packet during the handling of ifqop_deq_begin,
|
||||
* it may free it by calling ifq_mfreem(). This accounts for the drop,
|
||||
* and schedules the free of the mbuf outside the hold of ifq_mtx.
|
||||
* ifq_mfreeml() takes an mbuf list as an argument instead.
|
||||
*
|
||||
*
|
||||
* == Network Driver API
|
||||
*
|
||||
* The API used by network drivers is mostly documented in the
|
||||
* ifq_dequeue(9) manpage except for ifq_serialize().
|
||||
*
|
||||
* === ifq_serialize()
|
||||
*
|
||||
* A driver may run arbitrary work in the ifqueue serialiser context
|
||||
* via ifq_serialize(). The work to be done is represented by a task
|
||||
* that has been prepared with task_set.
|
||||
*
|
||||
* The work will be run in series with any other work dispatched by
|
||||
* ifq_start(), ifq_restart(), or other ifq_serialize() calls.
|
||||
*
|
||||
* Because the work may be run on another CPU, the lifetime of the
|
||||
* task and the work it represents can extend beyond the end of the
|
||||
* call to ifq_serialize() that dispatched it.
|
||||
*
|
||||
*
|
||||
* = ifqueue work serialisation
|
||||
*
|
||||
* ifqueues provide a mechanism to dispatch work to be run in a single
|
||||
* context. Work in this mechanism is represented by task structures.
|
||||
*
|
||||
* The tasks are run in a context similar to a taskq serviced by a
|
||||
* single kernel thread, except the work is run immediately by the
|
||||
* first CPU that dispatches work. If a second CPU attempts to dispatch
|
||||
* additional tasks while the first is still running, it will be queued
|
||||
* to be run by the first CPU. The second CPU will return immediately.
|
||||
*
|
||||
* = MP Safe Network Drivers
|
||||
*
|
||||
* An MP safe network driver is one in which its start routine can be
|
||||
* called by the network stack without holding the big kernel lock.
|
||||
*
|
||||
* == Attach
|
||||
*
|
||||
* A driver advertises its ability to run its start routine without
|
||||
* the kernel lock by setting the IFXF_MPSAFE flag in ifp->if_xflags
|
||||
* before calling if_attach(). Advertising an MPSAFE start routine
|
||||
* also implies that the driver understands that a network card can
|
||||
* have multiple rings or transmit queues, and therefore provides
|
||||
* if_qstart function (which takes an ifqueue pointer) instead of an
|
||||
* if_start function (which takes an ifnet pointer).
|
||||
*
|
||||
* If the hardware supports multiple transmit rings, it advertises
|
||||
* support for multiple rings to the network stack with if_attach_queues()
|
||||
* after the call to if_attach(). if_attach_queues allocates a struct
|
||||
* ifqueue for each hardware ring, which can then be initialised by
|
||||
* the driver with data for each ring.
|
||||
*
|
||||
* void drv_start(struct ifqueue *);
|
||||
*
|
||||
* void
|
||||
* drv_attach()
|
||||
* {
|
||||
* ...
|
||||
* ifp->if_xflags = IFXF_MPSAFE;
|
||||
* ifp->if_qstart = drv_start;
|
||||
* if_attach(ifp);
|
||||
*
|
||||
* if_attach_queues(ifp, DRV_NUM_TX_RINGS);
|
||||
* for (i = 0; i < DRV_NUM_TX_RINGS; i++) {
|
||||
* struct ifqueue *ifq = ifp->if_ifqs[i];
|
||||
* struct drv_tx_ring *ring = &sc->sc_tx_rings[i];
|
||||
*
|
||||
* ifq->ifq_softc = ring;
|
||||
* ring->ifq = ifq;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* The network stack will then call ifp->if_qstart via ifq_start()
|
||||
* to guarantee there is only one instance of that function running
|
||||
* for each ifq in the system, and to serialise it with other work
|
||||
* the driver may provide.
|
||||
*
|
||||
* == Initialise
|
||||
*
|
||||
* When the stack requests an interface be brought up (ie, drv_ioctl()
|
||||
* is called to handle SIOCSIFFLAGS with IFF_UP set in ifp->if_flags)
|
||||
* drivers should set IFF_RUNNING in ifp->if_flags, and then call
|
||||
* ifq_clr_oactive() against each ifq.
|
||||
*
|
||||
* == if_start
|
||||
*
|
||||
* ifq_start() checks that IFF_RUNNING is set in ifp->if_flags, that
|
||||
* ifq_is_oactive() does not return true, and that there are pending
|
||||
* packets to transmit via a call to ifq_len(). Therefore, drivers are
|
||||
* no longer responsible for doing this themselves.
|
||||
*
|
||||
* If a driver should not transmit packets while its link is down, use
|
||||
* ifq_purge() to flush pending packets from the transmit queue.
|
||||
*
|
||||
* Drivers for hardware should use the following pattern to transmit
|
||||
* packets:
|
||||
*
|
||||
* void
|
||||
* drv_start(struct ifqueue *ifq)
|
||||
* {
|
||||
* struct drv_tx_ring *ring = ifq->ifq_softc;
|
||||
* struct ifnet *ifp = ifq->ifq_if;
|
||||
* struct drv_softc *sc = ifp->if_softc;
|
||||
* struct mbuf *m;
|
||||
* int kick = 0;
|
||||
*
|
||||
* if (NO_LINK) {
|
||||
* ifq_purge(ifq);
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* for (;;) {
|
||||
* if (NO_SPACE(ring)) {
|
||||
* ifq_set_oactive(ifq);
|
||||
* break;
|
||||
* }
|
||||
*
|
||||
* m = ifq_dequeue(ifq);
|
||||
* if (m == NULL)
|
||||
* break;
|
||||
*
|
||||
* if (drv_encap(sc, ring, m) != 0) { // map and fill ring
|
||||
* m_freem(m);
|
||||
* continue;
|
||||
* }
|
||||
*
|
||||
* bpf_mtap();
|
||||
* }
|
||||
*
|
||||
* drv_kick(ring); // notify hw of new descriptors on the ring
|
||||
* }
|
||||
*
|
||||
* == Transmission completion
|
||||
*
|
||||
* The following pattern should be used for transmit queue interrupt
|
||||
* processing:
|
||||
*
|
||||
* void
|
||||
* drv_txeof(struct drv_tx_ring *ring)
|
||||
* {
|
||||
* struct ifqueue *ifq = ring->ifq;
|
||||
*
|
||||
* while (COMPLETED_PKTS(ring)) {
|
||||
* // unmap packets, m_freem() the mbufs.
|
||||
* }
|
||||
*
|
||||
* if (ifq_is_oactive(ifq))
|
||||
* ifq_restart(ifq);
|
||||
* }
|
||||
*
|
||||
* == Stop
|
||||
*
|
||||
* Bringing an interface down (ie, IFF_UP was cleared in ifp->if_flags)
|
||||
* should clear IFF_RUNNING in ifp->if_flags, and guarantee the start
|
||||
* routine is not running before freeing any resources it uses:
|
||||
*
|
||||
* void
|
||||
* drv_down(struct drv_softc *sc)
|
||||
* {
|
||||
* struct ifnet *ifp = &sc->sc_if;
|
||||
* struct ifqueue *ifq;
|
||||
* int i;
|
||||
*
|
||||
* CLR(ifp->if_flags, IFF_RUNNING);
|
||||
* DISABLE_INTERRUPTS();
|
||||
*
|
||||
* for (i = 0; i < sc->sc_num_queues; i++) {
|
||||
* ifq = ifp->if_ifqs[i];
|
||||
* ifq_barrier(ifq);
|
||||
* }
|
||||
*
|
||||
* intr_barrier(sc->sc_ih);
|
||||
*
|
||||
* FREE_RESOURCES();
|
||||
*
|
||||
* for (i = 0; i < sc->sc_num_queues; i++) {
|
||||
* ifq = ifp->if_ifqs[i];
|
||||
* ifq_clr_oactive(ifq);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
struct ifq_ops {
|
||||
unsigned int (*ifqop_idx)(unsigned int,
|
||||
const struct mbuf *);
|
||||
struct mbuf *(*ifqop_enq)(struct ifqueue *, struct mbuf *);
|
||||
struct mbuf *(*ifqop_deq_begin)(struct ifqueue *, void **);
|
||||
void (*ifqop_deq_commit)(struct ifqueue *,
|
||||
struct mbuf *, void *);
|
||||
void (*ifqop_purge)(struct ifqueue *,
|
||||
struct mbuf_list *);
|
||||
void *(*ifqop_alloc)(unsigned int, void *);
|
||||
void (*ifqop_free)(unsigned int, void *);
|
||||
unsigned int (*ifqop_idx)(unsigned int, const struct mbuf *);
|
||||
struct mbuf *(*ifqop_enq)(struct ifqueue *, struct mbuf *);
|
||||
struct mbuf *(*ifqop_deq_begin)(struct ifqueue *, void **);
|
||||
void (*ifqop_deq_commit)(struct ifqueue *, struct mbuf *,
|
||||
void *);
|
||||
void (*ifqop_purge)(struct ifqueue *, struct mbuf_list *);
|
||||
void *(*ifqop_alloc)(unsigned int, void *);
|
||||
void (*ifqop_free)(unsigned int, void *);
|
||||
};
|
||||
|
||||
extern const struct ifq_ops * const ifq_priq_ops;
|
||||
|
||||
/*
|
||||
* Interface send queues.
|
||||
*/
|
||||
extern const struct ifq_ops * const ifq_hfsc_ops;
|
||||
extern const struct ifq_ops * const ifq_fqcodel_ops;
|
||||
extern const struct pfq_ops * const pfq_hfsc_ops;
|
||||
extern const struct pfq_ops * const pfq_fqcodel_ops;
|
||||
|
||||
void ifq_init(struct ifqueue *, struct ifnet *, unsigned int);
|
||||
void ifq_init_maxlen(struct ifqueue *, unsigned int);
|
||||
void ifq_attach(struct ifqueue *, const struct ifq_ops *, void *);
|
||||
void ifq_destroy(struct ifqueue *);
|
||||
void ifq_add_data(struct ifqueue *, struct if_data *);
|
||||
int ifq_enqueue(struct ifqueue *, struct mbuf *);
|
||||
void ifq_start(struct ifqueue *);
|
||||
struct mbuf *ifq_deq_begin(struct ifqueue *);
|
||||
void ifq_deq_commit(struct ifqueue *, struct mbuf *);
|
||||
void ifq_deq_rollback(struct ifqueue *, struct mbuf *);
|
||||
struct mbuf *ifq_dequeue(struct ifqueue *);
|
||||
int ifq_hdatalen(struct ifqueue *);
|
||||
void ifq_init_maxlen(struct ifqueue *, unsigned int);
|
||||
unsigned int ifq_purge(struct ifqueue *);
|
||||
void ifq_mfreem(struct ifqueue *, struct mbuf *);
|
||||
void ifq_mfreeml(struct ifqueue *, struct mbuf_list *);
|
||||
unsigned int ifq_purge(struct ifqueue *);
|
||||
void *ifq_q_enter(struct ifqueue *, const struct ifq_ops *);
|
||||
void ifq_q_leave(struct ifqueue *, void *);
|
||||
void ifq_serialize(struct ifqueue *, struct task *);
|
||||
void ifq_barrier(struct ifqueue *);
|
||||
void ifq_set_oactive(struct ifqueue *);
|
||||
void ifq_deq_set_oactive(struct ifqueue *);
|
||||
|
||||
int ifq_deq_sleep(struct ifqueue *, struct mbuf **, int, int,
|
||||
const char *, volatile unsigned int *,
|
||||
volatile unsigned int *);
|
||||
int ifq_hdatalen(struct ifqueue *);
|
||||
|
||||
#define ifq_len(_ifq) READ_ONCE((_ifq)->ifq_len)
|
||||
#define ifq_empty(_ifq) (ifq_len(_ifq) == 0)
|
||||
@@ -472,36 +98,10 @@ ifq_is_oactive(struct ifqueue *ifq)
|
||||
return (ifq->ifq_oactive);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ifq_restart(struct ifqueue *ifq)
|
||||
{
|
||||
ifq_serialize(ifq, &ifq->ifq_restart);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
ifq_idx(struct ifqueue *ifq, unsigned int nifqs, const struct mbuf *m)
|
||||
{
|
||||
return ((*ifq->ifq_ops->ifqop_idx)(nifqs, m));
|
||||
}
|
||||
|
||||
/* ifiq */
|
||||
|
||||
void ifiq_init(struct ifiqueue *, struct ifnet *, unsigned int);
|
||||
void ifiq_destroy(struct ifiqueue *);
|
||||
int ifiq_input(struct ifiqueue *, struct mbuf_list *);
|
||||
int ifiq_enqueue_qlim(struct ifiqueue *, struct mbuf *,
|
||||
unsigned int);
|
||||
void ifiq_add_data(struct ifiqueue *, struct if_data *);
|
||||
|
||||
#define ifiq_len(_ifiq) READ_ONCE(ml_len(&(_ifiq)->ifiq_ml))
|
||||
#define ifiq_empty(_ifiq) (ifiq_len(_ifiq) == 0)
|
||||
|
||||
static inline int
|
||||
ifiq_enqueue(struct ifiqueue *ifiq, struct mbuf *m)
|
||||
{
|
||||
return ifiq_enqueue_qlim(ifiq, m, 0);
|
||||
}
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _NET_IFQ_H_ */
|
||||
#endif
|
||||
@@ -71,5 +71,8 @@ struct radix_node *rn_delete(void *, void *, struct radix_node_head *,
|
||||
struct radix_node *);
|
||||
struct radix_node *rn_lookup(void *, void *, struct radix_node_head *);
|
||||
struct radix_node *rn_match(void *, struct radix_node_head *);
|
||||
int rn_add_dupedkey(struct radix_node *saved_tt,
|
||||
struct radix_node_head *head, struct radix_node *tt, u_int8_t prio);
|
||||
int rn_initmask(void);
|
||||
|
||||
#endif /* _PFK_RADIX_H_ */
|
||||
@@ -1,82 +1,22 @@
|
||||
/* $OpenBSD: rtable.h,v 1.36 2025/07/15 09:55:49 dlg Exp $ */
|
||||
/* PFLINUX compat: <net/rtable.h> — minimal view of OpenBSD's routing
|
||||
* table API as used by PF. Linux has a single (policy-)routing FIB, so
|
||||
* per-rtableid trees do not exist; the route-to path (pf.c: rtable_iterate)
|
||||
* is replaced by the Linux FIB lookup in pfk_xmit.c (task T14). */
|
||||
#ifndef _PFK_RTABLE_H
|
||||
#define _PFK_RTABLE_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Martin Pieuchot
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifndef _NET_RTABLE_H_
|
||||
#define _NET_RTABLE_H_
|
||||
|
||||
#include <sys/rwlock.h>
|
||||
|
||||
struct art;
|
||||
|
||||
/*
|
||||
* Locks used to protect struct members in this file:
|
||||
* I immutable after creation
|
||||
* N net lock
|
||||
*/
|
||||
|
||||
struct rtable {
|
||||
struct rwlock r_lock;
|
||||
struct art *r_art; /* [I] */
|
||||
unsigned int r_off; /* [I] Offset of key in bytes */
|
||||
|
||||
struct sockaddr *r_source; /* [N] use optional src addr */
|
||||
struct pf_rtentry {
|
||||
void *rt_addr; /* destination */
|
||||
unsigned int rt_ifidx; /* egress ifindex */
|
||||
unsigned int rt_flags;
|
||||
int rt_listid;
|
||||
int rt_labelid;
|
||||
void *rt_ifa;
|
||||
};
|
||||
|
||||
/*
|
||||
* Newer routing table implementation based on ART (Allotment Routing
|
||||
* Table).
|
||||
*/
|
||||
int rtable_exists(unsigned int rtableid);
|
||||
struct pf_rtentry *rtable_iterate(struct pf_rtentry *rt);
|
||||
|
||||
#define rt_key(rt) ((rt)->rt_dest)
|
||||
#define rt_plen(rt) ((rt)->rt_plen)
|
||||
#define RT_ROOT(rt) (0)
|
||||
|
||||
int rtable_satoplen(sa_family_t, const struct sockaddr *);
|
||||
|
||||
void rtable_init(void);
|
||||
int rtable_exists(unsigned int);
|
||||
int rtable_empty(unsigned int);
|
||||
int rtable_add(unsigned int);
|
||||
unsigned int rtable_l2(unsigned int);
|
||||
unsigned int rtable_loindex(unsigned int);
|
||||
void rtable_l2set(unsigned int, unsigned int, unsigned int);
|
||||
|
||||
int rtable_setsource(unsigned int, int, struct sockaddr *);
|
||||
struct sockaddr *rtable_getsource(unsigned int, int);
|
||||
void rtable_clearsource(unsigned int, struct sockaddr *);
|
||||
struct rtentry *rtable_lookup(unsigned int, const struct sockaddr *,
|
||||
const struct sockaddr *, const struct sockaddr *, uint8_t);
|
||||
struct rtentry *rtable_match(unsigned int, const struct sockaddr *,
|
||||
uint32_t *);
|
||||
struct rtentry *rtable_iterate(struct rtentry *);
|
||||
int rtable_insert(unsigned int, struct sockaddr *,
|
||||
const struct sockaddr *, const struct sockaddr *, uint8_t,
|
||||
struct rtentry *);
|
||||
int rtable_delete(unsigned int, const struct sockaddr *,
|
||||
const struct sockaddr *, struct rtentry *);
|
||||
int rtable_walk(unsigned int, sa_family_t, struct rtentry **,
|
||||
int (*)(struct rtentry *, void *, unsigned int), void *);
|
||||
int rtable_read(unsigned int, sa_family_t,
|
||||
int (*)(const struct rtentry *, void *, unsigned int),
|
||||
void *);
|
||||
|
||||
int rtable_mpath_capable(unsigned int, sa_family_t);
|
||||
int rtable_mpath_reprio(unsigned int, struct sockaddr *, int,
|
||||
uint8_t, struct rtentry *);
|
||||
|
||||
#endif /* _NET_RTABLE_H_ */
|
||||
#endif
|
||||
@@ -10,4 +10,11 @@
|
||||
#ifndef INADDR_MULTICAST
|
||||
#define INADDR_MULTICAST 0xe0000000U
|
||||
#endif
|
||||
|
||||
/* BSD <netinet/in.h> union of socket address types */
|
||||
union sockaddr_union {
|
||||
struct sockaddr su;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
};
|
||||
#endif
|
||||
@@ -10,8 +10,12 @@
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((__packed__))
|
||||
#endif
|
||||
/* NOTE: the kernel redefines 'inline' as a macro that expands to
|
||||
* 'inline __gnu_inline __inline_maybe_unused notrace'; any attribute placed
|
||||
* between those tokens breaks the parse. Therefore __unused expands to
|
||||
* nothing here (unused *static inline* functions do not warn in GCC). */
|
||||
#ifndef __unused
|
||||
#define __unused __attribute__((__unused__))
|
||||
#define __unused
|
||||
#endif
|
||||
#ifndef __dead
|
||||
#define __dead __attribute__((__noreturn__))
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/* PFLINUX compat: <sys/mutex.h> — OpenBSD struct mutex over a Linux
|
||||
* counting semaphore. BSD entry points are MACROS calling pfk_* helpers,
|
||||
* after #undef of any same-named kernel macros (the kernel's own mutex_*
|
||||
* functions were expanded before pfk.h and are unaffected). */
|
||||
#ifndef _PFK_SYS_MUTEX_H
|
||||
#define _PFK_SYS_MUTEX_H
|
||||
|
||||
#define IPL_SOFTNET 6
|
||||
|
||||
struct pfk_mutex {
|
||||
struct semaphore s;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
void pfk_mutex_setup(struct pfk_mutex *m, const char *name);
|
||||
|
||||
#define PFK_MUTEX_INIT(obj) \
|
||||
{ .s = __SEMAPHORE_INITIALIZER(obj, 1), .name = #obj }
|
||||
|
||||
#undef mutex_init
|
||||
#undef mutex_destroy
|
||||
#undef mutex_is_locked
|
||||
#define mutex_init(m, n, f) pfk_mutex_setup((m), (n))
|
||||
#define mutex_enter(m) down(&(m)->s)
|
||||
#define mutex_leave(m) up(&(m)->s)
|
||||
#define mutex_try_enter(m, t) (down_trylock(&(m)->s) == 0)
|
||||
#define mutex_destroy(m) do { } while (0)
|
||||
#define mutex_is_locked(m) (atomic_long_read(&(m)->s.count) < 1)
|
||||
|
||||
/* MUTEX_INITIALIZER(ipl) used in static definitions:
|
||||
* struct mutex x = MUTEX_INITIALIZER(IPL_SOFTNET); */
|
||||
#define MUTEX_INITIALIZER(ipl) PFK_MUTEX_INIT(pfk_mtx_static)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
/* PFLINUX compat: <sys/pclock.h> — passclock type (PF uses struct pclock
|
||||
* members for per-domain stats; kept as a simple counter here). */
|
||||
#ifndef _PFK_PCLK_H
|
||||
#define _PFK_PCLK_H
|
||||
struct pclock {
|
||||
u_int64_t pclock_count[4];
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
/* PFLINUX compat: <sys/percpu.h> — OpenBSD cpumem over a
|
||||
* per-CPU-slot array (preempt disabled during access; counters only). */
|
||||
#ifndef _PFK_SYSPERCPU_H
|
||||
#define _PFK_SYSPERCPU_H
|
||||
|
||||
struct cpumem {
|
||||
void *cm_base;
|
||||
size_t cm_item;
|
||||
int cm_ncpu;
|
||||
};
|
||||
|
||||
struct cpumem_iter {
|
||||
unsigned int cpumem_iter_num;
|
||||
unsigned int cpumem_iter_cpus;
|
||||
unsigned int cpumem_iter_cpu;
|
||||
unsigned long cpumem_iter_obj;
|
||||
struct cpumem *cm;
|
||||
};
|
||||
|
||||
static inline struct cpumem *
|
||||
cpumem_malloc(size_t item, int flags)
|
||||
{
|
||||
struct cpumem *cm;
|
||||
gfp_t g = (flags & M_WAITOK) ? GFP_KERNEL : GFP_ATOMIC;
|
||||
|
||||
cm = kmalloc(sizeof(*cm), g);
|
||||
if (!cm)
|
||||
return NULL;
|
||||
cm->cm_ncpu = num_possible_cpus();
|
||||
cm->cm_base = vzalloc((size_t)cm->cm_ncpu * item);
|
||||
if (!cm->cm_base) {
|
||||
kfree(cm);
|
||||
return NULL;
|
||||
}
|
||||
cm->cm_item = item;
|
||||
return cm;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
cpumem_enter(struct cpumem *cm)
|
||||
{
|
||||
preempt_disable();
|
||||
return (char *)cm->cm_base + (size_t)smp_processor_id() * cm->cm_item;
|
||||
}
|
||||
|
||||
static inline void
|
||||
cpumem_leave(struct cpumem *cm, void *p)
|
||||
{
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static inline void
|
||||
cpumem_free(struct cpumem *cm, int size)
|
||||
{
|
||||
if (!cm)
|
||||
return;
|
||||
vfree(cm->cm_base);
|
||||
kfree(cm);
|
||||
}
|
||||
|
||||
/* BSD CPUMEM_FOREACH: iterate the per-CPU slots of a cpumem area. */
|
||||
static inline void *
|
||||
pfk_cpumem_at(struct cpumem *cm, unsigned int cpu)
|
||||
{
|
||||
if (!cm || !cm->cm_base || cpu >= (unsigned int)cm->cm_ncpu)
|
||||
return NULL;
|
||||
return (char *)cm->cm_base + (size_t)cpu * cm->cm_item;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
pfk_cpumem_first(struct cpumem_iter *it, struct cpumem *cm)
|
||||
{
|
||||
it->cpumem_iter_num = 0;
|
||||
it->cm = cm;
|
||||
return pfk_cpumem_at(cm, 0);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
pfk_cpumem_next(struct cpumem_iter *it, struct cpumem *cm)
|
||||
{
|
||||
it->cpumem_iter_num++;
|
||||
if (it->cpumem_iter_num >= (unsigned int)nr_cpu_ids)
|
||||
return NULL;
|
||||
return pfk_cpumem_at(cm, it->cpumem_iter_num);
|
||||
}
|
||||
|
||||
#define CPUMEM_FOREACH(var, it, cm) \
|
||||
for ((var) = pfk_cpumem_first((it), (cm)); \
|
||||
(var) != NULL; \
|
||||
(var) = pfk_cpumem_next((it), (cm)))
|
||||
|
||||
/* BSD cpumem_ref/cpumem_modify aliases */
|
||||
static inline void *
|
||||
cpumem_ref(struct cpumem *cm)
|
||||
{
|
||||
preempt_disable();
|
||||
return (char *)cm->cm_base + (size_t)smp_processor_id() * cm->cm_item;
|
||||
}
|
||||
|
||||
static inline void
|
||||
cpumem_drop(struct cpumem *cm, void *p)
|
||||
{
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,9 +6,9 @@
|
||||
struct refcnt { refcount_t rc; };
|
||||
#define REFCNT_INITIALIZER { .rc = REFCNT_INIT }
|
||||
|
||||
static inline void refcnt_init(struct refcnt *r, unsigned int v)
|
||||
static inline void refcnt_init(struct refcnt *r)
|
||||
{
|
||||
refcount_set(&r->rc, v ? (int)v : 1);
|
||||
refcount_set(&r->rc, 1);
|
||||
}
|
||||
static inline unsigned int refcnt_value(const struct refcnt *r)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/* PFLINUX compat: <sys/rwlock.h> — struct pfk_rwlock alias provided by
|
||||
* pfk.h before this point (include-guard re-entrancy); wrapper is a marker. */
|
||||
#ifndef _PFK_RWLOCK_H
|
||||
#define _PFK_RWLOCK_H
|
||||
/* struct rwlock == struct pfk_rwlock (see pfk.h) */
|
||||
#define LCK_MRW 0
|
||||
#endif
|
||||
@@ -821,115 +821,115 @@ int _rb_check(const struct rb_type *, void *, unsigned long);
|
||||
#define RBT_PROTOTYPE(_name, _type, _field, _cmp) \
|
||||
extern const struct rb_type *const _name##_RBT_TYPE; \
|
||||
\
|
||||
__unused static inline void \
|
||||
static inline void \
|
||||
_name##_RBT_INIT(struct _name *head) \
|
||||
{ \
|
||||
_rb_init(&head->rbh_root); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_INSERT(struct _name *head, struct _type *elm) \
|
||||
{ \
|
||||
return _rb_insert(_name##_RBT_TYPE, &head->rbh_root, elm); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_REMOVE(struct _name *head, struct _type *elm) \
|
||||
{ \
|
||||
return _rb_remove(_name##_RBT_TYPE, &head->rbh_root, elm); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_FIND(struct _name *head, const struct _type *key) \
|
||||
{ \
|
||||
return _rb_find(_name##_RBT_TYPE, &head->rbh_root, key); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_NFIND(struct _name *head, const struct _type *key) \
|
||||
{ \
|
||||
return _rb_nfind(_name##_RBT_TYPE, &head->rbh_root, key); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_ROOT(struct _name *head) \
|
||||
{ \
|
||||
return _rb_root(_name##_RBT_TYPE, &head->rbh_root); \
|
||||
} \
|
||||
\
|
||||
__unused static inline int \
|
||||
static inline int \
|
||||
_name##_RBT_EMPTY(struct _name *head) \
|
||||
{ \
|
||||
return _rb_empty(&head->rbh_root); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_MIN(struct _name *head) \
|
||||
{ \
|
||||
return _rb_min(_name##_RBT_TYPE, &head->rbh_root); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_MAX(struct _name *head) \
|
||||
{ \
|
||||
return _rb_max(_name##_RBT_TYPE, &head->rbh_root); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_NEXT(struct _type *elm) \
|
||||
{ \
|
||||
return _rb_next(_name##_RBT_TYPE, elm); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_PREV(struct _type *elm) \
|
||||
{ \
|
||||
return _rb_prev(_name##_RBT_TYPE, elm); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_LEFT(struct _type *elm) \
|
||||
{ \
|
||||
return _rb_left(_name##_RBT_TYPE, elm); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_RIGHT(struct _type *elm) \
|
||||
{ \
|
||||
return _rb_right(_name##_RBT_TYPE, elm); \
|
||||
} \
|
||||
\
|
||||
__unused static inline struct _type * \
|
||||
static inline struct _type * \
|
||||
_name##_RBT_PARENT(struct _type *elm) \
|
||||
{ \
|
||||
return _rb_parent(_name##_RBT_TYPE, elm); \
|
||||
} \
|
||||
\
|
||||
__unused static inline void \
|
||||
static inline void \
|
||||
_name##_RBT_SET_LEFT(struct _type *elm, struct _type *left) \
|
||||
{ \
|
||||
_rb_set_left(_name##_RBT_TYPE, elm, left); \
|
||||
} \
|
||||
\
|
||||
__unused static inline void \
|
||||
static inline void \
|
||||
_name##_RBT_SET_RIGHT(struct _type *elm, struct _type *right) \
|
||||
{ \
|
||||
_rb_set_right(_name##_RBT_TYPE, elm, right); \
|
||||
} \
|
||||
\
|
||||
__unused static inline void \
|
||||
static inline void \
|
||||
_name##_RBT_SET_PARENT(struct _type *elm, struct _type *parent) \
|
||||
{ \
|
||||
_rb_set_parent(_name##_RBT_TYPE, elm, parent); \
|
||||
} \
|
||||
\
|
||||
__unused static inline void \
|
||||
static inline void \
|
||||
_name##_RBT_POISON(struct _type *elm, unsigned long poison) \
|
||||
{ \
|
||||
_rb_poison(_name##_RBT_TYPE, elm, poison); \
|
||||
} \
|
||||
\
|
||||
__unused static inline int \
|
||||
static inline int \
|
||||
_name##_RBT_CHECK(struct _type *elm, unsigned long poison) \
|
||||
{ \
|
||||
return _rb_check(_name##_RBT_TYPE, elm, poison); \
|
||||
|
||||
Reference in new issue
Block a user