Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /* Virtual terminal [aka TeletYpe] interface routine
3 : * Copyright (C) 1997 Kunihiro Ishiguro
4 : */
5 :
6 : #ifndef _ZEBRA_VTY_H
7 : #define _ZEBRA_VTY_H
8 :
9 : #include <sys/types.h>
10 : #ifdef HAVE_LIBPCRE2_POSIX
11 : #ifndef _FRR_PCRE2_POSIX
12 : #define _FRR_PCRE2_POSIX
13 : #include <pcre2posix.h>
14 : #endif /* _FRR_PCRE2_POSIX */
15 : #elif defined(HAVE_LIBPCREPOSIX)
16 : #include <pcreposix.h>
17 : #else
18 : #include <regex.h>
19 : #endif /* HAVE_LIBPCRE2_POSIX */
20 :
21 : #include "frrevent.h"
22 : #include "log.h"
23 : #include "sockunion.h"
24 : #include "qobj.h"
25 : #include "compiler.h"
26 : #include "northbound.h"
27 : #include "zlog_live.h"
28 : #include "libfrr.h"
29 : #include "mgmt_fe_client.h"
30 :
31 : #ifdef __cplusplus
32 : extern "C" {
33 : #endif
34 :
35 : struct json_object;
36 :
37 : #define VTY_BUFSIZ 4096
38 : #define VTY_MAXHIST 20
39 : #define VTY_MAXDEPTH 8
40 :
41 : #define VTY_MAXCFGCHANGES 16
42 :
43 : struct vty_error {
44 : char error_buf[VTY_BUFSIZ];
45 : uint32_t line_num;
46 : int cmd_ret;
47 : };
48 :
49 : struct vty_cfg_change {
50 : char xpath[XPATH_MAXLEN];
51 : enum nb_operation operation;
52 : const char *value;
53 : };
54 :
55 : PREDECL_DLIST(vtys);
56 :
57 : /* VTY struct. */
58 : struct vty {
59 : struct vtys_item itm;
60 :
61 : /* File descripter of this vty. */
62 : int fd;
63 :
64 : /* output FD, to support stdin/stdout combination */
65 : int wfd;
66 :
67 : /* File output, used for VTYSH only */
68 : FILE *of;
69 : FILE *of_saved;
70 :
71 : /* whether we are using pager or not */
72 : bool is_paged;
73 :
74 : /* Is this vty connect to file or not */
75 : enum { VTY_TERM, /* telnet conn or stdin/stdout UI */
76 : VTY_FILE, /* reading and writing config files */
77 : VTY_SHELL, /* vtysh client side UI */
78 : VTY_SHELL_SERV, /* server-side vtysh connection */
79 : } type;
80 :
81 : /* Node status of this vty */
82 : int node;
83 :
84 : /* Failure count */
85 : int fail;
86 :
87 : /* Output filer regex */
88 : bool filter;
89 : regex_t include;
90 :
91 : /* Line buffer */
92 : struct buffer *lbuf;
93 :
94 : /* Output buffer. */
95 : struct buffer *obuf;
96 :
97 : /* Command input buffer */
98 : char *buf;
99 :
100 : /* Command input error buffer */
101 : struct list *error;
102 :
103 : /* Command cursor point */
104 : int cp;
105 :
106 : /* Command length */
107 : int length;
108 :
109 : /* Command max length. */
110 : int max;
111 :
112 : /* Histry of command */
113 : char *hist[VTY_MAXHIST];
114 :
115 : /* History lookup current point */
116 : int hp;
117 :
118 : /* History insert end point */
119 : int hindex;
120 :
121 : /* Changes enqueued to be applied in the candidate configuration. */
122 : size_t num_cfg_changes;
123 : struct nb_cfg_change cfg_changes[VTY_MAXCFGCHANGES];
124 :
125 : /* XPath of the current node */
126 : int xpath_index;
127 : char xpath[VTY_MAXDEPTH][XPATH_MAXLEN];
128 :
129 : /*
130 : * Keep track of how many SET_CFG requests has been sent so far that
131 : * has not been committed yet.
132 : */
133 : size_t mgmt_num_pending_setcfg;
134 :
135 : /* In configure mode. */
136 : bool config;
137 :
138 : /* Private candidate configuration mode. */
139 : bool private_config;
140 :
141 : /* Candidate configuration. */
142 : struct nb_config *candidate_config;
143 :
144 : /* Base candidate configuration. */
145 : struct nb_config *candidate_config_base;
146 :
147 : /* Dynamic transaction information. */
148 : bool pending_allowed;
149 : bool pending_commit;
150 : char *pending_cmds_buf;
151 : size_t pending_cmds_buflen;
152 : size_t pending_cmds_bufpos;
153 :
154 : /* Confirmed-commit timeout and rollback configuration. */
155 : struct event *t_confirmed_commit_timeout;
156 : struct nb_config *confirmed_commit_rollback;
157 :
158 : /* qobj object ID (replacement for "index") */
159 : uint64_t qobj_index;
160 :
161 : /* qobj second-level object ID (replacement for "index_sub") */
162 : uint64_t qobj_index_sub;
163 :
164 : /* For escape character. */
165 : unsigned char escape;
166 :
167 : /* Current vty status. */
168 : enum {
169 : VTY_NORMAL,
170 : VTY_CLOSE,
171 : VTY_MORE,
172 : VTY_MORELINE,
173 : VTY_PASSFD,
174 : } status;
175 :
176 : /* vtysh socket/fd passing (for terminal monitor) */
177 : int pass_fd;
178 :
179 : /* CLI command return value (likely CMD_SUCCESS) when pass_fd != -1 */
180 : uint8_t pass_fd_status[4];
181 :
182 : /* live logging target / terminal monitor */
183 : struct zlog_live_cfg live_log;
184 :
185 : /* IAC handling: was the last character received the
186 : IAC (interpret-as-command) escape character (and therefore the next
187 : character will be the command code)? Refer to Telnet RFC 854. */
188 : unsigned char iac;
189 :
190 : /* IAC SB (option subnegotiation) handling */
191 : unsigned char iac_sb_in_progress;
192 : /* At the moment, we care only about the NAWS (window size) negotiation,
193 : and that requires just a 5-character buffer (RFC 1073):
194 : <NAWS char> <16-bit width> <16-bit height> */
195 : #define TELNET_NAWS_SB_LEN 5
196 : unsigned char sb_buf[TELNET_NAWS_SB_LEN];
197 : /* How many subnegotiation characters have we received? We just drop
198 : those that do not fit in the buffer. */
199 : size_t sb_len;
200 :
201 : /* Window width/height. */
202 : int width;
203 : int height;
204 :
205 : /* Configure lines. */
206 : int lines;
207 :
208 : /* Read and write thread. */
209 : struct event *t_read;
210 : struct event *t_write;
211 :
212 : /* Timeout seconds and thread. */
213 : unsigned long v_timeout;
214 : struct event *t_timeout;
215 :
216 : /* What address is this vty comming from. */
217 : char address[SU_ADDRSTRLEN];
218 :
219 : /* "frame" output. This is buffered and will be printed if some
220 : * actual output follows, or will be discarded if the frame ends
221 : * without any output. */
222 : size_t frame_pos;
223 : char frame[1024];
224 :
225 : uint64_t mgmt_session_id; /* FE adapter identifies session w/ this */
226 : uint64_t mgmt_client_id; /* FE vty client identifies w/ this ID */
227 : uint64_t mgmt_req_id;
228 : /* set when we have sent mgmtd a *REQ command in response to some vty
229 : * CLI command and we are waiting on the reply so we can respond to the
230 : * vty user. */
231 : const char *mgmt_req_pending_cmd;
232 : bool mgmt_locked_candidate_ds;
233 : bool mgmt_locked_running_ds;
234 : /* Need to track when we file-lock in vtysh to re-lock on end/conf t
235 : * workaround
236 : */
237 : bool vtysh_file_locked;
238 : };
239 :
240 2 : static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
241 : {
242 2 : vty->node = node;
243 2 : vty->qobj_index = id;
244 0 : }
245 :
246 : /* note: VTY_PUSH_CONTEXT(..., NULL) doesn't work, since it will try to
247 : * dereference "NULL->qobj_node.nid" */
248 : #define VTY_PUSH_CONTEXT(nodeval, ptr) \
249 : vty_push_context(vty, nodeval, QOBJ_ID_0SAFE(ptr))
250 : #define VTY_PUSH_CONTEXT_NULL(nodeval) vty_push_context(vty, nodeval, 0ULL)
251 : #define VTY_PUSH_CONTEXT_SUB(nodeval, ptr) \
252 : do { \
253 : vty->node = nodeval; \
254 : /* qobj_index stays untouched */ \
255 : vty->qobj_index_sub = QOBJ_ID_0SAFE(ptr); \
256 : } while (0)
257 :
258 : /* can return NULL if context is invalid! */
259 : #define VTY_GET_CONTEXT(structname) \
260 : QOBJ_GET_TYPESAFE(vty->qobj_index, structname)
261 : #define VTY_GET_CONTEXT_SUB(structname) \
262 : QOBJ_GET_TYPESAFE(vty->qobj_index_sub, structname)
263 :
264 : /* will return if ptr is NULL. */
265 : #define VTY_CHECK_CONTEXT(ptr) \
266 : if (!ptr) { \
267 : vty_out(vty, \
268 : "Current configuration object was deleted " \
269 : "by another process.\n"); \
270 : return CMD_WARNING; \
271 : }
272 :
273 : /* struct structname *ptr = <context>; ptr will never be NULL. */
274 : #define VTY_DECLVAR_CONTEXT(structname, ptr) \
275 : struct structname *ptr = VTY_GET_CONTEXT(structname); \
276 : VTY_CHECK_CONTEXT(ptr);
277 : #define VTY_DECLVAR_CONTEXT_SUB(structname, ptr) \
278 : struct structname *ptr = VTY_GET_CONTEXT_SUB(structname); \
279 : VTY_CHECK_CONTEXT(ptr);
280 : #define VTY_DECLVAR_INSTANCE_CONTEXT(structname, ptr) \
281 : if (vty->qobj_index == 0) \
282 : return CMD_NOT_MY_INSTANCE; \
283 : struct structname *ptr = VTY_GET_CONTEXT(structname); \
284 : VTY_CHECK_CONTEXT(ptr);
285 :
286 : #define VTY_DECLVAR_CONTEXT_VRF(vrfptr) \
287 : struct vrf *vrfptr; \
288 : if (vty->node == CONFIG_NODE) \
289 : vrfptr = vrf_lookup_by_id(VRF_DEFAULT); \
290 : else \
291 : vrfptr = VTY_GET_CONTEXT(vrf); \
292 : VTY_CHECK_CONTEXT(vrfptr); \
293 : MACRO_REQUIRE_SEMICOLON() /* end */
294 :
295 : /* XPath macros. */
296 : #define VTY_PUSH_XPATH(nodeval, value) \
297 : do { \
298 : if (vty->xpath_index >= VTY_MAXDEPTH) { \
299 : vty_out(vty, "%% Reached maximum CLI depth (%u)\n", \
300 : VTY_MAXDEPTH); \
301 : return CMD_WARNING; \
302 : } \
303 : vty->node = nodeval; \
304 : strlcpy(vty->xpath[vty->xpath_index], value, \
305 : sizeof(vty->xpath[0])); \
306 : vty->xpath_index++; \
307 : } while (0)
308 :
309 : #define VTY_CURR_XPATH vty->xpath[vty->xpath_index - 1]
310 :
311 : #define VTY_CHECK_XPATH \
312 : do { \
313 : if (vty->type != VTY_FILE && !vty->private_config && \
314 : vty->xpath_index > 0 && \
315 : !yang_dnode_exists(vty->candidate_config->dnode, \
316 : VTY_CURR_XPATH)) { \
317 : vty_out(vty, \
318 : "Current configuration object was deleted " \
319 : "by another process.\n\n"); \
320 : return CMD_WARNING; \
321 : } \
322 : } while (0)
323 :
324 : struct vty_arg {
325 : const char *name;
326 : const char *value;
327 : const char **argv;
328 : int argc;
329 : };
330 :
331 : /* Integrated configuration file. */
332 : #define INTEGRATE_DEFAULT_CONFIG "frr.conf"
333 :
334 : /* Default time out value */
335 : #define VTY_TIMEOUT_DEFAULT 600
336 :
337 : /* Vty read buffer size. */
338 : #define VTY_READ_BUFSIZ 512
339 :
340 : /* Directory separator. */
341 : #ifndef DIRECTORY_SEP
342 : #define DIRECTORY_SEP '/'
343 : #endif /* DIRECTORY_SEP */
344 :
345 : #ifndef IS_DIRECTORY_SEP
346 : #define IS_DIRECTORY_SEP(c) ((c) == DIRECTORY_SEP)
347 : #endif
348 :
349 : extern struct nb_config *vty_mgmt_candidate_config;
350 : extern bool vty_log_commands;
351 :
352 : extern char const *const mgmt_daemons[];
353 : extern uint mgmt_daemons_count;
354 :
355 : /* Prototypes. */
356 : extern void vty_init(struct event_loop *m, bool do_command_logging);
357 : extern void vty_init_vtysh(void);
358 : extern void vty_terminate(void);
359 : extern void vty_reset(void);
360 : extern struct vty *vty_new(void);
361 : extern struct vty *vty_stdio(void (*atclose)(int isexit));
362 :
363 : /* - vty_frame() output goes to a buffer (for context-begin markers)
364 : * - vty_out() will first print this buffer, and clear it
365 : * - vty_endframe() clears the buffer without printing it, and prints an
366 : * extra string if the buffer was empty before (for context-end markers)
367 : */
368 : extern int vty_out(struct vty *, const char *, ...) PRINTFRR(2, 3);
369 : extern void vty_frame(struct vty *, const char *, ...) PRINTFRR(2, 3);
370 : extern void vty_endframe(struct vty *, const char *);
371 : extern bool vty_set_include(struct vty *vty, const char *regexp);
372 : /* returns CMD_SUCCESS so you can do a one-line "return vty_json(...)"
373 : * NULL check and json_object_free() is included.
374 : *
375 : * _no_pretty means do not add a bunch of newlines and dump the output
376 : * as densely as possible.
377 : */
378 : extern int vty_json(struct vty *vty, struct json_object *json);
379 : extern int vty_json_no_pretty(struct vty *vty, struct json_object *json);
380 : extern void vty_json_empty(struct vty *vty, struct json_object *json);
381 : /* post fd to be passed to the vtysh client
382 : * fd is owned by the VTY code after this and will be closed when done
383 : */
384 : extern void vty_pass_fd(struct vty *vty, int fd);
385 :
386 : extern FILE *vty_open_config(const char *config_file, char *config_default_dir);
387 : extern bool vty_read_config(struct nb_config *config, const char *config_file,
388 : char *config_default_dir);
389 : extern void vty_read_file(struct nb_config *config, FILE *confp);
390 : extern void vty_read_file_finish(struct vty *vty, struct nb_config *config);
391 : extern void vty_time_print(struct vty *, int);
392 : extern void vty_serv_start(const char *, unsigned short, const char *);
393 : extern void vty_serv_stop(void);
394 : extern void vty_close(struct vty *);
395 : extern char *vty_get_cwd(void);
396 : extern void vty_update_xpath(const char *oldpath, const char *newpath);
397 : extern int vty_config_enter(struct vty *vty, bool private_config,
398 : bool exclusive, bool file_lock);
399 : extern void vty_config_exit(struct vty *);
400 : extern int vty_config_node_exit(struct vty *);
401 : extern int vty_shell(struct vty *);
402 : extern int vty_shell_serv(struct vty *);
403 : extern void vty_hello(struct vty *);
404 :
405 : /* ^Z / SIGTSTP handling */
406 : extern void vty_stdio_suspend(void);
407 : extern void vty_stdio_resume(void);
408 : extern void vty_stdio_close(void);
409 :
410 : extern void vty_init_mgmt_fe(void);
411 : extern bool vty_mgmt_fe_enabled(void);
412 : extern bool vty_mgmt_should_process_cli_apply_changes(struct vty *vty);
413 :
414 : extern bool mgmt_vty_read_configs(void);
415 : extern int vty_mgmt_send_config_data(struct vty *vty, const char *xpath_base,
416 : bool implicit_commit);
417 : extern int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only,
418 : bool abort);
419 : extern int vty_mgmt_send_get_req(struct vty *vty, bool is_config,
420 : Mgmtd__DatastoreId datastore,
421 : const char **xpath_list, int num_req);
422 : extern int vty_mgmt_send_lockds_req(struct vty *vty, Mgmtd__DatastoreId ds_id,
423 : bool lock, bool scok);
424 : extern void vty_mgmt_resume_response(struct vty *vty, bool success);
425 :
426 0 : static inline bool vty_needs_implicit_commit(struct vty *vty)
427 : {
428 0 : return frr_get_cli_mode() == FRR_CLI_CLASSIC && !vty->pending_allowed;
429 : }
430 :
431 : #ifdef __cplusplus
432 : }
433 : #endif
434 :
435 : #endif /* _ZEBRA_VTY_H */
|