aboutsummaryrefslogtreecommitdiff
path: root/sys/net/debugnet.h
blob: 7b323ad113d76258a1f9a941dec62224c4099ad1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/*-
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
 *
 * Copyright (c) 2019 Isilon Systems, LLC.
 * Copyright (c) 2005-2014 Sandvine Incorporated
 * Copyright (c) 2000 Darrell Anderson <anderson@cs.duke.edu>
 * All rights reserved.
 *
 * 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$
 */

/*
 * Debugnet provides a reliable, bidirectional, UDP-encapsulated datagram
 * transport while a machine is in a debug state.  (N-1 CPUs stopped,
 * interrupts disabled, may or may not be in a panic(9) state.)  Only one
 * stream may be active at a time.  A dedicated server must be running to
 * accept connections.
 */

#pragma once

#include <sys/types.h>
#include <netinet/in.h>

/*
 * Debugnet protocol details.
 */
#define	DEBUGNET_HERALD		1	/* Connection handshake. */
#define	DEBUGNET_FINISHED	2	/* Close the connection. */
#define	DEBUGNET_DATA		3	/* Contains data. */

struct debugnet_msg_hdr {
	uint32_t	mh_type;	/* Debugnet message type. */
	uint32_t	mh_seqno;	/* Match acks with msgs. */
	uint64_t	mh_offset;	/* Offset in fragment. */
	uint32_t	mh_len;		/* Attached data (bytes). */
	uint32_t	mh_aux2;	/* Consumer-specific. */
} __packed;

struct debugnet_ack {
	uint32_t	da_seqno;	/* Match acks with msgs. */
} __packed;

#define	DEBUGNET_MAX_IN_FLIGHT	64

#ifdef _KERNEL
/*
 * Hook API for network drivers.
 */
enum debugnet_ev {
	DEBUGNET_START,
	DEBUGNET_END,
};

struct ifnet;
struct mbuf;
typedef void debugnet_init_t(struct ifnet *, int *nrxr, int *ncl, int *clsize);
typedef void debugnet_event_t(struct ifnet *, enum debugnet_ev);
typedef int debugnet_transmit_t(struct ifnet *, struct mbuf *);
typedef int debugnet_poll_t(struct ifnet *, int);

struct debugnet_methods {
	debugnet_init_t		*dn_init;
	debugnet_event_t	*dn_event;
	debugnet_transmit_t	*dn_transmit;
	debugnet_poll_t		*dn_poll;
};

#define	DEBUGNET_SUPPORTED_NIC(ifp)				\
	((ifp)->if_debugnet_methods != NULL && (ifp)->if_type == IFT_ETHER)

struct debugnet_pcb; /* opaque */

/*
 * Debugnet consumer API.
 */
struct debugnet_conn_params {
	struct ifnet	*dc_ifp;
	in_addr_t	dc_client;
	in_addr_t	dc_server;
	in_addr_t	dc_gateway;

	uint16_t	dc_herald_port;
	uint16_t	dc_client_port;

	const void	*dc_herald_data;
	uint32_t	dc_herald_datalen;

	/*
	 * Consistent with debugnet_send(), aux paramaters to debugnet
	 * functions are provided host-endian (but converted to
	 * network endian on the wire).
	 */
	uint32_t	dc_herald_aux2;
	uint64_t	dc_herald_offset;

	/*
	 * If NULL, debugnet is a unidirectional channel from panic machine to
	 * remote server (like netdump).
	 *
	 * If handler is non-NULL, packets received on the client port that are
	 * not just tx acks are forwarded to the provided handler.
	 *
	 * The mbuf chain will have all non-debugnet framing headers removed
	 * (ethernet, inet, udp).  It will start with a debugnet_msg_hdr, of
	 * which the header is guaranteed to be contiguous.  If m_pullup is
	 * used, the supplied in-out mbuf pointer should be updated
	 * appropriately.
	 *
	 * If the handler frees the mbuf chain, it should set the mbuf pointer
	 * to NULL.  Otherwise, the debugnet input framework will free the
	 * chain.
	 *
	 * The handler should ACK receieved packets with debugnet_ack_output.
	 */
	void		(*dc_rx_handler)(struct debugnet_pcb *, struct mbuf **);
};

/*
 * Open a stream to the specified server's herald port.
 *
 * If all goes well, the server will send ACK from a different port to our ack
 * port.  This allows servers to somewhat gracefully handle multiple debugnet
 * clients.  (Clients are limited to single connections.)
 *
 * Returns zero on success, or errno.
 */
int debugnet_connect(const struct debugnet_conn_params *,
    struct debugnet_pcb **pcb_out);

/*
 * Free a debugnet stream that was previously successfully opened.
 *
 * No attempt is made to cleanly terminate communication with the remote
 * server.  Consumers should first send an empty DEBUGNET_FINISHED message, or
 * otherwise let the remote know they are signing off.
 */
void debugnet_free(struct debugnet_pcb *);

/*
 * Send a message, with common debugnet_msg_hdr header, to the connected remote
 * server.
 *
 * - mhtype translates directly to mh_type (e.g., DEBUGNET_DATA, or some other
 *   protocol-specific type).
 * - Data and datalen describe the attached data; datalen may be zero.
 * - If auxdata is NULL, mh_offset's initial value and mh_aux2 will be zero.
 *   Otherwise, mh_offset's initial value will be auxdata->dp_offset_start and
 *   mh_aux2 will have the value of auxdata->dp_aux2.
 *
 * Returns zero on success, or an errno on failure.
 */
struct debugnet_proto_aux {
	uint64_t dp_offset_start;
	uint32_t dp_aux2;
};
int debugnet_send(struct debugnet_pcb *, uint32_t mhtype, const void *data,
    uint32_t datalen, const struct debugnet_proto_aux *auxdata);

/*
 * A simple wrapper around the above when no data or auxdata is needed.
 */
static inline int
debugnet_sendempty(struct debugnet_pcb *pcb, uint32_t mhtype)
{
	return (debugnet_send(pcb, mhtype, NULL, 0, NULL));
}

/*
 * Full-duplex RX should ACK received messages.
 */
int debugnet_ack_output(struct debugnet_pcb *, uint32_t seqno /*net endian*/);

/*
 * Check and/or wait for further packets.
 */
void debugnet_network_poll(struct debugnet_pcb *);

/*
 * PCB accessors.
 */

/*
 * Get the 48-bit MAC address of the discovered next hop (gateway, or
 * destination server if it is on the same segment.
 */
const unsigned char *debugnet_get_gw_mac(const struct debugnet_pcb *);

/*
 * Callbacks from core mbuf code.
 */
void debugnet_any_ifnet_update(struct ifnet *);

/*
 * DDB parsing helper for common debugnet options.
 *
 * -s <server> [-g <gateway -c <localip> -i <interface>]
 *
 * Order is not significant.  Interface is an online interface that supports
 * debugnet and can route to the debugnet server.  The other parameters are all
 * IP addresses.  Only the server parameter is required.  The others are
 * inferred automatically from the routing table, if not explicitly provided.
 *
 * Provides basic '-h' using provided 'cmd' string.
 *
 * Returns zero on success, or errno.
 */
struct debugnet_ddb_config {
	struct ifnet	*dd_ifp;	/* not ref'd */
	in_addr_t	dd_client;
	in_addr_t	dd_server;
	in_addr_t	dd_gateway;
	bool		dd_has_client : 1;
	bool		dd_has_gateway : 1;
};
int debugnet_parse_ddb_cmd(const char *cmd,
    struct debugnet_ddb_config *result);

/* Expose sysctl variables for netdump(4) to alias. */
extern int debugnet_npolls;
extern int debugnet_nretries;
extern int debugnet_arp_nretries;

/*
 * Conditionally-defined macros for device drivers so we can avoid ifdef
 * wrappers in every single implementation.
 */
#ifdef DEBUGNET
#define	DEBUGNET_DEFINE(driver)					\
	static debugnet_init_t driver##_debugnet_init;		\
	static debugnet_event_t driver##_debugnet_event;	\
	static debugnet_transmit_t driver##_debugnet_transmit;	\
	static debugnet_poll_t driver##_debugnet_poll;		\
								\
	static struct debugnet_methods driver##_debugnet_methods = { \
		.dn_init = driver##_debugnet_init,		\
		.dn_event = driver##_debugnet_event,		\
		.dn_transmit = driver##_debugnet_transmit,	\
		.dn_poll = driver##_debugnet_poll,		\
	}

#define	DEBUGNET_NOTIFY_MTU(ifp)	debugnet_any_ifnet_update(ifp)

#define	DEBUGNET_SET(ifp, driver)				\
	(ifp)->if_debugnet_methods = &driver##_debugnet_methods

#else /* !DEBUGNET || !INET */

#define	DEBUGNET_DEFINE(driver)
#define	DEBUGNET_NOTIFY_MTU(ifp)
#define	DEBUGNET_SET(ifp, driver)

#endif /* DEBUGNET && INET */
#endif /* _KERNEL */