summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/ifconfig/Makefile1
-rw-r--r--sbin/ifconfig/ifconfig.c18
-rw-r--r--sbin/ifconfig/ifpfsync.c3
-rw-r--r--sbin/ifconfig/ifstf.c157
-rw-r--r--sbin/ifconfig/ifvlan.c37
-rw-r--r--sbin/ipfw/Makefile2
-rw-r--r--sbin/ipfw/context.c148
-rw-r--r--sbin/ipfw/dummynet.c6
-rw-r--r--sbin/ipfw/ipfw2.c185
-rw-r--r--sbin/ipfw/ipfw2.h4
-rw-r--r--sbin/ipfw/main.c23
-rw-r--r--sbin/pfctl/parse.y536
-rw-r--r--sbin/pfctl/pfctl.c39
-rw-r--r--sbin/pfctl/pfctl_altq.c284
-rw-r--r--sbin/pfctl/pfctl_parser.c80
-rw-r--r--sbin/pfctl/pfctl_parser.h16
-rw-r--r--sbin/pfctl/pfctl_qstats.c68
-rw-r--r--sbin/route/route.c5
-rw-r--r--sbin/setkey/parse.y23
-rw-r--r--sbin/setkey/setkey.83
-rw-r--r--sbin/setkey/token.l5
21 files changed, 1524 insertions, 119 deletions
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
index 84509d7..0718081 100644
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -34,6 +34,7 @@ SRCS+= ifvlan.c # SIOC[GS]ETVLAN support
SRCS+= ifvxlan.c # VXLAN support
SRCS+= ifgre.c # GRE keys etc
SRCS+= ifgif.c # GIF reversed header workaround
+SRCS+= ifstf.c # STF configuration options
SRCS+= sfp.c # SFP/SFP+ information
DPADD+= ${LIBM}
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 19bd1ac..1b89e67 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -634,6 +634,23 @@ top:
return(0);
}
+static void
+setaddrfirst(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+
+ if (afp == NULL)
+ err(2, "No address family");
+ if (afp->af_getaddr == NULL)
+ err(2, "No appropriate functions from address family");
+ afp->af_getaddr(addr, ADDR);
+
+ strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
+ printf("Interface name: %s, socket %d, addr %s\n", name, s, addr);
+ if (ioctl(s, SIOCORDERIFADDR, afp->af_addreq) < 0)
+ err(1, "SIOCORDERIFADDR");
+}
+
/*ARGSUSED*/
static void
setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
@@ -1226,6 +1243,7 @@ static struct cmd basic_cmds[] = {
DEF_CMD("noicmp", IFF_LINK1, setifflags),
DEF_CMD_ARG("mtu", setifmtu),
DEF_CMD_ARG("name", setifname),
+ DEF_CMD_ARG("setfirst", setaddrfirst),
};
static __constructor void
diff --git a/sbin/ifconfig/ifpfsync.c b/sbin/ifconfig/ifpfsync.c
index 9dbe1d6..4094610 100644
--- a/sbin/ifconfig/ifpfsync.c
+++ b/sbin/ifconfig/ifpfsync.c
@@ -203,7 +203,8 @@ pfsync_status(int s)
if (preq.pfsyncr_syncdev[0] != '\0' ||
preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP) {
printf("maxupd: %d ", preq.pfsyncr_maxupdates);
- printf("defer: %s\n", preq.pfsyncr_defer ? "on" : "off");
+ printf("defer: %s\n", (preq.pfsyncr_defer & PFSYNCF_DEFER) ? "on" : "off");
+ printf("\tsyncok: %d\n", (preq.pfsyncr_defer & PFSYNCF_OK) ? 1 : 0);
}
}
diff --git a/sbin/ifconfig/ifstf.c b/sbin/ifconfig/ifstf.c
new file mode 100644
index 0000000..7d58909
--- /dev/null
+++ b/sbin/ifconfig/ifstf.c
@@ -0,0 +1,157 @@
+/*-
+ * Copyright 2013 Ermal Luci
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <sys/mbuf.h>
+#include <net/if_stf.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static int
+do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
+{
+ struct ifdrv ifd;
+
+ memset(&ifd, 0, sizeof(ifd));
+
+ strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
+ ifd.ifd_cmd = op;
+ ifd.ifd_len = argsize;
+ ifd.ifd_data = arg;
+
+ return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
+}
+
+static void
+stf_status(int s)
+{
+ struct stfv4args param;
+
+ if (do_cmd(s, STF_GV4NET, &param, sizeof(param), 0) < 0)
+ return;
+
+ printf("\tv4net %s/%d -> ", inet_ntoa(param.inaddr), param.prefix ? param.prefix : 32);
+ printf("tv4br %s\n", inet_ntoa(param.dstv4_addr));
+
+ return;
+}
+
+static void
+setstf_br(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct stfv4args req;
+ struct sockaddr_in sin;
+
+ memset(&req, 0, sizeof(req));
+
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+
+ if (!inet_aton(val, &sin.sin_addr))
+ errx(1, "%s: bad value", val);
+
+ req.dstv4_addr = sin.sin_addr;
+ if (do_cmd(s, STF_SDSTV4, &req, sizeof(req), 1) < 0)
+ err(1, "STF_SV4DST %s", val);
+}
+
+static void
+setstf_set(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct stfv4args req;
+ struct sockaddr_in sin;
+ const char *errstr;
+ char *p = NULL;
+
+ memset(&req, 0, sizeof(req));
+
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+
+ p = strrchr(val, '/');
+ if (p == NULL)
+ errx(2, "Wrong argument given");
+
+ *p = '\0';
+ if (!isdigit(*(p + 1)))
+ errstr = "invalid";
+ else
+ req.prefix = (int)strtonum(p + 1, 0, 32, &errstr);
+ if (errstr != NULL) {
+ *p = '/';
+ errx(1, "%s: bad value (width %s)", val, errstr);
+ }
+
+ if (!inet_aton(val, &sin.sin_addr))
+ errx(1, "%s: bad value", val);
+
+ req.inaddr = sin.sin_addr;
+ if (do_cmd(s, STF_SV4NET, &req, sizeof(req), 1) < 0)
+ err(1, "STF_SV4NET %s", val);
+}
+
+static struct cmd stf_cmds[] = {
+ DEF_CMD_ARG("stfv4net", setstf_set),
+ DEF_CMD_ARG("stfv4br", setstf_br),
+};
+static struct afswtch af_stf = {
+ .af_name = "af_stf",
+ .af_af = AF_UNSPEC,
+ .af_other_status = stf_status,
+};
+
+static __constructor void
+stf_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(stf_cmds); i++)
+ cmd_register(&stf_cmds[i]);
+ af_register(&af_stf);
+#undef N
+}
diff --git a/sbin/ifconfig/ifvlan.c b/sbin/ifconfig/ifvlan.c
index 944ae17..714e4e0 100644
--- a/sbin/ifconfig/ifvlan.c
+++ b/sbin/ifconfig/ifvlan.c
@@ -1,6 +1,10 @@
/*
- * Copyright (c) 1999
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ * Copyright (c) 1999 Bill Paul <wpaul@ctr.columbia.edu>
+ * Copyright (c) 2012 ADARA Networks, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Robert N. M. Watson under
+ * contract to ADARA Networks, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -79,10 +83,14 @@ vlan_status(int s)
{
struct vlanreq vreq;
- if (getvlan(s, &ifr, &vreq) != -1)
- printf("\tvlan: %d parent interface: %s\n",
- vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
- "<none>" : vreq.vlr_parent);
+ if (getvlan(s, &ifr, &vreq) == -1)
+ return;
+ printf("\tvlan: %d", vreq.vlr_tag);
+ if (ioctl(s, SIOCGVLANPCP, (caddr_t)&ifr) != -1)
+ printf(" vlanpcp: %u", ifr.ifr_vlan_pcp);
+ printf(" parent interface: %s", vreq.vlr_parent[0] == '\0' ?
+ "<none>" : vreq.vlr_parent);
+ printf("\n");
}
static void
@@ -150,6 +158,22 @@ DECL_CMD_FUNC(setvlandev, val, d)
}
static
+DECL_CMD_FUNC(setvlanpcp, val, d)
+{
+ u_long ul;
+ char *endp;
+
+ ul = strtoul(val, &endp, 0);
+ if (*endp != '\0')
+ errx(1, "invalid value for vlanpcp");
+ if (ul > 7)
+ errx(1, "value for vlanpcp out of range");
+ ifr.ifr_vlan_pcp = ul;
+ if (ioctl(s, SIOCSVLANPCP, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSVLANPCP");
+}
+
+static
DECL_CMD_FUNC(unsetvlandev, val, d)
{
struct vlanreq vreq;
@@ -170,6 +194,7 @@ DECL_CMD_FUNC(unsetvlandev, val, d)
static struct cmd vlan_cmds[] = {
DEF_CLONE_CMD_ARG("vlan", setvlantag),
DEF_CLONE_CMD_ARG("vlandev", setvlandev),
+ DEF_CMD_ARG("vlanpcp", setvlanpcp),
/* NB: non-clone cmds */
DEF_CMD_ARG("vlan", setvlantag),
DEF_CMD_ARG("vlandev", setvlandev),
diff --git a/sbin/ipfw/Makefile b/sbin/ipfw/Makefile
index 6aea26b..e137e08 100644
--- a/sbin/ipfw/Makefile
+++ b/sbin/ipfw/Makefile
@@ -3,7 +3,7 @@
.include <bsd.own.mk>
PROG= ipfw
-SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c
+SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c context.c
WARNS?= 2
.if ${MK_PF} != "no"
diff --git a/sbin/ipfw/context.c b/sbin/ipfw/context.c
new file mode 100644
index 0000000..bce576e
--- /dev/null
+++ b/sbin/ipfw/context.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2013 Ermal Lu‡i
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/ip_fw.h>
+
+#include "ipfw2.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+
+extern int ipfw_socket;
+
+int
+ipfw_context_handler(int ac, char **av)
+{
+ ip_fw3_opheader *op3;
+ int error = 0;
+ uint32_t action = 0;
+ socklen_t len, nlen;
+ char *ifname;
+
+ av++;
+ ac--;
+ NEED1("bad arguments, for usage summary ``ipfw''");
+
+ if (!strncmp(*av, "list", strlen(*av))) {
+ action = IP_FW_CTX_GET;
+ av++;
+ ac--;
+ if (ac > 0)
+ errx(EX_DATAERR, "list: does not take any extra arguments.");
+
+ } else {
+ co.ctx = atoi(*av);
+
+ av++;
+ ac--;
+ NEED1("bad arguments, for usage summary ``ipfw''");
+
+ if (!strncmp(*av, "create", strlen(*av)))
+ action = IP_FW_CTX_ADD;
+ else if (!strncmp(*av, "destroy", strlen(*av)))
+ action = IP_FW_CTX_DEL;
+ else {
+ if (!strncmp(*av, "madd", strlen(*av)))
+ action = IP_FW_CTX_ADDMEMBER;
+ else if (!strncmp(*av, "mdel", strlen(*av)))
+ action = IP_FW_CTX_DELMEMBER;
+ else
+ errx(EX_DATAERR, "Wrong parameters passed");
+
+ av++;
+ ac--;
+ NEED1("bad arguments, for usage summary ``ipfw''");
+
+ ifname = *av;
+ }
+
+ ac--;
+ if (ac > 0)
+ errx(EX_DATAERR, "context handling: Too many arguments passed");
+
+ }
+
+ if (co.test_only)
+ return (0);
+
+ if (ipfw_socket < 0)
+ ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (ipfw_socket < 0)
+ err(EX_UNAVAILABLE, "socket");
+
+ switch (action) {
+ case IP_FW_CTX_ADD:
+ case IP_FW_CTX_DEL:
+ case IP_FW_CTX_SET:
+ len = sizeof(ip_fw3_opheader);
+ op3 = alloca(len);
+ /* Zero reserved fields */
+ memset(op3, 0, sizeof(ip_fw3_opheader));
+ op3->opcode = action;
+ op3->ctxid = co.ctx;
+ error = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
+ break;
+ case IP_FW_CTX_ADDMEMBER:
+ case IP_FW_CTX_DELMEMBER:
+ len = sizeof(ip_fw3_opheader) + strlen(ifname) + 1;
+ op3 = alloca(len);
+ /* Zero reserved fields */
+ memset(op3, 0, sizeof(ip_fw3_opheader) + strlen(ifname) + 1);
+ memcpy((op3 + 1), ifname, strlen(ifname));
+ op3->opcode = action;
+ op3->ctxid = co.ctx;
+ error = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
+ break;
+ case IP_FW_CTX_GET:
+ len = sizeof(ip_fw3_opheader) + 1000;
+ nlen = len;
+ do {
+ if (nlen > len) {
+ len = nlen;
+ }
+ op3 = alloca(len);
+ /* Zero reserved fields */
+ memset(op3, 0, len);
+ op3->opcode = action;
+ op3->ctxid = co.ctx;
+ nlen = len;
+ error = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, &nlen);
+ } while (nlen > len && !error);
+
+ if (!error) {
+ if (nlen == 0)
+ printf("There are no contexts defined\n");
+ else
+ printf("Currently defined contexts and their members:\n%s\n", (char *)op3);
+ } else
+ err(EX_UNAVAILABLE, "Error returned: %s\n", strerror(error));
+
+ break;
+ }
+
+ return (error);
+}
diff --git a/sbin/ipfw/dummynet.c b/sbin/ipfw/dummynet.c
index 28dc2c7..c5b5253 100644
--- a/sbin/ipfw/dummynet.c
+++ b/sbin/ipfw/dummynet.c
@@ -538,10 +538,10 @@ read_bandwidth(char *arg, int *bandwidth, char *if_name, int namelen)
if_name[namelen] = '\0';
*bandwidth = 0;
} else { /* read bandwidth value */
- int bw;
+ double bw;
char *end = NULL;
- bw = strtoul(arg, &end, 0);
+ bw = strtod(arg, &end);
if (*end == 'K' || *end == 'k') {
end++;
bw *= 1000;
@@ -557,7 +557,7 @@ read_bandwidth(char *arg, int *bandwidth, char *if_name, int namelen)
if (bw < 0)
errx(EX_DATAERR, "bandwidth too large");
- *bandwidth = bw;
+ *bandwidth = (int)bw;
if (if_name)
if_name[0] = '\0';
}
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index f585ded..6d7d3d7 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -54,7 +54,7 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
-struct cmdline_opts co; /* global options */
+struct cmdline_opts co = { 0 }; /* global options */
int resvd_set_number = RESVD_SET;
@@ -422,6 +422,7 @@ safe_realloc(void *ptr, size_t size)
int
do_cmd(int optname, void *optval, uintptr_t optlen)
{
+ ip_fw3_opheader op3;
int i;
if (co.test_only)
@@ -432,6 +433,15 @@ do_cmd(int optname, void *optval, uintptr_t optlen)
if (ipfw_socket < 0)
err(EX_UNAVAILABLE, "socket");
+ if (optname != IP_FW3 && optname != IP_DUMMYNET3 && optname != -IP_DUMMYNET3) {
+ memset(&op3, 0, sizeof op3);
+ op3.ctxid = co.ctx;
+ op3.opcode = IP_FW_CTX_SET;
+ i = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, &op3, sizeof(op3));
+ if (i)
+ errx(EX_OSERR, "setsockopt: choosing context");
+ }
+
if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET ||
optname == IP_FW_ADD || optname == IP_FW3 ||
optname == IP_FW_NAT_GET_CONFIG ||
@@ -477,6 +487,7 @@ do_setcmd3(int optname, void *optval, socklen_t optlen)
memset(op3, 0, sizeof(ip_fw3_opheader));
memcpy(op3 + 1, optval, optlen);
op3->opcode = optname;
+ op3->ctxid = co.ctx;
return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
}
@@ -4122,8 +4133,9 @@ ipfw_flush(int force)
}
+static void table_list_entry(ipfw_table_xentry *);
static void table_list(uint16_t num, int need_header);
-static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
+static void table_fill_xentry(int ac, char *av[], ipfw_table_xentry *xent);
/*
* Retrieve maximum number of tables supported by ipfw(4) module.
@@ -4194,29 +4206,9 @@ ipfw_table_handler(int ac, char *av[])
if (_substrcmp(*av, "add") == 0 ||
_substrcmp(*av, "delete") == 0) {
do_add = **av == 'a';
- ac--; av++;
- if (!ac)
- errx(EX_USAGE, "address required");
- table_fill_xentry(*av, &xent);
+ table_fill_xentry(ac, av, &xent);
- ac--; av++;
- if (do_add && ac) {
- unsigned int tval;
- /* isdigit is a bit of a hack here.. */
- if (strchr(*av, (int)'.') == NULL && isdigit(**av)) {
- xent.value = strtoul(*av, NULL, 0);
- } else {
- if (lookup_host(*av, (struct in_addr *)&tval) == 0) {
- /* The value must be stored in host order *
- * so that the values < 65k can be distinguished */
- xent.value = ntohl(tval);
- } else {
- errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
- }
- }
- } else
- xent.value = 0;
if (do_setcmd3(do_add ? IP_FW_TABLE_XADD : IP_FW_TABLE_XDEL,
&xent, xent.len) < 0) {
/* If running silent, don't bomb out on these errors. */
@@ -4243,19 +4235,41 @@ ipfw_table_handler(int ac, char *av[])
do {
table_list(xent.tbl, is_all);
} while (++xent.tbl < a);
+ } else if (_substrcmp(*av, "entrystats") == 0) {
+ table_fill_xentry(ac, av, &xent);
+
+ if (do_setcmd3(IP_FW_TABLE_XLISTENTRY, &xent, xent.len) < 0) {
+ /* If running silent, don't bomb out on these errors. */
+ if (!(co.do_quiet))
+ err(EX_OSERR, "setsockopt(IP_FW_TABLE_XLISTENTRY)");
+ } else
+ table_list_entry(&xent);
+ } else if (_substrcmp(*av, "entryzerostats") == 0) {
+ table_fill_xentry(ac, av, &xent);
+
+ if (do_setcmd3(IP_FW_TABLE_XZEROENTRY, &xent, xent.len) < 0) {
+ /* If running silent, don't bomb out on these errors. */
+ if (!(co.do_quiet))
+ err(EX_OSERR, "setsockopt(IP_FW_TABLE_XZEROENTRY)");
+ }
} else
errx(EX_USAGE, "invalid table command %s", *av);
}
static void
-table_fill_xentry(char *arg, ipfw_table_xentry *xent)
+table_fill_xentry(int ac, char *av[], ipfw_table_xentry *xent)
{
- int addrlen, mask, masklen, type;
+ int addrlen, mask, masklen, type, do_add;
struct in6_addr *paddr;
uint32_t *pkey;
- char *p;
+ char *p, *arg;
uint32_t key;
+ do_add = **av == 'a';
+ ac--; av++;
+ if (!ac)
+ errx(EX_USAGE, "address required");
+
mask = 0;
type = 0;
addrlen = 0;
@@ -4270,7 +4284,20 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
* 4) port, uid/gid or other u32 key (base 10 format)
* 5) hostname
*/
- paddr = &xent->k.addr6;
+ if (ac > 1 && av && _substrcmp(*av, "mac") == 0) {
+ uint8_t _mask[8];
+
+ type = IPFW_TABLE_MIX;
+ get_mac_addr_mask(av[1], (uint8_t *)xent->mac_addr, _mask);
+ ac-=2; av+=2;
+ if (ac <= 0)
+ errx(EX_DATAERR, "wrong argument passed.");
+
+ paddr = (struct in6_addr *)&xent->k.addr6;
+ } else
+ paddr = &xent->k.addr6;
+
+ arg = *av;
if (ishexnumber(*arg) != 0 || *arg == ':') {
/* Remove / if exists */
if ((p = strchr(arg, '/')) != NULL) {
@@ -4283,9 +4310,11 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
errx(EX_DATAERR, "bad IPv4 mask width: %s",
p + 1);
- type = IPFW_TABLE_CIDR;
+ if (type == 0)
+ type = IPFW_TABLE_CIDR;
masklen = p ? mask : 32;
addrlen = sizeof(struct in_addr);
+ xent->flags = IPFW_TCF_INET;
} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
if (IN6_IS_ADDR_V4COMPAT(paddr))
errx(EX_DATAERR,
@@ -4294,10 +4323,14 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
errx(EX_DATAERR, "bad IPv6 mask width: %s",
p + 1);
- type = IPFW_TABLE_CIDR;
+ if (type == 0)
+ type = IPFW_TABLE_CIDR;
masklen = p ? mask : 128;
addrlen = sizeof(struct in6_addr);
} else {
+ if (type != 0 && type != IPFW_TABLE_MIX)
+ errx(EX_DATAERR, "Wrong value passed as address");
+
/* Port or any other key */
/* Skip non-base 10 entries like 'fa1' */
key = strtol(arg, &p, 10);
@@ -4338,11 +4371,88 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
masklen = 32;
type = IPFW_TABLE_CIDR;
addrlen = sizeof(struct in_addr);
+ xent->flags = IPFW_TCF_INET;
+ }
+
+ ac--; av++;
+ if (ac > 1 && av) {
+ if (_substrcmp(*av, "mac") == 0) {
+ uint8_t _mask[8];
+
+ if (type == 0)
+ type = IPFW_TABLE_CIDR;
+ get_mac_addr_mask(av[1], (uint8_t *)&xent->mac_addr, _mask);
+ ac-=2; av+=2;
+ }
}
+ if (do_add && ac > 0) {
+ unsigned int tval;
+ /* isdigit is a bit of a hack here.. */
+ if (strchr(*av, (int)'.') == NULL && isdigit(**av)) {
+ xent->value = strtoul(*av, NULL, 0);
+ } else {
+ if (lookup_host(*av, (struct in_addr *)&tval) == 0) {
+ /* The value must be stored in host order *
+ * so that the values < 65k can be distinguished */
+ xent->value = ntohl(tval);
+ } else {
+ errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
+ }
+ }
+ } else
+ xent->value = 0;
+
xent->type = type;
xent->masklen = masklen;
- xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
+ if (type == IPFW_TABLE_MIX)
+ xent->len = offsetof(ipfw_table_xentry, k) + addrlen + ETHER_ADDR_LEN;
+ else
+ xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
+}
+
+static void
+table_list_entry(ipfw_table_xentry *xent)
+{
+ struct in6_addr *addr6;
+ uint32_t tval;
+ char tbuf[128];
+
+ switch (xent->type) {
+ case IPFW_TABLE_CIDR:
+ /* IPv4 or IPv6 prefixes */
+ tval = xent->value;
+ addr6 = &xent->k.addr6;
+
+ if ((xent->flags & IPFW_TCF_INET) != 0) {
+ /* IPv4 address */
+ inet_ntop(AF_INET, (in_addr_t *)&addr6->s6_addr32[0], tbuf, sizeof(tbuf));
+ } else {
+ /* IPv6 address */
+ inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf));
+ }
+
+ if (co.do_value_as_ip) {
+ tval = htonl(tval);
+ printf("%s/%u %s %d %d %u\n", tbuf, xent->masklen,
+ inet_ntoa(*(struct in_addr *)&tval), pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
+ } else
+ printf("%s/%u %u %d %d %u\n", tbuf, xent->masklen, tval,
+ pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
+ break;
+ case IPFW_TABLE_INTERFACE:
+ /* Interface names */
+ tval = xent->value;
+ if (co.do_value_as_ip) {
+ tval = htonl(tval);
+ printf("%s %u %s %d %d %u\n", xent->k.iface, xent->masklen,
+ inet_ntoa(*(struct in_addr *)&tval), pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
+ } else
+ printf("%s %u %u %d %d %u\n", xent->k.iface, xent->masklen, tval,
+ pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
+
+ break;
+ }
}
static void
@@ -4364,6 +4474,7 @@ table_list(uint16_t num, int need_header)
a = (uint32_t *)(op3 + 1);
*a = num;
op3->opcode = IP_FW_TABLE_XGETSIZE;
+ op3->ctxid = co.ctx;
if (do_cmd(IP_FW3, op3, (uintptr_t)&l) < 0)
err(EX_OSERR, "getsockopt(IP_FW_TABLE_XGETSIZE)");
@@ -4374,6 +4485,7 @@ table_list(uint16_t num, int need_header)
l = *a;
tbl = safe_calloc(1, l);
tbl->opheader.opcode = IP_FW_TABLE_XLIST;
+ tbl->opheader.ctxid = co.ctx;
tbl->tbl = num;
if (do_cmd(IP_FW3, tbl, (uintptr_t)&l) < 0)
err(EX_OSERR, "getsockopt(IP_FW_TABLE_XLIST)");
@@ -4388,21 +4500,24 @@ table_list(uint16_t num, int need_header)
tval = xent->value;
addr6 = &xent->k.addr6;
-
if ((xent->flags & IPFW_TCF_INET) != 0) {
/* IPv4 address */
- inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, sizeof(tbuf));
+ inet_ntop(AF_INET, &addr6->s6_addr32[0], tbuf, sizeof(tbuf));
} else {
/* IPv6 address */
inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf));
}
+ printf("%s/%u", tbuf, xent->masklen);
+ if (xent->mac_addr)
+ printf(" mac %s", ether_ntoa((struct ether_addr *)&xent->mac_addr));
+
if (co.do_value_as_ip) {
tval = htonl(tval);
- printf("%s/%u %s\n", tbuf, xent->masklen,
+ printf(" %s\n",
inet_ntoa(*(struct in_addr *)&tval));
} else
- printf("%s/%u %u\n", tbuf, xent->masklen, tval);
+ printf(" %u\n", tval);
break;
case IPFW_TABLE_INTERFACE:
/* Interface names */
@@ -4413,6 +4528,8 @@ table_list(uint16_t num, int need_header)
inet_ntoa(*(struct in_addr *)&tval));
} else
printf("%s %u\n", xent->k.iface, tval);
+
+ break;
}
if (sz < xent->len)
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index 6e895b8..3ef9b19 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -54,6 +54,7 @@ struct cmdline_opts {
int use_set; /* work with specified set number */
/* 0 means all sets, otherwise apply to set use_set - 1 */
+ u_int ctx;
};
extern struct cmdline_opts co;
@@ -282,6 +283,9 @@ void dummynet_list(int ac, char *av[], int show_counters);
void dummynet_flush(void);
int ipfw_delete_pipe(int pipe_or_queue, int n);
+/* Contextes */
+int ipfw_context_handler(int, char **);
+
/* ipv6.c */
void print_unreach6_code(uint16_t code);
void print_ip6(struct _ipfw_insn_ip6 *cmd, char const *s);
diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c
index 82a299b..ab75a1b 100644
--- a/sbin/ipfw/main.c
+++ b/sbin/ipfw/main.c
@@ -262,7 +262,7 @@ ipfw_main(int oldac, char **oldav)
save_av = av;
optind = optreset = 1; /* restart getopt() */
- while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtv")) != -1)
+ while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtvx:")) != -1)
switch (ch) {
case 'a':
do_acct = 1;
@@ -335,6 +335,12 @@ ipfw_main(int oldac, char **oldav)
co.verbose = 1;
break;
+ case 'x':
+ co.ctx = atoi(optarg);
+ if (co.ctx == 0)
+ errx(EX_USAGE, "Context 0 is invalid");
+ break;
+
default:
free(save_av);
return 1;
@@ -362,7 +368,9 @@ ipfw_main(int oldac, char **oldav)
co.do_nat = 0;
co.do_pipe = 0;
co.use_set = 0;
- if (!strncmp(*av, "nat", strlen(*av)))
+ if (!strncmp(*av, "zone", strlen(*av)))
+ return (ipfw_context_handler(ac, av));
+ else if (!strncmp(*av, "nat", strlen(*av)))
co.do_nat = 1;
else if (!strncmp(*av, "pipe", strlen(*av)))
co.do_pipe = 1;
@@ -389,6 +397,9 @@ ipfw_main(int oldac, char **oldav)
}
NEED1("missing command");
+ if (!co.ctx && !co.do_pipe)
+ err(11, "Context is mandatory");
+
/*
* For pipes, queues and nats we normally say 'nat|pipe NN config'
* but the code is easier to parse as 'nat|pipe config NN'
@@ -458,7 +469,7 @@ ipfw_readfile(int ac, char *av[])
FILE *f = NULL;
pid_t preproc = 0;
- while ((c = getopt(ac, av, "cfNnp:qS")) != -1) {
+ while ((c = getopt(ac, av, "cfNnp:qSx:")) != -1) {
switch(c) {
case 'c':
co.do_compact = 1;
@@ -509,6 +520,12 @@ ipfw_readfile(int ac, char *av[])
co.show_sets = 1;
break;
+ case 'x':
+ co.ctx = atoi(optarg);
+ if (co.ctx == 0)
+ errx(EX_USAGE, "Context 0 is invalid");
+ break;
+
default:
errx(EX_USAGE, "bad arguments, for usage"
" summary ``ipfw''");
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 99c26c0..b5577e2 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#endif
#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_vlan_var.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -46,8 +48,10 @@ __FBSDID("$FreeBSD$");
#include <arpa/inet.h>
#include <altq/altq.h>
#include <altq/altq_cbq.h>
+#include <altq/altq_codel.h>
#include <altq/altq_priq.h>
#include <altq/altq_hfsc.h>
+#include <altq/altq_fairq.h>
#include <stdio.h>
#include <unistd.h>
@@ -158,6 +162,7 @@ struct node_icmp {
enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
+ PF_STATE_OPT_MAX_PACKETS,
PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
@@ -169,6 +174,7 @@ struct node_state_opt {
u_int32_t max_states;
u_int32_t max_src_states;
u_int32_t max_src_conn;
+ u_int32_t max_packets;
struct {
u_int32_t limit;
u_int32_t seconds;
@@ -215,6 +221,7 @@ struct filter_opts {
#define FOM_TOS 0x04
#define FOM_KEEP 0x08
#define FOM_SRCTRACK 0x10
+#define FOM_DSCP 0x20
struct node_uid *uid;
struct node_gid *gid;
struct {
@@ -225,7 +232,9 @@ struct filter_opts {
} flags;
struct node_icmp *icmpspec;
u_int32_t tos;
+ u_int32_t dscp;
u_int32_t prob;
+ u_int32_t tracker;
struct {
int action;
struct node_state_opt *options;
@@ -233,10 +242,19 @@ struct filter_opts {
int fragment;
int allowopts;
char *label;
+ char *schedule;
struct node_qassign queues;
char *tag;
char *match_tag;
u_int8_t match_tag_not;
+ struct {
+ uint8_t pcp[2];
+ uint8_t op;
+ uint8_t setpcp;
+ } ieee8021q_pcp;
+ u_int32_t dnpipe;
+ u_int32_t pdnpipe;
+ u_int32_t free_flags;
u_int rtableid;
struct {
struct node_host *addr;
@@ -246,6 +264,7 @@ struct filter_opts {
struct antispoof_opts {
char *label;
+ u_int32_t tracker;
u_int rtableid;
} antispoof_opts;
@@ -298,8 +317,9 @@ struct pool_opts {
} pool_opts;
-
+struct codel_opts codel_opts;
struct node_hfsc_opts hfsc_opts;
+struct node_fairq_opts fairq_opts;
struct node_state_opt *keep_state_defaults = NULL;
int disallow_table(struct node_host *, const char *);
@@ -337,6 +357,7 @@ int expand_skip_interface(struct node_if *);
int check_rulestate(int);
int getservice(char *);
int rule_label(struct pf_rule *, char *);
+int rule_schedule(struct pf_rule *, char *);
int rt_tableid_max(void);
void mv_rules(struct pf_ruleset *, struct pf_ruleset *);
@@ -422,6 +443,8 @@ typedef struct {
struct table_opts table_opts;
struct pool_opts pool_opts;
struct node_hfsc_opts hfsc_opts;
+ struct node_fairq_opts fairq_opts;
+ struct codel_opts codel_opts;
} v;
int lineno;
} YYSTYPE;
@@ -436,29 +459,31 @@ int parseport(char *, struct range *r, int);
%}
-%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
+%token PASS BLOCK MATCH SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
-%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
-%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
+%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL SCHEDULE
+%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DSCP DROP TABLE TRACKER
%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
%token ANTISPOOF FOR INCLUDE
%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
-%token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
-%token QUEUE PRIORITY QLIMIT RTABLE
+%token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
+%token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
+%token DNPIPE DNQUEUE
%token LOAD RULESET_OPTIMIZATION
%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
-%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
+%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS MAXPCKT
+%token IEEE8021QPCP IEEE8021QSETPCP
%token DIVERTTO DIVERTREPLY
%token <v.string> STRING
%token <v.number> NUMBER
%token <v.i> PORTBINARY
%type <v.interface> interface if_list if_item_not if_item
%type <v.number> number icmptype icmp6type uid gid
-%type <v.number> tos not yesno
+%type <v.number> tos dscp not yesno
%type <v.probability> probability
%type <v.i> no dir af fragcache optimizer
%type <v.i> sourcetrack flush unaryop statelock
@@ -473,8 +498,8 @@ int parseport(char *, struct range *r, int);
%type <v.icmp> icmp6_list icmp6_item
%type <v.number> reticmpspec reticmp6spec
%type <v.fromto> fromto
-%type <v.peer> ipportspec from to
-%type <v.host> ipspec toipspec xhost host dynaddr host_list
+%type <v.peer> ipportspec from to toipportspec
+%type <v.host> ipspec xhost host dynaddr host_list
%type <v.host> redir_host_list redirspec
%type <v.host> route_host route_host_list routespec
%type <v.os> os xos os_list
@@ -483,7 +508,7 @@ int parseport(char *, struct range *r, int);
%type <v.gid> gids gid_list gid_item
%type <v.route> route
%type <v.redirection> redirection redirpool
-%type <v.string> label stringall tag anchorname
+%type <v.string> label schedule stringall tag anchorname
%type <v.string> string varstring numberstring
%type <v.keep_state> keep
%type <v.state_opt> state_opt_spec state_opt_list state_opt_item
@@ -495,6 +520,8 @@ int parseport(char *, struct range *r, int);
%type <v.number> cbqflags_list cbqflags_item
%type <v.number> priqflags_list priqflags_item
%type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts
+%type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts
+%type <v.codel_opts> codelopts_list codelopts_item codel_opts
%type <v.queue_bwspec> bandwidth
%type <v.filter_opts> filter_opts filter_opt filter_opts_l
%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l
@@ -874,6 +901,11 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
YYERROR;
}
+ r.ieee8021q_pcp.pcp[0] = $9.ieee8021q_pcp.pcp[0];
+ r.ieee8021q_pcp.pcp[1] = $9.ieee8021q_pcp.pcp[1];
+ r.ieee8021q_pcp.op = $9.ieee8021q_pcp.op;
+ r.ieee8021q_pcp.setpcp = $9.ieee8021q_pcp.setpcp;
+
if ($9.match_tag)
if (strlcpy(r.match_tagname, $9.match_tag,
PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
@@ -1214,6 +1246,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
if (rule_label(&r, $5.label))
YYERROR;
r.rtableid = $5.rtableid;
+ r.cuid = $5.tracker;
j = calloc(1, sizeof(struct node_if));
if (j == NULL)
err(1, "antispoof: calloc");
@@ -1263,6 +1296,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
r.logif = $2.logif;
r.quick = $2.quick;
r.af = $4;
+ r.cuid = $5.tracker;
if (rule_label(&r, $5.label))
YYERROR;
r.rtableid = $5.rtableid;
@@ -1324,6 +1358,9 @@ antispoof_opt : label {
}
antispoof_opts.label = $1;
}
+ | TRACKER number {
+ antispoof_opts.tracker = $2;
+ }
| RTABLE NUMBER {
if ($2 < 0 || $2 > rt_tableid_max()) {
yyerror("invalid rtable id");
@@ -1466,7 +1503,7 @@ altqif : ALTQ interface queue_opts QUEUE qassign {
a.scheduler = $3.scheduler.qtype;
a.qlimit = $3.qlimit;
a.tbrsize = $3.tbrsize;
- if ($5 == NULL) {
+ if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) {
yyerror("no child queues specified");
YYERROR;
}
@@ -1598,14 +1635,22 @@ bandwidth : STRING {
bps = strtod($1, &cp);
if (cp != NULL) {
- if (!strcmp(cp, "b"))
+ if (!strcmp(cp, "b") || !strcmp(cp, "bit"))
; /* nothing */
- else if (!strcmp(cp, "Kb"))
+ else if (!strcmp(cp, "Kb") || !strcmp(cp, "Kbit"))
bps *= 1000;
- else if (!strcmp(cp, "Mb"))
+ else if (!strcmp(cp, "Mb") || !strcmp(cp, "Mbit"))
bps *= 1000 * 1000;
- else if (!strcmp(cp, "Gb"))
+ else if (!strcmp(cp, "Gb") || !strcmp(cp, "Gbit"))
bps *= 1000 * 1000 * 1000;
+ else if (!strcmp(cp, "B") || !strcmp(cp, "Byte"))
+ ; /* nothing */
+ else if (!strcmp(cp, "KB") || !strcmp(cp, "Kbyte"))
+ bps *= 1024;
+ else if (!strcmp(cp, "MB") || !strcmp(cp, "Mbyte"))
+ bps *= 1024 * 1024;
+ else if (!strcmp(cp, "GB") || !strcmp(cp, "Gbyte"))
+ bps *= 1024 * 1024 * 1024;
else if (!strcmp(cp, "%")) {
if (bps < 0 || bps > 100) {
yyerror("bandwidth spec "
@@ -1659,6 +1704,24 @@ scheduler : CBQ {
$$.qtype = ALTQT_HFSC;
$$.data.hfsc_opts = $3;
}
+ | FAIRQ {
+ $$.qtype = ALTQT_FAIRQ;
+ bzero(&$$.data.fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+ | FAIRQ '(' fairq_opts ')' {
+ $$.qtype = ALTQT_FAIRQ;
+ $$.data.fairq_opts = $3;
+ }
+ | CODEL {
+ $$.qtype = ALTQT_CODEL;
+ bzero(&$$.data.codel_opts,
+ sizeof(struct codel_opts));
+ }
+ | CODEL '(' codel_opts ')' {
+ $$.qtype = ALTQT_CODEL;
+ $$.data.codel_opts = $3;
+ }
;
cbqflags_list : cbqflags_item { $$ |= $1; }
@@ -1676,6 +1739,8 @@ cbqflags_item : STRING {
$$ = CBQCLF_RED|CBQCLF_ECN;
else if (!strcmp($1, "rio"))
$$ = CBQCLF_RIO;
+ else if (!strcmp($1, "codel"))
+ $$ = CBQCLF_CODEL;
else {
yyerror("unknown cbq flag \"%s\"", $1);
free($1);
@@ -1698,6 +1763,8 @@ priqflags_item : STRING {
$$ = PRCF_RED|PRCF_ECN;
else if (!strcmp($1, "rio"))
$$ = PRCF_RIO;
+ else if (!strcmp($1, "codel"))
+ $$ = PRCF_CODEL;
else {
yyerror("unknown priq flag \"%s\"", $1);
free($1);
@@ -1798,6 +1865,8 @@ hfscopts_item : LINKSHARE bandwidth {
hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
else if (!strcmp($1, "rio"))
hfsc_opts.flags |= HFCF_RIO;
+ else if (!strcmp($1, "codel"))
+ hfsc_opts.flags |= HFCF_CODEL;
else {
yyerror("unknown hfsc flag \"%s\"", $1);
free($1);
@@ -1807,6 +1876,102 @@ hfscopts_item : LINKSHARE bandwidth {
}
;
+fairq_opts : {
+ bzero(&fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+ fairqopts_list {
+ $$ = fairq_opts;
+ }
+ ;
+
+fairqopts_list : fairqopts_item
+ | fairqopts_list comma fairqopts_item
+ ;
+
+fairqopts_item : LINKSHARE bandwidth {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m2 = $2;
+ fairq_opts.linkshare.used = 1;
+ }
+ | LINKSHARE '(' bandwidth number bandwidth ')' {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m1 = $3;
+ fairq_opts.linkshare.d = $4;
+ fairq_opts.linkshare.m2 = $5;
+ fairq_opts.linkshare.used = 1;
+ }
+ | HOGS bandwidth {
+ fairq_opts.hogs_bw = $2;
+ }
+ | BUCKETS number {
+ fairq_opts.nbuckets = $2;
+ }
+ | STRING {
+ if (!strcmp($1, "default"))
+ fairq_opts.flags |= FARF_DEFAULTCLASS;
+ else if (!strcmp($1, "red"))
+ fairq_opts.flags |= FARF_RED;
+ else if (!strcmp($1, "ecn"))
+ fairq_opts.flags |= FARF_RED|FARF_ECN;
+ else if (!strcmp($1, "rio"))
+ fairq_opts.flags |= FARF_RIO;
+ else if (!strcmp($1, "codel"))
+ fairq_opts.flags |= FARF_CODEL;
+ else {
+ yyerror("unknown fairq flag \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+codel_opts : {
+ bzero(&codel_opts,
+ sizeof(struct codel_opts));
+ }
+ codelopts_list {
+ $$ = codel_opts;
+ }
+ ;
+
+codelopts_list : codelopts_item
+ | codelopts_list comma codelopts_item
+ ;
+
+codelopts_item : INTERVAL number {
+ if (codel_opts.interval) {
+ yyerror("interval already specified");
+ YYERROR;
+ }
+ codel_opts.interval = $2;
+ }
+ | TARGET number {
+ if (codel_opts.target) {
+ yyerror("target already specified");
+ YYERROR;
+ }
+ codel_opts.target = $2;
+ }
+ | STRING {
+ if (!strcmp($1, "ecn"))
+ codel_opts.ecn = 1;
+ else {
+ yyerror("unknown codel option \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
qassign : /* empty */ { $$ = NULL; }
| qassign_item { $$ = $1; }
| '{' optnl qassign_list '}' { $$ = $3; }
@@ -1878,6 +2043,11 @@ pfrule : action dir logquick interface route af proto fromto
r.prob = $9.prob;
r.rtableid = $9.rtableid;
+ r.ieee8021q_pcp.pcp[0] = $9.ieee8021q_pcp.pcp[0];
+ r.ieee8021q_pcp.pcp[1] = $9.ieee8021q_pcp.pcp[1];
+ r.ieee8021q_pcp.op = $9.ieee8021q_pcp.op;
+ r.ieee8021q_pcp.setpcp = $9.ieee8021q_pcp.setpcp;
+
r.af = $6;
if ($9.tag)
if (strlcpy(r.tagname, $9.tag,
@@ -1897,6 +2067,11 @@ pfrule : action dir logquick interface route af proto fromto
if (rule_label(&r, $9.label))
YYERROR;
free($9.label);
+ if (rule_schedule(&r, $9.schedule))
+ YYERROR;
+ free($9.schedule);
+ if ($9.tracker)
+ r.cuid = $9.tracker;
r.flags = $9.flags.b1;
r.flagset = $9.flags.b2;
if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
@@ -1928,7 +2103,14 @@ pfrule : action dir logquick interface route af proto fromto
#endif
}
- r.tos = $9.tos;
+ if ($9.tos) {
+ r.tos = $9.tos;
+ r.rule_flag |= PFRULE_TOS;
+ }
+ if ($9.dscp) {
+ r.tos = $9.dscp;
+ r.rule_flag |= PFRULE_DSCP;
+ }
r.keep_state = $9.keep.action;
o = $9.keep.options;
@@ -1960,6 +2142,14 @@ pfrule : action dir logquick interface route af proto fromto
}
r.rule_flag |= PFRULE_NOSYNC;
break;
+ case PF_STATE_OPT_MAX_PACKETS:
+ if (o->data.max_packets == 0) {
+ yyerror("max_packets must be"
+ "greater than 0");
+ YYERROR;
+ }
+ r.spare2 = o->data.max_packets;
+ break;
case PF_STATE_OPT_SRCTRACK:
if (srctrack) {
yyerror("state option "
@@ -2246,6 +2436,15 @@ pfrule : action dir logquick interface route af proto fromto
}
#endif
+ if ($9.dnpipe) {
+ r.dnpipe = $9.dnpipe;
+ if ($9.free_flags & PFRULE_DN_IS_PIPE)
+ r.free_flags |= PFRULE_DN_IS_PIPE;
+ else
+ r.free_flags |= PFRULE_DN_IS_QUEUE;
+ r.pdnpipe = $9.pdnpipe;
+ }
+
expand_rule(&r, $4, $5.host, $7, $8.src_os,
$8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
$9.uid, $9.gid, $9.icmpspec, "");
@@ -2306,6 +2505,14 @@ filter_opt : USER uids {
filter_opts.marker |= FOM_TOS;
filter_opts.tos = $2;
}
+ | dscp {
+ if (filter_opts.marker & FOM_DSCP) {
+ yyerror("dscp cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_DSCP;
+ filter_opts.dscp = $1;
+ }
| keep {
if (filter_opts.marker & FOM_KEEP) {
yyerror("modulate or keep cannot be redefined");
@@ -2315,6 +2522,9 @@ filter_opt : USER uids {
filter_opts.keep.action = $1.action;
filter_opts.keep.options = $1.options;
}
+ | TRACKER number {
+ filter_opts.tracker = $2;
+ }
| FRAGMENT {
filter_opts.fragment = 1;
}
@@ -2328,6 +2538,13 @@ filter_opt : USER uids {
}
filter_opts.label = $1;
}
+ | schedule {
+ if (filter_opts.schedule) {
+ yyerror("schedule label cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.schedule = $1;
+ }
| qname {
if (filter_opts.queues.qname) {
yyerror("queue cannot be redefined");
@@ -2335,6 +2552,32 @@ filter_opt : USER uids {
}
filter_opts.queues = $1;
}
+ | DNPIPE number {
+ filter_opts.dnpipe = $2;
+ filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
+ }
+ | DNPIPE '(' number ')' {
+ filter_opts.dnpipe = $3;
+ filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
+ }
+ | DNPIPE '(' number comma number ')' {
+ filter_opts.pdnpipe = $5;
+ filter_opts.dnpipe = $3;
+ filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
+ }
+ | DNQUEUE number {
+ filter_opts.dnpipe = $2;
+ filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
+ }
+ | DNQUEUE '(' number comma number ')' {
+ filter_opts.pdnpipe = $5;
+ filter_opts.dnpipe = $3;
+ filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
+ }
+ | DNQUEUE '(' number ')' {
+ filter_opts.dnpipe = $3;
+ filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
+ }
| TAG string {
filter_opts.tag = $2;
}
@@ -2354,6 +2597,98 @@ filter_opt : USER uids {
if (filter_opts.prob == 0)
filter_opts.prob = 1;
}
+ | IEEE8021QPCP STRING {
+ u_int pcp;
+
+ /*
+ * XXXRW: More complete set of operations, similar to
+ * ports.
+ */
+ if (!strcmp($2, "be"))
+ pcp = IEEE8021Q_PCP_BE;
+ else if (!strcmp($2, "bk"))
+ pcp = IEEE8021Q_PCP_BK;
+ else if (!strcmp($2, "ee"))
+ pcp = IEEE8021Q_PCP_EE;
+ else if (!strcmp($2, "ca"))
+ pcp = IEEE8021Q_PCP_CA;
+ else if (!strcmp($2, "vi"))
+ pcp = IEEE8021Q_PCP_VI;
+ else if (!strcmp($2, "vo"))
+ pcp = IEEE8021Q_PCP_VO;
+ else if (!strcmp($2, "ic"))
+ pcp = IEEE8021Q_PCP_IC;
+ else if (!strcmp($2, "nc"))
+ pcp = IEEE8021Q_PCP_NC;
+ else
+ pcp = 8; /* flag bad argument */
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_pcp value %s", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ filter_opts.ieee8021q_pcp.pcp[0] = pcp;
+ filter_opts.ieee8021q_pcp.pcp[1] = 0;
+ filter_opts.ieee8021q_pcp.op = PF_OP_EQ;
+ }
+ | IEEE8021QPCP number {
+ u_int pcp;
+
+ pcp = $2;
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_pcp value %u", pcp);
+ YYERROR;
+ }
+ filter_opts.ieee8021q_pcp.pcp[0] = pcp;
+ filter_opts.ieee8021q_pcp.pcp[1] = 0;
+ filter_opts.ieee8021q_pcp.op = PF_OP_EQ;
+ }
+ | IEEE8021QSETPCP STRING {
+ u_int pcp;
+
+ /*
+ * XXXRW: More complete set of operations, similar to
+ * ports.
+ */
+ if (!strcmp($2, "be"))
+ pcp = IEEE8021Q_PCP_BE;
+ else if (!strcmp($2, "bk"))
+ pcp = IEEE8021Q_PCP_BK;
+ else if (!strcmp($2, "ee"))
+ pcp = IEEE8021Q_PCP_EE;
+ else if (!strcmp($2, "ca"))
+ pcp = IEEE8021Q_PCP_CA;
+ else if (!strcmp($2, "vi"))
+ pcp = IEEE8021Q_PCP_VI;
+ else if (!strcmp($2, "vo"))
+ pcp = IEEE8021Q_PCP_VO;
+ else if (!strcmp($2, "ic"))
+ pcp = IEEE8021Q_PCP_IC;
+ else if (!strcmp($2, "nc"))
+ pcp = IEEE8021Q_PCP_NC;
+ else
+ pcp = 8; /* flag bad argument */
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_setpcp value %s",
+ $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ filter_opts.ieee8021q_pcp.setpcp = pcp | SETPCP_VALID;
+ }
+ | IEEE8021QSETPCP number {
+ u_int pcp;
+
+ pcp = $2;
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_setpcp value %u",
+ pcp);
+ YYERROR;
+ }
+ filter_opts.ieee8021q_pcp.setpcp = pcp | SETPCP_VALID;
+ }
| RTABLE NUMBER {
if ($2 < 0 || $2 > rt_tableid_max()) {
yyerror("invalid rtable id");
@@ -2421,6 +2756,7 @@ probability : STRING {
action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
+ | MATCH { $$.b1 = PF_MATCH; $$.b2 = $$.w = 0; }
| BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; }
;
@@ -2749,8 +3085,8 @@ ipspec : ANY { $$ = NULL; }
| '{' optnl host_list '}' { $$ = $3; }
;
-toipspec : TO ipspec { $$ = $2; }
- | /* empty */ { $$ = NULL; }
+toipportspec : TO ipportspec { $$ = $2; }
+ | /* empty */ { $$.host = NULL; $$.port = NULL; }
;
host_list : ipspec optnl { $$ = $1; }
@@ -3398,6 +3734,48 @@ tos : STRING {
}
;
+dscp : DSCP STRING {
+ if (!strcmp($2, "EF"))
+ $$ = DSCP_EF;
+ else if (!strcmp($2, "VA"))
+ $$ = DSCP_VA;
+ else if (!strcmp($2, "af11"))
+ $$ = DSCP_AF11;
+ else if (!strcmp($2, "af12"))
+ $$ = DSCP_AF12;
+ else if (!strcmp($2, "af13"))
+ $$ = DSCP_AF13;
+ else if (!strcmp($2, "af21"))
+ $$ = DSCP_AF21;
+ else if (!strcmp($2, "af22"))
+ $$ = DSCP_AF22;
+ else if (!strcmp($2, "af23"))
+ $$ = DSCP_AF23;
+ else if (!strcmp($2, "af31"))
+ $$ = DSCP_AF31;
+ else if (!strcmp($2, "af32"))
+ $$ = DSCP_AF32;
+ else if (!strcmp($2, "af33"))
+ $$ = DSCP_AF33;
+ else if (!strcmp($2, "af41"))
+ $$ = DSCP_AF41;
+ else if (!strcmp($2, "af42"))
+ $$ = DSCP_AF42;
+ else if (!strcmp($2, "af43"))
+ $$ = DSCP_AF43;
+ else if ($2[0] == '0' && $2[1] == 'x')
+ $$ = strtoul($2, NULL, 16) * 4;
+ else
+ $$ = strtoul($2, NULL, 10) * 4;
+ if (!$$ || $$ > 255) {
+ yyerror("illegal dscp value %s", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ ;
+
sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; }
| SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; }
| SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; }
@@ -3482,6 +3860,15 @@ state_opt_item : MAXIMUM NUMBER {
$$->next = NULL;
$$->tail = $$;
}
+ | MAXPCKT NUMBER {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_PACKETS;
+ $$->data.max_packets = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
| MAXSRCCONN NUMBER {
if ($2 < 0 || $2 > UINT_MAX) {
yyerror("only positive values permitted");
@@ -3604,6 +3991,11 @@ label : LABEL STRING {
}
;
+schedule : SCHEDULE STRING {
+ $$ = $2;
+ }
+ ;
+
qname : QUEUE STRING {
$$.qname = $2;
$$.pqname = NULL;
@@ -3979,7 +4371,7 @@ natrule : nataction interface af proto fromto tag tagged rtable
}
;
-binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
+binatrule : no BINAT natpasslog interface af proto FROM ipportspec toipportspec tag
tagged rtable redirection
{
struct pf_rule binat;
@@ -3987,7 +4379,7 @@ binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
if (check_rulestate(PFCTL_STATE_NAT))
YYERROR;
- if (disallow_urpf_failed($9, "\"urpf-failed\" is not "
+ if (disallow_urpf_failed($9.host, "\"urpf-failed\" is not "
"permitted as a binat destination"))
YYERROR;
@@ -4005,10 +4397,10 @@ binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
binat.log = $3.b2;
binat.logif = $3.w2;
binat.af = $5;
- if (!binat.af && $8 != NULL && $8->af)
- binat.af = $8->af;
- if (!binat.af && $9 != NULL && $9->af)
- binat.af = $9->af;
+ if (!binat.af && $8.host != NULL && $8.host->af)
+ binat.af = $8.host->af;
+ if (!binat.af && $9.host != NULL && $9.host->af)
+ binat.af = $9.host->af;
if (!binat.af && $13 != NULL && $13->host)
binat.af = $13->host->af;
@@ -4047,10 +4439,10 @@ binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
free($6);
}
- if ($8 != NULL && disallow_table($8, "invalid use of "
+ if ($8.host != NULL && disallow_table($8.host, "invalid use of "
"table <%s> as the source address of a binat rule"))
YYERROR;
- if ($8 != NULL && disallow_alias($8, "invalid use of "
+ if ($8.host != NULL && disallow_alias($8.host, "invalid use of "
"interface (%s) as the source address of a binat "
"rule"))
YYERROR;
@@ -4063,38 +4455,46 @@ binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
"redirect address of a binat rule"))
YYERROR;
- if ($8 != NULL) {
- if ($8->next) {
+ if ($8.host != NULL) {
+ if ($8.host->next) {
yyerror("multiple binat ip addresses");
YYERROR;
}
- if ($8->addr.type == PF_ADDR_DYNIFTL)
- $8->af = binat.af;
- if ($8->af != binat.af) {
+ if ($8.host->addr.type == PF_ADDR_DYNIFTL)
+ $8.host->af = binat.af;
+ if ($8.host->af != binat.af) {
yyerror("binat ip versions must match");
YYERROR;
}
- if (check_netmask($8, binat.af))
+ if (check_netmask($8.host, binat.af))
YYERROR;
- memcpy(&binat.src.addr, &$8->addr,
+ memcpy(&binat.src.addr, &$8.host->addr,
sizeof(binat.src.addr));
- free($8);
+ binat.src.neg = $8.host->not;
+ free($8.host);
}
- if ($9 != NULL) {
- if ($9->next) {
+ if ($9.host != NULL) {
+ if ($9.host->next) {
yyerror("multiple binat ip addresses");
YYERROR;
}
- if ($9->af != binat.af && $9->af) {
+ if ($9.host->af != binat.af && $9.host->af) {
yyerror("binat ip versions must match");
YYERROR;
}
- if (check_netmask($9, binat.af))
+ if (check_netmask($9.host, binat.af))
YYERROR;
- memcpy(&binat.dst.addr, &$9->addr,
+ memcpy(&binat.dst.addr, &$9.host->addr,
sizeof(binat.dst.addr));
- binat.dst.neg = $9->not;
- free($9);
+ binat.dst.neg = $9.host->not;
+ free($9.host);
+ }
+
+ if ($9.port != NULL) {
+ binat.dst.port[0] = $9.port->port[0];
+ binat.dst.port[1] = $9.port->port[1];
+ binat.dst.port_op = $9.port->op;
+ free($9.port);
}
if (binat.action == PF_NOBINAT) {
@@ -4440,6 +4840,15 @@ filter_consistent(struct pf_rule *r, int anchor_call)
"synproxy state or modulate state");
problems++;
}
+ if ((r->rule_flag & PFRULE_TOS) && (r->rule_flag & PFRULE_DSCP)) {
+ yyerror("tos and dscp cannot be used together");
+ problems++;
+ }
+ if (r->dnpipe && r->pdnpipe && !r->direction) {
+ yyerror("dummynet cannot be specified without direction");
+ problems++;
+ }
+
return (-problems);
}
@@ -4732,7 +5141,8 @@ expand_altq(struct pf_altq *a, struct node_if *interfaces,
if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
FREE_LIST(struct node_if, interfaces);
- FREE_LIST(struct node_queue, nqueues);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
return (0);
}
@@ -4823,7 +5233,8 @@ expand_altq(struct pf_altq *a, struct node_if *interfaces,
}
);
FREE_LIST(struct node_if, interfaces);
- FREE_LIST(struct node_queue, nqueues);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
return (errs);
}
@@ -4983,6 +5394,7 @@ expand_rule(struct pf_rule *r,
int added = 0, error = 0;
char ifname[IF_NAMESIZE];
char label[PF_RULE_LABEL_SIZE];
+ char schedule[PF_RULE_LABEL_SIZE];
char tagname[PF_TAG_NAME_SIZE];
char match_tagname[PF_TAG_NAME_SIZE];
struct pf_pooladdr *pa;
@@ -4991,6 +5403,8 @@ expand_rule(struct pf_rule *r,
if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
errx(1, "expand_rule: strlcpy");
+ if (strlcpy(schedule, r->schedule, sizeof(schedule)) > sizeof(schedule))
+ errx(1, "expand_rule: strlcpy");
if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
errx(1, "expand_rule: strlcpy");
if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
@@ -5042,6 +5456,9 @@ expand_rule(struct pf_rule *r,
if (strlcpy(r->label, label, sizeof(r->label)) >=
sizeof(r->label))
errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->schedule, schedule, sizeof(r->schedule)) >=
+ sizeof(r->schedule))
+ errx(1, "expand_rule: strlcpy");
if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
sizeof(r->tagname))
errx(1, "expand_rule: strlcpy");
@@ -5050,6 +5467,8 @@ expand_rule(struct pf_rule *r,
errx(1, "expand_rule: strlcpy");
expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->schedule, PF_RULE_LABEL_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
src_host, src_port, dst_host, dst_port, proto->proto);
expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
@@ -5226,15 +5645,21 @@ lookup(char *s)
{ "bitmask", BITMASK},
{ "block", BLOCK},
{ "block-policy", BLOCKPOLICY},
+ { "buckets", BUCKETS},
{ "cbq", CBQ},
{ "code", CODE},
+ { "codelq", CODEL},
{ "crop", FRAGCROP},
{ "debug", DEBUG},
{ "divert-reply", DIVERTREPLY},
{ "divert-to", DIVERTTO},
+ { "dnpipe", DNPIPE},
+ { "dnqueue", DNQUEUE},
{ "drop", DROP},
{ "drop-ovl", FRAGDROP},
+ { "dscp", DSCP},
{ "dup-to", DUPTO},
+ { "fairq", FAIRQ},
{ "fastroute", FASTROUTE},
{ "file", FILENAME},
{ "fingerprints", FINGERPRINTS},
@@ -5247,14 +5672,18 @@ lookup(char *s)
{ "global", GLOBAL},
{ "group", GROUP},
{ "hfsc", HFSC},
+ { "hogs", HOGS},
{ "hostid", HOSTID},
{ "icmp-type", ICMPTYPE},
{ "icmp6-type", ICMP6TYPE},
+ { "ieee8021q-pcp", IEEE8021QPCP},
+ { "ieee8021q-setpcp", IEEE8021QSETPCP},
{ "if-bound", IFBOUND},
{ "in", IN},
{ "include", INCLUDE},
{ "inet", INET},
{ "inet6", INET6},
+ { "interval", INTERVAL},
{ "keep", KEEP},
{ "label", LABEL},
{ "limit", LIMIT},
@@ -5262,8 +5691,10 @@ lookup(char *s)
{ "load", LOAD},
{ "log", LOG},
{ "loginterface", LOGINTERFACE},
+ { "match", MATCH},
{ "max", MAXIMUM},
{ "max-mss", MAXMSS},
+ { "max-packets", MAXPCKT},
{ "max-src-conn", MAXSRCCONN},
{ "max-src-conn-rate", MAXSRCCONNRATE},
{ "max-src-nodes", MAXSRCNODES},
@@ -5308,6 +5739,7 @@ lookup(char *s)
{ "rtable", RTABLE},
{ "rule", RULE},
{ "ruleset-optimization", RULESET_OPTIMIZATION},
+ { "schedule", SCHEDULE},
{ "scrub", SCRUB},
{ "set", SET},
{ "set-tos", SETTOS},
@@ -5324,10 +5756,12 @@ lookup(char *s)
{ "table", TABLE},
{ "tag", TAG},
{ "tagged", TAGGED},
+ { "target", TARGET},
{ "tbrsize", TBRSIZE},
{ "timeout", TIMEOUT},
{ "to", TO},
{ "tos", TOS},
+ { "tracker", TRACKER},
{ "ttl", TTL},
{ "upperlimit", UPPERLIMIT},
{ "urpf-failed", URPFFAILED},
@@ -5939,6 +6373,20 @@ rule_label(struct pf_rule *r, char *s)
return (0);
}
+int
+rule_schedule(struct pf_rule *r, char *s)
+{
+ if (s) {
+ if (strlcpy(r->schedule, s, sizeof(r->label)) >=
+ sizeof(r->label)) {
+ yyerror("rule schedule label too long (max %d chars)",
+ sizeof(r->label)-1);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
u_int16_t
parseicmpspec(char *w, sa_family_t af)
{
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index ea95320..20669c1 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -78,6 +78,7 @@ void pfctl_addrprefix(char *, struct pf_addr *);
int pfctl_kill_src_nodes(int, const char *, int);
int pfctl_net_kill_states(int, const char *, int);
int pfctl_label_kill_states(int, const char *, int);
+int pfctl_kill_schedule(int, const char *, int);
int pfctl_id_kill_states(int, const char *, int);
void pfctl_init_options(struct pfctl *);
int pfctl_load_options(struct pfctl *);
@@ -117,6 +118,7 @@ const char *optiopt = NULL;
char *pf_device = "/dev/pf";
char *ifaceopt;
char *tableopt;
+char *schedule = NULL;
const char *tblcmdopt;
int src_node_killers;
char *src_node_kill[2];
@@ -654,6 +656,25 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
}
int
+pfctl_kill_schedule(int dev, const char *sched, int opts)
+{
+ struct pfioc_schedule_kill psk;
+
+ memset(&psk, 0, sizeof(psk));
+ if (sched != NULL && strlcpy(psk.schedule, sched,
+ sizeof(psk.schedule)) >= sizeof(psk.schedule))
+ errx(1, "invalid schedule label: %s", sched);
+
+ if (ioctl(dev, DIOCKILLSCHEDULE, &psk))
+ err(1, "DIOCKILLSCHEDULE");
+
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "killed %d states from %s schedule label\n",
+ psk.numberkilled, sched);
+ return (0);
+}
+
+int
pfctl_label_kill_states(int dev, const char *iface, int opts)
{
struct pfioc_state_kill psk;
@@ -804,10 +825,17 @@ pfctl_print_rule_counters(struct pf_rule *rule, int opts)
(unsigned long long)(rule->bytes[0] +
rule->bytes[1]), (uintmax_t)rule->u_states_cur);
if (!(opts & PF_OPT_DEBUG))
+#ifdef PF_USER_INFO
printf(" [ Inserted: uid %u pid %u "
"State Creations: %-6ju]\n",
(unsigned)rule->cuid, (unsigned)rule->cpid,
(uintmax_t)rule->u_states_tot);
+#else
+ printf(" [ Inserted: pid %u "
+ "State Creations: %-6ju]\n",
+ (unsigned)rule->cpid,
+ (uintmax_t)rule->u_states_tot);
+#endif
}
}
@@ -2004,7 +2032,7 @@ main(int argc, char *argv[])
usage();
while ((ch = getopt(argc, argv,
- "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) {
+ "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:y:z")) != -1) {
switch (ch) {
case 'a':
anchoropt = optarg;
@@ -2118,6 +2146,12 @@ main(int argc, char *argv[])
opts |= PF_OPT_VERBOSE2;
opts |= PF_OPT_VERBOSE;
break;
+ case 'y':
+ if (schedule != NULL && strlen(schedule) > 64)
+ errx(1, "Schedule label cannot be more than 64 characters\n");
+ schedule = optarg;
+ mode = O_RDWR;
+ break;
case 'x':
debugopt = pfctl_lookup_option(optarg, debugopt_list);
if (debugopt == NULL) {
@@ -2326,6 +2360,9 @@ main(int argc, char *argv[])
if (src_node_killers)
pfctl_kill_src_nodes(dev, ifaceopt, opts);
+ if (schedule)
+ pfctl_kill_schedule(dev, schedule, opts);
+
if (tblcmdopt != NULL) {
error = pfctl_command_tables(argc, argv, tableopt,
tblcmdopt, rulesopt, anchorname, opts);
diff --git a/sbin/pfctl/pfctl_altq.c b/sbin/pfctl/pfctl_altq.c
index ae566f8..9a21754 100644
--- a/sbin/pfctl/pfctl_altq.c
+++ b/sbin/pfctl/pfctl_altq.c
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <limits.h>
#include <math.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -40,8 +41,10 @@ __FBSDID("$FreeBSD$");
#include <altq/altq.h>
#include <altq/altq_cbq.h>
+#include <altq/altq_codel.h>
#include <altq/altq_priq.h>
#include <altq/altq_hfsc.h>
+#include <altq/altq_fairq.h>
#include "pfctl_parser.h"
#include "pfctl.h"
@@ -59,6 +62,9 @@ static int cbq_compute_idletime(struct pfctl *, struct pf_altq *);
static int check_commit_cbq(int, int, struct pf_altq *);
static int print_cbq_opts(const struct pf_altq *);
+static int print_codel_opts(const struct pf_altq *,
+ const struct node_queue_opt *);
+
static int eval_pfqueue_priq(struct pfctl *, struct pf_altq *);
static int check_commit_priq(int, int, struct pf_altq *);
static int print_priq_opts(const struct pf_altq *);
@@ -68,6 +74,11 @@ static int check_commit_hfsc(int, int, struct pf_altq *);
static int print_hfsc_opts(const struct pf_altq *,
const struct node_queue_opt *);
+static int eval_pfqueue_fairq(struct pfctl *, struct pf_altq *);
+static int print_fairq_opts(const struct pf_altq *,
+ const struct node_queue_opt *);
+static int check_commit_fairq(int, int, struct pf_altq *);
+
static void gsc_add_sc(struct gen_sc *, struct service_curve *);
static int is_gsc_under_sc(struct gen_sc *,
struct service_curve *);
@@ -88,6 +99,8 @@ int eval_queue_opts(struct pf_altq *, struct node_queue_opt *,
u_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t);
void print_hfsc_sc(const char *, u_int, u_int, u_int,
const struct node_hfsc_sc *);
+void print_fairq_sc(const char *, u_int, u_int, u_int,
+ const struct node_fairq_sc *);
void
pfaltq_store(struct pf_altq *a)
@@ -173,6 +186,14 @@ print_altq(const struct pf_altq *a, unsigned int level,
if (!print_hfsc_opts(a, qopts))
printf("hfsc ");
break;
+ case ALTQT_FAIRQ:
+ if (!print_fairq_opts(a, qopts))
+ printf("fairq ");
+ break;
+ case ALTQT_CODEL:
+ if (!print_codel_opts(a, qopts))
+ printf("codel ");
+ break;
}
if (bw != NULL && bw->bw_percent > 0) {
@@ -203,7 +224,8 @@ print_queue(const struct pf_altq *a, unsigned int level,
printf("%s ", a->qname);
if (print_interface)
printf("on %s ", a->ifname);
- if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC) {
+ if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC ||
+ a->scheduler == ALTQT_FAIRQ) {
if (bw != NULL && bw->bw_percent > 0) {
if (bw->bw_percent < 100)
printf("bandwidth %u%% ", bw->bw_percent);
@@ -224,6 +246,9 @@ print_queue(const struct pf_altq *a, unsigned int level,
case ALTQT_HFSC:
print_hfsc_opts(a, qopts);
break;
+ case ALTQT_FAIRQ:
+ print_fairq_opts(a, qopts);
+ break;
}
}
@@ -240,15 +265,11 @@ eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
pa->ifbandwidth = bw->bw_absolute;
else
#ifdef __FreeBSD__
- if ((rate = getifspeed(pf->dev, pa->ifname)) == 0) {
-#else
- if ((rate = getifspeed(pa->ifname)) == 0) {
+ rate = getifspeed(pf->dev, pa->ifname);
+ if (rate == 0)
+ rate = IF_Mbps(1000);
#endif
- fprintf(stderr, "interface %s does not know its bandwidth, "
- "please specify an absolute bandwidth\n",
- pa->ifname);
- errors++;
- } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0)
+ if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0)
pa->ifbandwidth = rate;
errors += eval_queue_opts(pa, opts, pa->ifbandwidth);
@@ -294,6 +315,9 @@ check_commit_altq(int dev, int opts)
case ALTQT_HFSC:
error = check_commit_hfsc(dev, opts, altq);
break;
+ case ALTQT_FAIRQ:
+ error = check_commit_fairq(dev, opts, altq);
+ break;
default:
break;
}
@@ -342,7 +366,8 @@ eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
if (pa->qlimit == 0)
pa->qlimit = DEFAULT_QLIMIT;
- if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC) {
+ if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC ||
+ pa->scheduler == ALTQT_FAIRQ) {
pa->bandwidth = eval_bwspec(bw,
parent == NULL ? 0 : parent->bandwidth);
@@ -388,6 +413,9 @@ eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
case ALTQT_HFSC:
error = eval_pfqueue_hfsc(pf, pa);
break;
+ case ALTQT_FAIRQ:
+ error = eval_pfqueue_fairq(pf, pa);
+ break;
default:
break;
}
@@ -568,6 +596,8 @@ print_cbq_opts(const struct pf_altq *a)
printf(" ecn");
if (opts->flags & CBQCLF_RIO)
printf(" rio");
+ if (opts->flags & CBQCLF_CODEL)
+ printf(" codel");
if (opts->flags & CBQCLF_CLEARDSCP)
printf(" cleardscp");
if (opts->flags & CBQCLF_FLOWVALVE)
@@ -655,6 +685,8 @@ print_priq_opts(const struct pf_altq *a)
printf(" ecn");
if (opts->flags & PRCF_RIO)
printf(" rio");
+ if (opts->flags & PRCF_CODEL)
+ printf(" codel");
if (opts->flags & PRCF_CLEARDSCP)
printf(" cleardscp");
if (opts->flags & PRCF_DEFAULTCLASS)
@@ -700,13 +732,6 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
return (-1);
}
- if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) ||
- (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) ||
- (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) {
- warnx("m1 must be zero for convex curve: %s", pa->qname);
- return (-1);
- }
-
/*
* admission control:
* for the real-time service curve, the sum of the service curves
@@ -807,6 +832,85 @@ err_ret:
return (-1);
}
+/*
+ * FAIRQ support functions
+ */
+static int
+eval_pfqueue_fairq(struct pfctl *pf __unused, struct pf_altq *pa)
+{
+ struct pf_altq *altq, *parent;
+ struct fairq_opts *opts;
+ struct service_curve sc;
+
+ opts = &pa->pq_u.fairq_opts;
+
+ if (pa->parent[0] == 0) {
+ /* root queue */
+ opts->lssc_m1 = pa->ifbandwidth;
+ opts->lssc_m2 = pa->ifbandwidth;
+ opts->lssc_d = 0;
+ return (0);
+ }
+
+ LIST_INIT(&lssc);
+
+ /* if link_share is not specified, use bandwidth */
+ if (opts->lssc_m2 == 0)
+ opts->lssc_m2 = pa->bandwidth;
+
+ /*
+ * admission control:
+ * for the real-time service curve, the sum of the service curves
+ * should not exceed 80% of the interface bandwidth. 20% is reserved
+ * not to over-commit the actual interface bandwidth.
+ * for the link-sharing service curve, the sum of the child service
+ * curve should not exceed the parent service curve.
+ * for the upper-limit service curve, the assigned bandwidth should
+ * be smaller than the interface bandwidth, and the upper-limit should
+ * be larger than the real-time service curve when both are defined.
+ */
+ parent = qname_to_pfaltq(pa->parent, pa->ifname);
+ if (parent == NULL)
+ errx(1, "parent %s not found for %s", pa->parent, pa->qname);
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+
+ if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0)
+ continue;
+
+ /* if the class has a link-sharing service curve, add it. */
+ if (opts->lssc_m2 != 0 && altq->pq_u.fairq_opts.lssc_m2 != 0) {
+ sc.m1 = altq->pq_u.fairq_opts.lssc_m1;
+ sc.d = altq->pq_u.fairq_opts.lssc_d;
+ sc.m2 = altq->pq_u.fairq_opts.lssc_m2;
+ gsc_add_sc(&lssc, &sc);
+ }
+ }
+
+ /* check the link-sharing service curve. */
+ if (opts->lssc_m2 != 0) {
+ sc.m1 = parent->pq_u.fairq_opts.lssc_m1;
+ sc.d = parent->pq_u.fairq_opts.lssc_d;
+ sc.m2 = parent->pq_u.fairq_opts.lssc_m2;
+ if (!is_gsc_under_sc(&lssc, &sc)) {
+ warnx("link-sharing sc exceeds parent's sc");
+ goto err_ret;
+ }
+ }
+
+ gsc_destroy(&lssc);
+
+ return (0);
+
+err_ret:
+ gsc_destroy(&lssc);
+ return (-1);
+}
+
static int
check_commit_hfsc(int dev, int opts, struct pf_altq *pa)
{
@@ -847,6 +951,43 @@ check_commit_hfsc(int dev, int opts, struct pf_altq *pa)
}
static int
+check_commit_fairq(int dev __unused, int opts __unused, struct pf_altq *pa)
+{
+ struct pf_altq *altq, *def = NULL;
+ int default_class;
+ int error = 0;
+
+ /* check if fairq has one default queue for this interface */
+ default_class = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (altq->pq_u.fairq_opts.flags & FARF_DEFAULTCLASS) {
+ default_class++;
+ def = altq;
+ }
+ }
+ if (default_class != 1) {
+ warnx("should have one default queue on %s", pa->ifname);
+ return (1);
+ }
+ /* make sure the default queue is a leaf */
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) {
+ warnx("default queue is not a leaf");
+ error++;
+ }
+ }
+ return (error);
+}
+
+static int
print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
{
const struct hfsc_opts *opts;
@@ -871,6 +1012,8 @@ print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
printf(" ecn");
if (opts->flags & HFCF_RIO)
printf(" rio");
+ if (opts->flags & HFCF_CODEL)
+ printf(" codel");
if (opts->flags & HFCF_CLEARDSCP)
printf(" cleardscp");
if (opts->flags & HFCF_DEFAULTCLASS)
@@ -892,6 +1035,67 @@ print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
return (0);
}
+static int
+print_codel_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
+{
+ const struct codel_opts *opts;
+
+ opts = &a->pq_u.codel_opts;
+ if (opts->target || opts->interval || opts->ecn) {
+ printf("codel(");
+ if (opts->target)
+ printf(" target %d", opts->target);
+ if (opts->interval)
+ printf(" interval %d", opts->interval);
+ if (opts->ecn)
+ printf("ecn");
+ printf(" ) ");
+
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
+{
+ const struct fairq_opts *opts;
+ const struct node_fairq_sc *loc_lssc;
+
+ opts = &a->pq_u.fairq_opts;
+ if (qopts == NULL)
+ loc_lssc = NULL;
+ else
+ loc_lssc = &qopts->data.fairq_opts.linkshare;
+
+ if (opts->flags ||
+ (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
+ opts->lssc_d != 0))) {
+ printf("fairq(");
+ if (opts->flags & FARF_RED)
+ printf(" red");
+ if (opts->flags & FARF_ECN)
+ printf(" ecn");
+ if (opts->flags & FARF_RIO)
+ printf(" rio");
+ if (opts->flags & FARF_CODEL)
+ printf(" codel");
+ if (opts->flags & FARF_CLEARDSCP)
+ printf(" cleardscp");
+ if (opts->flags & FARF_DEFAULTCLASS)
+ printf(" default");
+ if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
+ opts->lssc_d != 0))
+ print_fairq_sc("linkshare", opts->lssc_m1, opts->lssc_d,
+ opts->lssc_m2, loc_lssc);
+ printf(" ) ");
+
+ return (1);
+ } else
+ return (0);
+}
+
/*
* admission control using generalized service curve
*/
@@ -1211,6 +1415,28 @@ eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts,
opts->data.hfsc_opts.upperlimit.d;
}
break;
+ case ALTQT_FAIRQ:
+ pa->pq_u.fairq_opts.flags = opts->data.fairq_opts.flags;
+ pa->pq_u.fairq_opts.nbuckets = opts->data.fairq_opts.nbuckets;
+ pa->pq_u.fairq_opts.hogs_m1 =
+ eval_bwspec(&opts->data.fairq_opts.hogs_bw, ref_bw);
+
+ if (opts->data.fairq_opts.linkshare.used) {
+ pa->pq_u.fairq_opts.lssc_m1 =
+ eval_bwspec(&opts->data.fairq_opts.linkshare.m1,
+ ref_bw);
+ pa->pq_u.fairq_opts.lssc_m2 =
+ eval_bwspec(&opts->data.fairq_opts.linkshare.m2,
+ ref_bw);
+ pa->pq_u.fairq_opts.lssc_d =
+ opts->data.fairq_opts.linkshare.d;
+ }
+ break;
+ case ALTQT_CODEL:
+ pa->pq_u.codel_opts.target = opts->data.codel_opts.target;
+ pa->pq_u.codel_opts.interval = opts->data.codel_opts.interval;
+ pa->pq_u.codel_opts.ecn = opts->data.codel_opts.ecn;
+ break;
default:
warnx("eval_queue_opts: unknown scheduler type %u",
opts->qtype);
@@ -1256,3 +1482,27 @@ print_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2,
if (d != 0)
printf(")");
}
+
+void
+print_fairq_sc(const char *scname, u_int m1, u_int d, u_int m2,
+ const struct node_fairq_sc *sc)
+{
+ printf(" %s", scname);
+
+ if (d != 0) {
+ printf("(");
+ if (sc != NULL && sc->m1.bw_percent > 0)
+ printf("%u%%", sc->m1.bw_percent);
+ else
+ printf("%s", rate2str((double)m1));
+ printf(" %u", d);
+ }
+
+ if (sc != NULL && sc->m2.bw_percent > 0)
+ printf(" %u%%", sc->m2.bw_percent);
+ else
+ printf(" %s", rate2str((double)m2));
+
+ if (d != 0)
+ printf(")");
+}
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 1f4375a..5b03a93 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -40,6 +40,8 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/proc.h>
#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_vlan_var.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -65,6 +67,8 @@ __FBSDID("$FreeBSD$");
void print_op (u_int8_t, const char *, const char *);
void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int);
void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
+void print_ieee8021q_pcp (u_int8_t, uint8_t, uint8_t);
+void print_ieee8021q_setpcp (u_int8_t);
void print_flags (u_int8_t);
void print_fromto(struct pf_rule_addr *, pf_osfp_t,
struct pf_rule_addr *, u_int8_t, u_int8_t, int, int);
@@ -353,6 +357,47 @@ print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax)
print_op(op, a1, a2);
}
+static const char *
+ieee8021q_pcp_name(u_int8_t pcp)
+{
+ const char *s;
+
+ if (pcp == IEEE8021Q_PCP_BE)
+ s = "be";
+ else if (pcp == IEEE8021Q_PCP_BK)
+ s = "bk";
+ else if (pcp == IEEE8021Q_PCP_EE)
+ s = "ee";
+ else if (pcp == IEEE8021Q_PCP_CA)
+ s = "ca";
+ else if (pcp == IEEE8021Q_PCP_VI)
+ s = "vi";
+ else if (pcp == IEEE8021Q_PCP_VO)
+ s = "vo";
+ else if (pcp == IEEE8021Q_PCP_IC)
+ s = "ic";
+ else if (pcp == IEEE8021Q_PCP_NC)
+ s = "nc";
+ else
+ s = "??";
+ return (s);
+}
+
+ void
+print_ieee8021q_pcp(u_int8_t op, u_int8_t pcp0, u_int8_t pcp1)
+{
+
+ printf(" ieee8021q-pcp");
+ print_op(op, ieee8021q_pcp_name(pcp0), ieee8021q_pcp_name(pcp1));
+}
+
+void
+print_ieee8021q_setpcp(u_int8_t pcp)
+{
+
+ printf(" ieee8021q-setpcp %s", ieee8021q_pcp_name(pcp));
+}
+
void
print_flags(u_int8_t f)
{
@@ -691,8 +736,14 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
int i, opts;
if (verbose)
+#ifdef PF_USER_INFO
printf("@%d ", r->nr);
- if (r->action > PF_NORDR)
+#else
+ printf("@%d(%u) ", r->nr, r->cuid);
+#endif
+ if (r->action == PF_MATCH)
+ printf("match");
+ else if (r->action > PF_NORDR)
printf("action(%d)", r->action);
else if (anchor_call[0]) {
if (anchor_call[0] == '_') {
@@ -847,8 +898,10 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
printf(" code %u", r->code-1);
}
}
- if (r->tos)
+ if (r->tos && (r->rule_flag & PFRULE_TOS))
printf(" tos 0x%2.2x", r->tos);
+ if (r->tos && (r->rule_flag & PFRULE_DSCP))
+ printf(" dscp 0x%2.2x", r->tos & DSCP_MASK);
if (!r->keep_state && r->action == PF_PASS && !anchor_call[0])
printf(" no state");
else if (r->keep_state == PF_STATE_NORMAL)
@@ -873,7 +926,7 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
printf(" probability %s%%", buf);
}
opts = 0;
- if (r->max_states || r->max_src_nodes || r->max_src_states)
+ if (r->max_states || r->max_src_nodes || r->max_src_states || r->spare2)
opts = 1;
if (r->rule_flag & PFRULE_NOSYNC)
opts = 1;
@@ -920,6 +973,12 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
printf("max-src-conn %u", r->max_src_conn);
opts = 0;
}
+ if (r->spare2) {
+ if (!opts)
+ printf(", ");
+ printf("max-packets %u", r->spare2);
+ opts = 0;
+ }
if (r->max_src_conn_rate.limit) {
if (!opts)
printf(", ");
@@ -999,6 +1058,14 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
}
if (r->label[0])
printf(" label \"%s\"", r->label);
+ if (r->dnpipe && r->pdnpipe)
+ printf(" %s(%d, %d)",
+ r->free_flags & PFRULE_DN_IS_PIPE ? "dnpipe" : "dnqueue",
+ r->dnpipe, r->pdnpipe);
+ else if (r->dnpipe)
+ printf(" %s %d",
+ r->free_flags & PFRULE_DN_IS_PIPE ? "dnpipe" : "dnqueue",
+ r->dnpipe);
if (r->qname[0] && r->pqname[0])
printf(" queue(%s, %s)", r->qname, r->pqname);
else if (r->qname[0])
@@ -1012,6 +1079,13 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
}
if (r->rtableid != -1)
printf(" rtable %u", r->rtableid);
+ if (r->ieee8021q_pcp.op != 0)
+ print_ieee8021q_pcp(r->ieee8021q_pcp.op,
+ r->ieee8021q_pcp.pcp[0], r->ieee8021q_pcp.pcp[1]);
+ if (r->ieee8021q_pcp.setpcp & SETPCP_VALID)
+ print_ieee8021q_setpcp(r->ieee8021q_pcp.setpcp &
+ SETPCP_PCP_MASK);
+
if (r->divert.port) {
#ifdef __FreeBSD__
printf(" divert-to %u", ntohs(r->divert.port));
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 5c909e9..2b7fea7 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -150,12 +150,28 @@ struct node_hfsc_opts {
int flags;
};
+struct node_fairq_sc {
+ struct node_queue_bw m1; /* slope of 1st segment; bps */
+ u_int d; /* x-projection of m1; msec */
+ struct node_queue_bw m2; /* slope of 2nd segment; bps */
+ u_int8_t used;
+};
+
+struct node_fairq_opts {
+ struct node_fairq_sc linkshare;
+ struct node_queue_bw hogs_bw;
+ u_int nbuckets;
+ int flags;
+};
+
struct node_queue_opt {
int qtype;
union {
struct cbq_opts cbq_opts;
+ struct codel_opts codel_opts;
struct priq_opts priq_opts;
struct node_hfsc_opts hfsc_opts;
+ struct node_fairq_opts fairq_opts;
} data;
};
diff --git a/sbin/pfctl/pfctl_qstats.c b/sbin/pfctl/pfctl_qstats.c
index 95371e4..8ffd87d 100644
--- a/sbin/pfctl/pfctl_qstats.c
+++ b/sbin/pfctl/pfctl_qstats.c
@@ -36,8 +36,10 @@ __FBSDID("$FreeBSD$");
#include <altq/altq.h>
#include <altq/altq_cbq.h>
+#include <altq/altq_codel.h>
#include <altq/altq_priq.h>
#include <altq/altq_hfsc.h>
+#include <altq/altq_fairq.h>
#include "pfctl.h"
#include "pfctl_parser.h"
@@ -46,6 +48,8 @@ union class_stats {
class_stats_t cbq_stats;
struct priq_classstats priq_stats;
struct hfsc_classstats hfsc_stats;
+ struct fairq_classstats fairq_stats;
+ struct codel_ifstats codel_stats;
};
#define AVGN_MAX 8
@@ -75,8 +79,10 @@ struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *,
void pfctl_print_altq_node(int, const struct pf_altq_node *,
unsigned, int);
void print_cbqstats(struct queue_stats);
+void print_codelstats(struct queue_stats);
void print_priqstats(struct queue_stats);
void print_hfscstats(struct queue_stats);
+void print_fairqstats(struct queue_stats);
void pfctl_free_altq_node(struct pf_altq_node *);
void pfctl_print_altq_nodestat(int,
const struct pf_altq_node *);
@@ -162,7 +168,7 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root)
return (-1);
}
#ifdef __FreeBSD__
- if (pa.altq.qid > 0 &&
+ if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) &&
!(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
#else
if (pa.altq.qid > 0) {
@@ -300,7 +306,7 @@ pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
void
pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
{
- if (a->altq.qid == 0)
+ if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
return;
#ifdef __FreeBSD__
@@ -317,6 +323,12 @@ pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
case ALTQT_HFSC:
print_hfscstats(a->qstats);
break;
+ case ALTQT_FAIRQ:
+ print_fairqstats(a->qstats);
+ break;
+ case ALTQT_CODEL:
+ print_codelstats(a->qstats);
+ break;
}
}
@@ -342,6 +354,28 @@ print_cbqstats(struct queue_stats cur)
}
void
+print_codelstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets,
+ (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes,
+ (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets +
+ cur.data.codel_stats.stats.drop_cnt.packets,
+ (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes +
+ cur.data.codel_stats.stats.drop_cnt.bytes);
+ printf(" [ qlength: %3d/%3d ]\n",
+ cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
print_priqstats(struct queue_stats cur)
{
printf(" [ pkts: %10llu bytes: %10llu "
@@ -382,6 +416,26 @@ print_hfscstats(struct queue_stats cur)
}
void
+print_fairqstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.fairq_stats.xmit_cnt.packets,
+ (unsigned long long)cur.data.fairq_stats.xmit_cnt.bytes,
+ (unsigned long long)cur.data.fairq_stats.drop_cnt.packets,
+ (unsigned long long)cur.data.fairq_stats.drop_cnt.bytes);
+ printf(" [ qlength: %3d/%3d ]\n",
+ cur.data.fairq_stats.qlength, cur.data.fairq_stats.qlimit);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
pfctl_free_altq_node(struct pf_altq_node *node)
{
while (node != NULL) {
@@ -402,7 +456,7 @@ update_avg(struct pf_altq_node *a)
u_int64_t b, p;
int n;
- if (a->altq.qid == 0)
+ if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
return;
qs = &a->qstats;
@@ -421,6 +475,14 @@ update_avg(struct pf_altq_node *a)
b = qs->data.hfsc_stats.xmit_cnt.bytes;
p = qs->data.hfsc_stats.xmit_cnt.packets;
break;
+ case ALTQT_FAIRQ:
+ b = qs->data.fairq_stats.xmit_cnt.bytes;
+ p = qs->data.fairq_stats.xmit_cnt.packets;
+ break;
+ case ALTQT_CODEL:
+ b = qs->data.codel_stats.cl_xmitcnt.bytes;
+ p = qs->data.codel_stats.cl_xmitcnt.packets;
+ break;
default:
b = 0;
p = 0;
diff --git a/sbin/route/route.c b/sbin/route/route.c
index f64f525..6f73ded 100644
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -1557,10 +1557,15 @@ rtmsg(int cmd, int flags, int fib)
print_rtmsg(&rtm, l);
if (debugonly)
return (0);
+testagain:
if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
if (errno == EPERM)
err(1, "writing to routing socket");
warn("writing to routing socket");
+ if (rtm.rtm_type == RTM_CHANGE) {
+ rtm.rtm_type = RTM_ADD;
+ goto testagain;
+ }
return (-1);
}
if (cmd == RTM_GET) {
diff --git a/sbin/setkey/parse.y b/sbin/setkey/parse.y
index c551c35..60e779d 100644
--- a/sbin/setkey/parse.y
+++ b/sbin/setkey/parse.y
@@ -100,6 +100,7 @@ extern void yyerror(const char *);
%token F_EXT EXTENSION NOCYCLICSEQ
%token ALG_AUTH ALG_AUTH_NOKEY
%token ALG_ENC ALG_ENC_NOKEY ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_ENC_OLD
+%token ALG_ENC_SALT
%token ALG_COMP
%token F_LIFETIME_HARD F_LIFETIME_SOFT
%token DECSTRING QUOTEDSTRING HEXSTRING STRING ANY
@@ -111,6 +112,7 @@ extern void yyerror(const char *);
%type <num> prefix protocol_spec upper_spec
%type <num> ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_ENC_OLD ALG_ENC_NOKEY
+%type <num> ALG_ENC_SALT
%type <num> ALG_AUTH ALG_AUTH_NOKEY
%type <num> ALG_COMP
%type <num> PR_ESP PR_AH PR_IPCOMP PR_TCP
@@ -402,6 +404,27 @@ enc_alg
return -1;
}
}
+ | ALG_ENC_SALT key_string
+ {
+ if ($1 < 0) {
+ yyerror("unsupported algorithm");
+ return -1;
+ }
+ p_alg_enc = $1;
+
+ p_key_enc_len = $2.len;
+
+ p_key_enc = $2.buf;
+ /*
+ * Salted keys include a 4 byte value that is
+ * not part of the key.
+ */
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+ p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len - 4)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
;
auth_alg
diff --git a/sbin/setkey/setkey.8 b/sbin/setkey/setkey.8
index 4306ec2..b6d4157 100644
--- a/sbin/setkey/setkey.8
+++ b/sbin/setkey/setkey.8
@@ -627,11 +627,12 @@ des-deriv 64 ipsec-ciph-des-derived-01
3des-deriv 192 no document
rijndael-cbc 128/192/256 rfc3602
aes-ctr 160/224/288 draft-ietf-ipsec-ciph-aes-ctr-03
+aes-gcm-16 160/224/288 rfc4106
camellia-cbc 128/192/256 rfc4312
.Ed
.Pp
Note that the first 128/192/256 bits of a key for
-.Li aes-ctr
+.Li aes-ctr or aes-gcm-16
will be used as AES key, and remaining 32 bits will be used as nonce.
.Pp
The following are the list of compression algorithms that can be used
diff --git a/sbin/setkey/token.l b/sbin/setkey/token.l
index c89982f..7f30859 100644
--- a/sbin/setkey/token.l
+++ b/sbin/setkey/token.l
@@ -159,15 +159,16 @@ tcp { yylval.num = 0; return(PR_TCP); }
{hyphen}E { BEGIN S_ENCALG; return(F_ENC); }
<S_ENCALG>des-cbc { yylval.num = SADB_EALG_DESCBC; BEGIN INITIAL; return(ALG_ENC); }
<S_ENCALG>3des-cbc { yylval.num = SADB_EALG_3DESCBC; BEGIN INITIAL; return(ALG_ENC); }
-<S_ENCALG>null { yylval.num = SADB_EALG_NULL; BEGIN INITIAL; return(ALG_ENC_NOKEY); }
+<S_ENCALG>null { yylval.num = SADB_EALG_NULL; BEGIN INITIAL; return(ALG_ENC); }
<S_ENCALG>simple { yylval.num = SADB_EALG_NULL; BEGIN INITIAL; return(ALG_ENC_OLD); }
<S_ENCALG>blowfish-cbc { yylval.num = SADB_X_EALG_BLOWFISHCBC; BEGIN INITIAL; return(ALG_ENC); }
<S_ENCALG>cast128-cbc { yylval.num = SADB_X_EALG_CAST128CBC; BEGIN INITIAL; return(ALG_ENC); }
<S_ENCALG>des-deriv { yylval.num = SADB_EALG_DESCBC; BEGIN INITIAL; return(ALG_ENC_DESDERIV); }
<S_ENCALG>des-32iv { yylval.num = SADB_EALG_DESCBC; BEGIN INITIAL; return(ALG_ENC_DES32IV); }
<S_ENCALG>rijndael-cbc { yylval.num = SADB_X_EALG_RIJNDAELCBC; BEGIN INITIAL; return(ALG_ENC); }
-<S_ENCALG>aes-ctr { yylval.num = SADB_X_EALG_AESCTR; BEGIN INITIAL; return(ALG_ENC); }
+<S_ENCALG>aes-ctr { yylval.num = SADB_X_EALG_AESCTR; BEGIN INITIAL; return(ALG_ENC_SALT); }
<S_ENCALG>camellia-cbc { yylval.num = SADB_X_EALG_CAMELLIACBC; BEGIN INITIAL; return(ALG_ENC); }
+<S_ENCALG>aes-gcm-16 { yylval.num = SADB_X_EALG_AESGCM16; BEGIN INITIAL; return(ALG_ENC_SALT); }
/* compression algorithms */
{hyphen}C { return(F_COMP); }
OpenPOWER on IntegriCloud