X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=docs%2Fgettingstarted%2Fdevelopers%2Finfrastructure.md;h=2c798f4a337fca54dc60fabd0fb41cbb0791980e;hb=ba4a5bf884516769211e75d11884a1e458323a21;hp=688c42133ed0c644187f784b58e546f2f4737629;hpb=06dcd45ff81e06bc8cf40ed487c0b2652d346a5a;p=vpp.git diff --git a/docs/gettingstarted/developers/infrastructure.md b/docs/gettingstarted/developers/infrastructure.md index 688c42133ed..2c798f4a337 100644 --- a/docs/gettingstarted/developers/infrastructure.md +++ b/docs/gettingstarted/developers/infrastructure.md @@ -48,13 +48,16 @@ macro! It's smart about NULL pointers.\] Typically, the user header is not present. User headers allow for other data structures to be built atop vppinfra vectors. Users may specify the -alignment for data elements via the [vec]()\*\_aligned macros. +alignment for first data element of a vector via the \[vec\]()\*\_aligned +macros. -Vectors elements can be any C type e.g. (int, double, struct bar). This +Vector elements can be any C type e.g. (int, double, struct bar). This is also true for data types built atop vectors (e.g. heap, pool, etc.). -Many macros have \_a variants supporting alignment of vector data and -\_h variants supporting non-zero-length vector headers. The \_ha -variants support both. +Many macros have \_a variants supporting alignment of vector elements +and \_h variants supporting non-zero-length vector headers. The \_ha +variants support both. Additionally cacheline alignment within a +vector element structure can be specified using the +\[CLIB_CACHE_LINE_ALIGN_MARK\]() macro. Inconsistent usage of header and/or alignment related macro variants will cause delayed, confusing failures. @@ -135,8 +138,8 @@ schemes may be used: ```c vec_add1 (result, 0) - or - result = format (result, "%c", 0); + or + result = format (result, "%c", 0); ``` Remember to vec\_free() the result if appropriate. Be careful not to @@ -158,8 +161,8 @@ format specification. For example: format\_junk() can invoke other user-format functions if desired. The programmer shoulders responsibility for argument type-checking. It is -typical for user format functions to blow up if the va\_arg(va, -type) macros don't match the caller's idea of reality. +typical for user format functions to blow up spectacularly if the +va\_arg(va, type) macros don't match the caller's idea of reality. Unformat -------- @@ -182,149 +185,153 @@ follows: Then loop parsing individual elements: ```c - while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT) + while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT) { if (unformat (&input, "value1 %d", &value1)) ;/* unformat sets value1 */ else if (unformat (&input, "value2 %d", &value2) ;/* unformat sets value2 */ else - return clib_error_return (0, "unknown input '%U'", + return clib_error_return (0, "unknown input '%U'", format_unformat_error, input); } ``` As with format, unformat implements a user-unformat function capability -via a "%U" user unformat function scheme. +via a "%U" user unformat function scheme. Generally, one can trivially +transform "format (s, "foo %d", foo) -> "unformat (input, "foo %d", &foo)". -Vppinfra errors and warnings ----------------------------- - -Many functions within the vpp dataplane have return-values of type -clib\_error\_t \*. Clib\_error\_t's are arbitrary strings with a bit of -metadata \[fatal, warning\] and are easy to announce. Returning a NULL -clib\_error\_t \* indicates "A-OK, no error." - -Clib\_warning(format-args) is a handy way to add debugging -output; clib warnings prepend function:line info to unambiguously locate -the message source. Clib\_unix\_warning() adds perror()-style Linux -system-call information. In production images, clib\_warnings result in -syslog entries. +Unformat implements a couple of handy non-scanf-like format specifiers: -Serialization -------------- +```c + unformat (input, "enable %=", &enable, 1 /* defaults to 1 */); + unformat (input, "bitzero %|", &mask, (1<<0)); + unformat (input, "bitone %|", &mask, (1<<1)); + +``` -Vppinfra serialization support allows the programmer to easily serialize -and unserialize complex data structures. +The phrase "enable %=" means "set the supplied variable to the default +value" if unformat parses the "enable" keyword all by itself. If +unformat parses "enable 123" set the supplied variable to 123. -The underlying primitive serialize/unserialize functions use network -byte-order, so there are no structural issues serializing on a -little-endian host and unserializing on a big-endian host. +We could clean up a number of hand-rolled "verbose" + "verbose %d" +argument parsing codes using "%=". -Event-logger, graphical event log viewer ----------------------------------------- +The phrase "bitzero %|" means "set the specified bit in the supplied +bitmask" if unformat parses "bitzero". Although it looks like it could +be fairly handy, it's very lightly used in the code base. -The vppinfra event logger provides very lightweight (sub-100ns) -precisely time-stamped event-logging services. See -./src/vppinfra/{elog.c, elog.h} +### How to parse a single input line -Serialization support makes it easy to save and ultimately to combine a -set of event logs. In a distributed system running NTP over a local LAN, -we find that event logs collected from multiple system elements can be -combined with a temporal uncertainty no worse than 50us. +Debug CLI command functions MUST NOT accidentally consume input +belonging to other debug CLI commands. Otherwise, it's impossible to +script a set of debug CLI commands which "work fine" when issued one +at a time. -A typical event definition and logging call looks like this: +This bit of code is NOT correct: ```c - ELOG_TYPE_DECLARE (e) = + /* Eats script input NOT beloging to it, and chokes! */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - .format = "tx-msg: stream %d local seq %d attempt %d", - .format_args = "i4i4i4", - }; - struct { u32 stream_id, local_sequence, retry_count; } * ed; - ed = ELOG_DATA (m->elog_main, e); - ed->stream_id = stream_id; - ed->local_sequence = local_sequence; - ed->retry_count = retry_count; + if (unformat (input, ...)) + ; + else if (unformat (input, ...)) + ; + else + return clib_error_return (0, "parse error: '%U'", + format_unformat_error, input); + } + } ``` -The ELOG\_DATA macro returns a pointer to 20 bytes worth of arbitrary -event data, to be formatted (offline, not at runtime) as described by -format\_args. Aside from obvious integer formats, the CLIB event logger -provides a couple of interesting additions. The "t4" format -pretty-prints enumerated values: +When executed as part of a script, such a function will return "parse +error: ''" every time, unless it happens to be the +last command in the script. + +Instead, use "unformat_line_input" to consume the rest of a line's +worth of input - everything past the path specified in the +VLIB_CLI_COMMAND declaration. + +For example, unformat_line_input with "my_command" set up as shown +below and user input "my path is clear" will produce an +unformat_input_t that contains "is clear". ```c - ELOG_TYPE_DECLARE (e) = - { - .format = "get_or_create: %s", - .format_args = "t4", - .n_enum_strings = 2, - .enum_strings = { "old", "new", }, + VLIB_CLI_COMMAND (...) = { + .path = "my path", }; ``` -The "t" format specifier indicates that the corresponding datum is an -index in the event's set of enumerated strings, as shown in the previous -event type definition. - -The “T” format specifier indicates that the corresponding datum is an -index in the event log’s string heap. This allows the programmer to emit -arbitrary formatted strings. One often combines this facility with a -hash table to keep the event-log string heap from growing arbitrarily -large. - -Noting the 20-octet limit per-log-entry data field, the event log -formatter supports arbitrary combinations of these data types. As in: -the ".format" field may contain one or more instances of the following: - -- i1 - 8-bit unsigned integer -- i2 - 16-bit unsigned integer -- i4 - 32-bit unsigned integer -- i8 - 64-bit unsigned integer -- f4 - float -- f8 - double -- s - NULL-terminated string - be careful -- sN - N-byte character array -- t1,2,4 - per-event enumeration ID -- T4 - Event-log string table offset - -The vpp engine event log is thread-safe, and is shared by all threads. -Take care not to serialize the computation. Although the event-logger is -about as fast as practicable, it's not appropriate for per-packet use in -hard-core data plane code. It's most appropriate for capturing rare -events - link up-down events, specific control-plane events and so -forth. - -The vpp engine has several debug CLI commands for manipulating its event -log: +Here's a bit of code which shows the required mechanics, in full: -``` - vpp# event-logger clear - vpp# event-logger save # for security, writes into /tmp/. - # must not contain '.' or '/' characters - vpp# show event-logger [all] [] # display the event log - # by default, the last 250 entries -``` +```c + static clib_error_t * + my_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) + { + unformat_input_t _line_input, *line_input = &_line_input; + u32 this, that; + clib_error_t *error = 0; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + /* + * Here, UNFORMAT_END_OF_INPUT is at the end of the line we consumed, + * not at the end of the script... + */ + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "this %u", &this)) + ; + else if (unformat (line_input, "that %u", &that)) + ; + else + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } + } + + + + done: + unformat_free (line_input); + return error; + } + /* *INDENT-OFF* */ + VLIB_CLI_COMMAND (my_command, static) = { + .path = "my path", + .function = my_command_fn", + }; + /* *INDENT-ON* */ -The event log defaults to 128K entries. The command-line argument "... -vlib { elog-events nnn } ..." configures the size of the event log. +``` -As described above, the vpp engine event log is thread-safe and shared. -To avoid confusing non-appearance of events logged by worker threads, -make sure to code vlib\_global\_main.elog\_main - instead of -vm->elog\_main. The latter form is correct in the main thread, but -will almost certainly produce bad results in worker threads. -G2 graphical event viewer -------------------------- +Vppinfra errors and warnings +---------------------------- -The g2 graphical event viewer can display serialized vppinfra event logs -directly, or via the c2cpel tool. +Many functions within the vpp dataplane have return-values of type +clib\_error\_t \*. Clib\_error\_t's are arbitrary strings with a bit of +metadata \[fatal, warning\] and are easy to announce. Returning a NULL +clib\_error\_t \* indicates "A-OK, no error." -
+Clib\_warning(format-args) is a handy way to add debugging +output; clib warnings prepend function:line info to unambiguously locate +the message source. Clib\_unix\_warning() adds perror()-style Linux +system-call information. In production images, clib\_warnings result in +syslog entries. -Todo: please convert wiki page and figures +Serialization +------------- -
+Vppinfra serialization support allows the programmer to easily serialize +and unserialize complex data structures. +The underlying primitive serialize/unserialize functions use network +byte-order, so there are no structural issues serializing on a +little-endian host and unserializing on a big-endian host.