The branch main has been updated by ks:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=99475087d63b4602a0213645bc17d82c3946e2fd

commit 99475087d63b4602a0213645bc17d82c3946e2fd
Author:     Kajetan Staszkiewicz <k...@freebsd.org>
AuthorDate: 2025-08-22 10:44:20 +0000
Commit:     Kajetan Staszkiewicz <k...@freebsd.org>
CommitDate: 2025-09-23 10:06:33 +0000

    pf: Add pfsync protocol for FreeBSD 15
    
    A new version of pfsync packet is introduced: 1500. This version solves
    the issues with data alignment introduced in version 1400 and adds syncing
    of information needed to sync states created by rules with af-to (original
    interface, af and proto separate for wire and stack keys), of rt_af
    needed for prefer-ipv6-nexthop, and of tag names.
    
    Reviewed by:    kp
    Sponsored by:   InnoGames GmbH
    Differential Revision:  https://reviews.freebsd.org/D52176
---
 contrib/tcpdump/print-pfsync.c |  14 +-
 share/man/man4/pfsync.4        |   2 +
 sys/net/if_pfsync.h            |   7 +-
 sys/net/pfvar.h                |  62 +++++-
 sys/netpfil/pf/if_pfsync.c     | 219 +++++++++++++++----
 sys/netpfil/pf/pf_ioctl.c      | 204 ++++++++++++++----
 tests/sys/netpfil/pf/pfsync.sh | 466 ++++++++++++++++++++++++++++++++++++++++-
 usr.bin/netstat/if.c           |  12 +-
 8 files changed, 883 insertions(+), 103 deletions(-)

diff --git a/contrib/tcpdump/print-pfsync.c b/contrib/tcpdump/print-pfsync.c
index e4f11930816c..e7885c4a9e00 100644
--- a/contrib/tcpdump/print-pfsync.c
+++ b/contrib/tcpdump/print-pfsync.c
@@ -102,6 +102,7 @@ struct pfsync_actions {
 static void    pfsync_print_clr(netdissect_options *, const void *);
 static void    pfsync_print_state_1301(netdissect_options *, const void *);
 static void    pfsync_print_state_1400(netdissect_options *, const void *);
+static void    pfsync_print_state_1500(netdissect_options *, const void *);
 static void    pfsync_print_ins_ack(netdissect_options *, const void *);
 static void    pfsync_print_upd_c(netdissect_options *, const void *);
 static void    pfsync_print_upd_req(netdissect_options *, const void *);
@@ -131,6 +132,8 @@ struct pfsync_actions actions[] = {
        { "eof", 0,                                     NULL },
        { "insert", sizeof(struct pfsync_state_1400),   pfsync_print_state_1400 
},
        { "update", sizeof(struct pfsync_state_1400),   pfsync_print_state_1400 
},
+       { "insert", sizeof(struct pfsync_state_1500),   pfsync_print_state_1500 
},
+       { "update", sizeof(struct pfsync_state_1500),   pfsync_print_state_1500 
},
 };
 
 static void
@@ -228,12 +231,21 @@ pfsync_print_state_1301(netdissect_options *ndo, const 
void *bp)
 static void
 pfsync_print_state_1400(netdissect_options *ndo, const void *bp)
 {
-       struct pfsync_state_1301 *st = (struct pfsync_state_1301 *)bp;
+       struct pfsync_state_1400 *st = (struct pfsync_state_1400 *)bp;
 
        fn_print_char(ndo, '\n');
        print_state(ndo, (union pfsync_state_union *)st, 
PFSYNC_MSG_VERSION_1400);
 }
 
+static void
+pfsync_print_state_1500(netdissect_options *ndo, const void *bp)
+{
+       struct pfsync_state_1500 *st = (struct pfsync_state_1500 *)bp;
+
+       fn_print_char(ndo, '\n');
+       print_state(ndo, (union pfsync_state_union *)st, 
PFSYNC_MSG_VERSION_1500);
+}
+
 static void
 pfsync_print_ins_ack(netdissect_options *ndo, const void *bp)
 {
diff --git a/share/man/man4/pfsync.4 b/share/man/man4/pfsync.4
index cc9c350ea875..c12bad74831f 100644
--- a/share/man/man4/pfsync.4
+++ b/share/man/man4/pfsync.4
@@ -162,6 +162,8 @@ FreeBSD releases 13.2 and older.
 Compatibility with FreeBSD 13.1 has been verified.
 .It Cm 1400
 FreeBSD release 14.0.
+.It Cm 1500
+FreeBSD release 15.0.
 .El
 .Sh SYSCTL VARIABLES
 The following variables can be entered at the
diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h
index e99df0b85ccf..7b3177e1137d 100644
--- a/sys/net/if_pfsync.h
+++ b/sys/net/if_pfsync.h
@@ -62,9 +62,10 @@ enum pfsync_msg_versions {
        PFSYNC_MSG_VERSION_UNSPECIFIED = 0,
        PFSYNC_MSG_VERSION_1301 = 1301,
        PFSYNC_MSG_VERSION_1400 = 1400,
+       PFSYNC_MSG_VERSION_1500 = 1500,
 };
 
-#define PFSYNC_MSG_VERSION_DEFAULT PFSYNC_MSG_VERSION_1400
+#define PFSYNC_MSG_VERSION_DEFAULT PFSYNC_MSG_VERSION_1500
 
 #define        PFSYNC_ACT_CLR          0       /* clear all states */
 #define        PFSYNC_ACT_INS_1301     1       /* insert state */
@@ -81,7 +82,9 @@ enum pfsync_msg_versions {
 #define        PFSYNC_ACT_EOF          12      /* end of frame */
 #define PFSYNC_ACT_INS_1400    13      /* insert state */
 #define PFSYNC_ACT_UPD_1400    14      /* update state */
-#define        PFSYNC_ACT_MAX          15
+#define PFSYNC_ACT_INS_1500    15      /* insert state */
+#define PFSYNC_ACT_UPD_1500    16      /* update state */
+#define        PFSYNC_ACT_MAX          17
 
 /*
  * A pfsync frame is built from a header followed by several sections which
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 8b102f198de8..d7d69615151d 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -452,6 +452,16 @@ VNET_DECLARE(struct rmlock, pf_rules_lock);
 #define        PF_RULES_RASSERT()      rm_assert(&V_pf_rules_lock, RA_RLOCKED)
 #define        PF_RULES_WASSERT()      rm_assert(&V_pf_rules_lock, RA_WLOCKED)
 
+VNET_DECLARE(struct rmlock, pf_tags_lock);
+#define        V_pf_tags_lock          VNET(pf_tags_lock)
+
+#define        PF_TAGS_RLOCK_TRACKER   struct rm_priotracker _pf_tags_tracker
+#define        PF_TAGS_RLOCK()         rm_rlock(&V_pf_tags_lock, 
&_pf_tags_tracker)
+#define        PF_TAGS_RUNLOCK()       rm_runlock(&V_pf_tags_lock, 
&_pf_tags_tracker)
+#define        PF_TAGS_WLOCK()         rm_wlock(&V_pf_tags_lock)
+#define        PF_TAGS_WUNLOCK()       rm_wunlock(&V_pf_tags_lock)
+#define        PF_TAGS_WASSERT()       rm_assert(&V_pf_tags_lock, RA_WLOCKED)
+
 extern struct mtx_padalign pf_table_stats_lock;
 #define        PF_TABLE_STATS_LOCK()   mtx_lock(&pf_table_stats_lock)
 #define        PF_TABLE_STATS_UNLOCK() mtx_unlock(&pf_table_stats_lock)
@@ -1209,11 +1219,11 @@ struct pfsync_state_1301 {
        u_int8_t         state_flags;
        u_int8_t         timeout;
        u_int8_t         sync_flags;
-       u_int8_t         updates;
+       u_int8_t         updates;       /* unused */
 } __packed;
 
 struct pfsync_state_1400 {
-       /* The beginning of the struct is compatible with previous versions */
+       /* The beginning of the struct is compatible with pfsync_state_1301 */
        u_int64_t        id;
        char             ifname[IFNAMSIZ];
        struct pfsync_state_key key[2];
@@ -1236,7 +1246,7 @@ struct pfsync_state_1400 {
        u_int8_t         __spare;
        u_int8_t         timeout;
        u_int8_t         sync_flags;
-       u_int8_t         updates;
+       u_int8_t         updates;       /* unused */
        /* The rest is not */
        u_int16_t        qid;
        u_int16_t        pqid;
@@ -1249,12 +1259,54 @@ struct pfsync_state_1400 {
        u_int8_t         set_prio[2];
        u_int8_t         rt;
        char             rt_ifname[IFNAMSIZ];
+} __packed;
 
+struct pfsync_state_1500 {
+       /* The beginning of the struct is compatible with pfsync_state_1301 */
+       u_int64_t        id;
+       char             ifname[IFNAMSIZ];
+       struct pfsync_state_key key[2];
+       struct pf_state_peer_export src;
+       struct pf_state_peer_export dst;
+       struct pf_addr   rt_addr;
+       u_int32_t        rule;
+       u_int32_t        anchor;
+       u_int32_t        nat_rule;
+       u_int32_t        creation;
+       u_int32_t        expire;
+       u_int32_t        packets[2][2];
+       u_int32_t        bytes[2][2];
+       u_int32_t        creatorid;
+       /* The rest is not, use the opportunity to fix alignment */
+       char             tagname[PF_TAG_NAME_SIZE];
+       char             rt_ifname[IFNAMSIZ];
+       char             orig_ifname[IFNAMSIZ];
+       int32_t          rtableid;
+       u_int16_t        state_flags;
+       u_int16_t        qid;
+       u_int16_t        pqid;
+       u_int16_t        dnpipe;
+       u_int16_t        dnrpipe;
+       u_int16_t        max_mss;
+       sa_family_t      wire_af;
+       sa_family_t      stack_af;
+       sa_family_t      rt_af;
+       u_int8_t         wire_proto;
+       u_int8_t         stack_proto;
+       u_int8_t         log;
+       u_int8_t         timeout;
+       u_int8_t         direction;
+       u_int8_t         rt;
+       u_int8_t         min_ttl;
+       u_int8_t         set_tos;
+       u_int8_t         set_prio[2];
+       u_int8_t         spare[3];      /* Improve struct alignment */
 } __packed;
 
 union pfsync_state_union {
        struct pfsync_state_1301 pfs_1301;
        struct pfsync_state_1400 pfs_1400;
+       struct pfsync_state_1500 pfs_1500;
 } __packed;
 
 #ifdef _KERNEL
@@ -2462,6 +2514,10 @@ int      pf_translate(struct pf_pdesc *, struct pf_addr 
*, u_int16_t,
            struct pf_addr *, u_int16_t, u_int16_t, int);
 int    pf_translate_af(struct pf_pdesc *);
 bool   pf_init_threshold(struct pf_kthreshold *, uint32_t, uint32_t);
+uint16_t       pf_tagname2tag(const char *);
+#ifdef ALTQ
+uint16_t       pf_qname2qid(const char *, bool);
+#endif /* ALTQ */
 
 void   pfr_initialize(void);
 void   pfr_cleanup(void);
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 7b9405ee1f8d..66bc99df2afa 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -153,6 +153,8 @@ static int (*pfsync_acts[])(struct mbuf *, int, int, int, 
int) = {
        pfsync_in_eof,                  /* PFSYNC_ACT_EOF */
        pfsync_in_ins,                  /* PFSYNC_ACT_INS_1400 */
        pfsync_in_upd,                  /* PFSYNC_ACT_UPD_1400 */
+       pfsync_in_ins,                  /* PFSYNC_ACT_INS_1500 */
+       pfsync_in_upd,                  /* PFSYNC_ACT_UPD_1500 */
 };
 
 struct pfsync_q {
@@ -165,9 +167,11 @@ struct pfsync_q {
 enum pfsync_q_id {
        PFSYNC_Q_INS_1301,
        PFSYNC_Q_INS_1400,
+       PFSYNC_Q_INS_1500,
        PFSYNC_Q_IACK,
        PFSYNC_Q_UPD_1301,
        PFSYNC_Q_UPD_1400,
+       PFSYNC_Q_UPD_1500,
        PFSYNC_Q_UPD_C,
        PFSYNC_Q_DEL_C,
        PFSYNC_Q_COUNT,
@@ -176,6 +180,7 @@ enum pfsync_q_id {
 /* Functions for building messages for given queue */
 static void    pfsync_out_state_1301(struct pf_kstate *, void *);
 static void    pfsync_out_state_1400(struct pf_kstate *, void *);
+static void    pfsync_out_state_1500(struct pf_kstate *, void *);
 static void    pfsync_out_iack(struct pf_kstate *, void *);
 static void    pfsync_out_upd_c(struct pf_kstate *, void *);
 static void    pfsync_out_del_c(struct pf_kstate *, void *);
@@ -184,9 +189,11 @@ static void        pfsync_out_del_c(struct pf_kstate *, 
void *);
 static struct pfsync_q pfsync_qs[] = {
        { pfsync_out_state_1301, sizeof(struct pfsync_state_1301), 
PFSYNC_ACT_INS_1301 },
        { pfsync_out_state_1400, sizeof(struct pfsync_state_1400), 
PFSYNC_ACT_INS_1400 },
+       { pfsync_out_state_1500, sizeof(struct pfsync_state_1500), 
PFSYNC_ACT_INS_1500 },
        { pfsync_out_iack,       sizeof(struct pfsync_ins_ack),    
PFSYNC_ACT_INS_ACK },
        { pfsync_out_state_1301, sizeof(struct pfsync_state_1301), 
PFSYNC_ACT_UPD_1301 },
        { pfsync_out_state_1400, sizeof(struct pfsync_state_1400), 
PFSYNC_ACT_UPD_1400 },
+       { pfsync_out_state_1500, sizeof(struct pfsync_state_1500), 
PFSYNC_ACT_UPD_1500 },
        { pfsync_out_upd_c,      sizeof(struct pfsync_upd_c),      
PFSYNC_ACT_UPD_C },
        { pfsync_out_del_c,      sizeof(struct pfsync_del_c),      
PFSYNC_ACT_DEL_C }
 };
@@ -195,9 +202,11 @@ static struct pfsync_q pfsync_qs[] = {
 static u_int8_t pfsync_qid_sstate[] = {
        PFSYNC_S_INS,   /* PFSYNC_Q_INS_1301 */
        PFSYNC_S_INS,   /* PFSYNC_Q_INS_1400 */
+       PFSYNC_S_INS,   /* PFSYNC_Q_INS_1500 */
        PFSYNC_S_IACK,  /* PFSYNC_Q_IACK */
        PFSYNC_S_UPD,   /* PFSYNC_Q_UPD_1301 */
        PFSYNC_S_UPD,   /* PFSYNC_Q_UPD_1400 */
+       PFSYNC_S_UPD,   /* PFSYNC_Q_UPD_1500 */
        PFSYNC_S_UPD_C, /* PFSYNC_Q_UPD_C */
        PFSYNC_S_DEL_C, /* PFSYNC_Q_DEL_C */
 };
@@ -525,13 +534,15 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
        struct pf_kstate        *st = NULL;
        struct pf_state_key     *skw = NULL, *sks = NULL;
        struct pf_krule         *r = NULL;
-       struct pfi_kkif         *kif;
+       struct pfi_kkif         *kif, *orig_kif;
        struct pfi_kkif         *rt_kif = NULL;
        struct pf_kpooladdr     *rpool_first;
        int                      error;
+       int                      n = 0;
        sa_family_t              rt_af = 0;
        uint8_t                  rt = 0;
-       int                      n = 0;
+       sa_family_t              wire_af, stack_af;
+       u_int8_t                 wire_proto, stack_proto;
 
        PF_RULES_RASSERT();
 
@@ -542,7 +553,11 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
                return (EINVAL);
        }
 
-       if ((kif = pfi_kkif_find(sp->pfs_1301.ifname)) == NULL) {
+       /*
+        * Check interfaces early on. Do it before allocating memory etc.
+        * Because there is a high chance there will be a lot more such states.
+        */
+       if ((kif = orig_kif = pfi_kkif_find(sp->pfs_1301.ifname)) == NULL) {
                if (V_pf_status.debug >= PF_DEBUG_MISC)
                        printf("%s: unknown interface: %s\n", __func__,
                            sp->pfs_1301.ifname);
@@ -551,6 +566,30 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
                return (0);     /* skip this state */
        }
 
+       /*
+        * States created with floating interface policy can be synchronized to
+        * hosts with different interfaces, because they are bound to V_pfi_all.
+        * But s->orig_kif still points to a real interface. Don't abort
+        * importing the state if orig_kif does not exists on the importing host
+        * but the state is not interface-bound.
+        */
+       if (msg_version == PFSYNC_MSG_VERSION_1500) {
+               orig_kif = pfi_kkif_find(sp->pfs_1500.orig_ifname);
+               if (orig_kif == NULL) {
+                       if (kif == V_pfi_all) {
+                               orig_kif = kif;
+                       } else {
+                               if (V_pf_status.debug >= PF_DEBUG_MISC)
+                                       printf("%s: unknown original interface:"
+                                           " %s\n", __func__,
+                                           sp->pfs_1500.orig_ifname);
+                               if (flags & PFSYNC_SI_IOCTL)
+                                       return (EINVAL);
+                               return (0);     /* skip this state */
+                       }
+               }
+       }
+
        /*
         * If the ruleset checksums match or the state is coming from the ioctl,
         * it's safe to associate the state with the rule of that number.
@@ -565,10 +604,6 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
        } else
                r = &V_pf_default_rule;
 
-       /*
-        * Check routing interface early on. Do it before allocating memory etc.
-        * because there is a high chance there will be a lot more such states.
-        */
        switch (msg_version) {
        case PFSYNC_MSG_VERSION_1301:
                /*
@@ -619,10 +654,12 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
                            "because of different ruleset", __func__);
                        return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
                }
+               wire_af = stack_af = sp->pfs_1301.af;
+               wire_proto = stack_proto = sp->pfs_1301.proto;
        break;
        case PFSYNC_MSG_VERSION_1400:
                /*
-                * On FreeBSD 14 and above we're not taking any chances.
+                * On FreeBSD 14 we're not taking any chances.
                 * We use the information synced to us.
                 */
                if (sp->pfs_1400.rt) {
@@ -641,6 +678,29 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
                         */
                        rt_af = sp->pfs_1400.af;
                }
+               wire_af = stack_af = sp->pfs_1400.af;
+               wire_proto = stack_proto = sp->pfs_1400.proto;
+       break;
+       case PFSYNC_MSG_VERSION_1500:
+               /*
+                * On FreeBSD 15 and above we're not taking any chances.
+                * We use the information synced to us.
+                */
+               if (sp->pfs_1500.rt) {
+                       rt_kif = pfi_kkif_find(sp->pfs_1500.rt_ifname);
+                       if (rt_kif == NULL) {
+                               DPFPRINTF(PF_DEBUG_MISC,
+                                   "%s: unknown route interface: %s",
+                                   __func__, sp->pfs_1500.rt_ifname);
+                               return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
+                       }
+                       rt = sp->pfs_1500.rt;
+                       rt_af = sp->pfs_1500.rt_af;
+               }
+               wire_af = sp->pfs_1500.wire_af;
+               stack_af = sp->pfs_1500.stack_af;
+               wire_proto = sp->pfs_1500.wire_proto;
+               stack_proto = sp->pfs_1500.stack_proto;
        break;
        }
 
@@ -667,8 +727,9 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
        ks = &sp->pfs_1301.key[PF_SK_STACK];
 #endif
 
-       if (PF_ANEQ(&kw->addr[0], &ks->addr[0], sp->pfs_1301.af) ||
-           PF_ANEQ(&kw->addr[1], &ks->addr[1], sp->pfs_1301.af) ||
+       if (wire_af != stack_af ||
+           PF_ANEQ(&kw->addr[0], &ks->addr[0], wire_af) ||
+           PF_ANEQ(&kw->addr[1], &ks->addr[1], wire_af) ||
            kw->port[0] != ks->port[0] ||
            kw->port[1] != ks->port[1]) {
                sks = uma_zalloc(V_pf_state_key_z, M_NOWAIT);
@@ -687,36 +748,19 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
        skw->addr[1] = kw->addr[1];
        skw->port[0] = kw->port[0];
        skw->port[1] = kw->port[1];
-       skw->proto = sp->pfs_1301.proto;
-       skw->af = sp->pfs_1301.af;
+       skw->proto = wire_proto;
+       skw->af = wire_af;
        if (sks != skw) {
                sks->addr[0] = ks->addr[0];
                sks->addr[1] = ks->addr[1];
                sks->port[0] = ks->port[0];
                sks->port[1] = ks->port[1];
-               sks->proto = sp->pfs_1301.proto;
-               sks->af = sp->pfs_1301.af;
+               sks->proto = stack_proto;
+               sks->af = stack_af;
        }
 
        /* copy to state */
-       bcopy(&sp->pfs_1301.rt_addr, &st->act.rt_addr, sizeof(st->act.rt_addr));
        st->creation = (time_uptime - ntohl(sp->pfs_1301.creation)) * 1000;
-       st->expire = pf_get_uptime();
-       if (sp->pfs_1301.expire) {
-               uint32_t timeout;
-
-               timeout = r->timeout[sp->pfs_1301.timeout];
-               if (!timeout)
-                       timeout = 
V_pf_default_rule.timeout[sp->pfs_1301.timeout];
-
-               /* sp->expire may have been adaptively scaled by export. */
-               st->expire -= (timeout - ntohl(sp->pfs_1301.expire)) * 1000;
-       }
-
-       st->direction = sp->pfs_1301.direction;
-       st->act.log = sp->pfs_1301.log;
-       st->timeout = sp->pfs_1301.timeout;
-
        st->act.rt = rt;
        st->act.rt_kif = rt_kif;
        st->act.rt_af = rt_af;
@@ -724,6 +768,12 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
        switch (msg_version) {
                case PFSYNC_MSG_VERSION_1301:
                        st->state_flags = sp->pfs_1301.state_flags;
+                       st->direction = sp->pfs_1301.direction;
+                       st->act.log = sp->pfs_1301.log;
+                       st->timeout = sp->pfs_1301.timeout;
+                       if (rt)
+                               bcopy(&sp->pfs_1301.rt_addr, &st->act.rt_addr,
+                                   sizeof(st->act.rt_addr));
                        /*
                         * In FreeBSD 13 pfsync lacks many attributes. Copy them
                         * from the rule if possible. If rule can't be matched
@@ -762,6 +812,9 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
                        break;
                case PFSYNC_MSG_VERSION_1400:
                        st->state_flags = ntohs(sp->pfs_1400.state_flags);
+                       st->direction = sp->pfs_1400.direction;
+                       st->act.log = sp->pfs_1400.log;
+                       st->timeout = sp->pfs_1400.timeout;
                        st->act.qid = ntohs(sp->pfs_1400.qid);
                        st->act.pqid = ntohs(sp->pfs_1400.pqid);
                        st->act.dnpipe = ntohs(sp->pfs_1400.dnpipe);
@@ -772,12 +825,47 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
                        st->act.max_mss = ntohs(sp->pfs_1400.max_mss);
                        st->act.set_prio[0] = sp->pfs_1400.set_prio[0];
                        st->act.set_prio[1] = sp->pfs_1400.set_prio[1];
+                       if (rt)
+                               bcopy(&sp->pfs_1400.rt_addr, &st->act.rt_addr,
+                                   sizeof(st->act.rt_addr));
+                       break;
+               case PFSYNC_MSG_VERSION_1500:
+                       st->state_flags = ntohs(sp->pfs_1500.state_flags);
+                       st->direction = sp->pfs_1500.direction;
+                       st->act.log = sp->pfs_1500.log;
+                       st->timeout = sp->pfs_1500.timeout;
+                       st->act.qid = ntohs(sp->pfs_1500.qid);
+                       st->act.pqid = ntohs(sp->pfs_1500.pqid);
+                       st->act.dnpipe = ntohs(sp->pfs_1500.dnpipe);
+                       st->act.dnrpipe = ntohs(sp->pfs_1500.dnrpipe);
+                       st->act.rtableid = ntohl(sp->pfs_1500.rtableid);
+                       st->act.min_ttl = sp->pfs_1500.min_ttl;
+                       st->act.set_tos = sp->pfs_1500.set_tos;
+                       st->act.max_mss = ntohs(sp->pfs_1500.max_mss);
+                       st->act.set_prio[0] = sp->pfs_1500.set_prio[0];
+                       st->act.set_prio[1] = sp->pfs_1500.set_prio[1];
+                       if (rt)
+                               bcopy(&sp->pfs_1500.rt_addr, &st->act.rt_addr,
+                                   sizeof(st->act.rt_addr));
+                       if (sp->pfs_1500.tagname[0] != 0)
+                               st->tag = pf_tagname2tag(sp->pfs_1500.tagname);
                        break;
                default:
                        panic("%s: Unsupported pfsync_msg_version %d",
                            __func__, msg_version);
        }
 
+       st->expire = pf_get_uptime();
+       if (sp->pfs_1301.expire) {
+               uint32_t timeout;
+               timeout = r->timeout[st->timeout];
+               if (!timeout)
+                       timeout = V_pf_default_rule.timeout[st->timeout];
+
+               /* sp->expire may have been adaptively scaled by export. */
+               st->expire -= (timeout - ntohl(sp->pfs_1301.expire)) * 1000;
+       }
+
        if (! (st->act.rtableid == -1 ||
            (st->act.rtableid >= 0 && st->act.rtableid < rt_numfibs)))
                goto cleanup;
@@ -797,7 +885,7 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
        if (!(flags & PFSYNC_SI_IOCTL))
                st->state_flags |= PFSTATE_NOSYNC;
 
-       if ((error = pf_state_insert(kif, kif, skw, sks, st)) != 0)
+       if ((error = pf_state_insert(kif, orig_kif, skw, sks, st)) != 0)
                goto cleanup_state;
 
        /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
@@ -1089,23 +1177,29 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, 
int flags, int action)
        struct mbuf *mp;
        union pfsync_state_union *sa, *sp;
        int i, offp, total_len, msg_version, msg_len;
+       u_int8_t timeout, direction;
+       sa_family_t af;
 
        switch (action) {
                case PFSYNC_ACT_INS_1301:
                        msg_len = sizeof(struct pfsync_state_1301);
-                       total_len = msg_len * count;
                        msg_version = PFSYNC_MSG_VERSION_1301;
                        break;
                case PFSYNC_ACT_INS_1400:
                        msg_len = sizeof(struct pfsync_state_1400);
-                       total_len = msg_len * count;
                        msg_version = PFSYNC_MSG_VERSION_1400;
                        break;
+               case PFSYNC_ACT_INS_1500:
+                       msg_len = sizeof(struct pfsync_state_1500);
+                       msg_version = PFSYNC_MSG_VERSION_1500;
+                       break;
                default:
                        V_pfsyncstats.pfsyncs_badver++;
                        return (-1);
        }
 
+       total_len = msg_len * count;
+
        mp = m_pulldown(m, offset, total_len, &offp);
        if (mp == NULL) {
                V_pfsyncstats.pfsyncs_badlen++;
@@ -1116,13 +1210,26 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, 
int flags, int action)
        for (i = 0; i < count; i++) {
                sp = (union pfsync_state_union *)((char *)sa + msg_len * i);
 
+               switch (msg_version) {
+                       case PFSYNC_MSG_VERSION_1301:
+                       case PFSYNC_MSG_VERSION_1400:
+                               af = sp->pfs_1301.af;
+                               timeout = sp->pfs_1301.timeout;
+                               direction = sp->pfs_1301.direction;
+                       break;
+                       case PFSYNC_MSG_VERSION_1500:
+                               af = sp->pfs_1500.wire_af;
+                               timeout = sp->pfs_1500.timeout;
+                               direction = sp->pfs_1500.direction;
+                       break;
+               }
+
                /* Check for invalid values. */
-               if (sp->pfs_1301.timeout >= PFTM_MAX ||
+               if (timeout >= PFTM_MAX ||
                    sp->pfs_1301.src.state > PF_TCPS_PROXY_DST ||
                    sp->pfs_1301.dst.state > PF_TCPS_PROXY_DST ||
-                   sp->pfs_1301.direction > PF_OUT ||
-                   (sp->pfs_1301.af != AF_INET &&
-                   sp->pfs_1301.af != AF_INET6)) {
+                   direction > PF_OUT ||
+                   (af != AF_INET && af != AF_INET6)) {
                        if (V_pf_status.debug >= PF_DEBUG_MISC)
                                printf("%s: invalid value\n", __func__);
                        V_pfsyncstats.pfsyncs_badval++;
@@ -1215,23 +1322,28 @@ pfsync_in_upd(struct mbuf *m, int offset, int count, 
int flags, int action)
        struct pf_kstate *st;
        struct mbuf *mp;
        int sync, offp, i, total_len, msg_len, msg_version;
+       u_int8_t timeout;
 
        switch (action) {
                case PFSYNC_ACT_UPD_1301:
                        msg_len = sizeof(struct pfsync_state_1301);
-                       total_len = msg_len * count;
                        msg_version = PFSYNC_MSG_VERSION_1301;
                        break;
                case PFSYNC_ACT_UPD_1400:
                        msg_len = sizeof(struct pfsync_state_1400);
-                       total_len = msg_len * count;
                        msg_version = PFSYNC_MSG_VERSION_1400;
                        break;
+               case PFSYNC_ACT_UPD_1500:
+                       msg_len = sizeof(struct pfsync_state_1500);
+                       msg_version = PFSYNC_MSG_VERSION_1500;
+                       break;
                default:
                        V_pfsyncstats.pfsyncs_badact++;
                        return (-1);
        }
 
+       total_len = msg_len * count;
+
        mp = m_pulldown(m, offset, total_len, &offp);
        if (mp == NULL) {
                V_pfsyncstats.pfsyncs_badlen++;
@@ -1242,8 +1354,18 @@ pfsync_in_upd(struct mbuf *m, int offset, int count, int 
flags, int action)
        for (i = 0; i < count; i++) {
                sp = (union pfsync_state_union *)((char *)sa + msg_len * i);
 
+               switch (msg_version) {
+                       case PFSYNC_MSG_VERSION_1301:
+                       case PFSYNC_MSG_VERSION_1400:
+                               timeout = sp->pfs_1301.timeout;
+                       break;
+                       case PFSYNC_MSG_VERSION_1500:
+                               timeout = sp->pfs_1500.timeout;
+                       break;
+               }
+
                /* check for invalid values */
-               if (sp->pfs_1301.timeout >= PFTM_MAX ||
+               if (timeout >= PFTM_MAX ||
                    sp->pfs_1301.src.state > PF_TCPS_PROXY_DST ||
                    sp->pfs_1301.dst.state > PF_TCPS_PROXY_DST) {
                        if (V_pf_status.debug >= PF_DEBUG_MISC) {
@@ -1288,7 +1410,7 @@ pfsync_in_upd(struct mbuf *m, int offset, int count, int 
flags, int action)
                        pfsync_alloc_scrub_memory(&sp->pfs_1301.dst, &st->dst);
                        pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst);
                        st->expire = pf_get_uptime();
-                       st->timeout = sp->pfs_1301.timeout;
+                       st->timeout = timeout;
                }
                st->pfsync_time = time_uptime;
 
@@ -1788,6 +1910,14 @@ pfsync_out_state_1400(struct pf_kstate *st, void *buf)
        pfsync_state_export(sp, st, PFSYNC_MSG_VERSION_1400);
 }
 
+static void
+pfsync_out_state_1500(struct pf_kstate *st, void *buf)
+{
+       union pfsync_state_union *sp = buf;
+
+       pfsync_state_export(sp, st, PFSYNC_MSG_VERSION_1500);
+}
+
 static void
 pfsync_out_iack(struct pf_kstate *st, void *buf)
 {
@@ -2455,6 +2585,8 @@ pfsync_sstate_to_qid(u_int8_t sync_state)
                                        return PFSYNC_Q_INS_1301;
                                case PFSYNC_MSG_VERSION_1400:
                                        return PFSYNC_Q_INS_1400;
+                               case PFSYNC_MSG_VERSION_1500:
+                                       return PFSYNC_Q_INS_1500;
                        }
                        break;
                case PFSYNC_S_IACK:
@@ -2465,6 +2597,8 @@ pfsync_sstate_to_qid(u_int8_t sync_state)
                                        return PFSYNC_Q_UPD_1301;
                                case PFSYNC_MSG_VERSION_1400:
                                        return PFSYNC_Q_UPD_1400;
+                               case PFSYNC_MSG_VERSION_1500:
+                                       return PFSYNC_Q_UPD_1500;
                        }
                        break;
                case PFSYNC_S_UPD_C:
@@ -3021,6 +3155,7 @@ pfsync_kstatus_to_softc(struct pfsync_kstatus *status, 
struct pfsync_softc *sc)
                        break;
                case PFSYNC_MSG_VERSION_1301:
                case PFSYNC_MSG_VERSION_1400:
+               case PFSYNC_MSG_VERSION_1500:
                        sc->sc_version = status->version;
                        break;
                default:
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index bd506c092da2..d58af6e5ec4d 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -116,7 +116,6 @@ static int           pf_rollback_altq(u_int32_t);
 static int              pf_commit_altq(u_int32_t);
 static int              pf_enable_altq(struct pf_altq *);
 static int              pf_disable_altq(struct pf_altq *);
-static uint16_t                 pf_qname2qid(const char *);
 static void             pf_qid_unref(uint16_t);
 #endif /* ALTQ */
 static int              pf_begin_rules(u_int32_t *, int, const char *);
@@ -214,8 +213,7 @@ static void          pf_init_tagset(struct pf_tagset *, 
unsigned int *,
 static void             pf_cleanup_tagset(struct pf_tagset *);
 static uint16_t                 tagname2hashindex(const struct pf_tagset *, 
const char *);
 static uint16_t                 tag2hashindex(const struct pf_tagset *, 
uint16_t);
-static u_int16_t        tagname2tag(struct pf_tagset *, const char *);
-static u_int16_t        pf_tagname2tag(const char *);
+static u_int16_t        tagname2tag(struct pf_tagset *, const char *, bool);
 static void             tag_unref(struct pf_tagset *, u_int16_t);
 
 struct cdev *pf_dev;
@@ -286,6 +284,7 @@ int pf_end_threads;
 struct proc *pf_purge_proc;
 
 VNET_DEFINE(struct rmlock, pf_rules_lock);
+VNET_DEFINE(struct rmlock, pf_tags_lock);
 VNET_DEFINE_STATIC(struct sx, pf_ioctl_lock);
 #define        V_pf_ioctl_lock         VNET(pf_ioctl_lock)
 struct sx                      pf_end_lock;
@@ -687,19 +686,50 @@ tag2hashindex(const struct pf_tagset *ts, uint16_t tag)
 }
 
 static u_int16_t
-tagname2tag(struct pf_tagset *ts, const char *tagname)
+tagname2tag(struct pf_tagset *ts, const char *tagname, bool add_new)
 {
        struct pf_tagname       *tag;
        u_int32_t                index;
        u_int16_t                new_tagid;
 
-       PF_RULES_WASSERT();
+       PF_TAGS_RLOCK_TRACKER;
+
+       PF_TAGS_RLOCK();
 
        index = tagname2hashindex(ts, tagname);
        TAILQ_FOREACH(tag, &ts->namehash[index], namehash_entries)
                if (strcmp(tagname, tag->name) == 0) {
                        tag->ref++;
-                       return (tag->tag);
+                       new_tagid = tag->tag;
+                       PF_TAGS_RUNLOCK();
+                       return (new_tagid);
+               }
+
+       /*
+        * When used for pfsync with queues we must not create new entries.
+        * Pf tags can be created just fine by this function, but queues
+        * require additional configuration. If they are missing on the target
+        * system we just ignore them
+        */
+       if (add_new == false) {
+               printf("%s: Not creating a new tag\n", __func__);
+               PF_TAGS_RUNLOCK();
+               return (0);
+       }
+
+       /*
+        * If a new entry must be created do it under a write lock.
+        * But first search again, somebody could have created the tag
+        * between unlocking the read lock and locking the write lock.
+        */
+       PF_TAGS_RUNLOCK();
+       PF_TAGS_WLOCK();
+       TAILQ_FOREACH(tag, &ts->namehash[index], namehash_entries)
+               if (strcmp(tagname, tag->name) == 0) {
+                       tag->ref++;
+                       new_tagid = tag->tag;
+                       PF_TAGS_WUNLOCK();
+                       return (new_tagid);
                }
 
        /*
@@ -716,16 +746,20 @@ tagname2tag(struct pf_tagset *ts, const char *tagname)
         * to rounding of the number of bits in the vector up to a multiple
         * of the vector word size at declaration/allocation time.
         */
-       if ((new_tagid == 0) || (new_tagid > TAGID_MAX))
+       if ((new_tagid == 0) || (new_tagid > TAGID_MAX)) {
+               PF_TAGS_WUNLOCK();
                return (0);
+       }
 
        /* Mark the tag as in use.  Bits are 0-based for BIT_CLR() */
        BIT_CLR(TAGID_MAX, new_tagid - 1, &ts->avail);
 
        /* allocate and fill new struct pf_tagname */
        tag = uma_zalloc(V_pf_tag_z, M_NOWAIT);
-       if (tag == NULL)
+       if (tag == NULL) {
+               PF_TAGS_WUNLOCK();
                return (0);
+       }
        strlcpy(tag->name, tagname, sizeof(tag->name));
        tag->tag = new_tagid;
        tag->ref = 1;
@@ -737,7 +771,29 @@ tagname2tag(struct pf_tagset *ts, const char *tagname)
        index = tag2hashindex(ts, new_tagid);
        TAILQ_INSERT_TAIL(&ts->taghash[index], tag, taghash_entries);
 
-       return (tag->tag);
+       PF_TAGS_WUNLOCK();
+       return (new_tagid);
+}
+
+static char *
+tag2tagname(struct pf_tagset *ts, u_int16_t tag)
+{
+       struct pf_tagname       *t;
+       uint16_t                 index;
+
+       PF_TAGS_RLOCK_TRACKER;
+
+       PF_TAGS_RLOCK();
+
+       index = tag2hashindex(ts, tag);
+       TAILQ_FOREACH(t, &ts->taghash[index], taghash_entries)
+               if (tag == t->tag) {
+                       PF_TAGS_RUNLOCK();
+                       return (t->name);
+               }
+
+       PF_TAGS_RUNLOCK();
+       return (NULL);
 }
 
 static void
@@ -746,7 +802,7 @@ tag_unref(struct pf_tagset *ts, u_int16_t tag)
        struct pf_tagname       *t;
        uint16_t                 index;
 
-       PF_RULES_WASSERT();
+       PF_TAGS_WLOCK();
 
        index = tag2hashindex(ts, tag);
        TAILQ_FOREACH(t, &ts->taghash[index], taghash_entries)
@@ -763,12 +819,20 @@ tag_unref(struct pf_tagset *ts, u_int16_t tag)
                        }
                        break;
                }
+
+       PF_TAGS_WUNLOCK();
 }
 
-static uint16_t
+uint16_t
 pf_tagname2tag(const char *tagname)
 {
-       return (tagname2tag(&V_pf_tags, tagname));
+       return (tagname2tag(&V_pf_tags, tagname, true));
+}
+
+static const char *
+pf_tag2tagname(uint16_t tag)
+{
+       return (tag2tagname(&V_pf_tags, tag));
 }
 
 static int
@@ -899,10 +963,16 @@ pf_commit_eth(uint32_t ticket, const char *anchor)
 }
 
 #ifdef ALTQ
-static uint16_t
-pf_qname2qid(const char *qname)
+uint16_t
+pf_qname2qid(const char *qname, bool add_new)
+{
+       return (tagname2tag(&V_pf_qids, qname, add_new));
+}
+
+static const char *
+pf_qid2qname(uint16_t qid)
 {
-       return (tagname2tag(&V_pf_qids, qname));
+       return (tag2tagname(&V_pf_qids, qid));
 }
 
 static void
@@ -1151,7 +1221,7 @@ pf_altq_ifnet_event(struct ifnet *ifp, int remove)
                }
                bcopy(a1, a2, sizeof(struct pf_altq));
 
-               if ((a2->qid = pf_qname2qid(a2->qname)) == 0) {
+               if ((a2->qid = pf_qname2qid(a2->qname, true)) == 0) {
                        error = EBUSY;
                        free(a2, M_PFALTQ);
                        break;
@@ -1606,7 +1676,7 @@ pf_export_kaltq(struct pf_altq *q, struct pfioc_altq_v1 
*pa, size_t ioc_size)
 #define ASSIGN_OPT(x) exported_q->pq_u.hfsc_opts.x = q->pq_u.hfsc_opts.x
 #define ASSIGN_OPT_SATU32(x) exported_q->pq_u.hfsc_opts.x = \
                            SATU32(q->pq_u.hfsc_opts.x)
-                       
+
                        ASSIGN_OPT_SATU32(rtsc_m1);
                        ASSIGN_OPT(rtsc_d);
                        ASSIGN_OPT_SATU32(rtsc_m2);
@@ -1620,7 +1690,7 @@ pf_export_kaltq(struct pf_altq *q, struct pfioc_altq_v1 
*pa, size_t ioc_size)
                        ASSIGN_OPT_SATU32(ulsc_m2);
 
                        ASSIGN_OPT(flags);
-                       
+
 #undef ASSIGN_OPT
 #undef ASSIGN_OPT_SATU32
                } else
@@ -1728,7 +1798,7 @@ pf_import_kaltq(struct pfioc_altq_v1 *pa, struct pf_altq 
*q, size_t ioc_size)
                        ASSIGN_OPT(ulsc_m2);
 
                        ASSIGN_OPT(flags);
-                       
+
 #undef ASSIGN_OPT
                } else
                        COPY(pq_u);
@@ -1760,7 +1830,7 @@ pf_import_kaltq(struct pfioc_altq_v1 *pa, struct pf_altq 
*q, size_t ioc_size)
                ASSIGN(qid);
                break;
        }
-       default:        
+       default:
                panic("%s: unhandled struct pfioc_altq version", __func__);
                break;
        }
@@ -2191,11 +2261,11 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
 #ifdef ALTQ
        /* set queue IDs */
        if (rule->qname[0] != 0) {
-               if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
+               if ((rule->qid = pf_qname2qid(rule->qname, true)) == 0)
                        ERROUT(EBUSY);
                else if (rule->pqname[0] != 0) {
                        if ((rule->pqid =
-                           pf_qname2qid(rule->pqname)) == 0)
+                           pf_qname2qid(rule->pqname, true)) == 0)
                                ERROUT(EBUSY);
                } else
                        rule->pqid = rule->qid;
@@ -3314,7 +3384,7 @@ DIOCGETETHRULE_error:
 #ifdef ALTQ
                /* set queue IDs */
                if (rule->qname[0] != 0) {
-                       if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
+                       if ((rule->qid = pf_qname2qid(rule->qname, true)) == 0)
                                error = EBUSY;
                        else
                                rule->qid = rule->qid;
@@ -3865,11 +3935,11 @@ DIOCGETRULENV_error:
                        /* set queue IDs */
                        if (newrule->qname[0] != 0) {
                                if ((newrule->qid =
-                                   pf_qname2qid(newrule->qname)) == 0)
+                                   pf_qname2qid(newrule->qname, true)) == 0)
                                        error = EBUSY;
                                else if (newrule->pqname[0] != 0) {
                                        if ((newrule->pqid =
-                                           pf_qname2qid(newrule->pqname)) == 0)
+                                           pf_qname2qid(newrule->pqname, 
true)) == 0)
                                                error = EBUSY;
                                } else
                                        newrule->pqid = newrule->qid;
@@ -4400,7 +4470,7 @@ DIOCGETSTATESV2_full:
                 * copy the necessary fields
                 */
                if (altq->qname[0] != 0) {
-                       if ((altq->qid = pf_qname2qid(altq->qname)) == 0) {
+                       if ((altq->qid = pf_qname2qid(altq->qname, true)) == 0) 
{
                                PF_RULES_WUNLOCK();
                                error = EBUSY;
                                free(altq, M_PFALTQ);
@@ -5723,6 +5793,7 @@ fail:
 void
 pfsync_state_export(union pfsync_state_union *sp, struct pf_kstate *st, int 
msg_version)
 {
+       const char      *tagname;
        bzero(sp, sizeof(union pfsync_state_union));
 
        /* copy from state key */
*** 680 LINES SKIPPED ***

Reply via email to