From: David Lamparter Date: Sun, 21 Mar 2021 16:35:43 +0000 (+0100) Subject: doc/developer: improve printfrr extension docs X-Git-Tag: base_8.0~195^2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=refs%2Fpull%2F8350%2Fhead;p=mirror%2Ffrr.git doc/developer: improve printfrr extension docs The table is getting rather clunky, let's just break this out and make it pretty there. Signed-off-by: David Lamparter --- diff --git a/doc/developer/_static/overrides.css b/doc/developer/_static/overrides.css index 1d702bb6e9..302b8d6bd7 100644 --- a/doc/developer/_static/overrides.css +++ b/doc/developer/_static/overrides.css @@ -214,6 +214,22 @@ pre { .highlight .na { color: var(--primary-2); } .highlight .nv { color: var(--complement-0); } +.rst-content code.frrfmtout { + background-color: var(--secondary-1-9); + border-color: var(--secondary-1-1); + font-size:100%; +} +.rst-content code.frrfmtout::before { + content: "⇒ \""; +} +.rst-content code.frrfmtout::after { + content: "\""; +} +.rst-content code.frrfmtout span { + color: var(--secondary-1-4); + font-size:100%; +} + strong { font-weight:500; } diff --git a/doc/developer/conf.py b/doc/developer/conf.py index f4bb65ec79..20265f4aad 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -17,6 +17,8 @@ import os import re import pygments from sphinx.highlighting import lexers +from sphinx.util import logging +logger = logging.getLogger(__name__) # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -362,11 +364,37 @@ texinfo_documents = [ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() +frrfmt_re = re.compile(r'^\s*%(?P[^\s]+)\s+\((?P.*)\)\s*$') + +def parse_frrfmt(env, text, node): + from sphinx import addnodes + + m = frrfmt_re.match(text) + if not m: + logger.warning('could not parse frrfmt:: %r' % (text), location=node) + node += addnodes.desc_name(text, text) + return text + + spec, types = m.group('spec'), m.group('types') + + node += addnodes.desc_sig_operator('%', '%') + node += addnodes.desc_name(spec + ' ', spec + ' ') + plist = addnodes.desc_parameterlist() + for typ in types.split(','): + typ = typ.strip() + plist += addnodes.desc_parameter(typ, typ) + node += plist + return '%' + spec + # custom extensions here def setup(app): # object type for FRR CLI commands, can be extended to document parent CLI # node later on app.add_object_type("clicmd", "clicmd") + + # printfrr extensions + app.add_object_type("frrfmt", "frrfmt", parse_node=parse_frrfmt) + # css overrides for HTML theme app.add_stylesheet("overrides.css") # load Pygments lexer for FRR config syntax diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst index f19554b532..b827afd6cc 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -1,5 +1,7 @@ .. _logging: +.. highlight:: c + Logging ======= @@ -52,50 +54,50 @@ are available: if (ret != buf) XFREE(MTYPE_FOO, ret); -Extensions -^^^^^^^^^^ - -``printfrr()`` format strings can be extended with suffixes after `%p` or -`%d`. The following extended format specifiers are available: - -+-----------+--------------------------+----------------------------------------------+ -| Specifier | Argument | Output | -+===========+==========================+==============================================+ -| ``%Lu`` | ``uint64_t`` | ``12345`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%Ld`` | ``int64_t`` | ``-12345`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pVA`` | ``struct va_format *`` | (recursive printfrr) | -+-----------+--------------------------+----------------------------------------------+ -| ``%pI4`` | ``struct in_addr *`` | ``1.2.3.4`` | -| | | | -| | ``in_addr_t *`` | | -+-----------+--------------------------+----------------------------------------------+ -| ``%pI6`` | ``struct in6_addr *`` | ``fe80::1234`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pIA`` | ``struct ipaddr *`` | ``1.2.3.4`` | -| | | | -| | | ``fe80::1234`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pFX`` | ``struct prefix *`` | ``fe80::1234/64`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pSG4`` | ``struct prefix_sg *`` | ``(*,1.2.3.4)`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pRN`` | ``struct route_node *`` | ``192.168.1.0/24`` (dst-only node) | -| | | | -| | | ``2001:db8::/32 from fe80::/64`` (SADR node) | -+-----------+--------------------------+----------------------------------------------+ -| ``%pNHv`` | ``struct nexthop *`` | ``1.2.3.4, via eth0`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pNHs`` | ``struct nexthop *`` | ``1.2.3.4 if 15`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pFX`` | ``struct bgp_dest *`` | ``fe80::1234/64`` (available in BGP only) | -+-----------+--------------------------+----------------------------------------------+ -| ``%.*pHX``| ``int len, void *ptr`` | ``12 34 56 78`` (hexdump) | -+-----------+--------------------------+----------------------------------------------+ +.. c:function:: ssize_t bprintfrr(struct fbuf *fb, const char *fmt, ...) +.. c:function:: ssize_t vbprintfrr(struct fbuf *fb, const char *fmt, va_list) + + These are the "lowest level" functions, which the other variants listed + above use to implement their functionality on top. Mainly useful for + implementing printfrr extensions since those get a ``struct fbuf *`` to + write their output to. + +.. c:macro:: FMT_NSTD(expr) + + This macro turns off/on format warnings as needed when non-ISO-C + compatible printfrr extensions are used (e.g. ``%.*p`` or ``%Ld``.):: + + vty_out(vty, "standard compatible %pI4\n", &addr); + FMT_NSTD(vty_out(vty, "non-standard %-47.*pHX\n", (int)len, buf)); + + When the frr-format plugin is in use, this macro is a no-op since the + frr-format plugin supports all printfrr extensions. Since the FRR CI + includes a system with the plugin enabled, this means format errors will + not slip by undetected even with FMT_NSTD. + +.. note:: + ``printfrr()`` does not support the ``%n`` format. + +AS-Safety +^^^^^^^^^ + +``printfrr()`` are AS-Safe under the following conditions: + +* the ``[v]as[n]printfrr`` variants are not AS-Safe (allocating memory) +* floating point specifiers are not AS-Safe (system printf is used for these) +* the positional ``%1$d`` syntax should not be used (8 arguments are supported + while AS-Safe) +* extensions are only AS-Safe if their printer is AS-Safe + +printfrr Extensions +------------------- + +``printfrr()`` format strings can be extended with suffixes after `%p` or `%d`. Printf features like field lengths can be used normally with these extensions, -e.g. ``%-15pI4`` works correctly. +e.g. ``%-15pI4`` works correctly, **except if the extension consumes the +width or precision**. Extensions that do so are listed below as ``%*pXX`` +rather than ``%pXX``. The extension specifier after ``%p`` or ``%d`` is always an uppercase letter; by means of established pattern uppercase letters and numbers form the type @@ -103,10 +105,7 @@ identifier which may be followed by lowercase flags. You can grep the FRR source for ``printfrr_ext_autoreg`` to see all extended printers and what exactly they do. More printers are likely to be added as -needed/useful, so the list above may become outdated. - -``%Ld`` is not an "extension" for printfrr; it's wired directly into the main -printf logic. +needed/useful, so the list here may be outdated. .. note:: @@ -115,16 +114,218 @@ printf logic. **not** available when calling ``snprintf`` directly. You need to call ``snprintfrr`` instead. -AS-Safety -^^^^^^^^^ +Networking data types +^^^^^^^^^^^^^^^^^^^^^ -``printfrr()`` are AS-Safe under the following conditions: +.. role:: frrfmtout(code) -* the ``[v]as[n]printfrr`` variants are not AS-Safe (allocating memory) -* floating point specifiers are not AS-Safe (system printf is used for these) -* the positional ``%1$d`` syntax should not be used (8 arguments are supported - while AS-Safe) -* extensions are only AS-Safe if their printer is AS-Safe +.. frrfmt:: %pI4 (struct in_addr *, in_addr_t *) + + :frrfmtout:`1.2.3.4` + +.. frrfmt:: %pI6 (struct in6_addr *) + + :frrfmtout:`fe80::1234` + +.. frrfmt:: %pEA (struct ethaddr *) + + :frrfmtout:`01:23:45:67:89:ab` + +.. frrfmt:: %pIA (struct ipaddr *) + + :frrfmtout:`1.2.3.4` / :frrfmtout:`fe80::1234` + +.. frrfmt:: %pFX (struct prefix *) + + :frrfmtout:`1.2.3.0/24` / :frrfmtout:`fe80::1234/64` + + This accepts the following types: + + - :c:struct:`prefix` + - :c:struct:`prefix_ipv4` + - :c:struct:`prefix_ipv6` + - :c:struct:`prefix_eth` + - :c:struct:`prefix_evpn` + - :c:struct:`prefix_fs` + + It does **not** accept the following types: + + - :c:struct:`prefix_ls` + - :c:struct:`prefix_rd` + - :c:struct:`prefix_ptr` + - :c:struct:`prefix_sg` (use :frrfmt:`%pSG4`) + - :c:union:`prefixptr` (dereference to get :c:struct:`prefix`) + - :c:union:`prefixconstptr` (dereference to get :c:struct:`prefix`) + +.. frrfmt:: %pSG4 (struct prefix_sg *) + + :frrfmtout:`(*,1.2.3.4)` + + This is *(S,G)* output for use in pimd. (Note prefix_sg is not a prefix + "subclass" like the other prefix_* structs.) + +.. frrfmt:: %pSU (union sockunion *) + + ``%pSU``: :frrfmtout:`1.2.3.4` / :frrfmtout:`fe80::1234` + + ``%pSUs``: :frrfmtout:`1.2.3.4` / :frrfmtout:`fe80::1234%89` + (adds IPv6 scope ID as integer) + + ``%pSUp``: :frrfmtout:`1.2.3.4:567` / :frrfmtout:`[fe80::1234]:567` + (adds port) + + ``%pSUps``: :frrfmtout:`1.2.3.4:567` / :frrfmtout:`[fe80::1234%89]:567` + (adds port and scope ID) + +.. frrfmt:: %pRN (struct route_node *, struct bgp_node *, struct agg_node *) + + :frrfmtout:`192.168.1.0/24` (dst-only node) + + :frrfmtout:`2001:db8::/32 from fe80::/64` (SADR node) + +.. frrfmt:: %pNH (struct nexthop *) + + ``%pNHvv``: :frrfmtout:`via 1.2.3.4, eth0` — verbose zebra format + + ``%pNHv``: :frrfmtout:`1.2.3.4, via eth0` — slightly less verbose zebra format + + ``%pNHs``: :frrfmtout:`1.2.3.4 if 15` — same as :c:func:`nexthop2str()` + +.. frrfmt:: %pBD (struct bgp_dest *) + + :frrfmtout:`fe80::1234/64` + + (only available in bgpd.) + +.. frrfmt:: %dPF (int) + + :frrfmtout:`AF_INET` + + Prints an `AF_*` / `PF_*` constant. ``PF`` is used here to avoid confusion + with `AFI` constants, even though the FRR codebase prefers `AF_INET` over + `PF_INET` & co. + +.. frrfmt:: %dSO (int) + + :frrfmtout:`SOCK_STREAM` + +General utility formats +^^^^^^^^^^^^^^^^^^^^^^^ + +.. frrfmt:: %m (no argument) + + :frrfmtout:`Permission denied` + + Prints ``strerror(errno)``. Does **not** consume any input argument, don't + pass ``errno``! + + (This is a GNU extension not specific to FRR. FRR guarantees it is + available on all systems in printfrr, though BSDs support it in printf too.) + +.. frrfmt:: %pSQ (char *) + + ([S]tring [Q]uote.) Like ``%s``, but produce a quoted string. Options: + + ``n`` - treat ``NULL`` as empty string instead. + + ``q`` - include ``""`` quotation marks. Note: ``NULL`` is printed as + ``(null)``, not ``"(null)"`` unless ``n`` is used too. This is + intentional. + + ``s`` - use escaping suitable for RFC5424 syslog. This means ``]`` is + escaped too. + + If a length is specified (``%*pSQ`` or ``%.*pSQ``), null bytes in the input + string do not end the string and are just printed as ``\x00``. + +.. frrfmt:: %pSE (char *) + + ([S]tring [E]scape.) Like ``%s``, but escape special characters. + Options: + + ``n`` - treat ``NULL`` as empty string instead. + + Unlike :frrfmt:`%pSQ`, this escapes many more characters that are fine for + a quoted string but not on their own. + + If a length is specified (``%*pSE`` or ``%.*pSE``), null bytes in the input + string do not end the string and are just printed as ``\x00``. + +.. frrfmt:: %pVA (struct va_format *) + + Recursively invoke printfrr, with arguments passed in through: + + .. c:struct:: va_format + + .. c:member:: const char *fmt + + Format string to use for the recursive printfrr call. + + .. c:member:: va_list *va + + Formatting arguments. Note this is passed as a pointer, not - as in + most other places - a direct struct reference. Internally uses + ``va_copy()`` so repeated calls can be made (e.g. for determining + output length.) + +.. frrfmt:: %pFB (struct fbuf *) + + Insert text from a ``struct fbuf *``, i.e. the output of a call to + :c:func:`bprintfrr()`. + +.. frrfmt:: %*pHX (void *, char *, unsigned char *) + + ``%pHX``: :frrfmtout:`12 34 56 78` + + ``%pHXc``: :frrfmtout:`12:34:56:78` (separate with [c]olon) + + ``%pHXn``: :frrfmtout:`12345678` (separate with [n]othing) + + Insert hexdump. This specifier requires a precision or width to be + specified. A precision (``%.*pHX``) takes precedence, but generates a + compiler warning since precisions are undefined for ``%p`` in ISO C. If + no precision is given, the width is used instead (and normal handling of + the width is suppressed). + + Note that width and precision are ``int`` arguments, not ``size_t``. Use + like:: + + char *buf; + size_t len; + + snprintfrr(out, sizeof(out), "... %*pHX ...", (int)len, buf); + + /* with padding to width - would generate a warning due to %.*p */ + FMT_NSTD(snprintfrr(out, sizeof(out), "... %-47.*pHX ...", (int)len, buf)); + +.. frrfmt:: %*pHS (void *, char *, unsigned char *) + + ``%pHS``: :frrfmtout:`hex.dump` + + This is a complementary format for :frrfmt:`%*pHX` to print the text + representation for a hexdump. Non-printable characters are replaced with + a dot. + +Integer formats +^^^^^^^^^^^^^^^ + +.. note:: + + These formats currently only exist for advanced type checking with the + ``frr-format`` GCC plugin. They should not be used directly since they will + cause compiler warnings when used without the plugin. Use with + :c:macro:`FMT_NSTD` if necessary. + + It is possible ISO C23 may introduce another format for these, possibly + ``%w64d`` discussed in `JTC 1/SC 22/WG 14/N2680 `_. + +.. frrfmt:: %Lu (uint64_t) + + :frrfmtout:`12345` + +.. frrfmt:: %Ld (int64_t) + + :frrfmtout:`-12345` Log levels ----------