> On 12 Oct 2015, at 12:00 AM, Alexandr Nedvedicky
> <[email protected]> wrote:
>
> Hello,
>
> patch below introduces struct refcnt to pfi_kif structure. Patch also changes
> pfi_kif_get() function to always return a reference to pfi_kif instance.
>
> Furthermore existing functions pfi_kif_ref()/pfi_kif_unref() are thrown away
> in favor of pfi_kif_take()/pfi_kif_rele(), which follow naming convention
> set by refcnt_init(9). Patch also removes kif reference types (enum
> pfi_kif_refs).
>
> Patch also updates if_pfsync.c file. I'm bit puzzled with test as follows
> in pfsync_in_clr():
>
> 770 for (i = 0; i < count; i++) {
> 771 clr = (struct pfsync_clr *)buf + len * i;
> 772 creatorid = clr->creatorid;
> 773
> 774 if (clr->ifname[0] == '\0') {
> ...
> 783 } else {
> 784 if (pfi_kif_get(clr->ifname) == NULL)
> 789 continue;
> 790
>
> I could not make any sense of line 784. Are we just making sure particular kif
> object exists for clr->ifname? Note pfi_kif_get() creates kif for us if it
> does not exist. If we want to query for kif existence only patch offers
> pfi_kif_check() function. I need some advice here if we should keep, what's
> currently in patch or switch to pfi_kif_check().
my name is probably against that code.
i didn't realise that pfi_kif_get creates a kif on demand. however, it also
uses malloc(, , M_NOWAIT) to try and allocate it, which can fail and cause
pfi_kif_get to return NULL.
>
> thanks and
> regards
> sasha
>
> ---------8<----------------8<----------------8<---------------8<--------
> Index: if_pfsync.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_pfsync.c,v
> retrieving revision 1.220
> diff -u -p -r1.220 if_pfsync.c
> --- if_pfsync.c 11 Sep 2015 08:17:06 -0000 1.220
> +++ if_pfsync.c 11 Oct 2015 13:46:11 -0000
> @@ -631,6 +631,8 @@ pfsync_state_import(struct pfsync_state
> }
> CLR(st->state_flags, PFSTATE_ACK);
>
> + pfi_kif_rele(kif);
> +
> return (0);
>
> cleanup:
> @@ -650,6 +652,9 @@ pfsync_state_import(struct pfsync_state
> pool_put(&pf_state_scrub_pl, st->src.scrub);
> pool_put(&pf_state_pl, st);
> }
> +
> + pfi_kif_rele(kif);
> +
> return (error);
> }
>
> @@ -759,6 +764,7 @@ pfsync_in_clr(caddr_t buf, int len, int
> struct pf_state *st, *nexts;
> struct pf_state_key *sk, *nextsk;
> struct pf_state_item *si;
> + struct pfi_kif *kif;
> u_int32_t creatorid;
>
> for (i = 0; i < count; i++) {
> @@ -775,7 +781,11 @@ pfsync_in_clr(caddr_t buf, int len, int
> }
> }
> } else {
> - if (pfi_kif_get(clr->ifname) == NULL)
> + /*
> + * Do we realize here the pfi_kif_get() actually
> + * creates kif for name if it does not exist?
> + */
> + if ((kif = pfi_kif_get(clr->ifname)) == NULL)
> continue;
>
> /* XXX correct? */
> @@ -791,6 +801,8 @@ pfsync_in_clr(caddr_t buf, int len, int
> }
> }
> }
> +
> + pfi_kif_rele(kif);
> }
> }
>
> Index: pf.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf.c,v
> retrieving revision 1.946
> diff -u -p -r1.946 pf.c
> --- pf.c 8 Oct 2015 11:36:51 -0000 1.946
> +++ pf.c 11 Oct 2015 13:46:14 -0000
> @@ -944,7 +944,7 @@ pf_state_insert(struct pfi_kif *kif, str
> TAILQ_INSERT_TAIL(&state_list, s, entry_list);
> pf_status.fcounters[FCNT_STATE_INSERT]++;
> pf_status.states++;
> - pfi_kif_ref(kif, PFI_KIF_REF_STATE);
> + pfi_kif_take(kif);
> #if NPFSYNC > 0
> pfsync_insert_state(s);
> #endif /* NPFSYNC > 0 */
> @@ -1315,7 +1315,7 @@ pf_free_state(struct pf_state *cur)
> pool_put(&pf_rule_item_pl, ri);
> }
> pf_normalize_tcp_cleanup(cur);
> - pfi_kif_unref(cur->kif, PFI_KIF_REF_STATE);
> + pfi_kif_rele(cur->kif);
> TAILQ_REMOVE(&state_list, cur, entry_list);
> if (cur->tag)
> pf_tag_unref(cur->tag);
> Index: pf_if.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf_if.c,v
> retrieving revision 1.80
> diff -u -p -r1.80 pf_if.c
> --- pf_if.c 4 Sep 2015 21:40:25 -0000 1.80
> +++ pf_if.c 11 Oct 2015 13:46:14 -0000
> @@ -107,7 +107,7 @@ pfi_kif_get(const char *kif_name)
> bzero(&s, sizeof(s));
> strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name));
> if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL)
> - return (kif);
> + return (pfi_kif_take(kif));
>
> /* create new one */
> if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT|M_ZERO)) == NULL)
> @@ -116,6 +116,7 @@ pfi_kif_get(const char *kif_name)
> strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name));
> kif->pfik_tzero = time_second;
> TAILQ_INIT(&kif->pfik_dynaddrs);
> + PF_REF_INIT(kif->pfik_refcnt);
>
> if (!strcmp(kif->pfik_name, "any")) {
> /* both so it works in the ioctl and the regular case */
> @@ -124,72 +125,21 @@ pfi_kif_get(const char *kif_name)
> }
>
> RB_INSERT(pfi_ifhead, &pfi_ifs, kif);
> + /*
> + * there is no pfi_kif_remove(), hence caller shares reference with
> + * pfi_ifs look up table.
> + */
> return (kif);
> }
>
> -void
> -pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
> -{
> - switch (what) {
> - case PFI_KIF_REF_RULE:
> - kif->pfik_rules++;
> - break;
> - case PFI_KIF_REF_STATE:
> - kif->pfik_states++;
> - break;
> - case PFI_KIF_REF_ROUTE:
> - kif->pfik_routes++;
> - break;
> - default:
> - panic("pfi_kif_ref with unknown type");
> - }
> -}
> -
> -void
> -pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
> +int
> +pfi_kif_check(const char *kif_name)
> {
> - if (kif == NULL)
> - return;
> -
> - switch (what) {
> - case PFI_KIF_REF_NONE:
> - break;
> - case PFI_KIF_REF_RULE:
> - if (kif->pfik_rules <= 0) {
> - DPFPRINTF(LOG_ERR,
> - "pfi_kif_unref: rules refcount <= 0");
> - return;
> - }
> - kif->pfik_rules--;
> - break;
> - case PFI_KIF_REF_STATE:
> - if (kif->pfik_states <= 0) {
> - DPFPRINTF(LOG_ERR,
> - "pfi_kif_unref: state refcount <= 0");
> - return;
> - }
> - kif->pfik_states--;
> - break;
> - case PFI_KIF_REF_ROUTE:
> - if (kif->pfik_routes <= 0) {
> - DPFPRINTF(LOG_ERR,
> - "pfi_kif_unref: state refcount <= 0");
> - return;
> - }
> - kif->pfik_routes--;
> - break;
> - default:
> - panic("pfi_kif_unref with unknown type");
> - }
> -
> - if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
> - return;
> -
> - if (kif->pfik_rules || kif->pfik_states || kif->pfik_routes)
> - return;
> + struct pfi_kif_cmp s;
>
> - RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
> - free(kif, PFI_MTYPE, 0);
> + bzero(&s, sizeof(s));
> + strlcpy(s.pfik_name, kif_name, sizeof (s.pfik_name));
> + return (RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s));
> }
>
> int
> @@ -258,7 +208,7 @@ pfi_detach_ifnet(struct ifnet *ifp)
>
> kif->pfik_ifp = NULL;
> ifp->if_pf_kif = NULL;
> - pfi_kif_unref(kif, PFI_KIF_REF_NONE);
> + pfi_kif_rele(kif);
>
> splx(s);
> }
> @@ -275,6 +225,7 @@ pfi_attach_ifgroup(struct ifg_group *ifg
> if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL)
> panic("pfi_kif_get failed");
>
> + KASSERT(kif->pfik_group == NULL);
> kif->pfik_group = ifg;
> ifg->ifg_pf_kif = (caddr_t)kif;
>
> @@ -295,7 +246,7 @@ pfi_detach_ifgroup(struct ifg_group *ifg
>
> kif->pfik_group = NULL;
> ifg->ifg_pf_kif = NULL;
> - pfi_kif_unref(kif, PFI_KIF_REF_NONE);
> + pfi_kif_rele(kif);
> splx(s);
> }
>
> @@ -312,6 +263,8 @@ pfi_group_change(const char *group)
>
> pfi_kif_update(kif);
>
> + pfi_kif_rele(kif);
> +
> splx(s);
> }
>
> @@ -371,7 +324,6 @@ pfi_dynaddr_setup(struct pf_addr_wrap *a
> rv = 1;
> goto _bad;
> }
> - pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE);
>
> dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
> if (af == AF_INET && dyn->pfid_net == 32)
> @@ -414,7 +366,7 @@ _bad:
> if (ruleset != NULL)
> pf_remove_if_empty_ruleset(ruleset);
> if (dyn->pfid_kif != NULL)
> - pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE);
> + pfi_kif_rele(dyn->pfid_kif);
> pool_put(&pfi_addr_pl, dyn);
> splx(s);
> return (rv);
> @@ -595,7 +547,7 @@ pfi_dynaddr_remove(struct pf_addr_wrap *
>
> s = splsoftnet();
> TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry);
> - pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE);
> + pfi_kif_rele(aw->p.dyn->pfid_kif);
> aw->p.dyn->pfid_kif = NULL;
> pfr_detach_table(aw->p.dyn->pfid_kt);
> aw->p.dyn->pfid_kt = NULL;
> @@ -709,14 +661,14 @@ pfi_get_ifaces(const char *name, struct
> if (*size > n++) {
> if (!p->pfik_tzero)
> p->pfik_tzero = time_second;
> - pfi_kif_ref(p, PFI_KIF_REF_RULE);
> + pfi_kif_take(p);
> if (copyout(p, buf++, sizeof(*buf))) {
> - pfi_kif_unref(p, PFI_KIF_REF_RULE);
> + pfi_kif_rele(p);
> splx(s);
> return (EFAULT);
> }
> nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
> - pfi_kif_unref(p, PFI_KIF_REF_RULE);
> + pfi_kif_rele(p);
> }
> }
> splx(s);
> @@ -810,3 +762,28 @@ pfi_unmask(void *addr)
> return (b);
> }
>
> +struct pfi_kif *
> +pfi_kif_take(struct pfi_kif *kif)
> +{
> + if (kif != pfi_all) {
> + PF_REF_TAKE(kif->pfik_refcnt);
> + }
> +
> + return (kif);
> +}
> +
> +void
> +pfi_kif_rele(struct pfi_kif *kif)
> +{
> + if (kif == pfi_all)
> + return;
> +
> + if (PF_REF_RELE(kif->pfik_refcnt)) {
> + KASSERT(kif->pfik_ifp == NULL);
> + KASSERT(kif->pfik_group == NULL);
> + KASSERT(TAILQ_EMPTY(&kif->pfik_dynaddrs));
> +
> + RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
> + free(kif, PFI_MTYPE, 0);
> + }
> +}
> Index: pf_ioctl.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf_ioctl.c,v
> retrieving revision 1.290
> diff -u -p -r1.290 pf_ioctl.c
> --- pf_ioctl.c 4 Sep 2015 21:40:25 -0000 1.290
> +++ pf_ioctl.c 11 Oct 2015 13:46:15 -0000
> @@ -289,11 +289,11 @@ pf_rm_rule(struct pf_rulequeue *rulequeu
> if (rule->overload_tbl)
> pfr_detach_table(rule->overload_tbl);
> }
> - pfi_kif_unref(rule->rcv_kif, PFI_KIF_REF_RULE);
> - pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
> - pfi_kif_unref(rule->rdr.kif, PFI_KIF_REF_RULE);
> - pfi_kif_unref(rule->nat.kif, PFI_KIF_REF_RULE);
> - pfi_kif_unref(rule->route.kif, PFI_KIF_REF_RULE);
> + PFI_KIF_RELE(rule->rcv_kif);
> + PFI_KIF_RELE(rule->kif);
> + PFI_KIF_RELE(rule->rdr.kif);
> + PFI_KIF_RELE(rule->nat.kif);
> + PFI_KIF_RELE(rule->route.kif);
> pf_anchor_remove(rule);
> pool_put(&pf_rule_pl, rule);
> }
> @@ -529,7 +529,7 @@ pf_free_queues(struct pf_queuehead *wher
> if (ifp && q->kif->pfik_ifp != ifp)
> continue;
> TAILQ_REMOVE(where, q, entries);
> - pfi_kif_unref(q->kif, PFI_KIF_REF_RULE);
> + PFI_KIF_RELE(q->kif);
> pool_put(&pf_queue_pl, q);
> }
> return (0);
> @@ -788,8 +788,6 @@ pf_kif_setup(char *ifname, struct pfi_ki
> *kif = pfi_kif_get(ifname);
> if (*kif == NULL)
> return (EINVAL);
> -
> - pfi_kif_ref(*kif, PFI_KIF_REF_RULE);
> } else
> *kif = NULL;
>
> @@ -1035,7 +1033,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
> break;
> }
> /* XXX resolve bw percentage specs */
> - pfi_kif_ref(qs->kif, PFI_KIF_REF_RULE);
> if (qs->qlimit == 0)
> qs->qlimit = HFSC_DEFAULT_QLIMIT;
> TAILQ_INSERT_TAIL(pf_queues_inactive, qs, entries);
> Index: pf_table.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf_table.c,v
> retrieving revision 1.115
> diff -u -p -r1.115 pf_table.c
> --- pf_table.c 7 Oct 2015 11:57:44 -0000 1.115
> +++ pf_table.c 11 Oct 2015 13:46:17 -0000
> @@ -847,8 +847,6 @@ pfr_create_kentry(struct pfr_addr *ad)
> case PFRKE_ROUTE:
> if (ad->pfra_ifname[0])
> ke->pfrke_rkif = pfi_kif_get(ad->pfra_ifname);
> - if (ke->pfrke_rkif)
> - pfi_kif_ref(ke->pfrke_rkif, PFI_KIF_REF_ROUTE);
> break;
> default:
> panic("unknown pfrke_type %d", ke->pfrke_type);
> @@ -893,8 +891,7 @@ pfr_destroy_kentry(struct pfr_kentry *ke
> if (ke->pfrke_counters)
> pool_put(&pfr_kcounters_pl, ke->pfrke_counters);
> if (ke->pfrke_type == PFRKE_COST || ke->pfrke_type == PFRKE_ROUTE)
> - pfi_kif_unref(((struct pfr_kentry_all *)ke)->pfrke_rkif,
> - PFI_KIF_REF_ROUTE);
> + pfi_kif_rele(((struct pfr_kentry_all *)ke)->pfrke_rkif);
> pool_put(&pfr_kentry_pl[ke->pfrke_type], ke);
> }
>
> Index: pfvar.h
> ===================================================================
> RCS file: /cvs/src/sys/net/pfvar.h,v
> retrieving revision 1.420
> diff -u -p -r1.420 pfvar.h
> --- pfvar.h 19 Aug 2015 21:22:41 -0000 1.420
> +++ pfvar.h 11 Oct 2015 13:46:17 -0000
> @@ -38,6 +38,7 @@
> #include <sys/tree.h>
> #include <sys/rwlock.h>
> #include <sys/syslimits.h>
> +#include <sys/refcnt.h>
>
> #include <net/radix.h>
> #include <net/route.h>
> @@ -55,6 +56,8 @@ struct ip6_hdr;
> #endif
> #endif
>
> +typedef struct refcnt pf_refcnt_t;
> +
> enum { PF_INOUT, PF_IN, PF_OUT, PF_FWD };
> enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT,
> PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER,
> @@ -1125,17 +1128,8 @@ struct pfi_kif {
> void *pfik_ah_cookie;
> struct ifnet *pfik_ifp;
> struct ifg_group *pfik_group;
> - int pfik_states;
> - int pfik_rules;
> - int pfik_routes;
> TAILQ_HEAD(, pfi_dynaddr) pfik_dynaddrs;
> -};
> -
> -enum pfi_kif_refs {
> - PFI_KIF_REF_NONE,
> - PFI_KIF_REF_STATE,
> - PFI_KIF_REF_RULE,
> - PFI_KIF_REF_ROUTE
> + pf_refcnt_t pfik_refcnt;
> };
>
> #define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface
> */
> @@ -1811,8 +1805,9 @@ extern struct pfi_kif *pfi_all;
>
> void pfi_initialize(void);
> struct pfi_kif *pfi_kif_get(const char *);
> -void pfi_kif_ref(struct pfi_kif *, enum pfi_kif_refs);
> -void pfi_kif_unref(struct pfi_kif *, enum pfi_kif_refs);
> +struct pfi_kif *pfi_kif_take(struct pfi_kif *);
> +void pfi_kif_rele(struct pfi_kif *);
> +int pfi_kif_check(const char *);
> int pfi_kif_match(struct pfi_kif *, struct pfi_kif *);
> void pfi_attach_ifnet(struct ifnet *);
> void pfi_detach_ifnet(struct ifnet *);
> @@ -1909,5 +1904,16 @@ void pf_cksum(struct pf_pdesc *,
> stru
>
> #endif /* _KERNEL */
>
> +#define PF_REF_INIT(_x_) refcnt_init(&(_x_))
> +
> +#define PF_REF_TAKE(_x_) refcnt_take(&(_x_))
> +
> +#define PF_REF_RELE(_x_) refcnt_rele(&(_x_))
> +
> +#define PFI_KIF_TAKE(_kif_) \
> + (((_kif_) != NULL) ? pfi_kif_take((_kif_)) : NULL)
> +
> +#define PFI_KIF_RELE(_kif_) \
> + (((_kif_) != NULL) ? pfi_kif_rele((_kif_)) : ((void)(0)))
>
> #endif /* _NET_PFVAR_H_ */
>
it all looks good to me. ok.
dlg