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 *);