Hello Richard,
thanks for taking a look at this. I'm not sure. ioctl() basically handles the
insertion/load of rules. Rule might be actually pre-loaded before desired
interface will come alive. So in general ioctl() always want to make
sure the pfi_kif interface object referenced by rule exists.
especially in cases where we do:
...->kif = pfi_kif_get(...)
> pf_ioctl.c
> 1031 qs->kif = pfi_kif_get(qs->ifname);
> 1032 if (qs->kif == NULL) {
> 1033 pool_put(&pf_queue_pl, qs);
> 1034 error = ESRCH;
> 1035 break;
> 1036 }
I took a quick look at your patch. I have one comment:
> - if ((kif = pfi_kif_get(sp->ifname)) == NULL) {
> + if ((kif = pfi_kif_find(sp->ifname)) == NULL) {
> DPFPRINTF(LOG_NOTICE, "pfsync_state_import: "
> "unknown interface: %s", sp->ifname);
> if (flags & PFSYNC_SI_IOCTL)
> @@ -493,6 +493,9 @@ pfsync_state_import(struct pfsync_state
> if (sp->af == 0)
> return (0); /* skip this state */
>
> + kif = pfi_kif_get(sp->ifname);
> + KASSERT(kif != NULL);
introducing pfi_kif_find() followed by pfi_kif_get() is overkill. I think
pfi_kif_find() should return a reference to existing kif and NULL if desired
interface does not exist. This is more friendly with respect to upcoming
MP changes.
thanks and
regards
sasha
On Thu, Oct 15, 2015 at 11:57:26AM +1300, Richard Procter wrote:
> Hi Sasha,
>
> I notice the calls in pf_ioctl.c below may not intend to create a new kif,
> either.
>
> In constrast all but one of the calls in pf_if.c treat pfi_kfi_get() == NULL
> as a panic, suggesting they test for out-of-memory conditions. The exception
> may also intend to find, not create.
>
> This confusion suggests that pfi_kif_get() is poorly named or does too much.
>
> I include a slight tweak on your patch below as another possibility, renaming
> check to find and using find in pfi_kif_get(). I find it hard to think of a
> better name for pfi_kif_get(), though. Maybe pfi_kif_realize(const char
> *kif_name)?
>
> best,
> Richard.
>
> These following may intend a find but I don't know for sure.
>
> pf_ioctl.c
> 1031 qs->kif = pfi_kif_get(qs->ifname);
> 1032 if (qs->kif == NULL) {
> 1033 pool_put(&pf_queue_pl, qs);
> 1034 error = ESRCH;
> 1035 break;
> 1036 }
>
> pf_ioctl.c
> 0785 pf_kif_setup(char *ifname, struct pfi_kif **kif)
> 0786 {
> 0787 if (ifname[0]) {
> 0788 *kif = pfi_kif_get(ifname);
> 0789 if (*kif == NULL)
> 0790 return (EINVAL);
> 0791
> 0792 pfi_kif_ref(*kif, PFI_KIF_REF_RULE);
> 0793 } else
> 0794 *kif = NULL;
> 0795
> 0796 return (0);
> 0797 }
> 0798
>
> pf_if.c
> 0365 s = splsoftnet();
> 0366 if (!strcmp(aw->v.ifname, "self"))
> 0367 dyn->pfid_kif = pfi_kif_get(IFG_ALL);
> 0368 else
> 0369 dyn->pfid_kif = pfi_kif_get(aw->v.ifname);
> 0370 if (dyn->pfid_kif == NULL) {
> 0371 rv = 1;
> 0372 goto _bad;
> 0373 }
>
> Index: net/if_pfsync.c
> ===================================================================
> --- net.orig/if_pfsync.c
> +++ net/if_pfsync.c
> @@ -482,7 +482,7 @@ pfsync_state_import(struct pfsync_state
> return (EINVAL);
> }
>
> - if ((kif = pfi_kif_get(sp->ifname)) == NULL) {
> + if ((kif = pfi_kif_find(sp->ifname)) == NULL) {
> DPFPRINTF(LOG_NOTICE, "pfsync_state_import: "
> "unknown interface: %s", sp->ifname);
> if (flags & PFSYNC_SI_IOCTL)
> @@ -493,6 +493,9 @@ pfsync_state_import(struct pfsync_state
> if (sp->af == 0)
> return (0); /* skip this state */
>
> + kif = pfi_kif_get(sp->ifname);
> + KASSERT(kif != NULL);
> +
> /*
> * 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.
> @@ -775,7 +778,7 @@ pfsync_in_clr(caddr_t buf, int len, int
> }
> }
> } else {
> - if (pfi_kif_get(clr->ifname) == NULL)
> + if (pfi_kif_find(clr->ifname) == NULL)
> continue;
>
> /* XXX correct? */
> Index: net/pf_if.c
> ===================================================================
> --- net.orig/pf_if.c
> +++ net/pf_if.c
> @@ -99,14 +99,22 @@ pfi_initialize(void)
> }
>
> struct pfi_kif *
> -pfi_kif_get(const char *kif_name)
> +pfi_kif_find(const char *kif_name)
> {
> - struct pfi_kif *kif;
> - struct pfi_kif_cmp s;
> + struct pfi_kif_cmp s;
>
> 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 (RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s));
> +}
> +
> +struct pfi_kif *
> +pfi_kif_get(const char *kif_name)
> +{
> + struct pfi_kif *kif;
> +
> + if ((kif = pfi_kif_find(kif_name)) != NULL)
> return (kif);
>
> /* create new one */
> Index: net/pfvar.h
> ===================================================================
> --- net.orig/pfvar.h
> +++ net/pfvar.h
> @@ -1810,6 +1810,7 @@ int pfr_ina_define(struct pfr_table *, s
> extern struct pfi_kif *pfi_all;
>
> void pfi_initialize(void);
> +struct pfi_kif *pfi_kif_find(const char *);
> 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);
>
>
> On 15/10/2015, at 2:11 AM, Alexandr Nedvedicky wrote:
>
> > Hello,
> >
> > While reviewing patch, which introduces MP-friendly reference counting for
> > pfi_kif objects (PF stuff), we've found some 'interesting detail' in
> > if_pfsync.c,
> > which I think should get addressed by extra patch.
> >
> > It looks like if_pfsync.c module does not realize, the pfi_kif_get()
> > actually
> > always attempt to create a pfi_kif instance, if it does not exist already.
> > This particular module rather needs a pfi_kif_check() function, which
> > returns 0
> > if pfi_kif does not exist for name, non-zero otherwise. To support my
> > statement I'm going to bring two snippets from if_pfsync.c:
> >
> > snippet (1)
> >
> > 470 pfsync_state_import(struct pfsync_state *sp, int flags)
> > 471 {
> > 472 struct pf_state *st = NULL;
> > 473 struct pf_state_key *skw = NULL, *sks = NULL;
> > 474 struct pf_rule *r = NULL;
> > 475 struct pfi_kif *kif;
> > 476 int pool_flags;
> > 477 int error;
> > 478
> > 479 if (sp->creatorid == 0) {
> > 480 DPFPRINTF(LOG_NOTICE, "pfsync_state_import: "
> > 481 "invalid creator id: %08x",
> > ntohl(sp->creatorid));
> > 482 return (EINVAL);
> > 483 }
> > 484
> > 485 if ((kif = pfi_kif_get(sp->ifname)) == NULL) {
> > 486 DPFPRINTF(LOG_NOTICE, "pfsync_state_import: "
> > 487 "unknown interface: %s", sp->ifname);
> > 488 if (flags & PFSYNC_SI_IOCTL)
> > 489 return (EINVAL);
> > 490 return (0); /* skip this state */
> > 491 }
> >
> > snippet (2)
> >
> > 756 pfsyn_in_clr(caddr_t buf, int len, int count, int flags)
> > 755 {
> > 756 struct pfsync_clr *clr;
> > 757 int i;
> > ...
> > 764 for (i = 0; i < count; i++) {
> > ... }
> > 777 } else {
> > 778 if (pfi_kif_get(clr->ifname) == NULL)
> > 779 continue;
> > ...
> > 795 }
> >
> > in both cases we actually want to use pfi_kif_get() to verify if interface
> > with
> > desired '->ifname' exists in PF. Consider we are trying to import state,
> > which
> > is bound to interface (if-bound). Let's further assume imported state is
> > bound
> > to `eexist0` interface. There is no such `eexist0` network interface on PF
> > node, where we attempt to import state to. In current if_pfsync.c so we
> > actually use pfi_kif_get() to create such interface for us in PF at least,
> > we
> > create pfi_kif with no real HW behind. This will keep imported state
> > consistent,
> > however it wastes resources, because the state is doomed to time out
> > anyway, as
> > there will be no matching packets for it. No one can expect there will be
> > packet bound to `eexist0` interface, if such interface does not exist.
> >
> > So I really think the if_pfsync.c should rather be doing pfi_kif_check()
> > instead of pfi_kif_get(). However I must admit I don't know all details
> > here.
> >
> > opinions/OKs much appreciated here...
> >
> > 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 14 Oct 2015 12:18:57 -0000
> > @@ -482,13 +482,15 @@ pfsync_state_import(struct pfsync_state
> > return (EINVAL);
> > }
> >
> > - if ((kif = pfi_kif_get(sp->ifname)) == NULL) {
> > + if (pfi_kif_check(sp->ifname) == 0) {
> > DPFPRINTF(LOG_NOTICE, "pfsync_state_import: "
> > "unknown interface: %s", sp->ifname);
> > if (flags & PFSYNC_SI_IOCTL)
> > return (EINVAL);
> > return (0); /* skip this state */
> > }
> > + kif = pfi_kif_get(sp->ifname);
> > + KASSERT(kif != NULL);
> >
> > if (sp->af == 0)
> > return (0); /* skip this state */
> > @@ -775,7 +777,7 @@ pfsync_in_clr(caddr_t buf, int len, int
> > }
> > }
> > } else {
> > - if (pfi_kif_get(clr->ifname) == NULL)
> > + if (pfi_kif_check(clr->ifname) == 0)
> > continue;
> >
> > /* XXX correct? */
> > 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 14 Oct 2015 12:18:58 -0000
> > @@ -127,6 +127,16 @@ pfi_kif_get(const char *kif_name)
> > return (kif);
> > }
> >
> > +int
> > +pfi_kif_check(const char *kif_name)
> > +{
> > + struct pfi_kif_cmp s;
> > +
> > + 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) != NULL);
> > +}
> > +
> > void
> > pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
> > {
> > Index: pfvar.h
> > ===================================================================
> > RCS file: /cvs/src/sys/net/pfvar.h,v
> > retrieving revision 1.421
> > diff -u -p -r1.421 pfvar.h
> > --- pfvar.h 13 Oct 2015 19:32:32 -0000 1.421
> > +++ pfvar.h 14 Oct 2015 12:18:59 -0000
> > @@ -1811,6 +1811,7 @@ extern struct pfi_kif *pfi_all;
> >
> > void pfi_initialize(void);
> > struct pfi_kif *pfi_kif_get(const char *);
> > +int pfi_kif_check(const char *);
> > void pfi_kif_ref(struct pfi_kif *, enum pfi_kif_refs);
> > void pfi_kif_unref(struct pfi_kif *, enum pfi_kif_refs);
> > int pfi_kif_match(struct pfi_kif *, struct pfi_kif *);
> >
>