Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F109256409
D35103.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
41 KB
Referenced Files
None
Subscribers
None
D35103.diff
View Options
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1,7 +1,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 14, 2021
+.Dd June 4, 2022
.Dt IPFW 8
.Os
.Sh NAME
@@ -1610,6 +1610,20 @@
.Ar labels .
.Ar labels
is a comma separated list of numeric flow labels.
+.It Cm dst-mac Ar table Ns Pq Ar name Ns Op , Ns Ar value
+Search for the destination MAC address entry in lookup table
+.Ar name .
+If not found, the match fails.
+Otherwise, the match succeeds and
+.Cm tablearg
+is set to the value extracted from the table.
+.It Cm src-mac Ar table Ns Pq Ar name Ns Op , Ns Ar value
+Search for the source MAC address entry in lookup table
+.Ar name .
+If not found, the match fails.
+Otherwise, the match succeeds and
+.Cm tablearg
+is set to the value extracted from the table.
.It Cm frag Ar spec
Matches IPv4 packets whose
.Cm ip_off
@@ -1823,7 +1837,7 @@
One or more
of source and destination addresses and ports can be
specified.
-.It Cm lookup Bro Cm dst-ip | dst-port | src-ip | src-port | uid | jail Brc Ar name
+.It Cm lookup Bro Cm dst-ip | dst-port | dst-mac | src-ip | src-port | src-mac | uid | jail Brc Ar name
Search an entry in lookup table
.Ar name
that matches the field specified as argument.
@@ -2133,7 +2147,7 @@
.Pp
The following table types are supported:
.Bl -tag -width indent
-.It Ar table-type : Ar addr | iface | number | flow
+.It Ar table-type : Ar addr | iface | number | flow | mac
.It Ar table-key : Ar addr Ns Oo / Ns Ar masklen Oc | iface-name | number | flow-spec
.It Ar flow-spec : Ar flow-field Ns Op , Ns Ar flow-spec
.It Ar flow-field : src-ip | proto | src-port | dst-ip | dst-port
@@ -2163,6 +2177,20 @@
Matches packet fields specified by
.Ar flow
type suboptions with table entries.
+.It Cm mac
+Matches MAC address.
+Each entry is represented by an
+.Ar addr Ns Op / Ns Ar masklen
+and will match all addresses with base
+.Ar addr
+and mask width of
+.Ar masklen
+bits.
+If
+.Ar masklen
+is not specified, it defaults to 48.
+When looking up an MAC address in a table, the most specific
+entry will match.
.El
.Pp
Tables require explicit creation via
@@ -2266,7 +2294,7 @@
The following lookup algorithms are supported:
.Bl -tag -width indent
.It Ar algo-desc : algo-name | "algo-name algo-data"
-.It Ar algo-name : Ar addr: radix | addr: hash | iface: array | number: array | flow: hash
+.It Ar algo-name : Ar addr: radix | addr: hash | iface: array | number: array | flow: hash | mac: radix
.It Cm addr: radix
Separate Radix trees for IPv4 and IPv6, the same way as the routing table (see
.Xr route 4 ) .
@@ -2291,6 +2319,8 @@
Auto-growing hash storing flow entries.
Search calculates hash on required packet fields and searches for matching
entries in selected bucket.
+.It Cm mac: radix
+Radix tree for MAC address
.El
.Pp
The
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -177,6 +177,8 @@
TOK_SRCIP,
TOK_DSTPORT,
TOK_SRCPORT,
+ TOK_DSTMAC,
+ TOK_SRCMAC,
TOK_ALL,
TOK_MASK,
TOK_FLOW_MASK,
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -300,12 +300,20 @@
/*
* The 'lookup' instruction accepts one of the following arguments.
- * -1 is a terminator for the list.
* Arguments are passed as v[1] in O_DST_LOOKUP options.
*/
-static int lookup_key[] = {
- TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT,
- TOK_UID, TOK_JAIL, TOK_DSCP, -1 };
+static struct _s_x lookup_keys[] = {
+ { "dst-ip", LOOKUP_DST_IP },
+ { "src-ip", LOOKUP_SRC_IP },
+ { "dst-port", LOOKUP_DST_PORT },
+ { "src-port", LOOKUP_SRC_PORT },
+ { "dst-mac", LOOKUP_DST_MAC },
+ { "src-mac", LOOKUP_SRC_MAC },
+ { "uid", LOOKUP_UID },
+ { "jail", LOOKUP_JAIL },
+ { "dscp", LOOKUP_DSCP },
+ { NULL, 0 },
+};
static struct _s_x rule_options[] = {
{ "tagged", TOK_TAGGED },
@@ -358,6 +366,8 @@
{ "src-ip", TOK_SRCIP },
{ "dst-port", TOK_DSTPORT },
{ "src-port", TOK_SRCPORT },
+ { "dst-mac", TOK_DSTMAC },
+ { "src-mac", TOK_SRCMAC },
{ "proto", TOK_PROTO },
{ "MAC", TOK_MAC },
{ "mac", TOK_MAC },
@@ -368,18 +378,18 @@
{ "ipsec", TOK_IPSEC },
{ "icmp6type", TOK_ICMP6TYPES },
{ "icmp6types", TOK_ICMP6TYPES },
- { "ext6hdr", TOK_EXT6HDR},
- { "flow-id", TOK_FLOWID},
- { "ipv6", TOK_IPV6},
- { "ip6", TOK_IPV6},
- { "ipv4", TOK_IPV4},
- { "ip4", TOK_IPV4},
- { "dst-ipv6", TOK_DSTIP6},
- { "dst-ip6", TOK_DSTIP6},
- { "src-ipv6", TOK_SRCIP6},
- { "src-ip6", TOK_SRCIP6},
- { "lookup", TOK_LOOKUP},
- { "flow", TOK_FLOW},
+ { "ext6hdr", TOK_EXT6HDR },
+ { "flow-id", TOK_FLOWID },
+ { "ipv6", TOK_IPV6 },
+ { "ip6", TOK_IPV6 },
+ { "ipv4", TOK_IPV4 },
+ { "ip4", TOK_IPV4 },
+ { "dst-ipv6", TOK_DSTIP6 },
+ { "dst-ip6", TOK_DSTIP6 },
+ { "src-ipv6", TOK_SRCIP6 },
+ { "src-ip6", TOK_SRCIP6 },
+ { "lookup", TOK_LOOKUP },
+ { "flow", TOK_FLOW },
{ "defer-action", TOK_SKIPACTION },
{ "defer-immediate-action", TOK_SKIPACTION },
{ "//", TOK_COMMENT },
@@ -1211,11 +1221,9 @@
bprintf(bp, " ");
if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
- uint32_t d = a[1];
- const char *arg = "<invalid>";
+ const char *arg;
- if (d < sizeof(lookup_key)/sizeof(lookup_key[0]))
- arg = match_value(rule_options, lookup_key[d]);
+ arg = match_value(lookup_keys, a[1]);
t = table_search_ctlv(fo->tstate,
((const ipfw_insn *)cmd)->arg1);
bprintf(bp, "lookup %s %s", arg, t);
@@ -1331,6 +1339,22 @@
format_mac(bp, mac->addr + 6, mac->mask + 6);
}
+static void
+print_mac_lookup(struct buf_pr *bp, const struct format_opts *fo,
+ const ipfw_insn *cmd)
+{
+ uint32_t len = F_LEN(cmd);
+ char *t;
+
+ bprintf(bp, " ");
+
+ t = table_search_ctlv(fo->tstate, cmd->arg1);
+ bprintf(bp, "table(%s", t);
+ if (len == F_INSN_SIZE(ipfw_insn_u32))
+ bprintf(bp, ",%u", ((const ipfw_insn_u32 *)cmd)->d[0]);
+ bprintf(bp, ")");
+}
+
static void
fill_icmptypes(ipfw_insn_u32 *cmd, char *av)
{
@@ -1518,6 +1542,14 @@
bprintf(bp, " dst-ip6");
print_ip6(bp, insntod(cmd, ip6));
break;
+ case O_MAC_SRC_LOOKUP:
+ bprintf(bp, " src-mac");
+ print_mac_lookup(bp, fo, cmd);
+ break;
+ case O_MAC_DST_LOOKUP:
+ bprintf(bp, " dst-mac");
+ print_mac_lookup(bp, fo, cmd);
+ break;
case O_FLOW6ID:
print_flow6id(bp, insntod(cmd, u32));
break;
@@ -2650,7 +2682,6 @@
int n, seen;
struct ip_fw_rule *r;
struct ip_fw_bcounter *cntr;
- int c = 0;
for (n = seen = 0; n < rcnt; n++,
rtlv = (ipfw_obj_tlv *)((caddr_t)rtlv + rtlv->length)) {
@@ -2669,7 +2700,6 @@
if (r->rulenum >= fo->first && r->rulenum <= fo->last) {
show_static_rule(co, fo, bp, r, cntr);
printf("%s", bp->buf);
- c += rtlv->length;
bp_flush(bp);
seen++;
}
@@ -2788,13 +2818,12 @@
char *endptr;
size_t readsz;
struct buf_pr bp;
- ipfw_obj_ctlv *ctlv, *tstate;
+ ipfw_obj_ctlv *ctlv;
ipfw_obj_tlv *rbase;
/*
* Handle tablenames TLV first, if any
*/
- tstate = NULL;
rbase = NULL;
dynbase = NULL;
dynsz = 0;
@@ -3682,6 +3711,29 @@
return cmd;
}
+static ipfw_insn *
+add_srcmac(ipfw_insn *cmd, char *av, struct tidx *tstate)
+{
+
+ if (strncmp(av, "table(", 6) == 0)
+ fill_table(cmd, av, O_MAC_SRC_LOOKUP, tstate);
+ else
+ errx(EX_DATAERR, "only mac table lookup is supported %s", av);
+ return cmd;
+}
+
+static ipfw_insn *
+add_dstmac(ipfw_insn *cmd, char *av, struct tidx *tstate)
+{
+
+ if (strncmp(av, "table(", 6) == 0)
+ fill_table(cmd, av, O_MAC_DST_LOOKUP, tstate);
+ else
+ errx(EX_DATAERR, "only mac table lookup is supported %s", av);
+ return cmd;
+}
+
+
static struct _s_x f_reserved_keywords[] = {
{ "altq", TOK_OR },
{ "//", TOK_OR },
@@ -4912,6 +4964,21 @@
}
break;
+
+ case TOK_SRCMAC:
+ NEED1("missing source MAC");
+ if (add_srcmac(cmd, *av, tstate)) {
+ av++;
+ }
+ break;
+
+ case TOK_DSTMAC:
+ NEED1("missing destination MAC");
+ if (add_dstmac(cmd, *av, tstate)) {
+ av++;
+ }
+ break;
+
case TOK_SRCPORT:
NEED1("missing source port");
if (_substrcmp(*av, "any") == 0 ||
@@ -5013,28 +5080,23 @@
case TOK_LOOKUP: {
ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
- int j;
if (!av[0] || !av[1])
errx(EX_USAGE, "format: lookup argument tablenum");
cmd->opcode = O_IP_DST_LOOKUP;
cmd->len |= F_INSN_SIZE(ipfw_insn) + 2;
- i = match_token(rule_options, *av);
- for (j = 0; lookup_key[j] >= 0 ; j++) {
- if (i == lookup_key[j])
- break;
- }
- if (lookup_key[j] <= 0)
+ i = match_token(lookup_keys, *av);
+ if (i == -1)
errx(EX_USAGE, "format: cannot lookup on %s", *av);
- __PAST_END(c->d, 1) = j; // i converted to option
+ __PAST_END(c->d, 1) = i;
av++;
- if ((j = pack_table(tstate, *av)) == 0)
+ if ((i = pack_table(tstate, *av)) == 0)
errx(EX_DATAERR, "Invalid table name: %s", *av);
- cmd->arg1 = j;
+ cmd->arg1 = i;
av++;
- }
+ }
break;
case TOK_FLOW:
NEED1("missing table name");
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c
--- a/sbin/ipfw/tables.c
+++ b/sbin/ipfw/tables.c
@@ -31,6 +31,7 @@
#include <string.h>
#include <sysexits.h>
+#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip_fw.h>
@@ -77,6 +78,7 @@
static struct _s_x tabletypes[] = {
{ "addr", IPFW_TABLE_ADDR },
+ { "mac", IPFW_TABLE_MAC },
{ "iface", IPFW_TABLE_INTERFACE },
{ "number", IPFW_TABLE_NUMBER },
{ "flow", IPFW_TABLE_FLOW },
@@ -1188,6 +1190,7 @@
char *p, *pp;
int mask, af;
struct in6_addr *paddr, tmp;
+ struct ether_addr *mac;
struct tflow_entry *tfe;
uint32_t key, *pkey;
uint16_t port;
@@ -1234,6 +1237,24 @@
af = AF_INET;
}
break;
+ case IPFW_TABLE_MAC:
+ /* Remove / if exists */
+ if ((p = strchr(arg, '/')) != NULL) {
+ *p = '\0';
+ mask = atoi(p + 1);
+ }
+
+ if (p != NULL && mask > 8 * ETHER_ADDR_LEN)
+ errx(EX_DATAERR, "bad MAC mask width: %s",
+ p + 1);
+
+ if ((mac = ether_aton(arg)) == NULL)
+ errx(EX_DATAERR, "Incorrect MAC address");
+
+ memcpy(tentry->k.mac, mac->octet, ETHER_ADDR_LEN);
+ masklen = p ? mask : 8 * ETHER_ADDR_LEN;
+ af = AF_LINK;
+ break;
case IPFW_TABLE_INTERFACE:
/* Assume interface name. Copy significant data only */
mask = MIN(strlen(arg), IF_NAMESIZE - 1);
@@ -1872,6 +1893,7 @@
{
char tbuf[128], pval[128];
const char *comma;
+ const u_char *mac;
void *paddr;
struct tflow_entry *tfe;
@@ -1884,6 +1906,13 @@
inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
printf("%s/%u %s\n", tbuf, tent->masklen, pval);
break;
+ case IPFW_TABLE_MAC:
+ /* MAC prefixes */
+ mac = tent->k.mac;
+ printf("%02x:%02x:%02x:%02x:%02x:%02x/%u %s\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ tent->masklen, pval);
+ break;
case IPFW_TABLE_INTERFACE:
/* Interface names */
printf("%s %s\n", tent->k.iface, pval);
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -295,9 +295,27 @@
O_SKIP_ACTION, /* none */
O_TCPMSS, /* arg1=MSS value */
+ O_MAC_SRC_LOOKUP, /* arg1=table number, u32=value */
+ O_MAC_DST_LOOKUP, /* arg1=table number, u32=value */
+
O_LAST_OPCODE /* not an opcode! */
};
+/*
+ * Defines key types used by lookup instruction
+ */
+enum ipfw_table_lookup_type {
+ LOOKUP_DST_IP,
+ LOOKUP_SRC_IP,
+ LOOKUP_DST_PORT,
+ LOOKUP_SRC_PORT,
+ LOOKUP_UID,
+ LOOKUP_JAIL,
+ LOOKUP_DSCP,
+ LOOKUP_DST_MAC,
+ LOOKUP_SRC_MAC,
+};
+
/*
* The extension header are filtered only for presence using a bit
* vector with a flag for each header.
@@ -754,7 +772,8 @@
#define IPFW_TABLE_INTERFACE 2 /* Table for holding interface names */
#define IPFW_TABLE_NUMBER 3 /* Table for holding ports/uid/gid/etc */
#define IPFW_TABLE_FLOW 4 /* Table for holding flow data */
-#define IPFW_TABLE_MAXTYPE 4 /* Maximum valid number */
+#define IPFW_TABLE_MAC 5 /* Table for holding mac address prefixes */
+#define IPFW_TABLE_MAXTYPE 5 /* Maximum valid number */
#define IPFW_TABLE_CIDR IPFW_TABLE_ADDR /* compat */
@@ -772,6 +791,9 @@
#define IPFW_VTYPE_NH4 0x00000200 /* IPv4 nexthop */
#define IPFW_VTYPE_NH6 0x00000400 /* IPv6 nexthop */
+/* MAC/InfiniBand/etc address length */
+#define IPFW_MAX_L2_ADDR_LEN 20
+
typedef struct _ipfw_table_entry {
in_addr_t addr; /* network address */
u_int32_t value; /* value */
@@ -895,10 +917,11 @@
uint16_t spare1;
union {
/* Longest field needs to be aligned by 8-byte boundary */
- struct in_addr addr; /* IPv4 address */
- uint32_t key; /* uid/gid/port */
- struct in6_addr addr6; /* IPv6 address */
- char iface[IF_NAMESIZE]; /* interface name */
+ struct in_addr addr; /* IPv4 address */
+ uint32_t key; /* uid/gid/port */
+ struct in6_addr addr6; /* IPv6 address */
+ char iface[IF_NAMESIZE]; /* interface name */
+ u_char mac[IPFW_MAX_L2_ADDR_LEN]; /* MAC address */
struct tflow_entry flow;
} k;
union {
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -2038,78 +2038,87 @@
case O_IP_DST_LOOKUP:
{
- void *pkey;
- uint32_t vidx, key;
- uint16_t keylen;
-
if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
+ void *pkey;
+ uint32_t vidx, key;
+ uint16_t keylen = 0; /* zero if can't match the packet */
+
/* Determine lookup key type */
vidx = ((ipfw_insn_u32 *)cmd)->d[1];
- if (vidx != 4 /* uid */ &&
- vidx != 5 /* jail */ &&
- is_ipv6 == 0 && is_ipv4 == 0)
- break;
- /* Determine key length */
- if (vidx == 0 /* dst-ip */ ||
- vidx == 1 /* src-ip */)
- keylen = is_ipv6 ?
- sizeof(struct in6_addr):
- sizeof(in_addr_t);
- else {
- keylen = sizeof(key);
- pkey = &key;
- }
- if (vidx == 0 /* dst-ip */)
- pkey = is_ipv4 ? (void *)&dst_ip:
- (void *)&args->f_id.dst_ip6;
- else if (vidx == 1 /* src-ip */)
- pkey = is_ipv4 ? (void *)&src_ip:
- (void *)&args->f_id.src_ip6;
- else if (vidx == 6 /* dscp */) {
- if (is_ipv4)
- key = ip->ip_tos >> 2;
+ switch (vidx) {
+ case LOOKUP_DST_IP:
+ case LOOKUP_SRC_IP:
+ /* Need IP frame */
+ if (is_ipv6 == 0 && is_ipv4 == 0)
+ break;
+ if (vidx == LOOKUP_DST_IP)
+ pkey = is_ipv6 ?
+ (void *)&args->f_id.dst_ip6:
+ (void *)&dst_ip;
else
- key = IPV6_DSCP(
- (struct ip6_hdr *)ip) >> 2;
- key &= 0x3f;
- } else if (vidx == 2 /* dst-port */ ||
- vidx == 3 /* src-port */) {
+ pkey = is_ipv6 ?
+ (void *)&args->f_id.src_ip6:
+ (void *)&src_ip;
+ keylen = is_ipv6 ?
+ sizeof(struct in6_addr):
+ sizeof(in_addr_t);
+ break;
+ case LOOKUP_DST_PORT:
+ case LOOKUP_SRC_PORT:
+ /* Need IP frame */
+ if (is_ipv6 == 0 && is_ipv4 == 0)
+ break;
/* Skip fragments */
if (offset != 0)
break;
/* Skip proto without ports */
if (proto != IPPROTO_TCP &&
- proto != IPPROTO_UDP &&
- proto != IPPROTO_UDPLITE &&
- proto != IPPROTO_SCTP)
+ proto != IPPROTO_UDP &&
+ proto != IPPROTO_UDPLITE &&
+ proto != IPPROTO_SCTP)
break;
- if (vidx == 2 /* dst-port */)
- key = dst_port;
- else
- key = src_port;
- }
-#ifndef USERSPACE
- else if (vidx == 4 /* uid */ ||
- vidx == 5 /* jail */) {
+ key = vidx == LOOKUP_DST_PORT ?
+ dst_port:
+ src_port;
+ pkey = &key;
+ keylen = sizeof(key);
+ break;
+ case LOOKUP_UID:
+ case LOOKUP_JAIL:
check_uidgid(
(ipfw_insn_u32 *)cmd,
args, &ucred_lookup,
-#ifdef __FreeBSD__
&ucred_cache);
- if (vidx == 4 /* uid */)
- key = ucred_cache->cr_uid;
- else if (vidx == 5 /* jail */)
- key = ucred_cache->cr_prison->pr_id;
-#else /* !__FreeBSD__ */
- (void *)&ucred_cache);
- if (vidx == 4 /* uid */)
- key = ucred_cache.uid;
- else if (vidx == 5 /* jail */)
- key = ucred_cache.xid;
-#endif /* !__FreeBSD__ */
+ key = vidx == LOOKUP_UID ?
+ ucred_cache->cr_uid:
+ ucred_cache->cr_prison->pr_id;
+ pkey = &key;
+ keylen = sizeof(key);
+ break;
+ case LOOKUP_DSCP:
+ /* Need IP frame */
+ if (is_ipv6 == 0 && is_ipv4 == 0)
+ break;
+ if (is_ipv6)
+ key = IPV6_DSCP(
+ (struct ip6_hdr *)ip) >> 2;
+ else
+ key = ip->ip_tos >> 2;
+ pkey = &key;
+ keylen = sizeof(key);
+ break;
+ case LOOKUP_DST_MAC:
+ case LOOKUP_SRC_MAC:
+ /* Need ether frame */
+ if ((args->flags & IPFW_ARGS_ETHER) == 0)
+ break;
+ pkey = vidx == LOOKUP_DST_MAC ?
+ eh->ether_dhost:
+ eh->ether_shost;
+ keylen = ETHER_ADDR_LEN;
+ break;
}
-#endif /* !USERSPACE */
- else
+ if (keylen == 0)
break;
match = ipfw_lookup_table(chain,
cmd->arg1, keylen, pkey, &vidx);
@@ -2155,6 +2164,36 @@
break;
}
+ case O_MAC_SRC_LOOKUP:
+ case O_MAC_DST_LOOKUP:
+ {
+ void *pkey;
+ uint32_t vidx;
+ uint16_t keylen = ETHER_ADDR_LEN;
+
+ /* Need ether frame */
+ if ((args->flags & IPFW_ARGS_ETHER) == 0)
+ break;
+
+ if (cmd->opcode == O_MAC_DST_LOOKUP)
+ pkey = eh->ether_dhost;
+ else
+ pkey = eh->ether_shost;
+
+ match = ipfw_lookup_table(chain, cmd->arg1,
+ keylen, pkey, &vidx);
+ if (!match)
+ break;
+ if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) {
+ match = ((ipfw_insn_u32 *)cmd)->d[0] ==
+ TARG_VAL(chain, vidx, tag);
+ if (!match)
+ break;
+ }
+ tablearg = vidx;
+ break;
+ }
+
case O_IP_FLOW_LOOKUP:
{
uint32_t v = 0;
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -1909,6 +1909,8 @@
ci->object_opcodes++;
break;
case O_IP_FLOW_LOOKUP:
+ case O_MAC_DST_LOOKUP:
+ case O_MAC_SRC_LOOKUP:
if (cmd->arg1 >= V_fw_tables_max) {
printf("ipfw: invalid table number %d\n",
cmd->arg1);
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -2752,26 +2752,19 @@
*/
v = ((ipfw_insn_u32 *)cmd)->d[1];
switch (v) {
- case 0:
- case 1:
- /* IPv4 src/dst */
+ case LOOKUP_DST_IP:
+ case LOOKUP_SRC_IP:
break;
- case 2:
- case 3:
- /* src/dst port */
+ case LOOKUP_DST_PORT:
+ case LOOKUP_SRC_PORT:
+ case LOOKUP_UID:
+ case LOOKUP_JAIL:
+ case LOOKUP_DSCP:
*ptype = IPFW_TABLE_NUMBER;
break;
- case 4:
- /* uid/gid */
- *ptype = IPFW_TABLE_NUMBER;
- break;
- case 5:
- /* jid */
- *ptype = IPFW_TABLE_NUMBER;
- break;
- case 6:
- /* dscp */
- *ptype = IPFW_TABLE_NUMBER;
+ case LOOKUP_DST_MAC:
+ case LOOKUP_SRC_MAC:
+ *ptype = IPFW_TABLE_MAC;
break;
}
}
@@ -2805,6 +2798,14 @@
return (0);
}
+static int
+classify_mac_lookup(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
+{
+ *puidx = cmd->arg1;
+ *ptype = IPFW_TABLE_MAC;
+ return (0);
+}
+
static void
update_arg1(ipfw_insn *cmd, uint16_t idx)
{
@@ -2955,6 +2956,26 @@
.create_object = create_table_compat,
.manage_sets = table_manage_sets,
},
+ {
+ .opcode = O_MAC_SRC_LOOKUP,
+ .etlv = IPFW_TLV_TBL_NAME,
+ .classifier = classify_mac_lookup,
+ .update = update_arg1,
+ .find_byname = table_findbyname,
+ .find_bykidx = table_findbykidx,
+ .create_object = create_table_compat,
+ .manage_sets = table_manage_sets,
+ },
+ {
+ .opcode = O_MAC_DST_LOOKUP,
+ .etlv = IPFW_TLV_TBL_NAME,
+ .classifier = classify_mac_lookup,
+ .update = update_arg1,
+ .find_byname = table_findbyname,
+ .find_bykidx = table_findbykidx,
+ .create_object = create_table_compat,
+ .manage_sets = table_manage_sets,
+ },
{
.opcode = O_XMIT,
.etlv = IPFW_TLV_TBL_NAME,
diff --git a/sys/netpfil/ipfw/ip_fw_table_algo.c b/sys/netpfil/ipfw/ip_fw_table_algo.c
--- a/sys/netpfil/ipfw/ip_fw_table_algo.c
+++ b/sys/netpfil/ipfw/ip_fw_table_algo.c
@@ -48,6 +48,7 @@
#include <sys/rmlock.h>
#include <sys/socket.h>
#include <sys/queue.h>
+#include <net/ethernet.h>
#include <net/if.h> /* ip_fw.h requires IFNAMSIZ */
#include <net/radix.h>
#include <net/route.h>
@@ -315,15 +316,17 @@
*/
#define KEY_LEN(v) *((uint8_t *)&(v))
/*
- * Do not require radix to compare more than actual IPv4/IPv6 address
+ * Do not require radix to compare more than actual IPv4/IPv6/MAC address
*/
#define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
#define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr))
+#define KEY_LEN_MAC (offsetof(struct sa_mac, mac_addr) + ETHER_ADDR_LEN)
#define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
#define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr))
+#define OFF_LEN_MAC (8 * offsetof(struct sa_mac, mac_addr))
-struct radix_addr_entry {
+struct addr_radix_entry {
struct radix_node rn[2];
struct sockaddr_in addr;
uint32_t value;
@@ -337,20 +340,25 @@
struct in6_addr sin6_addr;
};
-struct radix_addr_xentry {
+struct addr_radix_xentry {
struct radix_node rn[2];
struct sa_in6 addr6;
uint32_t value;
uint8_t masklen;
};
-struct radix_cfg {
+struct addr_radix_cfg {
struct radix_node_head *head4;
struct radix_node_head *head6;
size_t count4;
size_t count6;
};
+struct sa_mac {
+ uint8_t mac_len;
+ struct ether_addr mac_addr;
+};
+
struct ta_buf_radix
{
void *ent_ptr;
@@ -365,32 +373,36 @@
struct sa_in6 sa;
struct sa_in6 ma;
} a6;
+ struct {
+ struct sa_mac sa;
+ struct sa_mac ma;
+ } mac;
} addr;
};
-static int ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
+static int ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen,
uint32_t *val);
-static int ta_init_radix(struct ip_fw_chain *ch, void **ta_state,
+static int ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state,
struct table_info *ti, char *data, uint8_t tflags);
static int flush_radix_entry(struct radix_node *rn, void *arg);
-static void ta_destroy_radix(void *ta_state, struct table_info *ti);
-static void ta_dump_radix_tinfo(void *ta_state, struct table_info *ti,
+static void ta_destroy_addr_radix(void *ta_state, struct table_info *ti);
+static void ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti,
ipfw_ta_tinfo *tinfo);
-static int ta_dump_radix_tentry(void *ta_state, struct table_info *ti,
+static int ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti,
void *e, ipfw_obj_tentry *tent);
-static int ta_find_radix_tentry(void *ta_state, struct table_info *ti,
+static int ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti,
ipfw_obj_tentry *tent);
-static void ta_foreach_radix(void *ta_state, struct table_info *ti,
+static void ta_foreach_addr_radix(void *ta_state, struct table_info *ti,
ta_foreach_f *f, void *arg);
-static void tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa,
+static void tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa,
struct sockaddr *ma, int *set_mask);
-static int ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
+static int ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
void *ta_buf);
-static int ta_add_radix(void *ta_state, struct table_info *ti,
+static int ta_add_addr_radix(void *ta_state, struct table_info *ti,
struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static int ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
+static int ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
void *ta_buf);
-static int ta_del_radix(void *ta_state, struct table_info *ti,
+static int ta_del_addr_radix(void *ta_state, struct table_info *ti,
struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
void *ta_buf);
@@ -398,29 +410,29 @@
uint32_t count, uint64_t *pflags);
static int
-ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
+ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen,
uint32_t *val)
{
struct radix_node_head *rnh;
if (keylen == sizeof(in_addr_t)) {
- struct radix_addr_entry *ent;
+ struct addr_radix_entry *ent;
struct sockaddr_in sa;
KEY_LEN(sa) = KEY_LEN_INET;
sa.sin_addr.s_addr = *((in_addr_t *)key);
rnh = (struct radix_node_head *)ti->state;
- ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
+ ent = (struct addr_radix_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
if (ent != NULL) {
*val = ent->value;
return (1);
}
- } else {
- struct radix_addr_xentry *xent;
+ } else if (keylen == sizeof(struct in6_addr)) {
+ struct addr_radix_xentry *xent;
struct sa_in6 sa6;
KEY_LEN(sa6) = KEY_LEN_INET6;
memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
rnh = (struct radix_node_head *)ti->xstate;
- xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh));
+ xent = (struct addr_radix_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh));
if (xent != NULL) {
*val = xent->value;
return (1);
@@ -434,10 +446,10 @@
* New table
*/
static int
-ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
+ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
char *data, uint8_t tflags)
{
- struct radix_cfg *cfg;
+ struct addr_radix_cfg *cfg;
if (!rn_inithead(&ti->state, OFF_LEN_INET))
return (ENOMEM);
@@ -446,10 +458,10 @@
return (ENOMEM);
}
- cfg = malloc(sizeof(struct radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
+ cfg = malloc(sizeof(struct addr_radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
*ta_state = cfg;
- ti->lookup = ta_lookup_radix;
+ ti->lookup = ta_lookup_addr_radix;
return (0);
}
@@ -458,9 +470,9 @@
flush_radix_entry(struct radix_node *rn, void *arg)
{
struct radix_node_head * const rnh = arg;
- struct radix_addr_entry *ent;
+ struct addr_radix_entry *ent;
- ent = (struct radix_addr_entry *)
+ ent = (struct addr_radix_entry *)
rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, &rnh->rh);
if (ent != NULL)
free(ent, M_IPFW_TBL);
@@ -468,12 +480,12 @@
}
static void
-ta_destroy_radix(void *ta_state, struct table_info *ti)
+ta_destroy_addr_radix(void *ta_state, struct table_info *ti)
{
- struct radix_cfg *cfg;
+ struct addr_radix_cfg *cfg;
struct radix_node_head *rnh;
- cfg = (struct radix_cfg *)ta_state;
+ cfg = (struct addr_radix_cfg *)ta_state;
rnh = (struct radix_node_head *)(ti->state);
rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
@@ -490,31 +502,31 @@
* Provide algo-specific table info
*/
static void
-ta_dump_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
+ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
{
- struct radix_cfg *cfg;
+ struct addr_radix_cfg *cfg;
- cfg = (struct radix_cfg *)ta_state;
+ cfg = (struct addr_radix_cfg *)ta_state;
tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
tinfo->taclass4 = IPFW_TACLASS_RADIX;
tinfo->count4 = cfg->count4;
- tinfo->itemsize4 = sizeof(struct radix_addr_entry);
+ tinfo->itemsize4 = sizeof(struct addr_radix_entry);
tinfo->taclass6 = IPFW_TACLASS_RADIX;
tinfo->count6 = cfg->count6;
- tinfo->itemsize6 = sizeof(struct radix_addr_xentry);
+ tinfo->itemsize6 = sizeof(struct addr_radix_xentry);
}
static int
-ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
+ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti, void *e,
ipfw_obj_tentry *tent)
{
- struct radix_addr_entry *n;
+ struct addr_radix_entry *n;
#ifdef INET6
- struct radix_addr_xentry *xn;
+ struct addr_radix_xentry *xn;
#endif
- n = (struct radix_addr_entry *)e;
+ n = (struct addr_radix_entry *)e;
/* Guess IPv4/IPv6 radix by sockaddr family */
if (n->addr.sin_family == AF_INET) {
@@ -524,7 +536,7 @@
tent->v.kidx = n->value;
#ifdef INET6
} else {
- xn = (struct radix_addr_xentry *)e;
+ xn = (struct addr_radix_xentry *)e;
memcpy(&tent->k.addr6, &xn->addr6.sin6_addr,
sizeof(struct in6_addr));
tent->masklen = xn->masklen;
@@ -537,7 +549,7 @@
}
static int
-ta_find_radix_tentry(void *ta_state, struct table_info *ti,
+ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti,
ipfw_obj_tentry *tent)
{
struct radix_node_head *rnh;
@@ -550,7 +562,7 @@
sa.sin_addr.s_addr = tent->k.addr.s_addr;
rnh = (struct radix_node_head *)ti->state;
e = rnh->rnh_matchaddr(&sa, &rnh->rh);
- } else {
+ } else if (tent->subtype == AF_INET6) {
struct sa_in6 sa6;
KEY_LEN(sa6) = KEY_LEN_INET6;
memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr));
@@ -559,7 +571,7 @@
}
if (e != NULL) {
- ta_dump_radix_tentry(ta_state, ti, e, tent);
+ ta_dump_addr_radix_tentry(ta_state, ti, e, tent);
return (0);
}
@@ -567,7 +579,7 @@
}
static void
-ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
+ta_foreach_addr_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
void *arg)
{
struct radix_node_head *rnh;
@@ -595,7 +607,7 @@
#endif
static void
-tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa,
+tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa,
struct sockaddr *ma, int *set_mask)
{
int mlen;
@@ -647,13 +659,13 @@
}
static int
-ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
+ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
void *ta_buf)
{
struct ta_buf_radix *tb;
- struct radix_addr_entry *ent;
+ struct addr_radix_entry *ent;
#ifdef INET6
- struct radix_addr_xentry *xent;
+ struct addr_radix_xentry *xent;
#endif
struct sockaddr *addr, *mask;
int mlen, set_mask;
@@ -691,7 +703,7 @@
return (EINVAL);
}
- tei_to_sockaddr_ent(tei, addr, mask, &set_mask);
+ tei_to_sockaddr_ent_addr(tei, addr, mask, &set_mask);
/* Set pointers */
tb->addr_ptr = addr;
if (set_mask != 0)
@@ -701,25 +713,25 @@
}
static int
-ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
+ta_add_addr_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
void *ta_buf, uint32_t *pnum)
{
- struct radix_cfg *cfg;
+ struct addr_radix_cfg *cfg;
struct radix_node_head *rnh;
struct radix_node *rn;
struct ta_buf_radix *tb;
uint32_t *old_value, value;
- cfg = (struct radix_cfg *)ta_state;
+ cfg = (struct addr_radix_cfg *)ta_state;
tb = (struct ta_buf_radix *)ta_buf;
/* Save current entry value from @tei */
if (tei->subtype == AF_INET) {
rnh = ti->state;
- ((struct radix_addr_entry *)tb->ent_ptr)->value = tei->value;
+ ((struct addr_radix_entry *)tb->ent_ptr)->value = tei->value;
} else {
rnh = ti->xstate;
- ((struct radix_addr_xentry *)tb->ent_ptr)->value = tei->value;
+ ((struct addr_radix_xentry *)tb->ent_ptr)->value = tei->value;
}
/* Search for an entry first */
@@ -729,9 +741,9 @@
return (EEXIST);
/* Record already exists. Update value if we're asked to */
if (tei->subtype == AF_INET)
- old_value = &((struct radix_addr_entry *)rn)->value;
+ old_value = &((struct addr_radix_entry *)rn)->value;
else
- old_value = &((struct radix_addr_xentry *)rn)->value;
+ old_value = &((struct addr_radix_xentry *)rn)->value;
value = *old_value;
*old_value = tei->value;
@@ -764,7 +776,7 @@
}
static int
-ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
+ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
void *ta_buf)
{
struct ta_buf_radix *tb;
@@ -793,7 +805,7 @@
} else
return (EINVAL);
- tei_to_sockaddr_ent(tei, addr, mask, &set_mask);
+ tei_to_sockaddr_ent_addr(tei, addr, mask, &set_mask);
tb->addr_ptr = addr;
if (set_mask != 0)
tb->mask_ptr = mask;
@@ -802,15 +814,15 @@
}
static int
-ta_del_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
+ta_del_addr_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
void *ta_buf, uint32_t *pnum)
{
- struct radix_cfg *cfg;
+ struct addr_radix_cfg *cfg;
struct radix_node_head *rnh;
struct radix_node *rn;
struct ta_buf_radix *tb;
- cfg = (struct radix_cfg *)ta_state;
+ cfg = (struct addr_radix_cfg *)ta_state;
tb = (struct ta_buf_radix *)ta_buf;
if (tei->subtype == AF_INET)
@@ -825,9 +837,9 @@
/* Save entry value to @tei */
if (tei->subtype == AF_INET)
- tei->value = ((struct radix_addr_entry *)rn)->value;
+ tei->value = ((struct addr_radix_entry *)rn)->value;
else
- tei->value = ((struct radix_addr_xentry *)rn)->value;
+ tei->value = ((struct addr_radix_xentry *)rn)->value;
tb->ent_ptr = rn;
@@ -871,17 +883,17 @@
.type = IPFW_TABLE_ADDR,
.flags = TA_FLAG_DEFAULT,
.ta_buf_size = sizeof(struct ta_buf_radix),
- .init = ta_init_radix,
- .destroy = ta_destroy_radix,
- .prepare_add = ta_prepare_add_radix,
- .prepare_del = ta_prepare_del_radix,
- .add = ta_add_radix,
- .del = ta_del_radix,
+ .init = ta_init_addr_radix,
+ .destroy = ta_destroy_addr_radix,
+ .prepare_add = ta_prepare_add_addr_radix,
+ .prepare_del = ta_prepare_del_addr_radix,
+ .add = ta_add_addr_radix,
+ .del = ta_del_addr_radix,
.flush_entry = ta_flush_radix_entry,
- .foreach = ta_foreach_radix,
- .dump_tentry = ta_dump_radix_tentry,
- .find_tentry = ta_find_radix_tentry,
- .dump_tinfo = ta_dump_radix_tinfo,
+ .foreach = ta_foreach_addr_radix,
+ .dump_tentry = ta_dump_addr_radix_tentry,
+ .find_tentry = ta_find_addr_radix_tentry,
+ .dump_tinfo = ta_dump_addr_radix_tinfo,
.need_modify = ta_need_modify_radix,
};
@@ -4006,6 +4018,328 @@
.print_config = ta_print_kfib_config,
};
+struct mac_radix_entry {
+ struct radix_node rn[2];
+ uint32_t value;
+ uint8_t masklen;
+ struct sa_mac sa;
+};
+
+struct mac_radix_cfg {
+ struct radix_node_head *head;
+ size_t count;
+};
+
+static int
+ta_lookup_mac_radix(struct table_info *ti, void *key, uint32_t keylen,
+ uint32_t *val)
+{
+ struct radix_node_head *rnh;
+
+ if (keylen == ETHER_ADDR_LEN) {
+ struct mac_radix_entry *ent;
+ struct sa_mac sa;
+ KEY_LEN(sa) = KEY_LEN_MAC;
+ memcpy(sa.mac_addr.octet, key, ETHER_ADDR_LEN);
+ rnh = (struct radix_node_head *)ti->state;
+ ent = (struct mac_radix_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
+ if (ent != NULL) {
+ *val = ent->value;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static int
+ta_init_mac_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
+ char *data, uint8_t tflags)
+{
+ struct mac_radix_cfg *cfg;
+
+ if (!rn_inithead(&ti->state, OFF_LEN_MAC))
+ return (ENOMEM);
+
+ cfg = malloc(sizeof(struct mac_radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
+
+ *ta_state = cfg;
+ ti->lookup = ta_lookup_mac_radix;
+
+ return (0);
+}
+
+static void
+ta_destroy_mac_radix(void *ta_state, struct table_info *ti)
+{
+ struct mac_radix_cfg *cfg;
+ struct radix_node_head *rnh;
+
+ cfg = (struct mac_radix_cfg *)ta_state;
+
+ rnh = (struct radix_node_head *)(ti->state);
+ rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
+ rn_detachhead(&ti->state);
+
+ free(cfg, M_IPFW);
+}
+
+static void
+tei_to_sockaddr_ent_mac(struct tentry_info *tei, struct sockaddr *sa,
+ struct sockaddr *ma, int *set_mask)
+{
+ int mlen, i;
+ struct sa_mac *addr, *mask;
+ u_char *cp;
+
+ mlen = tei->masklen;
+ addr = (struct sa_mac *)sa;
+ mask = (struct sa_mac *)ma;
+ /* Set 'total' structure length */
+ KEY_LEN(*addr) = KEY_LEN_MAC;
+ KEY_LEN(*mask) = KEY_LEN_MAC;
+
+ for (i = mlen, cp = mask->mac_addr.octet; i >= 8; i -= 8)
+ *cp++ = 0xFF;
+ if (i > 0)
+ *cp = ~((1 << (8 - i)) - 1);
+
+ addr->mac_addr = *((struct ether_addr *)tei->paddr);
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ addr->mac_addr.octet[i] &= mask->mac_addr.octet[i];
+
+ if (mlen != 8 * ETHER_ADDR_LEN)
+ *set_mask = 1;
+ else
+ *set_mask = 0;
+}
+
+static int
+ta_prepare_add_mac_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
+{
+ struct ta_buf_radix *tb;
+ struct mac_radix_entry *ent;
+ struct sockaddr *addr, *mask;
+ int mlen, set_mask;
+
+ tb = (struct ta_buf_radix *)ta_buf;
+
+ mlen = tei->masklen;
+ set_mask = 0;
+
+ if (tei->subtype == AF_LINK) {
+ if (mlen > 8 * ETHER_ADDR_LEN)
+ return (EINVAL);
+ ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
+ ent->masklen = mlen;
+
+ addr = (struct sockaddr *)&ent->sa;
+ mask = (struct sockaddr *)&tb->addr.mac.ma;
+ tb->ent_ptr = ent;
+ } else {
+ /* Unknown CIDR type */
+ return (EINVAL);
+ }
+
+ tei_to_sockaddr_ent_mac(tei, addr, mask, &set_mask);
+ /* Set pointers */
+ tb->addr_ptr = addr;
+ if (set_mask != 0)
+ tb->mask_ptr = mask;
+
+ return (0);
+}
+
+static int
+ta_add_mac_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
+ void *ta_buf, uint32_t *pnum)
+{
+ struct mac_radix_cfg *cfg;
+ struct radix_node_head *rnh;
+ struct radix_node *rn;
+ struct ta_buf_radix *tb;
+ uint32_t *old_value, value;
+
+ cfg = (struct mac_radix_cfg *)ta_state;
+ tb = (struct ta_buf_radix *)ta_buf;
+
+ /* Save current entry value from @tei */
+ rnh = ti->state;
+ ((struct mac_radix_entry *)tb->ent_ptr)->value = tei->value;
+
+ /* Search for an entry first */
+ rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
+ if (rn != NULL) {
+ if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
+ return (EEXIST);
+ /* Record already exists. Update value if we're asked to */
+ old_value = &((struct mac_radix_entry *)rn)->value;
+
+ value = *old_value;
+ *old_value = tei->value;
+ tei->value = value;
+
+ /* Indicate that update has happened instead of addition */
+ tei->flags |= TEI_FLAGS_UPDATED;
+ *pnum = 0;
+
+ return (0);
+ }
+
+ if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
+ return (EFBIG);
+
+ rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh, tb->ent_ptr);
+ if (rn == NULL) {
+ /* Unknown error */
+ return (EINVAL);
+ }
+
+ cfg->count++;
+ tb->ent_ptr = NULL;
+ *pnum = 1;
+
+ return (0);
+}
+
+static int
+ta_prepare_del_mac_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
+{
+ struct ta_buf_radix *tb;
+ struct sockaddr *addr, *mask;
+ int mlen, set_mask;
+
+ tb = (struct ta_buf_radix *)ta_buf;
+
+ mlen = tei->masklen;
+ set_mask = 0;
+
+ if (tei->subtype == AF_LINK) {
+ if (mlen > 8 * ETHER_ADDR_LEN)
+ return (EINVAL);
+
+ addr = (struct sockaddr *)&tb->addr.mac.sa;
+ mask = (struct sockaddr *)&tb->addr.mac.ma;
+ } else
+ return (EINVAL);
+
+ tei_to_sockaddr_ent_mac(tei, addr, mask, &set_mask);
+ tb->addr_ptr = addr;
+ if (set_mask != 0)
+ tb->mask_ptr = mask;
+
+ return (0);
+}
+
+static int
+ta_del_mac_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
+ void *ta_buf, uint32_t *pnum)
+{
+ struct mac_radix_cfg *cfg;
+ struct radix_node_head *rnh;
+ struct radix_node *rn;
+ struct ta_buf_radix *tb;
+
+ cfg = (struct mac_radix_cfg *)ta_state;
+ tb = (struct ta_buf_radix *)ta_buf;
+ rnh = ti->state;
+
+ rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
+
+ if (rn == NULL)
+ return (ENOENT);
+
+ /* Save entry value to @tei */
+ tei->value = ((struct mac_radix_entry *)rn)->value;
+
+ tb->ent_ptr = rn;
+ cfg->count--;
+ *pnum = 1;
+
+ return (0);
+}
+
+static void
+ta_foreach_mac_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
+ void *arg)
+{
+ struct radix_node_head *rnh;
+
+ rnh = (struct radix_node_head *)(ti->state);
+ rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
+}
+
+static void
+ta_dump_mac_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
+{
+ struct mac_radix_cfg *cfg;
+
+ cfg = (struct mac_radix_cfg *)ta_state;
+
+ tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
+ tinfo->taclass4 = IPFW_TACLASS_RADIX;
+ tinfo->count4 = cfg->count;
+ tinfo->itemsize4 = sizeof(struct mac_radix_entry);
+}
+
+static int
+ta_dump_mac_radix_tentry(void *ta_state, struct table_info *ti, void *e,
+ ipfw_obj_tentry *tent)
+{
+ struct mac_radix_entry *n = (struct mac_radix_entry *)e;
+
+ memcpy(tent->k.mac, n->sa.mac_addr.octet, ETHER_ADDR_LEN);
+ tent->masklen = n->masklen;
+ tent->subtype = AF_LINK;
+ tent->v.kidx = n->value;
+
+ return (0);
+}
+
+static int
+ta_find_mac_radix_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent)
+{
+ struct radix_node_head *rnh;
+ void *e;
+
+ e = NULL;
+ if (tent->subtype == AF_LINK) {
+ struct sa_mac sa;
+ KEY_LEN(sa) = KEY_LEN_MAC;
+ memcpy(tent->k.mac, sa.mac_addr.octet, ETHER_ADDR_LEN);
+ rnh = (struct radix_node_head *)ti->state;
+ e = rnh->rnh_matchaddr(&sa, &rnh->rh);
+ }
+
+ if (e != NULL) {
+ ta_dump_mac_radix_tentry(ta_state, ti, e, tent);
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+struct table_algo mac_radix = {
+ .name = "mac:radix",
+ .type = IPFW_TABLE_MAC,
+ .flags = TA_FLAG_DEFAULT,
+ .ta_buf_size = sizeof(struct ta_buf_radix),
+ .init = ta_init_mac_radix,
+ .destroy = ta_destroy_mac_radix,
+ .prepare_add = ta_prepare_add_mac_radix,
+ .prepare_del = ta_prepare_del_mac_radix,
+ .add = ta_add_mac_radix,
+ .del = ta_del_mac_radix,
+ .flush_entry = ta_flush_radix_entry,
+ .foreach = ta_foreach_mac_radix,
+ .dump_tentry = ta_dump_mac_radix_tentry,
+ .find_tentry = ta_find_mac_radix_tentry,
+ .dump_tinfo = ta_dump_mac_radix_tinfo,
+ .need_modify = ta_need_modify_radix,
+};
+
void
ipfw_table_algo_init(struct ip_fw_chain *ch)
{
@@ -4021,6 +4355,7 @@
ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx);
ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx);
+ ipfw_add_table_algo(ch, &mac_radix, sz, &mac_radix.idx);
}
void
@@ -4033,4 +4368,5 @@
ipfw_del_table_algo(ch, number_array.idx);
ipfw_del_table_algo(ch, flow_hash.idx);
ipfw_del_table_algo(ch, addr_kfib.idx);
+ ipfw_del_table_algo(ch, mac_radix.idx);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 3, 4:50 PM (21 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16438666
Default Alt Text
D35103.diff (41 KB)
Attached To
Mode
D35103: ipfw: Support radix tables and table lookup for MAC addresses
Attached
Detach File
Event Timeline
Log In to Comment