/* SPDX-License-Identifier: GPL-2.0-or-later * Copyright Red Hat * Author: David Gibson * * Definitions for the global table of packet flows. */ #ifndef FLOW_TABLE_H #define FLOW_TABLE_H #include "tcp_conn.h" #include "icmp_flow.h" #include "udp_flow.h" /** * struct flow_free_cluster - Information about a cluster of free entries * @f: Generic flow information * @n: Number of entries in the free cluster (including this one) * @next: Index of next free cluster */ struct flow_free_cluster { /* Must be first element */ struct flow_common f; unsigned n; unsigned next; }; /** * union flow - Descriptor for a logical packet flow (e.g. connection) * @f: Fields common between all variants * @tcp: Fields for non-spliced TCP connections * @tcp_splice: Fields for spliced TCP connections */ union flow { struct flow_common f; struct flow_free_cluster free; struct tcp_tap_conn tcp; struct tcp_splice_conn tcp_splice; struct icmp_ping_flow ping; struct udp_flow udp; }; /* Global Flow Table */ extern unsigned flow_first_free; extern union flow flowtab[]; /** * flow_foreach_sidei() - 'for' type macro to step through each side of flow * @sidei_: Takes value INISIDE, then TGTSIDE */ #define flow_foreach_sidei(sidei_) \ for ((sidei_) = INISIDE; (sidei_) < SIDES; (sidei_)++) /** flow_idx() - Index of flow from common structure * @f: Common flow fields pointer * * Return: index of @f in the flow table */ static inline unsigned flow_idx(const struct flow_common *f) { return (union flow *)f - flowtab; } /** FLOW_IDX() - Find the index of a flow * @f_: Flow pointer, either union flow * or protocol specific * * Return: index of @f in the flow table */ #define FLOW_IDX(f_) (flow_idx(&(f_)->f)) /** FLOW() - Flow entry at a given index * @idx: Flow index * * Return: pointer to entry @idx in the flow table */ #define FLOW(idx) (&flowtab[(idx)]) /** flow_at_sidx() - Flow entry for a given sidx * @sidx: Flow & side index * * Return: pointer to the corresponding flow entry, or NULL */ static inline union flow *flow_at_sidx(flow_sidx_t sidx) { if (!flow_sidx_valid(sidx)) return NULL; return FLOW(sidx.flowi); } /** pif_at_sidx() - Interface for a given flow and side * @sidx: Flow & side index * * Return: pif for the flow & side given by @sidx */ static inline uint8_t pif_at_sidx(flow_sidx_t sidx) { const union flow *flow = flow_at_sidx(sidx); if (!flow) return PIF_NONE; return flow->f.pif[sidx.sidei]; } /** flowside_at_sidx() - Retrieve a specific flowside * @sidx: Flow & side index * * Return: Flowside for the flow & side given by @sidx */ static inline const struct flowside *flowside_at_sidx(flow_sidx_t sidx) { const union flow *flow = flow_at_sidx(sidx); if (!flow) return NULL; return &flow->f.side[sidx.sidei]; } /** flow_sidx_opposite() - Get the other side of the same flow * @sidx: Flow & side index * * Return: sidx for the other side of the same flow as @sidx */ static inline flow_sidx_t flow_sidx_opposite(flow_sidx_t sidx) { if (!flow_sidx_valid(sidx)) return FLOW_SIDX_NONE; return (flow_sidx_t){.flowi = sidx.flowi, .sidei = !sidx.sidei}; } /** flow_sidx() - Index of one side of a flow from common structure * @f: Common flow fields pointer * @sidei: Which side to refer to (0 or 1) * * Return: index of @f and @side in the flow table */ static inline flow_sidx_t flow_sidx(const struct flow_common *f, unsigned sidei) { /* cppcheck-suppress [knownConditionTrueFalse, unmatchedSuppression] */ ASSERT(sidei == !!sidei); return (flow_sidx_t){ .sidei = sidei, .flowi = flow_idx(f), }; } /** FLOW_SIDX() - Find the index of one side of a flow * @f_: Flow pointer, either union flow * or protocol specific * @sidei: Which side to index (0 or 1) * * Return: index of @f and @side in the flow table */ #define FLOW_SIDX(f_, sidei) (flow_sidx(&(f_)->f, (sidei))) union flow *flow_alloc(void); void flow_alloc_cancel(union flow *flow); const struct flowside *flow_initiate_af(union flow *flow, uint8_t pif, sa_family_t af, const void *saddr, in_port_t sport, const void *daddr, in_port_t dport); const struct flowside *flow_initiate_sa(union flow *flow, uint8_t pif, const union sockaddr_inany *ssa, in_port_t dport); const struct flowside *flow_target_af(union flow *flow, uint8_t pif, sa_family_t af, const void *saddr, in_port_t sport, const void *daddr, in_port_t dport); const struct flowside *flow_target(const struct ctx *c, union flow *flow, uint8_t proto); union flow *flow_set_type(union flow *flow, enum flow_type type); #define FLOW_SET_TYPE(flow_, t_, var_) (&flow_set_type((flow_), (t_))->var_) void flow_activate(struct flow_common *f); #define FLOW_ACTIVATE(flow_) \ (flow_activate(&(flow_)->f)) #endif /* FLOW_TABLE_H */