On 21/02/18(Wed) 02:37, Henning Brauer wrote:
> Here comes generic delay functionality for pf.
> The manpage bits are missing for the moment, but it's really simple to
> use:
> 
> match in set delay 10000
> 
> delay is in ms. should I change the parser to explicitely require
> "ms", as in "match in set delay 10000ms"?
> I have a pool_sethardlimit as a "last resort" style upper limit of
> delayed packets held, hardcoded to 10000 right now - does that need to
> be tunable? if not - what value? I'll obviously make it a define at
> least.
> delay range is 1-65535ms - is 65s too excessive, aka do we need to
> impose a lower upper limit?
> 
> I would welcome a few tests (and then oks from ppl with the right @) so
> that we can go further once the basic functionality is in. And yes,
> things like a delay range with random value in between chosen can be
> added later. Getting the basic delay machinery, foremost in if.c, right
> is the main goal now, the pf side is relatively easy to twiddle with. 

I'd suggest moving the pool allocation and the function in net/pf*.c
and only have a function call under #if NPF > 0.

More comments inline.

> Index: sys/net/if.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if.c,v
> retrieving revision 1.547
> diff -u -p -r1.547 if.c
> --- sys/net/if.c      20 Feb 2018 03:46:45 -0000      1.547
> +++ sys/net/if.c      21 Feb 2018 01:26:37 -0000
> @@ -127,6 +127,10 @@
>  
>  #if NPF > 0
>  #include <net/pfvar.h>
> +#include <sys/pool.h>
> +
> +#define      IF_TIMEOUTPL_LIMIT      10000
> +struct pool  iftimeopl;

I'd suggest defining your own structure containing a timeout and a mbuf
pointer instead of abusing ph_cookie.  Since you're already allocating
something it doesn't matter much and you're code won't be broken by
a future refactoring.

>  #endif
>  
>  void if_attachsetup(struct ifnet *);
> @@ -164,6 +168,10 @@ void     ifa_print_all(void);
>  
>  void if_qstart_compat(struct ifqueue *);
>  
> +#if NPF > 0
> +void if_enqueue_delayed(void *);
> +#endif
> +
>  /*
>   * interface index map
>   *
> @@ -261,6 +269,14 @@ ifinit(void)
>       }
>  
>       net_tick(&net_tick_to);
> +
> +#if NPF > 0
> +     pool_init(&iftimeopl, sizeof(struct timeout), 0, IPL_SOFTNET, 0,
> +         "iftimeout", NULL);
> +     pool_sethardlimit(&iftimeopl, IF_TIMEOUTPL_LIMIT, "iftimeout pool "
> +         "limit exceeded, dropping packets", 60);
> +/* XXX hardlimit as last resort safeguard, limit? */
> +#endif
>  }
>  
>  static struct if_idxmap if_idxmap = {
> @@ -674,12 +690,44 @@ if_qstart_compat(struct ifqueue *ifq)
>       KERNEL_UNLOCK();
>  }
>  
> +#if NPF > 0
> +void
> +if_enqueue_delayed(void *arg)
> +{
> +     struct mbuf     *m = arg;
> +     struct ifnet    *ifp;
> +     struct timeout  *to = m->m_pkthdr.ph_cookie;
> +
> +     ifp = if_get(m->m_pkthdr.ph_ifidx);
> +     if (ifp != NULL) {
> +             if_enqueue(ifp, m);
> +             if_put(ifp);
> +     }

You're leaking a mbuf if the interface has been detached.

> +     pool_put(&iftimeopl, to);
> +}
> +#endif
> +
>  int
>  if_enqueue(struct ifnet *ifp, struct mbuf *m)
>  {
>       unsigned int idx;
>       struct ifqueue *ifq;
>       int error;
> +
> +#if NPF > 0
> +     if (m->m_pkthdr.pf.delay > 0) {
> +             struct timeout *to;
> +
> +             if ((to = pool_get(&iftimeopl, PR_NOWAIT)) == NULL)
> +                     return (ENOBUFS);
> +             timeout_set(to, if_enqueue_delayed, m);
> +             timeout_add_msec(to, m->m_pkthdr.pf.delay);
> +             m->m_pkthdr.pf.delay = 0;
> +             m->m_pkthdr.ph_cookie = to;
> +             m->m_pkthdr.ph_ifidx = ifp->if_index;
> +             return (0);
> +     }
> +#endif       
>  
>  #if NBRIDGE > 0
>       if (ifp->if_bridgeport && (m->m_flags & M_PROTO1) == 0) {
> Index: sys/net/pf.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf.c,v
> retrieving revision 1.1061
> diff -u -p -r1.1061 pf.c
> --- sys/net/pf.c      18 Feb 2018 21:45:30 -0000      1.1061
> +++ sys/net/pf.c      21 Feb 2018 01:16:00 -0000
> @@ -3484,6 +3484,8 @@ pf_rule_to_actions(struct pf_rule *r, st
>               a->set_prio[0] = r->set_prio[0];
>               a->set_prio[1] = r->set_prio[1];
>       }
> +     if (r->rule_flag & PFRULE_SETDELAY)
> +             a->delay = r->delay;
>  }
>  
>  #define PF_TEST_ATTRIB(t, a)                 \
> @@ -3979,6 +3981,7 @@ pf_create_state(struct pf_pdesc *pd, str
>  #endif       /* NPFSYNC > 0 */
>       s->set_prio[0] = act->set_prio[0];
>       s->set_prio[1] = act->set_prio[1];
> +     s->delay = act->delay;
>       SLIST_INIT(&s->src_nodes);
>  
>       switch (pd->proto) {
> @@ -7025,6 +7028,7 @@ done:
>                               if (s->state_flags & PFSTATE_SETPRIO)
>                                       pd.m->m_pkthdr.pf.prio = s->set_prio[0];
>                       }
> +                     pd.m->m_pkthdr.pf.delay = s->delay;
>               } else {
>                       pf_scrub(pd.m, r->scrub_flags, pd.af, r->min_ttl,
>                           r->set_tos);
> @@ -7037,6 +7041,7 @@ done:
>                               if (r->scrub_flags & PFSTATE_SETPRIO)
>                                       pd.m->m_pkthdr.pf.prio = r->set_prio[0];
>                       }
> +                     pd.m->m_pkthdr.pf.delay = r->delay;
>               }
>       }
>  
> Index: sys/net/pfvar.h
> ===================================================================
> RCS file: /cvs/src/sys/net/pfvar.h,v
> retrieving revision 1.476
> diff -u -p -r1.476 pfvar.h
> --- sys/net/pfvar.h   9 Feb 2018 09:35:03 -0000       1.476
> +++ sys/net/pfvar.h   10 Feb 2018 01:24:43 -0000
> @@ -459,11 +459,12 @@ struct pf_rule_actions {
>       u_int16_t       pqid;
>       u_int16_t       max_mss;
>       u_int16_t       flags;
> +     u_int16_t       delay;
>       u_int8_t        log;
>       u_int8_t        set_tos;
>       u_int8_t        min_ttl;
>       u_int8_t        set_prio[2];
> -     u_int8_t        pad[3];
> +     u_int8_t        pad[1];
>  };
>  
>  union pf_rule_ptr {
> @@ -546,6 +547,7 @@ struct pf_rule {
>       u_int16_t                tag;
>       u_int16_t                match_tag;
>       u_int16_t                scrub_flags;
> +     u_int16_t                delay;
>  
>       struct pf_rule_uid       uid;
>       struct pf_rule_gid       gid;
> @@ -605,8 +607,9 @@ struct pf_rule {
>  #define      PFRULE_RETURNICMP       0x0004
>  #define      PFRULE_RETURN           0x0008
>  #define      PFRULE_NOSYNC           0x0010
> -#define PFRULE_SRCTRACK              0x0020  /* track source states */
> -#define PFRULE_RULESRCTRACK  0x0040  /* per rule */
> +#define      PFRULE_SRCTRACK         0x0020  /* track source states */
> +#define      PFRULE_RULESRCTRACK     0x0040  /* per rule */
> +#define      PFRULE_SETDELAY         0x0080
>  
>  /* rule flags again */
>  #define PFRULE_IFBOUND               0x00010000      /* if-bound */
> @@ -761,6 +764,7 @@ struct pf_state {
>       int32_t                  creation;
>       int32_t                  expire;
>       int32_t                  pfsync_time;
> +     int                      rtableid[2];   /* rtables stack and wire */
>       u_int16_t                qid;
>       u_int16_t                pqid;
>       u_int16_t                tag;
> @@ -781,14 +785,13 @@ struct pf_state {
>       u_int8_t                 timeout;
>       u_int8_t                 sync_state; /* PFSYNC_S_x */
>       u_int8_t                 sync_updates;
> -     int                      rtableid[2];   /* rtables stack and wire */
>       u_int8_t                 min_ttl;
>       u_int8_t                 set_tos;
>       u_int8_t                 set_prio[2];
>       u_int16_t                max_mss;
>       u_int16_t                if_index_in;
>       u_int16_t                if_index_out;
> -     u_int8_t                 pad2[2];
> +     u_int16_t                delay;
>  };
>  
>  /*
> Index: sys/sys/mbuf.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/mbuf.h,v
> retrieving revision 1.235
> diff -u -p -r1.235 mbuf.h
> --- sys/sys/mbuf.h    11 Feb 2018 00:24:13 -0000      1.235
> +++ sys/sys/mbuf.h    11 Feb 2018 04:47:44 -0000
> @@ -100,10 +100,11 @@ struct pkthdr_pf {
>       struct inpcb    *inp;           /* connected pcb for outgoing packet */
>       u_int32_t        qid;           /* queue id */
>       u_int16_t        tag;           /* tag id */
> +     u_int16_t        delay;         /* delay packet by X ms */
>       u_int8_t         flags;
>       u_int8_t         routed;
>       u_int8_t         prio;
> -     u_int8_t         pad[3];
> +     u_int8_t         pad;
>  };
>  
>  /* pkthdr_pf.flags */
> Index: sbin/pfctl/parse.y
> ===================================================================
> RCS file: /cvs/src/sbin/pfctl/parse.y,v
> retrieving revision 1.670
> diff -u -p -r1.670 parse.y
> --- sbin/pfctl/parse.y        8 Feb 2018 09:15:46 -0000       1.670
> +++ sbin/pfctl/parse.y        9 Feb 2018 01:25:46 -0000
> @@ -236,6 +236,7 @@ struct filter_opts {
>  #define FOM_SETPRIO  0x0400
>  #define FOM_ONCE     0x1000
>  #define FOM_PRIO     0x2000
> +#define FOM_SETDELAY 0x4000
>       struct node_uid         *uid;
>       struct node_gid         *gid;
>       struct node_if          *rcv;
> @@ -262,6 +263,7 @@ struct filter_opts {
>       u_int                    rtableid;
>       u_int8_t                 prio;
>       u_int8_t                 set_prio[2];
> +     u_int16_t                delay;
>       struct divertspec        divert;
>       struct redirspec         nat;
>       struct redirspec         rdr;
> @@ -477,7 +479,7 @@ int       parseport(char *, struct range *r, i
>  %token       BITMASK RANDOM SOURCEHASH ROUNDROBIN LEASTSTATES STATICPORT 
> PROBABILITY
>  %token       WEIGHT BANDWIDTH FLOWS QUANTUM
>  %token       QUEUE PRIORITY QLIMIT RTABLE RDOMAIN MINIMUM BURST PARENT
> -%token       LOAD RULESET_OPTIMIZATION RTABLE RDOMAIN PRIO ONCE DEFAULT
> +%token       LOAD RULESET_OPTIMIZATION RTABLE RDOMAIN PRIO ONCE DEFAULT DELAY
>  %token       STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
>  %token       MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW MAXPKTRATE
>  %token       TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE
> @@ -978,6 +980,10 @@ anchorrule       : ANCHOR anchorname dir quick
>                               r.set_prio[1] = $9.set_prio[1];
>                               r.scrub_flags |= PFSTATE_SETPRIO;
>                       }
> +                     if ($9.marker & FOM_SETDELAY) {
> +                             r.delay = $9.delay;
> +                             r.rule_flag |= PFRULE_SETDELAY;
> +                     }
>  
>                       decide_address_family($8.src.host, &r.af);
>                       decide_address_family($8.dst.host, &r.af);
> @@ -1913,6 +1919,11 @@ pfrule         : action dir logquick interface 
>                               r.rule_flag |= PFRULE_FRAGMENT;
>                       r.allow_opts = $8.allowopts;
>  
> +                     if ($8.marker & FOM_SETDELAY) {
> +                             r.delay = $8.delay;
> +                             r.rule_flag |= PFRULE_SETDELAY;
> +                     }
> +
>                       decide_address_family($7.src.host, &r.af);
>                       decide_address_family($7.dst.host, &r.af);
>  
> @@ -2308,6 +2319,19 @@ filter_set     : prio {
>                       filter_opts.marker |= FOM_SETTOS;
>                       filter_opts.settos = $2;
>               }
> +             | DELAY NUMBER {
> +                     if (filter_opts.delay) {
> +                             yyerror("delay cannot be respecified");
> +                             YYERROR;
> +                     }
> +                     if ($2 < 0 || $2 > 0xffff) {
> +                             yyerror("illegal delay value %d (0-%u)", $2,
> +                                 0xffff);
> +                             YYERROR;
> +                     }
> +                     filter_opts.marker |= FOM_SETDELAY;
> +                     filter_opts.delay = $2;
> +             }
>               ;
>  
>  prio         : PRIO NUMBER {
> @@ -5110,6 +5134,7 @@ lookup(char *s)
>               { "code",               CODE},
>               { "debug",              DEBUG},
>               { "default",            DEFAULT},
> +             { "delay",              DELAY},
>               { "divert-packet",      DIVERTPACKET},
>               { "divert-reply",       DIVERTREPLY},
>               { "divert-to",          DIVERTTO},
> Index: sbin/pfctl/pfctl_parser.c
> ===================================================================
> RCS file: /cvs/src/sbin/pfctl/pfctl_parser.c,v
> retrieving revision 1.319
> diff -u -p -r1.319 pfctl_parser.c
> --- sbin/pfctl/pfctl_parser.c 8 Feb 2018 02:26:39 -0000       1.319
> +++ sbin/pfctl/pfctl_parser.c 9 Feb 2018 01:25:46 -0000
> @@ -871,30 +871,35 @@ print_rule(struct pf_rule *r, const char
>               printf(" max-pkt-rate %u/%u", r->pktrate.limit,
>                   r->pktrate.seconds);
>  
> -     if (r->scrub_flags & PFSTATE_SETMASK || r->qname[0]) {
> +     if (r->scrub_flags & PFSTATE_SETMASK || r->qname[0] ||
> +         r->rule_flag & PFRULE_SETDELAY) {
>               char *comma = "";
>               printf(" set (");
>               if (r->scrub_flags & PFSTATE_SETPRIO) {
>                       if (r->set_prio[0] == r->set_prio[1])
> -                             printf("%s prio %u", comma, r->set_prio[0]);
> +                             printf("%sprio %u", comma, r->set_prio[0]);
>                       else
> -                             printf("%s prio(%u, %u)", comma, r->set_prio[0],
> +                             printf("%sprio(%u, %u)", comma, r->set_prio[0],
>                                   r->set_prio[1]);
> -                     comma = ",";
> +                     comma = ", ";
>               }
>               if (r->qname[0]) {
>                       if (r->pqname[0])
> -                             printf("%s queue(%s, %s)", comma, r->qname,
> +                             printf("%squeue(%s, %s)", comma, r->qname,
>                                   r->pqname);
>                       else
> -                             printf("%s queue %s", comma, r->qname);
> -                     comma = ",";
> +                             printf("%squeue %s", comma, r->qname);
> +                     comma = ", ";
>               }
>               if (r->scrub_flags & PFSTATE_SETTOS) {
> -                     printf("%s tos 0x%2.2x", comma, r->set_tos);
> -                     comma = ",";
> +                     printf("%stos 0x%2.2x", comma, r->set_tos);
> +                     comma = ", ";
>               }
> -             printf(" )");
> +             if (r->rule_flag & PFRULE_SETDELAY) {
> +                     printf("%sdelay %u", comma, r->delay);
> +                     comma = ", ";
> +             }
> +             printf(")");
>       }
>  
>       ropts = 0;
> 

Reply via email to