Legacy iptables uses '-c PCNT BCNT' format in listed rules, nft-variant
used '[PCNT BCNT]' prefix like with iptables-save.

In order to pass the counter format preference along, FMT_C_COUNTS is
introduced and related 'format' checks adjusted.

Since legacy iptables prints the counters between matches and target,
this change affects save_matches_and_target() function. In order to get
access to the rule counters, it's declaration is adjusted to receive
iptables_command_state pointer instead of match, target and jumpto
pointers from the same object.

While being at it, integrate jump to user-defined chain into it as well
since the related code in both callers was almost identical. Though
since different rule flags are used between iptables and ip6tables, pass
a 'goto_flag' boolean instead of the actual 'flags' bitfield.

Signed-off-by: Phil Sutter <p...@nwl.cc>
---
 include/xtables.h                             |  1 +
 iptables/nft-ipv4.c                           | 10 +---
 iptables/nft-ipv6.c                           | 10 +---
 iptables/nft-shared.c                         | 29 +++++++----
 iptables/nft-shared.h                         |  7 ++-
 iptables/nft.c                                | 10 +++-
 .../testcases/iptables/0003-list-rules_0      | 48 +++++++++++++++++++
 7 files changed, 83 insertions(+), 32 deletions(-)
 create mode 100755 iptables/tests/shell/testcases/iptables/0003-list-rules_0

diff --git a/include/xtables.h b/include/xtables.h
index e4d235028deea..bf169b08186f5 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -537,6 +537,7 @@ extern void xtables_save_string(const char *value);
 #define FMT_NONEWLINE          0x0080
 #define FMT_LINENUMBERS                0x0100
 #define FMT_EBT_SAVE           0x0200
+#define FMT_C_COUNTS           0x0400
 
 #define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \
                         | FMT_NUMERIC | FMT_NOTABLE)
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index eaf861d1f76e7..4446a3276a9fa 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -358,14 +358,8 @@ static void nft_ipv4_save_rule(const void *data, unsigned 
int format)
                printf("-f ");
        }
 
-       save_matches_and_target(cs->matches, cs->target,
-                               cs->jumpto, cs->fw.ip.flags, &cs->fw);
-
-       if (cs->target == NULL && strlen(cs->jumpto) > 0) {
-               printf("-%c %s", cs->fw.ip.flags & IPT_F_GOTO ? 'g' : 'j',
-                      cs->jumpto);
-       }
-       printf("\n");
+       save_matches_and_target(cs, cs->fw.ip.flags & IPT_F_GOTO,
+                               &cs->fw, format);
 }
 
 static void nft_ipv4_proto_parse(struct iptables_command_state *cs,
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index fa5b8c89f3db6..dfdcc0515079d 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -296,14 +296,8 @@ static void nft_ipv6_save_rule(const void *data, unsigned 
int format)
                          cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask,
                          cs->fw6.ipv6.outiface, cs->fw6.ipv6.outiface_mask);
 
-       save_matches_and_target(cs->matches, cs->target,
-                               cs->jumpto, cs->fw6.ipv6.flags, &cs->fw6);
-
-       if (cs->target == NULL && strlen(cs->jumpto) > 0) {
-               printf("-%c %s", cs->fw6.ipv6.flags & IP6T_F_GOTO ? 'g' : 'j',
-                      cs->jumpto);
-       }
-       printf("\n");
+       save_matches_and_target(cs, cs->fw6.ipv6.flags & IP6T_F_GOTO,
+                               &cs->fw6, format);
 }
 
 /* These are invalid numbers as upper layer protocol */
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 66db7ed1fa34f..5b55c7c0a7052 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -813,13 +813,13 @@ void nft_ipv46_save_chain(const struct nftnl_chain *c, 
const char *policy)
               chain, policy ?: "-", pkts, bytes);
 }
 
-void save_matches_and_target(struct xtables_rule_match *m,
-                            struct xtables_target *target,
-                            const char *jumpto, uint8_t flags, const void *fw)
+void save_matches_and_target(const struct iptables_command_state *cs,
+                            bool goto_flag, const void *fw,
+                            unsigned int format)
 {
        struct xtables_rule_match *matchp;
 
-       for (matchp = m; matchp; matchp = matchp->next) {
+       for (matchp = cs->matches; matchp; matchp = matchp->next) {
                if (matchp->match->alias) {
                        printf("-m %s",
                               matchp->match->alias(matchp->match->m));
@@ -833,15 +833,24 @@ void save_matches_and_target(struct xtables_rule_match *m,
                printf(" ");
        }
 
-       if (target != NULL) {
-               if (target->alias) {
-                       printf("-j %s", target->alias(target->t));
+       if ((format & (FMT_NOCOUNTS | FMT_C_COUNTS)) == FMT_C_COUNTS)
+               printf("-c %llu %llu ",
+                      (unsigned long long)cs->counters.pcnt,
+                      (unsigned long long)cs->counters.bcnt);
+
+       if (cs->target != NULL) {
+               if (cs->target->alias) {
+                       printf("-j %s", cs->target->alias(cs->target->t));
                } else
-                       printf("-j %s", jumpto);
+                       printf("-j %s", cs->jumpto);
 
-               if (target->save != NULL)
-                       target->save(fw, target->t);
+               if (cs->target->save != NULL)
+                       cs->target->save(fw, cs->target->t);
+       } else if (strlen(cs->jumpto) > 0) {
+               printf("-%c %s", goto_flag ? 'g' : 'j', cs->jumpto);
        }
+
+       printf("\n");
 }
 
 void print_matches_and_target(struct iptables_command_state *cs,
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 1f5c8a8130c69..49e2fa10fc828 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -166,10 +166,9 @@ void save_rule_details(const struct iptables_command_state 
*cs,
                       unsigned const char *outiface_mask);
 void save_counters(const void *data);
 void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy);
-void save_matches_and_target(struct xtables_rule_match *m,
-                            struct xtables_target *target,
-                            const char *jumpto,
-                            uint8_t flags, const void *fw);
+void save_matches_and_target(const struct iptables_command_state *cs,
+                            bool goto_flag, const void *fw,
+                            unsigned int format);
 
 struct nft_family_ops *nft_family_ops_lookup(int family);
 
diff --git a/iptables/nft.c b/iptables/nft.c
index 1c076510962b3..7fd261c3d0e3a 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -1201,7 +1201,7 @@ nft_rule_print_save(const struct nftnl_rule *r, enum 
nft_rule_print type,
        ops = nft_family_ops_lookup(family);
        ops->rule_to_cs(r, &cs);
 
-       if (!(format & FMT_NOCOUNTS) && ops->save_counters)
+       if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)) && ops->save_counters)
                ops->save_counters(&cs);
 
        /* print chain name */
@@ -2397,6 +2397,7 @@ int nft_rule_list_save(struct nft_handle *h, const char 
*chain,
        struct nftnl_chain_list *list;
        struct nftnl_chain_list_iter *iter;
        struct nftnl_chain *c;
+       unsigned int format;
        int ret = 1;
 
        list = nft_chain_dump(h);
@@ -2410,6 +2411,11 @@ int nft_rule_list_save(struct nft_handle *h, const char 
*chain,
        if (iter == NULL)
                goto err;
 
+       if (counters < 0)
+               format = FMT_C_COUNTS;
+       else if (counters == 0)
+               format = FMT_NOCOUNTS;
+
        c = nftnl_chain_list_iter_next(iter);
        while (c != NULL) {
                const char *chain_table =
@@ -2423,7 +2429,7 @@ int nft_rule_list_save(struct nft_handle *h, const char 
*chain,
                        goto next;
 
                ret = __nft_rule_list(h, chain_name, table, rulenum,
-                                     counters ? 0 : FMT_NOCOUNTS, list_save);
+                                     format, list_save);
 
                /* we printed the chain we wanted, stop processing. */
                if (chain)
diff --git a/iptables/tests/shell/testcases/iptables/0003-list-rules_0 
b/iptables/tests/shell/testcases/iptables/0003-list-rules_0
new file mode 100755
index 0000000000000..2e87ce5a6aec0
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0003-list-rules_0
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+set -e
+
+$XT_MULTI iptables -N foo
+$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j ACCEPT
+$XT_MULTI iptables -A FORWARD -i eth42 -o eth23 -g foo
+$XT_MULTI iptables -t nat -A OUTPUT -o eth123 -m mark --mark 0x42 -j ACCEPT
+
+EXPECT='-P INPUT ACCEPT
+-P FORWARD ACCEPT
+-P OUTPUT ACCEPT
+-N foo
+-A FORWARD -i eth23 -o eth42 -j ACCEPT
+-A FORWARD -i eth42 -o eth23 -g foo'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -S)
+
+EXPECT='-P INPUT ACCEPT -c 0 0
+-P FORWARD ACCEPT -c 0 0
+-P OUTPUT ACCEPT -c 0 0
+-N foo
+-A FORWARD -i eth23 -o eth42 -c 0 0 -j ACCEPT
+-A FORWARD -i eth42 -o eth23 -c 0 0 -g foo'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -v -S)
+
+EXPECT='-P FORWARD ACCEPT
+-A FORWARD -i eth23 -o eth42 -j ACCEPT
+-A FORWARD -i eth42 -o eth23 -g foo'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -S FORWARD)
+
+EXPECT='-P FORWARD ACCEPT -c 0 0
+-A FORWARD -i eth23 -o eth42 -c 0 0 -j ACCEPT
+-A FORWARD -i eth42 -o eth23 -c 0 0 -g foo'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -v -S FORWARD)
+
+EXPECT='-P OUTPUT ACCEPT
+-A OUTPUT -o eth123 -m mark --mark 0x42 -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -t nat -S OUTPUT)
+
+EXPECT='-P OUTPUT ACCEPT -c 0 0
+-A OUTPUT -o eth123 -m mark --mark 0x42 -c 0 0 -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -v -t nat -S OUTPUT)
-- 
2.18.0

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to