summaryrefslogtreecommitdiffstats
path: root/lib/debug.h
blob: a72657bdafaf78d020a72f0c817a3aa9a0178f34 (plain)
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
/*
 * Debugging utilities.
 * Copyright (C) 2018  Cumulus Networks, Inc.
 * Quentin Young
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; see the file COPYING; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */
#ifndef _FRRDEBUG_H
#define _FRRDEBUG_H

#include <zebra.h>
#include "command.h"
#include "frratomic.h"

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Debugging modes.
 *
 * FRR's convention is that a debug statement issued under the vty CONFIG_NODE
 * persists to the config file, whereas the same debug statement issued from
 * the ENABLE_NODE only persists for the current session. These are mapped to
 * DEBUG_MODE_CONF and DEBUG_MODE_TERM respectively.
 *
 * They are not mutually exclusive and are placed in the MSB of the flags
 * field in a debugging record.
 */
#define DEBUG_MODE_TERM 0x01000000
#define DEBUG_MODE_CONF 0x02000000
#define DEBUG_MODE_ALL (DEBUG_MODE_TERM | DEBUG_MODE_CONF)
#define DEBUG_MODE_NONE 0x00000000
#define DEBUG_OPT_ALL 0x00FFFFFF
#define DEBUG_OPT_NONE 0x00000000


/*
 * Debugging record.
 *
 * All operations on this record exposed in this header are MT-safe.
 *
 * flags
 *    A bitfield with the following format (bytes high to low)
 *    - [0] Debugging mode field (MSB)  | Mode
 *    - [1] Arbitrary flag field        | Option
 *    - [2] Arbitrary flag field        | Option
 *    - [3] Arbitrary flag field (LSB)  | Option
 *
 *              ALL THESE BYTES ARE YOURS - EXCEPT MODE.
 *                      ATTEMPT NO BIT OPS THERE.
 *
 *    The MSB of this field determines the debug mode, Use the DEBUG_MODE*
 *    macros to manipulate this byte.
 *
 *    The low 3 bytes of this field may be used to store arbitrary information.
 *    Usually they are used to store flags that tune how detailed the logging
 *    for a particular debug record is. Use the DEBUG_OPT* macros to manipulate
 *    those bytes.
 *
 *    All operations performed on this field should be done using the macros
 *    later in this header file. They are guaranteed to be atomic operations
 *    with respect to this field. Using anything except the macros to
 *    manipulate the flags field in a multithreaded environment results in
 *    undefined behavior.
 *
 * desc
 *    Human-readable description of this debugging record.
 */
struct debug {
	atomic_uint_fast32_t flags;
	const char *desc;
};

PREDECL_LIST(debug_cb_list);
/*
 * Callback set for debugging code.
 *
 * debug_set_all
 *    Function pointer to call when the user requests that all debugs have a
 *    mode set.
 */
struct debug_callbacks {
	/*
	 * Linked list of Callbacks to call
	 */
	struct debug_cb_list_item item;

	/*
	 * flags
	 *    flags to set on debug flag fields
	 *
	 * set
	 *    true: set flags
	 *    false: unset flags
	 */
	void (*debug_set_all)(uint32_t flags, bool set);
};

/*
 * Check if a mode is set for a debug.
 *
 * MT-Safe
 */
#define DEBUG_MODE_CHECK(name, mode)                                           \
	CHECK_FLAG_ATOMIC(&(name)->flags, (mode)&DEBUG_MODE_ALL)

/*
 * Check if an option bit is set for a debug.
 *
 * MT-Safe
 */
#define DEBUG_OPT_CHECK(name, opt)                                             \
	CHECK_FLAG_ATOMIC(&(name)->flags, (opt)&DEBUG_OPT_ALL)

/*
 * Check if bits are set for a debug.
 *
 * MT-Safe
 */
#define DEBUG_FLAGS_CHECK(name, fl) CHECK_FLAG_ATOMIC(&(name)->flags, (fl))

/*
 * Set modes on a debug.
 *
 * MT-Safe
 */
#define DEBUG_MODE_SET(name, mode, onoff)                                      \
	do {                                                                   \
		if (onoff)                                                     \
			SET_FLAG_ATOMIC(&(name)->flags,                        \
					(mode)&DEBUG_MODE_ALL);                \
		else                                                           \
			UNSET_FLAG_ATOMIC(&(name)->flags,                      \
					  (mode)&DEBUG_MODE_ALL);              \
	} while (0)

/* Convenience macros for specific set operations. */
#define DEBUG_MODE_ON(name, mode) DEBUG_MODE_SET(name, mode, true)
#define DEBUG_MODE_OFF(name, mode) DEBUG_MODE_SET(name, mode, false)

/*
 * Set options on a debug.
 *
 * MT-Safe
 */
#define DEBUG_OPT_SET(name, opt, onoff)                                        \
	do {                                                                   \
		if (onoff)                                                     \
			SET_FLAG_ATOMIC(&(name)->flags, (opt)&DEBUG_OPT_ALL);  \
		else                                                           \
			UNSET_FLAG_ATOMIC(&(name)->flags,                      \
					  (opt)&DEBUG_OPT_ALL);                \
	} while (0)

/* Convenience macros for specific set operations. */
#define DEBUG_OPT_ON(name, opt) DEBUG_OPT_SET(name, opt, true)
#define DEBUG_OPT_OFF(name, opt) DEBUG_OPT_SET(name, opt, true)

/*
 * Set bits on a debug.
 *
 * MT-Safe
 */
#define DEBUG_FLAGS_SET(name, fl, onoff)                                       \
	do {                                                                   \
		if (onoff)                                                     \
			SET_FLAG_ATOMIC(&(name)->flags, (fl));                 \
		else                                                           \
			UNSET_FLAG_ATOMIC(&(name)->flags, (fl));               \
	} while (0)

/* Convenience macros for specific set operations. */
#define DEBUG_FLAGS_ON(name, fl) DEBUG_FLAGS_SET(&(name)->flags, (type), true)
#define DEBUG_FLAGS_OFF(name, fl) DEBUG_FLAGS_SET(&(name)->flags, (type), false)

/*
 * Unset all modes and options on a debug.
 *
 * MT-Safe
 */
#define DEBUG_CLEAR(name) RESET_FLAG_ATOMIC(&(name)->flags)

/*
 * Set all modes and options on a debug.
 *
 * MT-Safe
 */
#define DEBUG_ON(name)                                                         \
	SET_FLAG_ATOMIC(&(name)->flags, DEBUG_MODE_ALL | DEBUG_OPT_ALL)

/*
 * Map a vty node to the correct debugging mode flags. FRR behaves such that a
 * debug statement issued under the config node persists to the config file,
 * whereas the same debug statement issued from the enable node only persists
 * for the current session.
 *
 * MT-Safe
 */
#define DEBUG_NODE2MODE(vtynode)                                               \
	(((vtynode) == CONFIG_NODE) ? DEBUG_MODE_ALL : DEBUG_MODE_TERM)

/*
 * Debug at the given level to the default logging destination.
 *
 * MT-Safe
 */
#define DEBUG(level, name, fmt, ...)                                           \
	do {                                                                   \
		if (DEBUG_MODE_CHECK(name, DEBUG_MODE_ALL))                    \
			zlog_##level(fmt, ##__VA_ARGS__);                      \
	} while (0)

/* Convenience macros for the various levels. */
#define DEBUGE(name, fmt, ...) DEBUG(err, name, fmt, ##__VA_ARGS__)
#define DEBUGW(name, fmt, ...) DEBUG(warn, name, fmt, ##__VA_ARGS__)
#define DEBUGI(name, fmt, ...) DEBUG(info, name, fmt, ##__VA_ARGS__)
#define DEBUGN(name, fmt, ...) DEBUG(notice, name, fmt, ##__VA_ARGS__)
#define DEBUGD(name, fmt, ...) DEBUG(debug, name, fmt, ##__VA_ARGS__)

/*
 * Optional initializer for debugging. Highly recommended.
 *
 * This function installs common debugging commands and allows the caller to
 * specify callbacks to take when these commands are issued, allowing the
 * caller to respond to events such as a request to turn off all debugs.
 *
 * MT-Safe
 */
void debug_init(struct debug_callbacks *cb);

/*
 * Turn on the cli to turn on/off debugs.
 * Should only be called by libfrr
 */
void debug_init_cli(void);

#ifdef __cplusplus
}
#endif

#endif /* _FRRDEBUG_H */