xref: /freebsd-13-stable/sys/net/debugnet.h (revision f8167e0404dab9ffeaca95853dd237ab7c587f82)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2019 Isilon Systems, LLC.
5  * Copyright (c) 2005-2014 Sandvine Incorporated
6  * Copyright (c) 2000 Darrell Anderson <anderson@cs.duke.edu>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 /*
32  * Debugnet provides a reliable, bidirectional, UDP-encapsulated datagram
33  * transport while a machine is in a debug state.  (N-1 CPUs stopped,
34  * interrupts disabled, may or may not be in a panic(9) state.)  Only one
35  * stream may be active at a time.  A dedicated server must be running to
36  * accept connections.
37  */
38 
39 #pragma once
40 
41 #include <sys/types.h>
42 #include <netinet/in.h>
43 
44 /*
45  * Debugnet protocol details.
46  */
47 #define	DEBUGNET_HERALD		1	/* Connection handshake. */
48 #define	DEBUGNET_FINISHED	2	/* Close the connection. */
49 #define	DEBUGNET_DATA		3	/* Contains data. */
50 
51 struct debugnet_msg_hdr {
52 	uint32_t	mh_type;	/* Debugnet message type. */
53 	uint32_t	mh_seqno;	/* Match acks with msgs. */
54 	uint64_t	mh_offset;	/* Offset in fragment. */
55 	uint32_t	mh_len;		/* Attached data (bytes). */
56 	uint32_t	mh_aux2;	/* Consumer-specific. */
57 } __packed;
58 
59 struct debugnet_ack {
60 	uint32_t	da_seqno;	/* Match acks with msgs. */
61 } __packed;
62 
63 #define	DEBUGNET_MAX_IN_FLIGHT	64
64 
65 #ifdef _KERNEL
66 /*
67  * Hook API for network drivers.
68  */
69 enum debugnet_ev {
70 	DEBUGNET_START,
71 	DEBUGNET_END,
72 };
73 
74 struct ifnet;
75 struct mbuf;
76 typedef void debugnet_init_t(struct ifnet *, int *nrxr, int *ncl, int *clsize);
77 typedef void debugnet_event_t(struct ifnet *, enum debugnet_ev);
78 typedef int debugnet_transmit_t(struct ifnet *, struct mbuf *);
79 typedef int debugnet_poll_t(struct ifnet *, int);
80 
81 struct debugnet_methods {
82 	debugnet_init_t		*dn_init;
83 	debugnet_event_t	*dn_event;
84 	debugnet_transmit_t	*dn_transmit;
85 	debugnet_poll_t		*dn_poll;
86 };
87 
88 #define	DEBUGNET_SUPPORTED_NIC(ifp)				\
89 	((ifp)->if_debugnet_methods != NULL && (ifp)->if_type == IFT_ETHER)
90 
91 struct debugnet_pcb; /* opaque */
92 
93 /*
94  * Debugnet consumer API.
95  */
96 struct debugnet_conn_params {
97 	struct ifnet	*dc_ifp;
98 	in_addr_t	dc_client;
99 	in_addr_t	dc_server;
100 	in_addr_t	dc_gateway;
101 
102 	uint16_t	dc_herald_port;
103 	uint16_t	dc_client_port;
104 
105 	const void	*dc_herald_data;
106 	uint32_t	dc_herald_datalen;
107 
108 	/*
109 	 * Consistent with debugnet_send(), aux parameters to debugnet
110 	 * functions are provided host-endian (but converted to
111 	 * network endian on the wire).
112 	 */
113 	uint32_t	dc_herald_aux2;
114 	uint64_t	dc_herald_offset;
115 
116 	/*
117 	 * If NULL, debugnet is a unidirectional channel from panic machine to
118 	 * remote server (like netdump).
119 	 *
120 	 * If handler is non-NULL, packets received on the client port that are
121 	 * not just tx acks are forwarded to the provided handler.
122 	 *
123 	 * The mbuf chain will have all non-debugnet framing headers removed
124 	 * (ethernet, inet, udp).  It will start with a debugnet_msg_hdr, of
125 	 * which the header is guaranteed to be contiguous.  If m_pullup is
126 	 * used, the supplied in-out mbuf pointer should be updated
127 	 * appropriately.
128 	 *
129 	 * If the handler frees the mbuf chain, it should set the mbuf pointer
130 	 * to NULL.  Otherwise, the debugnet input framework will free the
131 	 * chain.
132 	 *
133 	 * The handler should ACK receieved packets with debugnet_ack_output.
134 	 */
135 	void		(*dc_rx_handler)(struct debugnet_pcb *, struct mbuf **);
136 };
137 
138 /*
139  * Open a stream to the specified server's herald port.
140  *
141  * If all goes well, the server will send ACK from a different port to our ack
142  * port.  This allows servers to somewhat gracefully handle multiple debugnet
143  * clients.  (Clients are limited to single connections.)
144  *
145  * Returns zero on success, or errno.
146  */
147 int debugnet_connect(const struct debugnet_conn_params *,
148     struct debugnet_pcb **pcb_out);
149 
150 /*
151  * Free a debugnet stream that was previously successfully opened.
152  *
153  * No attempt is made to cleanly terminate communication with the remote
154  * server.  Consumers should first send an empty DEBUGNET_FINISHED message, or
155  * otherwise let the remote know they are signing off.
156  */
157 void debugnet_free(struct debugnet_pcb *);
158 
159 /*
160  * Send a message, with common debugnet_msg_hdr header, to the connected remote
161  * server.
162  *
163  * - mhtype translates directly to mh_type (e.g., DEBUGNET_DATA, or some other
164  *   protocol-specific type).
165  * - Data and datalen describe the attached data; datalen may be zero.
166  * - If auxdata is NULL, mh_offset's initial value and mh_aux2 will be zero.
167  *   Otherwise, mh_offset's initial value will be auxdata->dp_offset_start and
168  *   mh_aux2 will have the value of auxdata->dp_aux2.
169  *
170  * Returns zero on success, or an errno on failure.
171  */
172 struct debugnet_proto_aux {
173 	uint64_t dp_offset_start;
174 	uint32_t dp_aux2;
175 };
176 int debugnet_send(struct debugnet_pcb *, uint32_t mhtype, const void *data,
177     uint32_t datalen, const struct debugnet_proto_aux *auxdata);
178 
179 /*
180  * A simple wrapper around the above when no data or auxdata is needed.
181  */
182 static inline int
debugnet_sendempty(struct debugnet_pcb * pcb,uint32_t mhtype)183 debugnet_sendempty(struct debugnet_pcb *pcb, uint32_t mhtype)
184 {
185 	return (debugnet_send(pcb, mhtype, NULL, 0, NULL));
186 }
187 
188 /*
189  * Full-duplex RX should ACK received messages.
190  */
191 int debugnet_ack_output(struct debugnet_pcb *, uint32_t seqno /*net endian*/);
192 
193 /*
194  * Check and/or wait for further packets.
195  */
196 void debugnet_network_poll(struct debugnet_pcb *);
197 
198 /*
199  * PCB accessors.
200  */
201 
202 /*
203  * Get the 48-bit MAC address of the discovered next hop (gateway, or
204  * destination server if it is on the same segment.
205  */
206 const unsigned char *debugnet_get_gw_mac(const struct debugnet_pcb *);
207 
208 /*
209  * Callbacks from core mbuf code.
210  */
211 void debugnet_any_ifnet_update(struct ifnet *);
212 
213 /*
214  * DDB parsing helper for common debugnet options.
215  *
216  * -s <server> [-g <gateway -c <localip> -i <interface>]
217  *
218  * Order is not significant.  Interface is an online interface that supports
219  * debugnet and can route to the debugnet server.  The other parameters are all
220  * IP addresses.  Only the server parameter is required.  The others are
221  * inferred automatically from the routing table, if not explicitly provided.
222  *
223  * Provides basic '-h' using provided 'cmd' string.
224  *
225  * Returns zero on success, or errno.
226  */
227 struct debugnet_ddb_config {
228 	struct ifnet	*dd_ifp;	/* not ref'd */
229 	in_addr_t	dd_client;
230 	in_addr_t	dd_server;
231 	in_addr_t	dd_gateway;
232 	bool		dd_has_client : 1;
233 	bool		dd_has_gateway : 1;
234 };
235 int debugnet_parse_ddb_cmd(const char *cmd,
236     struct debugnet_ddb_config *result);
237 
238 /* Expose sysctl variables for netdump(4) to alias. */
239 extern int debugnet_npolls;
240 extern int debugnet_nretries;
241 extern int debugnet_arp_nretries;
242 
243 /*
244  * Conditionally-defined macros for device drivers so we can avoid ifdef
245  * wrappers in every single implementation.
246  */
247 #ifdef DEBUGNET
248 #define	DEBUGNET_DEFINE(driver)					\
249 	static debugnet_init_t driver##_debugnet_init;		\
250 	static debugnet_event_t driver##_debugnet_event;	\
251 	static debugnet_transmit_t driver##_debugnet_transmit;	\
252 	static debugnet_poll_t driver##_debugnet_poll;		\
253 								\
254 	static struct debugnet_methods driver##_debugnet_methods = { \
255 		.dn_init = driver##_debugnet_init,		\
256 		.dn_event = driver##_debugnet_event,		\
257 		.dn_transmit = driver##_debugnet_transmit,	\
258 		.dn_poll = driver##_debugnet_poll,		\
259 	}
260 
261 #define	DEBUGNET_NOTIFY_MTU(ifp)	debugnet_any_ifnet_update(ifp)
262 
263 #define	DEBUGNET_SET(ifp, driver)				\
264 	(ifp)->if_debugnet_methods = &driver##_debugnet_methods
265 
266 #else /* !DEBUGNET || !INET */
267 
268 #define	DEBUGNET_DEFINE(driver)
269 #define	DEBUGNET_NOTIFY_MTU(ifp)
270 #define	DEBUGNET_SET(ifp, driver)
271 
272 #endif /* DEBUGNET && INET */
273 #endif /* _KERNEL */
274