The branch main has been updated by kp:

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

commit fc6e50699615c93f39d008709f87c754d9b6c7d3
Author:     Kristof Provost <[email protected]>
AuthorDate: 2023-12-13 15:55:28 +0000
Commit:     Kristof Provost <[email protected]>
CommitDate: 2024-01-16 08:45:55 +0000

    pflow: add RFC8158 NAT support
    
    Extend pflow(4) to send NAT44 Session Create and Delete events.
    This applies only to IPFIX (i.e. proto version 10), and requires no
    user configuration.
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D43114
---
 sbin/pfctl/parse.y     |  16 ++++
 sys/net/pflow.h        |  44 ++++++++++
 sys/netpfil/pf/pf.c    |   3 +-
 sys/netpfil/pf/pflow.c | 213 +++++++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 260 insertions(+), 16 deletions(-)

diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 94b7e241cd25..9ec86f898240 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -4680,6 +4680,7 @@ natrule           : nataction interface af proto fromto 
tag tagged rtable
                    redirpool pool_opts
                {
                        struct pfctl_rule       r;
+                       struct node_state_opt   *o;
 
                        if (check_rulestate(PFCTL_STATE_NAT))
                                YYERROR;
@@ -4855,6 +4856,21 @@ natrule          : nataction interface af proto fromto 
tag tagged rtable
                                r.rpool.mape = $10.mape;
                        }
 
+                       o = keep_state_defaults;
+                       while (o) {
+                               switch (o->type) {
+                               case PF_STATE_OPT_PFLOW:
+                                       if (r.rule_flag & PFRULE_PFLOW) {
+                                               yyerror("state pflow option: "
+                                                   "multiple definitions");
+                                               YYERROR;
+                                       }
+                                       r.rule_flag |= PFRULE_PFLOW;
+                                       break;
+                               }
+                               o = o->next;
+                       }
+
                        expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
                            $5.src_os, $5.src.host, $5.src.port, $5.dst.host,
                            $5.dst.port, 0, 0, 0, "");
diff --git a/sys/net/pflow.h b/sys/net/pflow.h
index 4a63f7640629..84fcf1327a17 100644
--- a/sys/net/pflow.h
+++ b/sys/net/pflow.h
@@ -68,6 +68,14 @@
 #define PFIX_IE_destinationIPv6Address          28
 #define PFIX_IE_flowStartMilliseconds          152
 #define PFIX_IE_flowEndMilliseconds            153
+#define PFIX_IE_postNATSourceIPv4Address       225
+#define PFIX_IE_postNATDestinationIPv4Address  226
+#define PFIX_IE_postNAPTSourceTransportPort    227
+#define PFIX_IE_postNAPTDestinationTransportPort       228
+#define PFIX_IE_natEvent                       230
+#define PFIX_NAT_EVENT_SESSION_CREATE          4
+#define PFIX_NAT_EVENT_SESSION_DELETE          5
+#define PFIX_IE_timeStamp                      323
 
 struct pflow_flow {
        u_int32_t       src_ip;
@@ -148,10 +156,28 @@ struct pflow_ipfix_tmpl_ipv6 {
 #define PFLOW_IPFIX_TMPL_IPV6_ID 257
 } __packed;
 
+struct pflow_ipfix_tmpl_nat44 {
+       struct pflow_tmpl_hdr   h;
+       struct pflow_tmpl_fspec timestamp;
+       struct pflow_tmpl_fspec nat_event;
+       struct pflow_tmpl_fspec protocol;
+       struct pflow_tmpl_fspec src_ip;
+       struct pflow_tmpl_fspec src_port;
+       struct pflow_tmpl_fspec postnat_src_ip;
+       struct pflow_tmpl_fspec postnat_src_port;
+       struct pflow_tmpl_fspec dst_ip;
+       struct pflow_tmpl_fspec dst_port;
+       struct pflow_tmpl_fspec postnat_dst_ip;
+       struct pflow_tmpl_fspec postnat_dst_port;
+#define PFLOW_IPFIX_TMPL_NAT44_FIELD_COUNT 11
+#define PFLOW_IPFIX_TMPL_NAT44_ID 258
+};
+
 struct pflow_ipfix_tmpl {
        struct pflow_set_header set_header;
        struct pflow_ipfix_tmpl_ipv4    ipv4_tmpl;
        struct pflow_ipfix_tmpl_ipv6    ipv6_tmpl;
+       struct pflow_ipfix_tmpl_nat44   nat44_tmpl;
 } __packed;
 
 struct pflow_ipfix_flow4 {
@@ -186,6 +212,20 @@ struct pflow_ipfix_flow6 {
        /* XXX padding needed? */
 } __packed;
 
+struct pflow_ipfix_nat4 {
+       u_int64_t       timestamp;      /* timeStamp */
+       u_int8_t        nat_event;      /* natEvent */
+       u_int8_t        protocol;       /* protocolIdentifier */
+       u_int32_t       src_ip;         /* sourceIPv4Address */
+       u_int16_t       src_port;       /* sourceTransportPort */
+       u_int32_t       postnat_src_ip; /* postNATSourceIPv4Address */
+       u_int16_t       postnat_src_port;/* postNAPTSourceTransportPort */
+       u_int32_t       dest_ip;        /* destinationIPv4Address */
+       u_int16_t       dest_port;      /* destinationTransportPort */
+       u_int32_t       postnat_dest_ip;/* postNATDestinationIPv4Address */
+       u_int16_t       postnat_dest_port;/* postNAPTDestinationTransportPort */
+} __packed;
+
 #ifdef _KERNEL
 
 struct pflow_softc {
@@ -199,13 +239,16 @@ struct pflow_softc {
        unsigned int             sc_count;
        unsigned int             sc_count4;
        unsigned int             sc_count6;
+       unsigned int             sc_count_nat4;
        unsigned int             sc_maxcount;
        unsigned int             sc_maxcount4;
        unsigned int             sc_maxcount6;
+       unsigned int             sc_maxcount_nat4;
        u_int64_t                sc_gcounter;
        u_int32_t                sc_sequence;
        struct callout           sc_tmo;
        struct callout           sc_tmo6;
+       struct callout           sc_tmo_nat4;
        struct callout           sc_tmo_tmpl;
        struct intr_event       *sc_swi_ie;
        void                    *sc_swi_cookie;
@@ -219,6 +262,7 @@ struct pflow_softc {
        u_int32_t                sc_observation_dom;
        struct mbuf             *sc_mbuf;       /* current cumulative mbuf */
        struct mbuf             *sc_mbuf6;      /* current cumulative mbuf */
+       struct mbuf             *sc_mbuf_nat4;
        CK_LIST_ENTRY(pflow_softc) sc_next;
        struct epoch_context     sc_epoch_ctx;
 };
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 89f6e000f6cf..9bd9828a99d9 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -4875,7 +4875,8 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, 
struct pf_krule *a,
                s->state_flags |= PFSTATE_SLOPPY;
        if (pd->flags & PFDESC_TCP_NORM) /* Set by old-style scrub rules */
                s->state_flags |= PFSTATE_SCRUB_TCP;
-       if (r->rule_flag & PFRULE_PFLOW)
+       if ((r->rule_flag & PFRULE_PFLOW) ||
+           (nr != NULL && nr->rule_flag & PFRULE_PFLOW))
                s->state_flags |= PFSTATE_PFLOW;
 
        s->act.log = pd->act.log & PF_LOG_ALL;
diff --git a/sys/netpfil/pf/pflow.c b/sys/netpfil/pf/pflow.c
index 398851bf17d0..ce5e8ec6547c 100644
--- a/sys/netpfil/pf/pflow.c
+++ b/sys/netpfil/pf/pflow.c
@@ -70,6 +70,12 @@
 #define DPRINTF(x)
 #endif
 
+enum pflow_family_t {
+       PFLOW_INET,
+       PFLOW_INET6,
+       PFLOW_NAT4,
+};
+
 static void    pflow_output_process(void *);
 static int     pflow_create(int);
 static int     pflow_destroy(int, bool);
@@ -80,12 +86,13 @@ static int  pflowvalidsockaddr(const struct sockaddr *, 
int);
 static struct mbuf     *pflow_get_mbuf(struct pflow_softc *, u_int16_t);
 static void    pflow_flush(struct pflow_softc *);
 static int     pflow_sendout_v5(struct pflow_softc *);
-static int     pflow_sendout_ipfix(struct pflow_softc *, sa_family_t);
+static int     pflow_sendout_ipfix(struct pflow_softc *, enum pflow_family_t);
 static int     pflow_sendout_ipfix_tmpl(struct pflow_softc *);
 static int     pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *);
 static void    pflow_timeout(void *);
 static void    pflow_timeout6(void *);
 static void    pflow_timeout_tmpl(void *);
+static void    pflow_timeout_nat4(void *);
 static void    copy_flow_data(struct pflow_flow *, struct pflow_flow *,
        const struct pf_kstate *, struct pf_state_key *, int, int);
 static void    copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *,
@@ -106,6 +113,9 @@ static int  copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 
*flow,
        struct pflow_softc *sc);
 static int     copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow,
        struct pflow_softc *sc);
+static int     copy_nat_ipfix_4_to_m(struct pflow_ipfix_nat4 *,
+       const struct pf_kstate *, struct pflow_softc *,
+       uint8_t, uint64_t);
 
 static const char pflowname[] = "pflow";
 
@@ -303,6 +313,53 @@ pflow_create(int unit)
            htons(PFIX_IE_protocolIdentifier);
        pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.len = htons(1);
 
+       /* NAT44 create template */
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.h.tmpl_id =
+           htons(PFLOW_IPFIX_TMPL_NAT44_ID);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.h.field_count =
+           htons(PFLOW_IPFIX_TMPL_NAT44_FIELD_COUNT);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.timestamp.field_id =
+           htons(PFIX_IE_timeStamp);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.timestamp.len =
+           htons(8);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.nat_event.field_id =
+           htons(PFIX_IE_natEvent);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.nat_event.len =
+           htons(1);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.protocol.field_id =
+           htons(PFIX_IE_protocolIdentifier);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.protocol.len = htons(1);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.src_ip.field_id =
+           htons(PFIX_IE_sourceIPv4Address);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.src_ip.len =
+           htons(4);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.src_port.field_id =
+           htons(PFIX_IE_sourceTransportPort);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.src_port.len = htons(2);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_ip.field_id =
+           htons(PFIX_IE_postNATSourceIPv4Address);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_ip.len =
+           htons(4);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_port.field_id =
+           htons(PFIX_IE_postNAPTSourceTransportPort);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_port.len =
+           htons(2);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_ip.field_id =
+           htons(PFIX_IE_destinationIPv4Address);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_ip.len =
+           htons(4);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_port.field_id =
+           htons(PFIX_IE_destinationTransportPort);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_port.len = htons(2);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_ip.field_id =
+           htons(PFIX_IE_postNATDestinationIPv4Address);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_ip.len =
+           htons(4);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_port.field_id =
+           htons(PFIX_IE_postNAPTDestinationTransportPort);
+       pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_port.len =
+           htons(2);
+
        pflowif->sc_id = unit;
        pflowif->sc_vnet = curvnet;
 
@@ -311,6 +368,7 @@ pflow_create(int unit)
 
        callout_init_mtx(&pflowif->sc_tmo, &pflowif->sc_lock, 0);
        callout_init_mtx(&pflowif->sc_tmo6, &pflowif->sc_lock, 0);
+       callout_init_mtx(&pflowif->sc_tmo_nat4, &pflowif->sc_lock, 0);
        callout_init_mtx(&pflowif->sc_tmo_tmpl, &pflowif->sc_lock, 0);
 
        error = swi_add(&pflowif->sc_swi_ie, pflowname, pflow_output_process,
@@ -374,10 +432,12 @@ pflow_destroy(int unit, bool drain)
 
        callout_drain(&sc->sc_tmo);
        callout_drain(&sc->sc_tmo6);
+       callout_drain(&sc->sc_tmo_nat4);
        callout_drain(&sc->sc_tmo_tmpl);
 
        m_freem(sc->sc_mbuf);
        m_freem(sc->sc_mbuf6);
+       m_freem(sc->sc_mbuf_nat4);
 
        PFLOW_LOCK(sc);
        mbufq_drain(&sc->sc_outputqueue);
@@ -425,18 +485,26 @@ pflowvalidsockaddr(const struct sockaddr *sa, int 
ignore_port)
 int
 pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz)
 {
+       size_t min;
 
        sc->sc_maxcount4 = (mtu - hdrsz -
            sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4);
        sc->sc_maxcount6 = (mtu - hdrsz -
            sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow6);
+       sc->sc_maxcount_nat4 = (mtu - hdrsz -
+           sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_nat4);
        if (sc->sc_maxcount4 > PFLOW_MAXFLOWS)
                sc->sc_maxcount4 = PFLOW_MAXFLOWS;
        if (sc->sc_maxcount6 > PFLOW_MAXFLOWS)
                sc->sc_maxcount6 = PFLOW_MAXFLOWS;
-       return (hdrsz + sizeof(struct udpiphdr) +
-           MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4),
-           sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6)));
+       if (sc->sc_maxcount_nat4 > PFLOW_MAXFLOWS)
+               sc->sc_maxcount_nat4 = PFLOW_MAXFLOWS;
+
+       min = MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4),
+           sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6));
+       min = MIN(min, sc->sc_maxcount_nat4 * sizeof(struct pflow_ipfix_nat4));
+
+       return (hdrsz + sizeof(struct udpiphdr) + min);
 }
 
 static void
@@ -628,6 +696,28 @@ copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *flow1,
        flow1->tos = flow2->tos = st->rule.ptr->tos;
 }
 
+static void
+copy_nat_ipfix_4_data(struct pflow_ipfix_nat4 *nat1,
+    struct pflow_ipfix_nat4 *nat2, const struct pf_kstate *st,
+    struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst)
+{
+       nat1->src_ip = nat2->dest_ip = 
st->key[PF_SK_STACK]->addr[src].v4.s_addr;
+       nat1->src_port = nat2->dest_port = st->key[PF_SK_STACK]->port[src];
+       nat1->dest_ip = nat2->src_ip = 
st->key[PF_SK_STACK]->addr[dst].v4.s_addr;
+       nat1->dest_port = nat2->src_port = st->key[PF_SK_STACK]->port[dst];
+       nat1->postnat_src_ip = nat2->postnat_dest_ip = 
st->key[PF_SK_WIRE]->addr[src].v4.s_addr;
+       nat1->postnat_src_port = nat2->postnat_dest_port = 
st->key[PF_SK_WIRE]->port[src];
+       nat1->postnat_dest_ip = nat2->postnat_src_ip = 
st->key[PF_SK_WIRE]->addr[dst].v4.s_addr;
+       nat1->postnat_dest_port = nat2->postnat_src_port = 
st->key[PF_SK_WIRE]->port[dst];
+       nat1->protocol = nat2->protocol = sk->proto;
+
+       /*
+        * Because we have to generate a create and delete event we'll fill out 
the
+        * timestamp and nat_event fields when we transmit. As opposed to doing 
this
+        * work a second time.
+       */
+}
+
 static void
 export_pflow(const struct pf_kstate *st)
 {
@@ -755,7 +845,7 @@ copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, 
struct pflow_softc *sc)
        sc->sc_count4++;
 
        if (sc->sc_count4 >= sc->sc_maxcount4)
-               ret = pflow_sendout_ipfix(sc, AF_INET);
+               ret = pflow_sendout_ipfix(sc, PFLOW_INET);
        return(ret);
 }
 
@@ -785,11 +875,46 @@ copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, 
struct pflow_softc *sc)
        sc->sc_count6++;
 
        if (sc->sc_count6 >= sc->sc_maxcount6)
-               ret = pflow_sendout_ipfix(sc, AF_INET6);
+               ret = pflow_sendout_ipfix(sc, PFLOW_INET6);
 
        return(ret);
 }
 
+int
+copy_nat_ipfix_4_to_m(struct pflow_ipfix_nat4 *nat, const struct pf_kstate *st,
+    struct pflow_softc *sc, uint8_t event, uint64_t timestamp)
+{
+       int             ret = 0;
+
+       PFLOW_ASSERT(sc);
+
+       if (sc->sc_mbuf_nat4 == NULL) {
+               if ((sc->sc_mbuf_nat4 =
+                   pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_NAT44_ID)) == NULL) {
+                       return (ENOBUFS);
+               }
+               sc->sc_count_nat4 = 0;
+               callout_reset(&sc->sc_tmo, PFLOW_TIMEOUT * hz,
+                   pflow_timeout_nat4, sc);
+       }
+
+       nat->nat_event = event;
+       nat->timestamp = htobe64(pf_get_time() - (pf_get_uptime() - timestamp));
+       m_copyback(sc->sc_mbuf_nat4, PFLOW_SET_HDRLEN +
+           (sc->sc_count_nat4 * sizeof(struct pflow_ipfix_nat4)),
+           sizeof(struct pflow_ipfix_nat4), (caddr_t)nat);
+       sc->sc_count_nat4++;
+
+       if (V_pflowstats.pflow_flows == sc->sc_gcounter)
+               V_pflowstats.pflow_flows++;
+
+       sc->sc_gcounter++;
+       if (sc->sc_count_nat4 >= sc->sc_maxcount_nat4)
+               ret = pflow_sendout_ipfix(sc, PFLOW_NAT4);
+
+       return (ret);
+}
+
 static int
 pflow_pack_flow(const struct pf_kstate *st, struct pf_state_key *sk,
     struct pflow_softc *sc)
@@ -815,17 +940,30 @@ pflow_pack_flow(const struct pf_kstate *st, struct 
pf_state_key *sk,
        return (ret);
 }
 
+static bool
+pflow_is_natd(const struct pf_kstate *st)
+{
+       /* If ports or addresses are different we've been NAT-ed. */
+       return (memcmp(st->key[PF_SK_WIRE], st->key[PF_SK_STACK],
+           sizeof(struct pf_addr) * 2 + sizeof(uint16_t) * 2) != 0);
+}
+
 static int
 pflow_pack_flow_ipfix(const struct pf_kstate *st, struct pf_state_key *sk,
     struct pflow_softc *sc)
 {
        struct pflow_ipfix_flow4         flow4_1, flow4_2;
+       struct pflow_ipfix_nat4          nat4_1, nat4_2;
        struct pflow_ipfix_flow6         flow6_1, flow6_2;
        int                              ret = 0;
+       bool                             nat = false;
+
        if (sk->af == AF_INET) {
                bzero(&flow4_1, sizeof(flow4_1));
                bzero(&flow4_2, sizeof(flow4_2));
 
+               nat = pflow_is_natd(st);
+
                if (st->direction == PF_OUT)
                        copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
                            1, 0);
@@ -833,11 +971,30 @@ pflow_pack_flow_ipfix(const struct pf_kstate *st, struct 
pf_state_key *sk,
                        copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
                            0, 1);
 
-               if (st->bytes[0] != 0) /* first flow from state */
+               if (nat)
+                       copy_nat_ipfix_4_data(&nat4_1, &nat4_2, st, sk, sc, 1, 
0);
+
+               if (st->bytes[0] != 0) /* first flow from state */ {
                        ret = copy_flow_ipfix_4_to_m(&flow4_1, sc);
 
-               if (st->bytes[1] != 0) /* second flow from state */
+                       if (ret == 0 && nat) {
+                               ret = copy_nat_ipfix_4_to_m(&nat4_1, st, sc,
+                                   PFIX_NAT_EVENT_SESSION_CREATE, 
st->creation);
+                               ret |= copy_nat_ipfix_4_to_m(&nat4_1, st, sc,
+                                   PFIX_NAT_EVENT_SESSION_DELETE, st->expire);
+                       }
+               }
+
+               if (st->bytes[1] != 0) /* second flow from state */ {
                        ret = copy_flow_ipfix_4_to_m(&flow4_2, sc);
+
+                       if (ret == 0 && nat) {
+                               ret = copy_nat_ipfix_4_to_m(&nat4_2, st, sc,
+                                   PFIX_NAT_EVENT_SESSION_CREATE, 
st->creation);
+                               ret |= copy_nat_ipfix_4_to_m(&nat4_2, st, sc,
+                                   PFIX_NAT_EVENT_SESSION_DELETE, st->expire);
+                       }
+               }
        } else if (sk->af == AF_INET6) {
                bzero(&flow6_1, sizeof(flow6_1));
                bzero(&flow6_2, sizeof(flow6_2));
@@ -871,7 +1028,7 @@ pflow_timeout(void *v)
                pflow_sendout_v5(sc);
                break;
        case PFLOW_PROTO_10:
-               pflow_sendout_ipfix(sc, AF_INET);
+               pflow_sendout_ipfix(sc, PFLOW_INET);
                break;
        default: /* NOTREACHED */
                panic("Unsupported version %d", sc->sc_version);
@@ -892,7 +1049,7 @@ pflow_timeout6(void *v)
                return;
 
        CURVNET_SET(sc->sc_vnet);
-       pflow_sendout_ipfix(sc, AF_INET6);
+       pflow_sendout_ipfix(sc, PFLOW_INET6);
        CURVNET_RESTORE();
 }
 
@@ -911,6 +1068,21 @@ pflow_timeout_tmpl(void *v)
        CURVNET_RESTORE();
 }
 
+static void
+pflow_timeout_nat4(void *v)
+{
+       struct pflow_softc      *sc = v;
+
+       PFLOW_ASSERT(sc);
+
+       if (sc->sc_version != PFLOW_PROTO_10)
+               return;
+
+       CURVNET_SET(sc->sc_vnet);
+       pflow_sendout_ipfix(sc, PFLOW_NAT4);
+       CURVNET_RESTORE();
+}
+
 static void
 pflow_flush(struct pflow_softc *sc)
 {
@@ -921,8 +1093,9 @@ pflow_flush(struct pflow_softc *sc)
                pflow_sendout_v5(sc);
                break;
        case PFLOW_PROTO_10:
-               pflow_sendout_ipfix(sc, AF_INET);
-               pflow_sendout_ipfix(sc, AF_INET6);
+               pflow_sendout_ipfix(sc, PFLOW_INET);
+               pflow_sendout_ipfix(sc, PFLOW_INET6);
+               pflow_sendout_ipfix(sc, PFLOW_NAT4);
                break;
        default: /* NOTREACHED */
                break;
@@ -960,7 +1133,7 @@ pflow_sendout_v5(struct pflow_softc *sc)
 }
 
 static int
-pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af)
+pflow_sendout_ipfix(struct pflow_softc *sc, enum pflow_family_t af)
 {
        struct mbuf                     *m;
        struct pflow_v10_header         *h10;
@@ -971,7 +1144,7 @@ pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af)
        PFLOW_ASSERT(sc);
 
        switch (af) {
-       case AF_INET:
+       case PFLOW_INET:
                m = sc->sc_mbuf;
                callout_stop(&sc->sc_tmo);
                if (m == NULL)
@@ -981,7 +1154,7 @@ pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af)
                set_length = sizeof(struct pflow_set_header)
                    + sc->sc_count4 * sizeof(struct pflow_ipfix_flow4);
                break;
-       case AF_INET6:
+       case PFLOW_INET6:
                m = sc->sc_mbuf6;
                callout_stop(&sc->sc_tmo6);
                if (m == NULL)
@@ -991,6 +1164,16 @@ pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t 
af)
                set_length = sizeof(struct pflow_set_header)
                    + sc->sc_count6 * sizeof(struct pflow_ipfix_flow6);
                break;
+       case PFLOW_NAT4:
+               m = sc->sc_mbuf_nat4;
+               callout_stop(&sc->sc_tmo_nat4);
+               if (m == NULL)
+                       return (0);
+               sc->sc_mbuf_nat4 = NULL;
+               count = sc->sc_count_nat4;
+               set_length = sizeof(struct pflow_set_header)
+                   + sc->sc_count_nat4 * sizeof(struct pflow_ipfix_nat4);
+               break;
        default:
                panic("Unsupported AF %d", af);
        }

Reply via email to