tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

NPF PFIL_OUT direction fails for bridge



I am playing around with rumpkernel and NetBSD with BRIDGE_IPF enabled. I have a bridge with 2 interfaces dpdk0 and dpdk1.
NPF rules are such that all stateful filtering happens on dpdk0 interface only. dpdk1 has a single rule NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_PASS | NPF_RULE_FINAL.

PFIL_IN direction (packets from bridge_forward) works just fine - npf hooks are called and npf connection tracking entries are created as expected.

PFIL_OUT direction (packets from bridge_enqueue) does not work - npf hook is called but mbuf chain is not what npf code expects.

Let me explain what happens. Please refer to bridge_ipf() code (sys/net/if_bridge.c).

If you look at bridge_ipf(), it strips ethernet header, calls pfil hooks and restores ethernet header by adding it back with M_PREPEND(). Even though mbuf has leading space (we just removed same amount of bytes with m_adj()), it cannot be used because mbuf is not writable. Thus M_PREPEND() causes adding of new mbuf.

So on first pass (PFIL_IN) everything is fine, but on second pass (PFIL_OUT) we end up with mbuf chain where first mbuf is empty before call to pfil hooks.
Normally this wouldn't be a problem but npf code (specifically npf_cache_ip()) seems to assume that data has been pulled up. It ends up checking IP version from first byte of L2 header and fails.

Current code in bridge_ipf() calls bridge_ip_checkbasic()/bridge_ip6_checkbasic() that does pullup. But it only calls it for PFIL_IN direction. Why is it not done for both directions?

Long story short, attached patch fixed the issue for me.

Thanks,
Krists

--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -2557,13 +2557,13 @@ bridge_ipf(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
 	switch (ether_type)
 	{
 	case ETHERTYPE_IP :
-		error = (dir == PFIL_IN) ? bridge_ip_checkbasic(mp) : 0;
+		error = bridge_ip_checkbasic(mp);
 		if (error == 0)
 			error = pfil_run_hooks(inet_pfil_hook, mp, ifp, dir);
 		break;
 # ifdef INET6
 	case ETHERTYPE_IPV6 :
-		error = (dir == PFIL_IN) ? bridge_ip6_checkbasic(mp) : 0;
+		error = bridge_ip6_checkbasic(mp);
 		if (error == 0)
 			error = pfil_run_hooks(inet6_pfil_hook, mp, ifp, dir);
 		break;


Home | Main Index | Thread Index | Old Index