Page MenuHomeFreeBSD

D35103.id105860.diff
No OneTemporary

D35103.id105860.diff

diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -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
@@ -305,7 +305,7 @@
*/
static int lookup_key[] = {
TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT,
- TOK_UID, TOK_JAIL, TOK_DSCP, -1 };
+ TOK_UID, TOK_JAIL, TOK_DSCP, TOK_DSTMAC, TOK_SRCMAC, -1 };
static struct _s_x rule_options[] = {
{ "tagged", TOK_TAGGED },
@@ -358,6 +358,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 },
@@ -378,6 +380,8 @@
{ "dst-ip6", TOK_DSTIP6},
{ "src-ipv6", TOK_SRCIP6},
{ "src-ip6", TOK_SRCIP6},
+ { "dst-mac", TOK_DSTMAC},
+ { "src-mac", TOK_SRCMAC},
{ "lookup", TOK_LOOKUP},
{ "flow", TOK_FLOW},
{ "defer-action", TOK_SKIPACTION },
@@ -1331,6 +1335,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 +1538,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;
@@ -3682,6 +3710,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 +4963,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 ||
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,6 +295,9 @@
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! */
};
@@ -754,7 +757,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 +776,9 @@
#define IPFW_VTYPE_NH4 0x00000200 /* IPv4 nexthop */
#define IPFW_VTYPE_NH6 0x00000400 /* IPv6 nexthop */
+/* MAC/InfiniBand/etc address length */
+#define L2_ADDR_LEN 20
+
typedef struct _ipfw_table_entry {
in_addr_t addr; /* network address */
u_int32_t value; /* value */
@@ -899,6 +906,7 @@
uint32_t key; /* uid/gid/port */
struct in6_addr addr6; /* IPv6 address */
char iface[IF_NAMESIZE]; /* interface name */
+ u_char mac[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
@@ -2047,14 +2047,25 @@
vidx = ((ipfw_insn_u32 *)cmd)->d[1];
if (vidx != 4 /* uid */ &&
vidx != 5 /* jail */ &&
+ vidx != 7 /* dst mac */ &&
+ vidx != 8 /* src mac */ &&
is_ipv6 == 0 && is_ipv4 == 0)
break;
+
+ if ((vidx == 7 /* dst-mac */ ||
+ vidx == 8 /* src-mac */) &&
+ (args->flags & IPFW_ARGS_ETHER) == 0)
+ break; /* only for L2 */
+
/* Determine key length */
if (vidx == 0 /* dst-ip */ ||
vidx == 1 /* src-ip */)
keylen = is_ipv6 ?
sizeof(struct in6_addr):
sizeof(in_addr_t);
+ else if (vidx == 7 /* dst-mac */ ||
+ vidx == 8 /* src-mac */)
+ keylen = ETHER_ADDR_LEN;
else {
keylen = sizeof(key);
pkey = &key;
@@ -2087,6 +2098,10 @@
key = dst_port;
else
key = src_port;
+ } else if (cmd->arg1 == 7 /* dst-mac */) {
+ pkey = eh->ether_dhost;
+ } else if (cmd->arg1 == 8 /* src-mac */) {
+ pkey = eh->ether_shost;
}
#ifndef USERSPACE
else if (vidx == 4 /* uid */ ||
@@ -2155,6 +2170,35 @@
break;
}
+ case O_MAC_SRC_LOOKUP:
+ case O_MAC_DST_LOOKUP:
+ {
+ void *pkey;
+ uint32_t vidx;
+ uint16_t keylen = ETHER_ADDR_LEN;
+
+ if ((args->flags & IPFW_ARGS_ETHER) == 0)
+ break; /* only for L2 */
+
+ 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
@@ -2773,6 +2773,12 @@
/* dscp */
*ptype = IPFW_TABLE_NUMBER;
break;
+ case 7:
+ /* dst-mac */
+ case 8:
+ /* src-mac */
+ *ptype = IPFW_TABLE_MAC;
+ break;
}
}
@@ -2805,6 +2811,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 +2969,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, 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, 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 len;
+ struct ether_addr 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];
+ struct sa_mac sa;
+ uint32_t value;
+ uint8_t masklen;
+};
+
+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.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->addr.octet; i >= 8; i -= 8)
+ *cp++ = 0xFF;
+ if (i > 0)
+ *cp = ~((1 << (8 - i)) - 1);
+
+ addr->addr = *((struct ether_addr *)tei->paddr);
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ addr->addr.octet[i] &= mask->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.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.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

Mime Type
text/plain
Expires
Sat, May 23, 1:55 PM (9 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33447718
Default Alt Text
D35103.id105860.diff (34 KB)

Event Timeline