Reduce the size of struct ip_fw_args from 240 to 128 bytes on amd64.
And refactor the code to avoid unneeded initialization to reduce overhead of per-packet processing. ipfw(4) can be invoked by pfil(9) framework for each packet several times. Each call uses on-stack variable of type struct ip_fw_args to keep the state of ipfw(4) processing. Currently this variable has 240 bytes size on amd64. Each time ipfw(4) does bzero() on it, and then it initializes some fields. glebius@ has reported that they at Netflix discovered, that initialization of this variable produces significant overhead on packet processing. After patching I managed to increase performance of packet processing on simple routing with ipfw(4) firewalling to about 11% from 9.8Mpps up to 11Mpps (Xeon E5-2660 v4@ + Mellanox 100G card). Introduced new field flags, it is used to keep track of what fields was initialized. Some fields were moved into the anonymous union, to reduce the size. They all are mutually exclusive. dummypar field was unused, and therefore it is removed. The hopstore6 field type was changed from sockaddr_in6 to a bit smaller struct ip_fw_nh6. And now the size of struct ip_fw_args is 128 bytes. ipfw_chk() was modified to properly handle ip_fw_args.flags instead of rely on checking for NULL pointers. Reviewed by: gallatin Obtained from: Yandex LLC MFC after: 1 month Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D18690
This commit is contained in:
parent
c962ca9f2d
commit
1cdf23bc03
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=342908
@ -1191,6 +1191,7 @@ set_match(struct ip_fw_args *args, int slot,
|
||||
args->rule.slot = slot + 1; /* we use 0 as a marker */
|
||||
args->rule.rule_id = 1 + chain->map[slot]->id;
|
||||
args->rule.rulenum = chain->map[slot]->rulenum;
|
||||
args->flags |= IPFW_ARGS_REF;
|
||||
}
|
||||
|
||||
#ifndef LINEAR_SKIPTO
|
||||
@ -1376,17 +1377,12 @@ ipfw_chk(struct ip_fw_args *args)
|
||||
* Only valid for IPv4 packets.
|
||||
*/
|
||||
uint8_t proto;
|
||||
uint16_t src_port = 0, dst_port = 0; /* NOTE: host format */
|
||||
uint16_t src_port, dst_port; /* NOTE: host format */
|
||||
struct in_addr src_ip, dst_ip; /* NOTE: network format */
|
||||
int iplen = 0;
|
||||
int pktlen;
|
||||
uint16_t etype = 0; /* Host order stored ether type */
|
||||
uint16_t etype; /* Host order stored ether type */
|
||||
|
||||
/*
|
||||
* dyn_dir = MATCH_UNKNOWN when rules unchecked,
|
||||
* MATCH_NONE when checked and not matched (q = NULL),
|
||||
* MATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL)
|
||||
*/
|
||||
struct ipfw_dyn_info dyn_info;
|
||||
struct ip_fw *q = NULL;
|
||||
struct ip_fw_chain *chain = &V_layer3_chain;
|
||||
@ -1415,9 +1411,6 @@ ipfw_chk(struct ip_fw_args *args)
|
||||
dst_ip.s_addr = 0; /* make sure it is initialized */
|
||||
src_ip.s_addr = 0; /* make sure it is initialized */
|
||||
pktlen = m->m_pkthdr.len;
|
||||
args->f_id.fib = M_GETFIB(m); /* note mbuf not altered) */
|
||||
proto = args->f_id.proto = 0; /* mark f_id invalid */
|
||||
/* XXX 0 is a valid proto: IP/IPv6 Hop-by-Hop Option */
|
||||
|
||||
DYN_INFO_INIT(&dyn_info);
|
||||
/*
|
||||
@ -1441,18 +1434,19 @@ do { \
|
||||
/*
|
||||
* if we have an ether header,
|
||||
*/
|
||||
if (args->eh)
|
||||
if (args->flags & IPFW_ARGS_ETHER)
|
||||
etype = ntohs(args->eh->ether_type);
|
||||
else
|
||||
etype = 0;
|
||||
|
||||
/* Identify IP packets and fill up variables. */
|
||||
if (pktlen >= sizeof(struct ip6_hdr) &&
|
||||
(args->eh == NULL || etype == ETHERTYPE_IPV6) && ip->ip_v == 6) {
|
||||
(etype == 0 || etype == ETHERTYPE_IPV6) && ip->ip_v == 6) {
|
||||
struct ip6_hdr *ip6 = (struct ip6_hdr *)ip;
|
||||
|
||||
is_ipv6 = 1;
|
||||
args->f_id.addr_type = 6;
|
||||
hlen = sizeof(struct ip6_hdr);
|
||||
proto = ip6->ip6_nxt;
|
||||
|
||||
/* Search extension headers to find upper layer protocols */
|
||||
while (ulp == NULL && offset == 0) {
|
||||
switch (proto) {
|
||||
@ -1627,20 +1621,18 @@ do { \
|
||||
}
|
||||
ip = mtod(m, struct ip *);
|
||||
ip6 = (struct ip6_hdr *)ip;
|
||||
args->f_id.addr_type = 6;
|
||||
args->f_id.src_ip6 = ip6->ip6_src;
|
||||
args->f_id.dst_ip6 = ip6->ip6_dst;
|
||||
args->f_id.src_ip = 0;
|
||||
args->f_id.dst_ip = 0;
|
||||
args->f_id.flow_id6 = ntohl(ip6->ip6_flow);
|
||||
iplen = ntohs(ip6->ip6_plen) + sizeof(*ip6);
|
||||
} else if (pktlen >= sizeof(struct ip) &&
|
||||
(args->eh == NULL || etype == ETHERTYPE_IP) && ip->ip_v == 4) {
|
||||
is_ipv4 = 1;
|
||||
(etype == 0 || etype == ETHERTYPE_IP) && ip->ip_v == 4) {
|
||||
is_ipv4 = 1;
|
||||
hlen = ip->ip_hl << 2;
|
||||
args->f_id.addr_type = 4;
|
||||
|
||||
/*
|
||||
* Collect parameters into local variables for faster matching.
|
||||
* Collect parameters into local variables for faster
|
||||
* matching.
|
||||
*/
|
||||
proto = ip->ip_p;
|
||||
src_ip = ip->ip_src;
|
||||
@ -1693,23 +1685,31 @@ do { \
|
||||
}
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
args->f_id.addr_type = 4;
|
||||
args->f_id.src_ip = ntohl(src_ip.s_addr);
|
||||
args->f_id.dst_ip = ntohl(dst_ip.s_addr);
|
||||
} else {
|
||||
proto = 0;
|
||||
src_port = dst_port = 0;
|
||||
dst_ip.s_addr = src_ip.s_addr = 0;
|
||||
|
||||
args->f_id.addr_type = 1; /* XXX */
|
||||
}
|
||||
#undef PULLUP_TO
|
||||
pktlen = iplen < pktlen ? iplen: pktlen;
|
||||
if (proto) { /* we may have port numbers, store them */
|
||||
args->f_id.proto = proto;
|
||||
args->f_id.src_port = src_port = ntohs(src_port);
|
||||
args->f_id.dst_port = dst_port = ntohs(dst_port);
|
||||
}
|
||||
|
||||
/* Properly initialize the rest of f_id */
|
||||
args->f_id.proto = proto;
|
||||
args->f_id.src_port = src_port = ntohs(src_port);
|
||||
args->f_id.dst_port = dst_port = ntohs(dst_port);
|
||||
args->f_id.fib = M_GETFIB(m);
|
||||
|
||||
IPFW_PF_RLOCK(chain);
|
||||
if (! V_ipfw_vnet_ready) { /* shutting down, leave NOW. */
|
||||
IPFW_PF_RUNLOCK(chain);
|
||||
return (IP_FW_PASS); /* accept */
|
||||
}
|
||||
if (args->rule.slot) {
|
||||
if (args->flags & IPFW_ARGS_REF) {
|
||||
/*
|
||||
* Packet has already been tagged as a result of a previous
|
||||
* match on rule args->rule aka args->rule_id (PIPE, QUEUE,
|
||||
@ -1837,7 +1837,7 @@ do { \
|
||||
break;
|
||||
|
||||
case O_MACADDR2:
|
||||
if (args->eh != NULL) { /* have MAC header */
|
||||
if (args->flags & IPFW_ARGS_ETHER) {
|
||||
u_int32_t *want = (u_int32_t *)
|
||||
((ipfw_insn_mac *)cmd)->addr;
|
||||
u_int32_t *mask = (u_int32_t *)
|
||||
@ -1852,7 +1852,7 @@ do { \
|
||||
break;
|
||||
|
||||
case O_MAC_TYPE:
|
||||
if (args->eh != NULL) {
|
||||
if (args->flags & IPFW_ARGS_ETHER) {
|
||||
u_int16_t *p =
|
||||
((ipfw_insn_u16 *)cmd)->ports;
|
||||
int i;
|
||||
@ -1873,19 +1873,21 @@ do { \
|
||||
break;
|
||||
|
||||
case O_LAYER2:
|
||||
match = (args->eh != NULL);
|
||||
match = (args->flags & IPFW_ARGS_ETHER);
|
||||
break;
|
||||
|
||||
case O_DIVERTED:
|
||||
{
|
||||
/* For diverted packets, args->rule.info
|
||||
if ((args->flags & IPFW_ARGS_REF) == 0)
|
||||
break;
|
||||
/*
|
||||
* For diverted packets, args->rule.info
|
||||
* contains the divert port (in host format)
|
||||
* reason and direction.
|
||||
*/
|
||||
uint32_t i = args->rule.info;
|
||||
match = (i&IPFW_IS_MASK) == IPFW_IS_DIVERT &&
|
||||
cmd->arg1 & ((i & IPFW_INFO_IN) ? 1 : 2);
|
||||
}
|
||||
match = ((args->rule.info & IPFW_IS_MASK) ==
|
||||
IPFW_IS_DIVERT) && (
|
||||
((args->rule.info & IPFW_INFO_IN) ?
|
||||
1: 2) & cmd->arg1);
|
||||
break;
|
||||
|
||||
case O_PROTO:
|
||||
@ -2057,7 +2059,8 @@ do { \
|
||||
#ifdef INET6
|
||||
/* FALLTHROUGH */
|
||||
case O_IP6_SRC_ME:
|
||||
match= is_ipv6 && ipfw_localip6(&args->f_id.src_ip6);
|
||||
match = is_ipv6 &&
|
||||
ipfw_localip6(&args->f_id.src_ip6);
|
||||
#endif
|
||||
break;
|
||||
|
||||
@ -2093,7 +2096,8 @@ do { \
|
||||
#ifdef INET6
|
||||
/* FALLTHROUGH */
|
||||
case O_IP6_DST_ME:
|
||||
match= is_ipv6 && ipfw_localip6(&args->f_id.dst_ip6);
|
||||
match = is_ipv6 &&
|
||||
ipfw_localip6(&args->f_id.dst_ip6);
|
||||
#endif
|
||||
break;
|
||||
|
||||
@ -2691,8 +2695,8 @@ do { \
|
||||
|
||||
case O_DIVERT:
|
||||
case O_TEE:
|
||||
if (args->eh) /* not on layer 2 */
|
||||
break;
|
||||
if (args->flags & IPFW_ARGS_ETHER)
|
||||
break; /* not on layer 2 */
|
||||
/* otherwise this is terminal */
|
||||
l = 0; /* exit inner loop */
|
||||
done = 1; /* exit outer loop */
|
||||
@ -2868,8 +2872,8 @@ do { \
|
||||
break;
|
||||
|
||||
case O_FORWARD_IP:
|
||||
if (args->eh) /* not valid on layer2 pkts */
|
||||
break;
|
||||
if (args->flags & IPFW_ARGS_ETHER)
|
||||
break; /* not valid on layer2 pkts */
|
||||
if (q != f ||
|
||||
dyn_info.direction == MATCH_FORWARD) {
|
||||
struct sockaddr_in *sa;
|
||||
@ -2886,32 +2890,22 @@ do { \
|
||||
* table_value as next_hop6 address.
|
||||
*/
|
||||
if (is_ipv6) {
|
||||
struct sockaddr_in6 *sa6;
|
||||
struct ip_fw_nh6 *nh6;
|
||||
|
||||
sa6 = args->next_hop6 =
|
||||
&args->hopstore6;
|
||||
sa6->sin6_family = AF_INET6;
|
||||
sa6->sin6_len = sizeof(*sa6);
|
||||
sa6->sin6_addr = TARG_VAL(
|
||||
args->flags |= IPFW_ARGS_NH6;
|
||||
nh6 = &args->hopstore6;
|
||||
nh6->sin6_addr = TARG_VAL(
|
||||
chain, tablearg, nh6);
|
||||
sa6->sin6_port = sa->sin_port;
|
||||
/*
|
||||
* Set sin6_scope_id only for
|
||||
* link-local unicast addresses.
|
||||
*/
|
||||
if (IN6_IS_ADDR_LINKLOCAL(
|
||||
&sa6->sin6_addr))
|
||||
sa6->sin6_scope_id =
|
||||
TARG_VAL(chain,
|
||||
tablearg,
|
||||
zoneid);
|
||||
nh6->sin6_port = sa->sin_port;
|
||||
nh6->sin6_scope_id = TARG_VAL(
|
||||
chain, tablearg, zoneid);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
args->flags |= IPFW_ARGS_NH4;
|
||||
args->hopstore.sin_port =
|
||||
sa->sin_port;
|
||||
sa = args->next_hop =
|
||||
&args->hopstore;
|
||||
sa = &args->hopstore;
|
||||
sa->sin_family = AF_INET;
|
||||
sa->sin_len = sizeof(*sa);
|
||||
sa->sin_addr.s_addr = htonl(
|
||||
@ -2919,7 +2913,8 @@ do { \
|
||||
nh4));
|
||||
}
|
||||
} else {
|
||||
args->next_hop = sa;
|
||||
args->flags |= IPFW_ARGS_NH4PTR;
|
||||
args->next_hop = sa;
|
||||
}
|
||||
}
|
||||
retval = IP_FW_PASS;
|
||||
@ -2929,13 +2924,14 @@ do { \
|
||||
|
||||
#ifdef INET6
|
||||
case O_FORWARD_IP6:
|
||||
if (args->eh) /* not valid on layer2 pkts */
|
||||
break;
|
||||
if (args->flags & IPFW_ARGS_ETHER)
|
||||
break; /* not valid on layer2 pkts */
|
||||
if (q != f ||
|
||||
dyn_info.direction == MATCH_FORWARD) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
sin6 = &(((ipfw_insn_sa6 *)cmd)->sa);
|
||||
args->flags |= IPFW_ARGS_NH6PTR;
|
||||
args->next_hop6 = sin6;
|
||||
}
|
||||
retval = IP_FW_PASS;
|
||||
@ -2964,7 +2960,7 @@ do { \
|
||||
if (fib >= rt_numfibs)
|
||||
fib = 0;
|
||||
M_SETFIB(m, fib);
|
||||
args->f_id.fib = fib;
|
||||
args->f_id.fib = fib; /* XXX */
|
||||
l = 0; /* exit inner loop */
|
||||
break;
|
||||
}
|
||||
@ -3011,6 +3007,7 @@ do { \
|
||||
struct cfg_nat *t;
|
||||
int nat_id;
|
||||
|
||||
args->rule.info = 0;
|
||||
set_match(args, f_pos, chain);
|
||||
/* Check if this is 'global' nat rule */
|
||||
if (cmd->arg1 == IP_FW_NAT44_GLOBAL) {
|
||||
@ -3063,6 +3060,7 @@ do { \
|
||||
else
|
||||
ip->ip_sum = in_cksum(m, hlen);
|
||||
retval = IP_FW_REASS;
|
||||
args->rule.info = 0;
|
||||
set_match(args, f_pos, chain);
|
||||
}
|
||||
done = 1; /* exit outer loop */
|
||||
|
@ -107,7 +107,7 @@ ipfw_log(struct ip_fw_chain *chain, struct ip_fw *f, u_int hlen,
|
||||
char action2[92], proto[128], fragment[32];
|
||||
|
||||
if (V_fw_verbose == 0) {
|
||||
if (args->eh) /* layer2, use orig hdr */
|
||||
if (args->flags & IPFW_ARGS_ETHER) /* layer2, use orig hdr */
|
||||
ipfw_bpf_mtap2(args->eh, ETHER_HDR_LEN, m);
|
||||
else {
|
||||
/* Add fake header. Later we will store
|
||||
|
@ -126,13 +126,11 @@ ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
{
|
||||
struct ip_fw_args args;
|
||||
struct m_tag *tag;
|
||||
int ipfw;
|
||||
int ret;
|
||||
int ipfw, ret;
|
||||
|
||||
/* convert dir to IPFW values */
|
||||
dir = (dir == PFIL_IN) ? DIR_IN : DIR_OUT;
|
||||
bzero(&args, sizeof(args));
|
||||
|
||||
args.flags = 0;
|
||||
again:
|
||||
/*
|
||||
* extract and remove the tag if present. If we are left
|
||||
@ -144,6 +142,7 @@ ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
m_tag_delete(*m0, tag);
|
||||
if (args.rule.info & IPFW_ONEPASS)
|
||||
return (0);
|
||||
args.flags |= IPFW_ARGS_REF;
|
||||
}
|
||||
|
||||
args.m = *m0;
|
||||
@ -157,53 +156,82 @@ ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
__func__));
|
||||
|
||||
/* breaking out of the switch means drop */
|
||||
ret = 0; /* default return value for pass */
|
||||
switch (ipfw) {
|
||||
case IP_FW_PASS:
|
||||
/* next_hop may be set by ipfw_chk */
|
||||
if (args.next_hop == NULL && args.next_hop6 == NULL)
|
||||
break; /* pass */
|
||||
if ((args.flags & (IPFW_ARGS_NH4 | IPFW_ARGS_NH4PTR |
|
||||
IPFW_ARGS_NH6 | IPFW_ARGS_NH6PTR)) == 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
#if (!defined(INET6) && !defined(INET))
|
||||
ret = EACCES;
|
||||
#else
|
||||
{
|
||||
struct m_tag *fwd_tag;
|
||||
void *psa;
|
||||
size_t len;
|
||||
|
||||
KASSERT(args.next_hop == NULL || args.next_hop6 == NULL,
|
||||
("%s: both next_hop=%p and next_hop6=%p not NULL", __func__,
|
||||
args.next_hop, args.next_hop6));
|
||||
#ifdef INET6
|
||||
if (args.next_hop6 != NULL)
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
#ifdef INET
|
||||
if (args.next_hop != NULL)
|
||||
if (args.flags & (IPFW_ARGS_NH4 | IPFW_ARGS_NH4PTR)) {
|
||||
MPASS((args.flags & (IPFW_ARGS_NH4 |
|
||||
IPFW_ARGS_NH4PTR)) != (IPFW_ARGS_NH4 |
|
||||
IPFW_ARGS_NH4PTR));
|
||||
MPASS((args.flags & (IPFW_ARGS_NH6 |
|
||||
IPFW_ARGS_NH6PTR)) == 0);
|
||||
len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
/* Incoming packets should not be tagged so we do not
|
||||
psa = (args.flags & IPFW_ARGS_NH4) ?
|
||||
&args.hopstore : args.next_hop;
|
||||
if (in_localip(satosin(psa)->sin_addr))
|
||||
(*m0)->m_flags |= M_FASTFWD_OURS;
|
||||
(*m0)->m_flags |= M_IP_NEXTHOP;
|
||||
}
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
if (args.flags & (IPFW_ARGS_NH6 | IPFW_ARGS_NH6PTR)) {
|
||||
MPASS((args.flags & (IPFW_ARGS_NH6 |
|
||||
IPFW_ARGS_NH6PTR)) != (IPFW_ARGS_NH6 |
|
||||
IPFW_ARGS_NH6PTR));
|
||||
MPASS((args.flags & (IPFW_ARGS_NH4 |
|
||||
IPFW_ARGS_NH4PTR)) == 0);
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
psa = args.next_hop6;
|
||||
(*m0)->m_flags |= M_IP6_NEXTHOP;
|
||||
}
|
||||
#endif /* INET6 */
|
||||
/*
|
||||
* Incoming packets should not be tagged so we do not
|
||||
* m_tag_find. Outgoing packets may be tagged, so we
|
||||
* reuse the tag if present.
|
||||
*/
|
||||
fwd_tag = (dir == DIR_IN) ? NULL :
|
||||
tag = (dir == DIR_IN) ? NULL :
|
||||
m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
|
||||
if (fwd_tag != NULL) {
|
||||
m_tag_unlink(*m0, fwd_tag);
|
||||
if (tag != NULL) {
|
||||
m_tag_unlink(*m0, tag);
|
||||
} else {
|
||||
fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, len,
|
||||
tag = m_tag_get(PACKET_TAG_IPFORWARD, len,
|
||||
M_NOWAIT);
|
||||
if (fwd_tag == NULL) {
|
||||
if (tag == NULL) {
|
||||
ret = EACCES;
|
||||
break; /* i.e. drop */
|
||||
}
|
||||
}
|
||||
if ((args.flags & IPFW_ARGS_NH6) == 0)
|
||||
bcopy(psa, tag + 1, len);
|
||||
m_tag_prepend(*m0, tag);
|
||||
ret = 0;
|
||||
#ifdef INET6
|
||||
if (args.next_hop6 != NULL) {
|
||||
/* IPv6 next hop needs additional handling */
|
||||
if (args.flags & (IPFW_ARGS_NH6 | IPFW_ARGS_NH6PTR)) {
|
||||
struct sockaddr_in6 *sa6;
|
||||
|
||||
sa6 = (struct sockaddr_in6 *)(fwd_tag + 1);
|
||||
bcopy(args.next_hop6, sa6, len);
|
||||
sa6 = satosin6(tag + 1);
|
||||
if (args.flags & IPFW_ARGS_NH6) {
|
||||
sa6->sin6_family = AF_INET6;
|
||||
sa6->sin6_len = sizeof(*sa6);
|
||||
sa6->sin6_addr = args.hopstore6.sin6_addr;
|
||||
sa6->sin6_port = args.hopstore6.sin6_port;
|
||||
sa6->sin6_scope_id =
|
||||
args.hopstore6.sin6_scope_id;
|
||||
}
|
||||
/*
|
||||
* If nh6 address is link-local we should convert
|
||||
* it to kernel internal form before doing any
|
||||
@ -215,18 +243,8 @@ ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
}
|
||||
if (in6_localip(&sa6->sin6_addr))
|
||||
(*m0)->m_flags |= M_FASTFWD_OURS;
|
||||
(*m0)->m_flags |= M_IP6_NEXTHOP;
|
||||
}
|
||||
#endif
|
||||
#ifdef INET
|
||||
if (args.next_hop != NULL) {
|
||||
bcopy(args.next_hop, (fwd_tag+1), len);
|
||||
if (in_localip(args.next_hop->sin_addr))
|
||||
(*m0)->m_flags |= M_FASTFWD_OURS;
|
||||
(*m0)->m_flags |= M_IP_NEXTHOP;
|
||||
}
|
||||
#endif
|
||||
m_tag_prepend(*m0, fwd_tag);
|
||||
#endif /* INET6 */
|
||||
}
|
||||
#endif /* INET || INET6 */
|
||||
break;
|
||||
@ -239,6 +257,7 @@ ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
ret = EACCES;
|
||||
if (ip_dn_io_ptr == NULL)
|
||||
break; /* i.e. drop */
|
||||
MPASS(args->flags & IPFW_ARGS_REF);
|
||||
if (mtod(*m0, struct ip *)->ip_v == 4)
|
||||
ret = ip_dn_io_ptr(m0, dir, &args);
|
||||
else if (mtod(*m0, struct ip *)->ip_v == 6)
|
||||
@ -262,6 +281,7 @@ ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
ret = EACCES;
|
||||
break; /* i.e. drop */
|
||||
}
|
||||
MPASS(args->flags & IPFW_ARGS_REF);
|
||||
ret = ipfw_divert(m0, dir, &args.rule,
|
||||
(ipfw == IP_FW_TEE) ? 1 : 0);
|
||||
/* continue processing for the original packet (tee). */
|
||||
@ -275,6 +295,7 @@ ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
ret = EACCES;
|
||||
break; /* i.e. drop */
|
||||
}
|
||||
MPASS(args->flags & IPFW_ARGS_REF);
|
||||
ret = ng_ipfw_input_p(m0, dir, &args,
|
||||
(ipfw == IP_FW_NGTEE) ? 1 : 0);
|
||||
if (ipfw == IP_FW_NGTEE) /* ignore errors for NGTEE */
|
||||
@ -283,13 +304,15 @@ ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
|
||||
case IP_FW_NAT:
|
||||
/* honor one-pass in case of successful nat */
|
||||
if (V_fw_one_pass)
|
||||
break; /* ret is already 0 */
|
||||
if (V_fw_one_pass) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
goto again;
|
||||
|
||||
case IP_FW_REASS:
|
||||
goto again; /* continue with packet */
|
||||
|
||||
|
||||
default:
|
||||
KASSERT(0, ("%s: unknown retval", __func__));
|
||||
}
|
||||
@ -300,7 +323,7 @@ ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
*m0 = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -310,15 +333,14 @@ int
|
||||
ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
struct inpcb *inp)
|
||||
{
|
||||
struct ether_header *eh;
|
||||
struct ip_fw_args args;
|
||||
struct ether_header save_eh;
|
||||
struct ether_header *eh;
|
||||
struct m_tag *mtag;
|
||||
struct mbuf *m;
|
||||
int i, ret;
|
||||
struct ip_fw_args args;
|
||||
struct m_tag *mtag;
|
||||
|
||||
bzero(&args, sizeof(args));
|
||||
|
||||
args.flags = IPFW_ARGS_ETHER;
|
||||
again:
|
||||
/* fetch start point from rule, if any. remove the tag if present. */
|
||||
mtag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
|
||||
@ -327,6 +349,7 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
m_tag_delete(*m0, mtag);
|
||||
if (args.rule.info & IPFW_ONEPASS)
|
||||
return (0);
|
||||
args.flags |= IPFW_ARGS_REF;
|
||||
}
|
||||
|
||||
/* I need some amt of data to be contiguous */
|
||||
@ -345,10 +368,8 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
|
||||
args.m = m; /* the packet we are looking at */
|
||||
args.oif = dir == PFIL_OUT ? ifp: NULL; /* destination, if any */
|
||||
args.next_hop = NULL; /* we do not support forward yet */
|
||||
args.next_hop6 = NULL; /* we do not support forward yet */
|
||||
args.eh = &save_eh; /* MAC header for bridged/MAC packets */
|
||||
args.inp = NULL; /* used by ipfw uid/gid/jail rules */
|
||||
args.inp = inp; /* used by ipfw uid/gid/jail rules */
|
||||
i = ipfw_chk(&args);
|
||||
m = args.m;
|
||||
if (m != NULL) {
|
||||
@ -379,14 +400,14 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
|
||||
case IP_FW_DUMMYNET:
|
||||
ret = EACCES;
|
||||
int dir2;
|
||||
|
||||
if (ip_dn_io_ptr == NULL)
|
||||
break; /* i.e. drop */
|
||||
|
||||
*m0 = NULL;
|
||||
dir2 = (dir == PFIL_IN) ? DIR_IN : DIR_OUT;
|
||||
ip_dn_io_ptr(&m, dir2 | PROTO_LAYER2, &args);
|
||||
dir = (dir == PFIL_IN) ? DIR_IN : DIR_OUT;
|
||||
MPASS(args->flags & IPFW_ARGS_REF);
|
||||
ip_dn_io_ptr(&m, dir | PROTO_LAYER2, &args);
|
||||
return 0;
|
||||
|
||||
case IP_FW_NGTEE:
|
||||
@ -395,6 +416,7 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
ret = EACCES;
|
||||
break; /* i.e. drop */
|
||||
}
|
||||
MPASS(args->flags & IPFW_ARGS_REF);
|
||||
ret = ng_ipfw_input_p(m0, (dir == PFIL_IN) ? DIR_IN : DIR_OUT,
|
||||
&args, (i == IP_FW_NGTEE) ? 1 : 0);
|
||||
if (i == IP_FW_NGTEE) /* ignore errors for NGTEE */
|
||||
@ -411,7 +433,7 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
*m0 = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* do the divert, return 1 on error 0 on success */
|
||||
|
@ -83,11 +83,13 @@ struct _ip6dn_args {
|
||||
* efficient to pass variables around and extend the interface.
|
||||
*/
|
||||
struct ip_fw_args {
|
||||
struct mbuf *m; /* the mbuf chain */
|
||||
struct ifnet *oif; /* output interface */
|
||||
struct sockaddr_in *next_hop; /* forward address */
|
||||
struct sockaddr_in6 *next_hop6; /* ipv6 forward address */
|
||||
|
||||
uint32_t flags;
|
||||
#define IPFW_ARGS_ETHER 0x0001 /* has valid ethernet header */
|
||||
#define IPFW_ARGS_NH4 0x0002 /* has IPv4 next hop in hopstore */
|
||||
#define IPFW_ARGS_NH6 0x0004 /* has IPv6 next hop in hopstore */
|
||||
#define IPFW_ARGS_NH4PTR 0x0008 /* has IPv4 next hop in next_hop */
|
||||
#define IPFW_ARGS_NH6PTR 0x0010 /* has IPv6 next hop in next_hop6 */
|
||||
#define IPFW_ARGS_REF 0x0020 /* has valid ipfw_rule_ref */
|
||||
/*
|
||||
* On return, it points to the matching rule.
|
||||
* On entry, rule.slot > 0 means the info is valid and
|
||||
@ -95,19 +97,33 @@ struct ip_fw_args {
|
||||
* If chain_id == chain->id && slot >0 then jump to that slot.
|
||||
* Otherwise, we locate the first rule >= rulenum:rule_id
|
||||
*/
|
||||
struct ipfw_rule_ref rule; /* match/restart info */
|
||||
struct ipfw_rule_ref rule; /* match/restart info */
|
||||
|
||||
struct ether_header *eh; /* for bridged packets */
|
||||
|
||||
struct ipfw_flow_id f_id; /* grabbed from IP header */
|
||||
//uint32_t cookie; /* a cookie depending on rule action */
|
||||
struct inpcb *inp;
|
||||
|
||||
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
|
||||
union { /* store here if cannot use a pointer */
|
||||
struct sockaddr_in hopstore;
|
||||
struct sockaddr_in6 hopstore6;
|
||||
struct ifnet *oif; /* output interface */
|
||||
struct inpcb *inp;
|
||||
union {
|
||||
/*
|
||||
* We don't support forwarding on layer2, thus we can
|
||||
* keep eh pointer in this union.
|
||||
* next_hop[6] pointers can be used to point to next hop
|
||||
* stored in rule's opcode to avoid copying into hopstore.
|
||||
* Also, it is expected that all 0x1-0x10 flags are mutually
|
||||
* exclusive.
|
||||
*/
|
||||
struct ether_header *eh; /* for bridged packets */
|
||||
struct sockaddr_in *next_hop;
|
||||
struct sockaddr_in6 *next_hop6;
|
||||
/* ipfw next hop storage */
|
||||
struct sockaddr_in hopstore;
|
||||
struct ip_fw_nh6 {
|
||||
struct in6_addr sin6_addr;
|
||||
uint32_t sin6_scope_id;
|
||||
uint16_t sin6_port;
|
||||
} hopstore6;
|
||||
};
|
||||
|
||||
struct mbuf *m; /* the mbuf chain */
|
||||
struct ipfw_flow_id f_id; /* grabbed from IP header */
|
||||
};
|
||||
|
||||
MALLOC_DECLARE(M_IPFW);
|
||||
|
Loading…
Reference in New Issue
Block a user