| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-2-Clause |
| 3 | * |
| 4 | * Copyright (c) 2007-2009 Robert N. M. Watson |
| 5 | * Copyright (c) 2010-2011 Juniper Networks, Inc. |
| 6 | * All rights reserved. |
| 7 | * |
| 8 | * This software was developed by Robert N. M. Watson under contract |
| 9 | * to Juniper Networks, Inc. |
| 10 | * |
| 11 | * Redistribution and use in source and binary forms, with or without |
| 12 | * modification, are permitted provided that the following conditions |
| 13 | * are met: |
| 14 | * 1. Redistributions of source code must retain the above copyright |
| 15 | * notice, this list of conditions and the following disclaimer. |
| 16 | * 2. Redistributions in binary form must reproduce the above copyright |
| 17 | * notice, this list of conditions and the following disclaimer in the |
| 18 | * documentation and/or other materials provided with the distribution. |
| 19 | * |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 30 | * SUCH DAMAGE. |
| 31 | */ |
| 32 | |
| 33 | #ifndef _NET_NETISR_H_ |
| 34 | #define _NET_NETISR_H_ |
| 35 | |
| 36 | /* |
| 37 | * The netisr (network interrupt service routine) provides a deferred |
| 38 | * execution evironment in which (generally inbound) network processing can |
| 39 | * take place. Protocols register handlers which will be executed directly, |
| 40 | * or via deferred dispatch, depending on the circumstances. |
| 41 | * |
| 42 | * Historically, this was implemented by the BSD software ISR facility; it is |
| 43 | * now implemented via a software ithread (SWI). |
| 44 | */ |
| 45 | |
| 46 | /* |
| 47 | * Protocol numbers, which are encoded in monitoring applications and kernel |
| 48 | * modules. Internally, these are used in bit shift operations so must have |
| 49 | * a value 0 < proto < 32; we currently further limit at compile-time to 16 |
| 50 | * for array-sizing purposes. |
| 51 | */ |
| 52 | #define	NETISR_IP	1 |
| 53 | #define	NETISR_IGMP	2		/* IGMPv3 output queue */ |
| 54 | #define	NETISR_ROUTE	3		/* routing socket */ |
| 55 | #define	NETISR_ARP	4		/* same as AF_LINK */ |
| 56 | #define	NETISR_ETHER	5		/* ethernet input */ |
| 57 | #define	NETISR_IPV6	6 |
| 58 | #define	NETISR_IP_DIRECT	9	/* direct-dispatch IPv4 */ |
| 59 | #define	NETISR_IPV6_DIRECT	10	/* direct-dispatch IPv6 */ |
| 60 | |
| 61 | /* |
| 62 | * Protocol ordering and affinity policy constants. See the detailed |
| 63 | * discussion of policies later in the file. |
| 64 | */ |
| 65 | #define	NETISR_POLICY_SOURCE	1	/* Maintain source ordering. */ |
| 66 | #define	NETISR_POLICY_FLOW	2	/* Maintain flow ordering. */ |
| 67 | #define	NETISR_POLICY_CPU	3	/* Protocol determines CPU placement. */ |
| 68 | |
| 69 | /* |
| 70 | * Protocol dispatch policy constants; selects whether and when direct |
| 71 | * dispatch is permitted. |
| 72 | */ |
| 73 | #define	NETISR_DISPATCH_DEFAULT		0	/* Use global default. */ |
| 74 | #define	NETISR_DISPATCH_DEFERRED	1	/* Always defer dispatch. */ |
| 75 | #define	NETISR_DISPATCH_HYBRID		2	/* Allow hybrid dispatch. */ |
| 76 | #define	NETISR_DISPATCH_DIRECT		3	/* Always direct dispatch. */ |
| 77 | |
| 78 | /* |
| 79 | * Monitoring data structures, exported by sysctl(2). |
| 80 | * |
| 81 | * Three sysctls are defined. First, a per-protocol structure exported by |
| 82 | * net.isr.proto. |
| 83 | */ |
| 84 | #define	NETISR_NAMEMAXLEN	32 |
| 85 | struct sysctl_netisr_proto { |
| 86 | 	u_int	snp_version;			/* Length of struct. */ |
| 87 | 	char	snp_name[NETISR_NAMEMAXLEN];	/* nh_name */ |
| 88 | 	u_int	snp_proto;			/* nh_proto */ |
| 89 | 	u_int	snp_qlimit;			/* nh_qlimit */ |
| 90 | 	u_int	snp_policy;			/* nh_policy */ |
| 91 | 	u_int	snp_flags;			/* Various flags. */ |
| 92 | 	u_int	snp_dispatch;			/* Dispatch policy. */ |
| 93 | 	u_int	_snp_ispare[6]; |
| 94 | }; |
| 95 | |
| 96 | /* |
| 97 | * Flags for sysctl_netisr_proto.snp_flags. |
| 98 | */ |
| 99 | #define	NETISR_SNP_FLAGS_M2FLOW		0x00000001	/* nh_m2flow */ |
| 100 | #define	NETISR_SNP_FLAGS_M2CPUID	0x00000002	/* nh_m2cpuid */ |
| 101 | #define	NETISR_SNP_FLAGS_DRAINEDCPU	0x00000004	/* nh_drainedcpu */ |
| 102 | |
| 103 | /* |
| 104 | * Next, a structure per-workstream, with per-protocol data, exported as |
| 105 | * net.isr.workstream. |
| 106 | */ |
| 107 | struct sysctl_netisr_workstream { |
| 108 | 	u_int	snws_version;			/* Length of struct. */ |
| 109 | 	u_int	snws_flags;			/* Various flags. */ |
| 110 | 	u_int	snws_wsid;			/* Workstream ID. */ |
| 111 | 	u_int	snws_cpu;			/* nws_cpu */ |
| 112 | 	u_int	_snws_ispare[12]; |
| 113 | }; |
| 114 | |
| 115 | /* |
| 116 | * Flags for sysctl_netisr_workstream.snws_flags |
| 117 | */ |
| 118 | #define	NETISR_SNWS_FLAGS_INTR		0x00000001	/* nws_intr_event */ |
| 119 | |
| 120 | /* |
| 121 | * Finally, a per-workstream-per-protocol structure, exported as |
| 122 | * net.isr.work. |
| 123 | */ |
| 124 | struct sysctl_netisr_work { |
| 125 | 	u_int	snw_version;			/* Length of struct. */ |
| 126 | 	u_int	snw_wsid;			/* Workstream ID. */ |
| 127 | 	u_int	snw_proto;			/* Protocol number. */ |
| 128 | 	u_int	snw_len;			/* nw_len */ |
| 129 | 	u_int	snw_watermark;			/* nw_watermark */ |
| 130 | 	u_int	_snw_ispare[3]; |
| 131 | |
| 132 | 	uint64_t	snw_dispatched;		/* nw_dispatched */ |
| 133 | 	uint64_t	snw_hybrid_dispatched;	/* nw_hybrid_dispatched */ |
| 134 | 	uint64_t	snw_qdrops;		/* nw_qdrops */ |
| 135 | 	uint64_t	snw_queued;		/* nw_queued */ |
| 136 | 	uint64_t	snw_handled;		/* nw_handled */ |
| 137 | |
| 138 | 	uint64_t	_snw_llspare[7]; |
| 139 | }; |
| 140 | |
| 141 | #ifdef _KERNEL |
| 142 | |
| 143 | /*- |
| 144 | * Protocols express ordering constraints and affinity preferences by |
| 145 | * implementing one or neither of nh_m2flow and nh_m2cpuid, which are used by |
| 146 | * netisr to determine which per-CPU workstream to assign mbufs to. |
| 147 | * |
| 148 | * The following policies may be used by protocols: |
| 149 | * |
| 150 | * NETISR_POLICY_SOURCE - netisr should maintain source ordering without |
| 151 | * advice from the protocol. netisr will ignore any |
| 152 | * flow IDs present on the mbuf for the purposes of |
| 153 | * work placement. |
| 154 | * |
| 155 | * NETISR_POLICY_FLOW - netisr should maintain flow ordering as defined by |
| 156 | * the mbuf header flow ID field. If the protocol |
| 157 | * implements nh_m2flow, then netisr will query the |
| 158 | * protocol in the event that the mbuf doesn't have a |
| 159 | * flow ID, falling back on source ordering. |
| 160 | * |
| 161 | * NETISR_POLICY_CPU - netisr will delegate all work placement decisions to |
| 162 | * the protocol, querying nh_m2cpuid for each packet. |
| 163 | * |
| 164 | * Protocols might make decisions about work placement based on an existing |
| 165 | * calculated flow ID on the mbuf, such as one provided in hardware, the |
| 166 | * receive interface pointed to by the mbuf (if any), the optional source |
| 167 | * identifier passed at some dispatch points, or even parse packet headers to |
| 168 | * calculate a flow. Both protocol handlers may return a new mbuf pointer |
| 169 | * for the chain, or NULL if the packet proves invalid or m_pullup() fails. |
| 170 | * |
| 171 | * XXXRW: If we eventually support dynamic reconfiguration, there should be |
| 172 | * protocol handlers to notify them of CPU configuration changes so that they |
| 173 | * can rebalance work. |
| 174 | */ |
| 175 | struct mbuf; |
| 176 | typedef void		 netisr_handler_t(struct mbuf *m); |
| 177 | typedef struct mbuf	*netisr_m2cpuid_t(struct mbuf *m, uintptr_t source, |
| 178 | 			 u_int *cpuid); |
| 179 | typedef	struct mbuf	*netisr_m2flow_t(struct mbuf *m, uintptr_t source); |
| 180 | typedef void		 netisr_drainedcpu_t(u_int cpuid); |
| 181 | |
| 182 | #define	NETISR_CPUID_NONE	((u_int)-1)	/* No affinity returned. */ |
| 183 | |
| 184 | /* |
| 185 | * Data structure describing a protocol handler. |
| 186 | */ |
| 187 | struct netisr_handler { |
| 188 | 	const char	*nh_name;	/* Character string protocol name. */ |
| 189 | 	netisr_handler_t *nh_handler;	/* Protocol handler. */ |
| 190 | 	netisr_m2flow_t	*nh_m2flow;	/* Query flow for untagged packet. */ |
| 191 | 	netisr_m2cpuid_t *nh_m2cpuid;	/* Query CPU to process mbuf on. */ |
| 192 | 	netisr_drainedcpu_t *nh_drainedcpu; /* Callback when drained a queue. */ |
| 193 | 	u_int		 nh_proto;	/* Integer protocol ID. */ |
| 194 | 	u_int		 nh_qlimit;	/* Maximum per-CPU queue depth. */ |
| 195 | 	u_int		 nh_policy;	/* Work placement policy. */ |
| 196 | 	u_int		 nh_dispatch;	/* Dispatch policy. */ |
| 197 | 	u_int		 nh_ispare[4];	/* For future use. */ |
| 198 | 	void		*nh_pspare[4];	/* For future use. */ |
| 199 | }; |
| 200 | |
| 201 | /* |
| 202 | * Register, unregister, and other netisr handler management functions. |
| 203 | */ |
| 204 | void	netisr_clearqdrops(const struct netisr_handler *nhp); |
| 205 | void	netisr_getqdrops(const struct netisr_handler *nhp, |
| 206 | 	 u_int64_t *qdropsp); |
| 207 | void	netisr_getqlimit(const struct netisr_handler *nhp, u_int *qlimitp); |
| 208 | void	netisr_register(const struct netisr_handler *nhp); |
| 209 | int	netisr_setqlimit(const struct netisr_handler *nhp, u_int qlimit); |
| 210 | void	netisr_unregister(const struct netisr_handler *nhp); |
| 211 | #ifdef VIMAGE |
| 212 | void	netisr_register_vnet(const struct netisr_handler *nhp); |
| 213 | void	netisr_unregister_vnet(const struct netisr_handler *nhp); |
| 214 | #endif |
| 215 | |
| 216 | /* |
| 217 | * Process a packet destined for a protocol, and attempt direct dispatch. |
| 218 | * Supplemental source ordering information can be passed using the _src |
| 219 | * variant. |
| 220 | */ |
| 221 | int	netisr_dispatch(u_int proto, struct mbuf *m); |
| 222 | int	netisr_dispatch_src(u_int proto, uintptr_t source, struct mbuf *m); |
| 223 | int	netisr_queue(u_int proto, struct mbuf *m); |
| 224 | int	netisr_queue_src(u_int proto, uintptr_t source, struct mbuf *m); |
| 225 | |
| 226 | /* |
| 227 | * Provide a default implementation of "map an ID to a CPU ID". |
| 228 | */ |
| 229 | u_int	netisr_default_flow2cpu(u_int flowid); |
| 230 | |
| 231 | /* |
| 232 | * Utility routines to return the number of CPUs participting in netisr, and |
| 233 | * to return a mapping from a number to a CPU ID that can be used with the |
| 234 | * scheduler. |
| 235 | */ |
| 236 | u_int	netisr_get_cpucount(void); |
| 237 | u_int	netisr_get_cpuid(u_int cpunumber); |
| 238 | |
| 239 | /* |
| 240 | * Interfaces between DEVICE_POLLING and netisr. |
| 241 | */ |
| 242 | void	netisr_sched_poll(void); |
| 243 | void	netisr_poll(void); |
| 244 | void	netisr_pollmore(void); |
| 245 | |
| 246 | #endif /* !_KERNEL */ |
| 247 | #endif /* !_NET_NETISR_H_ */ |