On Sun, Apr 05, 2015 at 12:06 +0200, Alexandr Nedvedicky wrote:
> Hello,
> 
> while testing PBR on Solaris we found out the pfi_kif instances
> are not removed from pfi_ifs table. We took a look at crashdump
> and have seen pfik_route counter at those object is still
> non-zero, while all rules were gone.
> 
> looking at sources we can see the 'pfik_route' (PFI_KIF_REF_ROUTE)
> reference is being grabbed in pfr_create_kentry():
> 
> 840   case PFRKE_ROUTE:
> 841           if (ad->pfra_ifname[0])
> 842                   ke->pfrke_rkif = pfi_kif_get(ad->pfra_ifname);
> 843           if (ke->pfrke_rkif)
> 844                   pfi_kif_ref(ke->pfrke_rkif, PFI_KIF_REF_ROUTE);
> 845           break;
> 846   default:
> 847           panic("unknown pfrke_type %d", ke->pfrke_type);
> 848           break;
> 
> however we have not found any matching pfi_kif_ref() command, which
> would remove the reference created by pfr_create_kentry(). It seems
> to us the call to
> 
>       pfi_kif_unref(ke->pfrke_rkif, PFI_KIF_REF_ROUTE)
> 
> is missing at pfr_destroy_kentry(). We created patch against OpenBSD CURRENT.
> We have no OpenBSD boxes around, where we could verify our fix.
> 
> also for your info: IPF in Solaris is on its death row. PF in 11.3
> release will be available as optional firewall. We hope to make PF
> default (and only firewall) in Solaris 12. You've made excellent job,
> your PF is crystal-clear design.
> 
> kind regards
> sasha
> 
> ----------- cut here to get a patch ---------------
> 
> Index: pf_table.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf_table.c,v
> retrieving revision 1.106
> diff -u -r1.106 pf_table.c
> --- pf_table.c  14 Mar 2015 03:38:51 -0000      1.106
> +++ pf_table.c  5 Apr 2015 09:59:58 -0000
> @@ -877,6 +877,17 @@
>  {
>         if (ke->pfrke_counters)
>                 pool_put(&pfr_kcounters_pl, ke->pfrke_counters);
> +
> +       switch (ke->pfrke_type) {
> +       case PFRKE_COST:
> +               /* FALLTHROUGH */
> +       case PFRKE_ROUTE:
> +               if (ke->pfrke_rkif != NULL) {
> +                       pfi_kif_unref(ke->pfrke_rkif, PFI_KIF_REF_ROUTE);
> +               }
> +               break;
> +       default:
> +       }
>         pool_put(&pfr_kentry_pl[ke->pfrke_type], ke);
>  }
> 
> 

Hi,

Your analysis is correct.  I'd drop the switch statement here for
simplicity though.

Anyone's willing to OK?

diff --git sys/net/pf_table.c sys/net/pf_table.c
index 10e6e4f..6c32c68 100644
--- sys/net/pf_table.c
+++ sys/net/pf_table.c
@@ -875,10 +875,13 @@ pfr_destroy_kentries(struct pfr_kentryworkq *workq)
 void
 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);
        pool_put(&pfr_kentry_pl[ke->pfrke_type], ke);
 }
 
 void
 pfr_insert_kentries(struct pfr_ktable *kt,

Reply via email to