summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--bgpd/bgp_bmp.c2
-rw-r--r--lib/atomlist.h2
-rw-r--r--lib/filter.c18
-rw-r--r--lib/typerb.h2
-rw-r--r--lib/typesafe.h2
-rw-r--r--python/tsexpand.py131
-rw-r--r--tests/topotests/nb_config/test_nb_config.py4
-rw-r--r--vtysh/vtysh.c102
-rw-r--r--vtysh/vtysh.h4
10 files changed, 253 insertions, 15 deletions
diff --git a/.gitignore b/.gitignore
index 07cdb11a21..60b4189952 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,6 +62,7 @@
*.cg.dot
*.cg.svg
*.xref
+*_tsexpand.h
### gcov outputs
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index 2f3be0bc9d..bf08e30509 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -2496,7 +2496,7 @@ DEFPY(bmp_stats_send_experimental,
{
VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
- bt->stats_send_experimental = !!no;
+ bt->stats_send_experimental = !no;
return CMD_SUCCESS;
}
diff --git a/lib/atomlist.h b/lib/atomlist.h
index 2b6a3a176f..faf1d7324e 100644
--- a/lib/atomlist.h
+++ b/lib/atomlist.h
@@ -6,8 +6,10 @@
#ifndef _FRR_ATOMLIST_H
#define _FRR_ATOMLIST_H
+#ifndef _TYPESAFE_EXPAND_MACROS
#include "typesafe.h"
#include "frratomic.h"
+#endif /* _TYPESAFE_EXPAND_MACROS */
#ifdef __cplusplus
extern "C" {
diff --git a/lib/filter.c b/lib/filter.c
index 5a0790f8bf..0722bed1cb 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -458,7 +458,6 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi,
struct filter_cisco *filter;
bool first;
json_object *json = NULL;
- json_object *json_proto = NULL;
master = access_master_get(afi);
if (master == NULL) {
@@ -469,12 +468,7 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi,
if (use_json)
json = json_object_new_object();
-
- /* Print the name of the protocol */
- if (json) {
- json_proto = json_object_new_object();
- json_object_object_add(json, frr_protoname, json_proto);
- } else
+ else
vty_out(vty, "%s:\n", frr_protoname);
for (access = master->str.head; access; access = access->next) {
@@ -496,7 +490,7 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi,
if (json) {
json_acl = json_object_new_object();
- json_object_object_add(json_proto,
+ json_object_object_add(json,
access->name,
json_acl);
@@ -596,7 +590,7 @@ DEFUN (show_mac_access_list_name,
return filter_show(vty, argv[3]->arg, AFI_L2VPN, false);
}
-DEFUN (show_ip_access_list,
+DEFUN_NOSH (show_ip_access_list,
show_ip_access_list_cmd,
"show ip access-list [json]",
SHOW_STR
@@ -608,7 +602,7 @@ DEFUN (show_ip_access_list,
return filter_show(vty, NULL, AFI_IP, uj);
}
-DEFUN (show_ip_access_list_name,
+DEFUN_NOSH (show_ip_access_list_name,
show_ip_access_list_name_cmd,
"show ip access-list ACCESSLIST4_NAME [json]",
SHOW_STR
@@ -622,7 +616,7 @@ DEFUN (show_ip_access_list_name,
return filter_show(vty, argv[idx_acl]->arg, AFI_IP, uj);
}
-DEFUN (show_ipv6_access_list,
+DEFUN_NOSH (show_ipv6_access_list,
show_ipv6_access_list_cmd,
"show ipv6 access-list [json]",
SHOW_STR
@@ -634,7 +628,7 @@ DEFUN (show_ipv6_access_list,
return filter_show(vty, NULL, AFI_IP6, uj);
}
-DEFUN (show_ipv6_access_list_name,
+DEFUN_NOSH (show_ipv6_access_list_name,
show_ipv6_access_list_name_cmd,
"show ipv6 access-list ACCESSLIST6_NAME [json]",
SHOW_STR
diff --git a/lib/typerb.h b/lib/typerb.h
index b020a665f6..93370e1012 100644
--- a/lib/typerb.h
+++ b/lib/typerb.h
@@ -9,8 +9,10 @@
#ifndef _FRR_TYPERB_H
#define _FRR_TYPERB_H
+#ifndef _TYPESAFE_EXPAND_MACROS
#include <string.h>
#include "typesafe.h"
+#endif /* _TYPESAFE_EXPAND_MACROS */
#ifdef __cplusplus
extern "C" {
diff --git a/lib/typesafe.h b/lib/typesafe.h
index 93258c5954..fc028049a4 100644
--- a/lib/typesafe.h
+++ b/lib/typesafe.h
@@ -6,10 +6,12 @@
#ifndef _FRR_TYPESAFE_H
#define _FRR_TYPESAFE_H
+#ifndef _TYPESAFE_EXPAND_MACROS
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "compiler.h"
+#endif /* _TYPESAFE_EXPAND_MACROS */
#ifdef __cplusplus
extern "C" {
diff --git a/python/tsexpand.py b/python/tsexpand.py
new file mode 100644
index 0000000000..5d6099750f
--- /dev/null
+++ b/python/tsexpand.py
@@ -0,0 +1,131 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: MIT
+#
+# 2024 by David Lamparter
+#
+# this tool edits an FRR source .c file to expand the typesafe DECLARE_DLIST
+# et al. definitions. This can be helpful to get better warnings/errors from
+# GCC when something re. a typesafe container is involved. You can also use
+# it on .h files.
+# The actual expansions created by this tool are written to separate files
+# called something like "lib/cspf__visited_tsexpand.h" (for a container named
+# "visited")
+#
+# THIS TOOL EDITS THE FILE IN PLACE. MAKE A BACKUP IF YOU HAVE UNSAVED WORK
+# IN PROGRESS (which is likely because you're debugging a typesafe container
+# problem!)
+#
+# The PREDECL_XYZ is irrelevant for this tool, it needs to be run on the file
+# that has the DECLARE_XYZ (can be .c or .h)
+#
+# the lines added by this tool all have /* $ts_expand: remove$ */ at the end
+# you can undo the effects of this tool by calling sed:
+#
+# sed -e '/\$ts_expand: remove\$/ d' -i.orig filename.c
+
+import os
+import sys
+import re
+import subprocess
+import shlex
+
+decl_re = re.compile(
+ r"""(?<=\n)[ \t]*DECLARE_(LIST|ATOMLIST|DLIST|HEAP|HASH|(SORTLIST|SKIPLIST|RBTREE|ATOMSORT)_(NON)?UNIQ)\(\s*(?P<name>[^, \t\n]+)\s*,[^)]+\)\s*;[ \t]*\n"""
+)
+kill_re = re.compile(r"""(?<=\n)[^\n]*/\* \$ts_expand: remove\$ \*/\n""")
+
+src_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+# some files may be compiled with different CPPFLAGS, that's not supported
+# here...
+cpp = subprocess.check_output(
+ ["make", "var-CPP", "var-AM_CPPFLAGS", "var-DEFS"], cwd=src_root
+)
+cpp = shlex.split(cpp.decode("UTF-8"))
+
+
+def process_file(filename):
+ with open(filename, "r") as ifd:
+ data = ifd.read()
+
+ data = kill_re.sub("", data)
+
+ before = 0
+
+ dirname = os.path.dirname(filename)
+ basename = os.path.basename(filename).removesuffix(".c").removesuffix(".h")
+
+ xname = filename + ".exp"
+ with open(filename + ".exp", "w") as ofd:
+ for m in decl_re.finditer(data):
+ s = m.start()
+ e = m.end()
+ ofd.write(data[before:s])
+
+ # start gcc/clang with some "magic" options to make it expand the
+ # typesafe macros, but nothing else.
+ # -P removes the "#line" markers (which are useless because
+ # everything ends up on one line anyway)
+ # -D_TYPESAFE_EXPAND_MACROS prevents the system header files
+ # (stddef.h, stdint.h, etc.) from being included and expanded
+ # -imacros loads the macro definitions from typesafe.h, but
+ # doesn't include any of the "plain text" (i.e. prototypes
+ # and outside-macro struct definitions) from it
+ # atomlist.h is sufficient because it includes typesafe.h which
+ # includes typerb.h, that's all of them
+ p_expand = subprocess.Popen(
+ cpp
+ + [
+ "-P",
+ "-D_TYPESAFE_EXPAND_MACROS",
+ "-imacros",
+ "lib/atomlist.h",
+ "-",
+ ],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ cwd=src_root,
+ )
+ # the output will look like shit, all on one line. format it.
+ p_format = subprocess.Popen(
+ ["clang-format", "-"],
+ stdin=p_expand.stdout,
+ stdout=subprocess.PIPE,
+ cwd=src_root,
+ )
+ # pipe between cpp & clang-format needs to be closed
+ p_expand.stdout.close()
+
+ # ... and finally, write the DECLARE_XYZ statement, and ONLY that
+ # statements. No headers, no other definitions.
+ p_expand.stdin.write(data[s:e].encode("UTF-8"))
+ p_expand.stdin.close()
+
+ odata = b""
+ while rd := p_format.stdout.read():
+ odata = odata + rd
+
+ p_expand.wait()
+ p_format.wait()
+
+ # and now that we have the expanded text, write it out, put an
+ # #include in the .c file, and put "#if 0" around the original
+ # DECLARE_XYZ statement (otherwise it'll be duplicate...)
+ newname = os.path.join(dirname, f"{basename}__{m.group('name')}_tsexpand.h")
+ with open(newname, "wb") as nfd:
+ nfd.write(odata)
+
+ ofd.write(f'#include "{newname}" /* $ts_expand: remove$ */\n')
+ ofd.write("#if 0 /* $ts_expand: remove$ */\n")
+ ofd.write(data[s:e])
+ ofd.write("#endif /* $ts_expand: remove$ */\n")
+ before = e
+
+ ofd.write(data[before:])
+
+ os.rename(xname, filename)
+
+
+if __name__ == "__main__":
+ for filename in sys.argv[1:]:
+ process_file(filename)
diff --git a/tests/topotests/nb_config/test_nb_config.py b/tests/topotests/nb_config/test_nb_config.py
index 8def19ffd5..9099ef10b8 100644
--- a/tests/topotests/nb_config/test_nb_config.py
+++ b/tests/topotests/nb_config/test_nb_config.py
@@ -50,7 +50,7 @@ def test_access_list_config_ordering(tgen):
output = r1.vtysh_cmd("show ip access-list test json")
got = json.loads(output)
expected = json.loads(
- '{"ZEBRA":{"test":{"type":"Standard", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "address":"10.0.0.1", "mask":"0.0.0.0"}]}}}'
+ '{"zebra":{"test":{"type":"Standard", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "address":"10.0.0.1", "mask":"0.0.0.0"}]}}}'
)
result = json_cmp(got, expected)
assert result is None
@@ -63,7 +63,7 @@ def test_access_list_config_ordering(tgen):
output = r1.vtysh_cmd("show ip access-list test json")
got = json.loads(output)
expected = json.loads(
- '{"ZEBRA":{"test":{"type":"Zebra", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "prefix":"10.0.0.0/8", "exact-match":false}]}}}'
+ '{"zebra":{"test":{"type":"Zebra", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "prefix":"10.0.0.0/8", "exact-match":false}]}}}'
)
result = json_cmp(got, expected)
assert result is None
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 1a358017dc..b1c957d043 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -3628,6 +3628,104 @@ DEFPY (show_ipv6_prefix_list_detail,
return CMD_SUCCESS;
}
+static void show_access_list_send(afi_t afi, const char *access_list, bool json)
+{
+ unsigned int i;
+ bool first = true;
+ char command_line[128];
+
+ if (afi == AFI_IP)
+ snprintf(command_line, sizeof(command_line),
+ "do show ip access-list ");
+ else if (afi == AFI_IP6)
+ snprintf(command_line, sizeof(command_line),
+ "do show ipv6 access-list ");
+ if (access_list)
+ strlcat(command_line, access_list, sizeof(command_line));
+ if (json) {
+ strlcat(command_line, " json", sizeof(command_line));
+ vty_out(vty, "{");
+ }
+
+ for (i = 0; i < array_size(vtysh_client); i++) {
+ const struct vtysh_client *client = &vtysh_client[i];
+ bool is_connected = true;
+
+ if (!CHECK_FLAG(client->flag, VTYSH_ACCESS_LIST_SHOW))
+ continue;
+
+ for (; client; client = client->next)
+ if (client->fd < 0)
+ is_connected = false;
+
+ if (!is_connected)
+ continue;
+
+ if (json && !first)
+ vty_out(vty, ",");
+ else
+ first = false;
+
+ if (json)
+ vty_out(vty, "\"%s\":", vtysh_client[i].name);
+
+ vtysh_client_execute_name(vtysh_client[i].name, command_line);
+ }
+
+ if (json)
+ vty_out(vty, "}\n");
+}
+
+DEFPY (show_ip_access_list,
+ show_ip_access_list_cmd,
+ "show ip access-list [json$uj]",
+ SHOW_STR
+ IP_STR
+ "List IP access lists\n"
+ JSON_STR)
+{
+ show_access_list_send(AFI_IP, NULL, !!uj);
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_access_list_name,
+ show_ip_access_list_name_cmd,
+ "show ip access-list ACCESSLIST4_NAME$name [json$uj]",
+ SHOW_STR
+ IP_STR
+ "List IP access lists\n"
+ "IP access-list name\n"
+ JSON_STR)
+{
+ show_access_list_send(AFI_IP, name, !!uj);
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ipv6_access_list,
+ show_ipv6_access_list_cmd,
+ "show ipv6 access-list [json$uj]",
+ SHOW_STR
+ IPV6_STR
+ "List IPv6 access lists\n"
+ JSON_STR)
+{
+ show_access_list_send(AFI_IP6, NULL, !!uj);
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ipv6_access_list_name,
+ show_ipv6_access_list_name_cmd,
+ "show ipv6 access-list ACCESSLIST6_NAME$name [json$uj]",
+ SHOW_STR
+ IPV6_STR
+ "List IPv6 access lists\n"
+ "IPv6 access-list name\n"
+ JSON_STR)
+{
+ show_access_list_send(AFI_IP6, name, !!uj);
+ return CMD_SUCCESS;
+}
+
DEFUN (vtysh_integrated_config,
vtysh_integrated_config_cmd,
"service integrated-vtysh-config",
@@ -5234,6 +5332,10 @@ void vtysh_init_vty(void)
install_element(ENABLE_NODE, &show_ipv6_prefix_list_cmd);
install_element(ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd);
install_element(ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd);
+ install_element(ENABLE_NODE, &show_ip_access_list_cmd);
+ install_element(ENABLE_NODE, &show_ip_access_list_name_cmd);
+ install_element(ENABLE_NODE, &show_ipv6_access_list_cmd);
+ install_element(ENABLE_NODE, &show_ipv6_access_list_name_cmd);
/* "write terminal" command. */
install_element(ENABLE_NODE, &vtysh_write_terminal_cmd);
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 131fbef8ba..b1d57aa3c2 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -68,6 +68,10 @@ extern struct event_loop *master;
VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | \
VTYSH_BGPD | VTYSH_ISISD | VTYSH_PIMD | VTYSH_EIGRPD | \
VTYSH_FABRICD
+#define VTYSH_ACCESS_LIST_SHOW \
+ VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | \
+ VTYSH_BGPD | VTYSH_ISISD | VTYSH_PIMD | VTYSH_EIGRPD | \
+ VTYSH_FABRICD
#define VTYSH_PREFIX_LIST_SHOW \
VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | \
VTYSH_BGPD | VTYSH_ISISD | VTYSH_PIMD | VTYSH_EIGRPD | \