Date: Tue, 10 Feb 2026 12:07:09 +0000 From: Andrey V. Elsukov <ae@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Cc: Boris Lytochkin <lytboris@gmail.com> Subject: git: 704ec5e68c44 - stable/14 - ipfw: add ability to run ipfw(8) binary with 15.0+ kernel module Message-ID: <698b1f6d.32357.78a6474f@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch stable/14 has been updated by ae: URL: https://cgit.FreeBSD.org/src/commit/?id=704ec5e68c44f08d83f3b0daa315c6143338863f commit 704ec5e68c44f08d83f3b0daa315c6143338863f Author: Boris Lytochkin <lytboris@gmail.com> AuthorDate: 2026-02-10 11:50:20 +0000 Commit: Andrey V. Elsukov <ae@FreeBSD.org> CommitDate: 2026-02-10 11:50:20 +0000 ipfw: add ability to run ipfw(8) binary with 15.0+ kernel module After D46183 the KBI was changed and this made the upgrade procedure to 15.0+ version a bit difficult, because the old binary can not load firewall rules when the new kernel is loaded. This commit adds the sbin/ipfw15 binary that uses new KBI, and then original sbin/ipfw can detect new KBI and run the new binary instead. PR: 291562 Reviewed by: jhb, glebius Fixes: 4a77657cbc01 MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D54763 --- sbin/Makefile | 1 + sbin/ipfw/main.c | 26 + sbin/ipfw15/Makefile | 23 + sbin/ipfw15/Makefile.depend | 19 + sbin/ipfw15/altq.c | 152 + sbin/ipfw15/dummynet.c | 2016 ++++++++ sbin/ipfw15/include15/alias15.h | 259 + sbin/ipfw15/include15/netinet/ip_dummynet15.h | 284 ++ sbin/ipfw15/include15/netinet/ip_fw15.h | 1172 +++++ sbin/ipfw15/include15/netinet6/ip_fw_nat64_15.h | 212 + sbin/ipfw15/include15/netinet6/ip_fw_nptv6_15.h | 52 + sbin/ipfw15/ip_fw15.h | 1172 +++++ sbin/ipfw15/ipfw.8 | 5094 +++++++++++++++++++ sbin/ipfw15/ipfw2.c | 6129 +++++++++++++++++++++++ sbin/ipfw15/ipfw2.h | 470 ++ sbin/ipfw15/ipv6.c | 519 ++ sbin/ipfw15/main.c | 716 +++ sbin/ipfw15/nat.c | 1196 +++++ sbin/ipfw15/nat64clat.c | 536 ++ sbin/ipfw15/nat64lsn.c | 901 ++++ sbin/ipfw15/nat64stl.c | 552 ++ sbin/ipfw15/nptv6.c | 452 ++ sbin/ipfw15/tables.c | 2096 ++++++++ 23 files changed, 24049 insertions(+) diff --git a/sbin/Makefile b/sbin/Makefile index cbfff38cc626..3afe1c6d1d1e 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -78,6 +78,7 @@ SUBDIR.${MK_HAST}+= hastd SUBDIR.${MK_INET6}+= rtsol SUBDIR.${MK_IPFILTER}+= ipf SUBDIR.${MK_IPFW}+= ipfw +SUBDIR.${MK_IPFW}+= ipfw15 SUBDIR.${MK_IPFW}+= natd SUBDIR.${MK_OPENSSL}+= decryptcore SUBDIR.${MK_PF}+= pfctl diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c index 1e5f4fbafc1d..3d5cfc96af46 100644 --- a/sbin/ipfw/main.c +++ b/sbin/ipfw/main.c @@ -18,6 +18,7 @@ * Command line interface for IP firewall facility */ +#include <sys/stat.h> #include <sys/wait.h> #include <ctype.h> #include <err.h> @@ -30,6 +31,8 @@ #include <unistd.h> #include <libgen.h> +#include <osreldate.h> + #include "ipfw2.h" static void @@ -690,6 +693,29 @@ main(int ac, char *av[]) else g_co.prog = cmdline_prog_ipfw; + /* + * KBI-incompatibility detected, check for availability of ipfw/dnctl15 + * binaries and run them instead + */ + if (getosreldate() >= 1500000) { + const char *releng15_progname; + int ret; + + if (g_co.prog == cmdline_prog_ipfw) + releng15_progname = "/sbin/ipfw15"; + else + releng15_progname = "/sbin/dnctl15"; + + printf("WARNING! KBI incompatibility for ipfw is detected," + " trying to run %s.\n", releng15_progname); + + if ((ret = execv(releng15_progname, av)) < 0) { + printf("execv(%s) error: %s\n", releng15_progname, + strerror(errno)); + } + return (ret); + } + /* * If the last argument is an absolute pathname, interpret it * as a file to be preprocessed. diff --git a/sbin/ipfw15/Makefile b/sbin/ipfw15/Makefile new file mode 100644 index 000000000000..b28b365caa84 --- /dev/null +++ b/sbin/ipfw15/Makefile @@ -0,0 +1,23 @@ +.include <src.opts.mk> + +PACKAGE=ipfw15 +PROG= ipfw15 + +CFLAGS+= -I ${.CURDIR}/include15 + +LINKS= ${BINDIR}/ipfw15 ${BINDIR}/dnctl15 +MK_MAN= no + +SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c tables.c +SRCS+= nat64clat.c nat64lsn.c nat64stl.c nptv6.c + +.if ${MK_PF} != "no" +SRCS+= altq.c +CFLAGS+=-DPF +.endif + +LIBADD= jail util + +.include <bsd.prog.mk> + +CWARNFLAGS+= -Wno-cast-align diff --git a/sbin/ipfw15/Makefile.depend b/sbin/ipfw15/Makefile.depend new file mode 100644 index 000000000000..774db391da26 --- /dev/null +++ b/sbin/ipfw15/Makefile.depend @@ -0,0 +1,19 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/arpa \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libalias/libalias \ + lib/libc \ + lib/libcompiler_rt \ + lib/libjail \ + lib/libutil \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/sbin/ipfw15/altq.c b/sbin/ipfw15/altq.c new file mode 100644 index 000000000000..a49f450e046c --- /dev/null +++ b/sbin/ipfw15/altq.c @@ -0,0 +1,152 @@ +/*- + * Copyright (c) 2002-2003 Luigi Rizzo + * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp + * Copyright (c) 1994 Ugen J.S.Antsilevich + * + * Idea and grammar partially left from: + * Copyright (c) 1993 Daniel Boulet + * + * 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. + * + * NEW command line interface for IP firewall facility + * + * altq interface + */ + +#define PFIOC_USE_LATEST + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/sockio.h> + +#include "ipfw2.h" + +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> +#include <fcntl.h> + +#include <net/if.h> /* IFNAMSIZ */ +#include <net/pfvar.h> +#include <netinet/in.h> /* in_addr */ +#include <netinet/ip_fw15.h> + +/* + * Map between current altq queue id numbers and names. + */ +static TAILQ_HEAD(, pf_altq) altq_entries = + TAILQ_HEAD_INITIALIZER(altq_entries); + +void +altq_set_enabled(int enabled) +{ + int pffd; + + pffd = open("/dev/pf", O_RDWR); + if (pffd == -1) + err(EX_UNAVAILABLE, + "altq support opening pf(4) control device"); + if (enabled) { + if (ioctl(pffd, DIOCSTARTALTQ) != 0 && errno != EEXIST) + err(EX_UNAVAILABLE, "enabling altq"); + } else { + if (ioctl(pffd, DIOCSTOPALTQ) != 0 && errno != ENOENT) + err(EX_UNAVAILABLE, "disabling altq"); + } + close(pffd); +} + +static void +altq_fetch(void) +{ + struct pfioc_altq pfioc; + struct pf_altq *altq; + int pffd; + unsigned int mnr; + static int altq_fetched = 0; + + if (altq_fetched) + return; + altq_fetched = 1; + pffd = open("/dev/pf", O_RDONLY); + if (pffd == -1) { + warn("altq support opening pf(4) control device"); + return; + } + bzero(&pfioc, sizeof(pfioc)); + pfioc.version = PFIOC_ALTQ_VERSION; + if (ioctl(pffd, DIOCGETALTQS, &pfioc) != 0) { + warn("altq support getting queue list"); + close(pffd); + return; + } + mnr = pfioc.nr; + for (pfioc.nr = 0; pfioc.nr < mnr; pfioc.nr++) { + if (ioctl(pffd, DIOCGETALTQ, &pfioc) != 0) { + if (errno == EBUSY) + break; + warn("altq support getting queue list"); + close(pffd); + return; + } + if (pfioc.altq.qid == 0) + continue; + altq = safe_calloc(1, sizeof(*altq)); + *altq = pfioc.altq; + TAILQ_INSERT_TAIL(&altq_entries, altq, entries); + } + close(pffd); +} + +u_int32_t +altq_name_to_qid(const char *name) +{ + struct pf_altq *altq; + + altq_fetch(); + TAILQ_FOREACH(altq, &altq_entries, entries) + if (strcmp(name, altq->qname) == 0) + break; + if (altq == NULL) + errx(EX_DATAERR, "altq has no queue named `%s'", name); + return altq->qid; +} + +static const char * +altq_qid_to_name(u_int32_t qid) +{ + struct pf_altq *altq; + + altq_fetch(); + TAILQ_FOREACH(altq, &altq_entries, entries) + if (qid == altq->qid) + break; + if (altq == NULL) + return NULL; + return altq->qname; +} + +void +print_altq_cmd(struct buf_pr *bp, const ipfw_insn_altq *altqptr) +{ + if (altqptr) { + const char *qname; + + qname = altq_qid_to_name(altqptr->qid); + if (qname == NULL) + bprintf(bp, " altq ?<%u>", altqptr->qid); + else + bprintf(bp, " altq %s", qname); + } +} diff --git a/sbin/ipfw15/dummynet.c b/sbin/ipfw15/dummynet.c new file mode 100644 index 000000000000..0d8132f6e249 --- /dev/null +++ b/sbin/ipfw15/dummynet.c @@ -0,0 +1,2016 @@ +/*- + * Codel/FQ_Codel and PIE/FQ_PIE Code: + * Copyright (C) 2016 Centre for Advanced Internet Architectures, + * Swinburne University of Technology, Melbourne, Australia. + * Portions of this code were made possible in part by a gift from + * The Comcast Innovation Fund. + * Implemented by Rasool Al-Saadi <ralsaadi@swin.edu.au> + * + * Copyright (c) 2002-2003,2010 Luigi Rizzo + * + * 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. + * + * dummynet support + */ + +#define NEW_AQM +#include <sys/limits.h> +#include <sys/param.h> +#include <sys/socket.h> +/* XXX there are several sysctl leftover here */ +#include <sys/sysctl.h> + +#include "ipfw2.h" + +#ifdef NEW_AQM +#include <stdint.h> +#endif + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <libutil.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/ip_fw15.h> +#include <netinet/ip_dummynet15.h> +#include <arpa/inet.h> /* inet_ntoa */ + + +static struct _s_x dummynet_params[] = { + { "plr", TOK_PLR }, + { "noerror", TOK_NOERROR }, + { "buckets", TOK_BUCKETS }, + { "dst-ip", TOK_DSTIP }, + { "src-ip", TOK_SRCIP }, + { "dst-port", TOK_DSTPORT }, + { "src-port", TOK_SRCPORT }, + { "proto", TOK_PROTO }, + { "weight", TOK_WEIGHT }, + { "lmax", TOK_LMAX }, + { "maxlen", TOK_LMAX }, + { "all", TOK_ALL }, + { "mask", TOK_MASK }, /* alias for both */ + { "sched_mask", TOK_SCHED_MASK }, + { "flow_mask", TOK_FLOW_MASK }, + { "droptail", TOK_DROPTAIL }, + { "ecn", TOK_ECN }, + { "red", TOK_RED }, + { "gred", TOK_GRED }, +#ifdef NEW_AQM + { "codel", TOK_CODEL}, /* Codel AQM */ + { "fq_codel", TOK_FQ_CODEL}, /* FQ-Codel */ + { "pie", TOK_PIE}, /* PIE AQM */ + { "fq_pie", TOK_FQ_PIE}, /* FQ-PIE */ +#endif + { "bw", TOK_BW }, + { "bandwidth", TOK_BW }, + { "delay", TOK_DELAY }, + { "link", TOK_LINK }, + { "pipe", TOK_PIPE }, + { "queue", TOK_QUEUE }, + { "flowset", TOK_FLOWSET }, + { "sched", TOK_SCHED }, + { "pri", TOK_PRI }, + { "priority", TOK_PRI }, + { "type", TOK_TYPE }, + { "flow-id", TOK_FLOWID}, + { "dst-ipv6", TOK_DSTIP6}, + { "dst-ip6", TOK_DSTIP6}, + { "src-ipv6", TOK_SRCIP6}, + { "src-ip6", TOK_SRCIP6}, + { "profile", TOK_PROFILE}, + { "burst", TOK_BURST}, + { "dummynet-params", TOK_NULL }, + { NULL, 0 } /* terminator */ +}; + +#ifdef NEW_AQM +/* AQM/extra sched parameters tokens*/ +static struct _s_x aqm_params[] = { + { "target", TOK_TARGET}, + { "interval", TOK_INTERVAL}, + { "limit", TOK_LIMIT}, + { "flows", TOK_FLOWS}, + { "quantum", TOK_QUANTUM}, + { "ecn", TOK_ECN}, + { "noecn", TOK_NO_ECN}, + { "tupdate", TOK_TUPDATE}, + { "max_burst", TOK_MAX_BURST}, + { "max_ecnth", TOK_MAX_ECNTH}, + { "alpha", TOK_ALPHA}, + { "beta", TOK_BETA}, + { "capdrop", TOK_CAPDROP}, + { "nocapdrop", TOK_NO_CAPDROP}, + { "onoff", TOK_ONOFF}, + { "dre", TOK_DRE}, + { "ts", TOK_TS}, + { "derand", TOK_DERAND}, + { "noderand", TOK_NO_DERAND}, + { NULL, 0 } /* terminator */ +}; +#endif + +#define O_NEXT(p, len) ((void *)((char *)p + len)) + +static void +oid_fill(struct dn_id *oid, int len, int type, uintptr_t id) +{ + oid->len = len; + oid->type = type; + oid->subtype = 0; + oid->id = id; +} + +/* make room in the buffer and move the pointer forward */ +static void * +o_next(struct dn_id **o, int len, int type) +{ + struct dn_id *ret = *o; + oid_fill(ret, len, type, 0); + *o = O_NEXT(*o, len); + return ret; +} + +#ifdef NEW_AQM + +/* Codel flags */ +enum { + CODEL_ECN_ENABLED = 1 +}; + +/* PIE flags, from PIE kernel module */ +enum { + PIE_ECN_ENABLED = 1, + PIE_CAPDROP_ENABLED = 2, + PIE_ON_OFF_MODE_ENABLED = 4, + PIE_DEPRATEEST_ENABLED = 8, + PIE_DERAND_ENABLED = 16 +}; + +#define PIE_FIX_POINT_BITS 13 +#define PIE_SCALE (1L<<PIE_FIX_POINT_BITS) + +/* integer to time */ +static void +us_to_time(int t, char *strt) +{ + if (t < 0) + strt[0]='\0'; + else if ( t==0 ) + sprintf(strt,"%d", t); + else if (t< 1000) + sprintf(strt,"%dus", t); + else if (t < 1000000) + sprintf(strt,"%gms", (float) t / 1000); + else + sprintf(strt,"%gfs", (float) t / 1000000); +} + +/* + * returns -1 if s is not a valid time, otherwise, return time in us + */ +static long +time_to_us(const char *s) +{ + int i, dots = 0; + int len = strlen(s); + char strt[16]="", stru[16]=""; + + if (len>15) + return -1; + for (i = 0; i<len && (isdigit(s[i]) || s[i]=='.') ; i++) + if (s[i]=='.') { + if (dots) + return -1; + else + dots++; + } + + if (!i) + return -1; + strncpy(strt, s, i); + if (i<len) + strcpy(stru, s+i); + else + strcpy(stru, "ms"); + + if (!strcasecmp(stru, "us")) + return atol(strt); + if (!strcasecmp(stru, "ms")) + return (strtod(strt, NULL) * 1000); + if (!strcasecmp(stru, "s")) + return (strtod(strt, NULL)*1000000); + + return -1; +} + + +/* Get AQM or scheduler extra parameters */ +static void +get_extra_parms(uint32_t nr, char *out, int subtype) +{ + struct dn_extra_parms *ep; + int ret; + char strt1[15], strt2[15], strt3[15]; + u_int l; + + /* prepare the request */ + l = sizeof(struct dn_extra_parms); + ep = safe_calloc(1, l); + memset(ep, 0, sizeof(*ep)); + *out = '\0'; + + oid_fill(&ep->oid, l, DN_CMD_GET, DN_API_VERSION); + ep->oid.len = l; + ep->oid.subtype = subtype; + ep->nr = nr; + + ret = do_cmd(-IP_DUMMYNET3, ep, (uintptr_t)&l); + if (ret) { + free(ep); + errx(EX_DATAERR, "Error getting extra parameters\n"); + } + + switch (subtype) { + case DN_AQM_PARAMS: + if( !strcasecmp(ep->name, "codel")) { + us_to_time(ep->par[0], strt1); + us_to_time(ep->par[1], strt2); + l = sprintf(out, " AQM CoDel target %s interval %s", + strt1, strt2); + if (ep->par[2] & CODEL_ECN_ENABLED) + l = sprintf(out + l, " ECN"); + else + l += sprintf(out + l, " NoECN"); + } else if( !strcasecmp(ep->name, "pie")) { + us_to_time(ep->par[0], strt1); + us_to_time(ep->par[1], strt2); + us_to_time(ep->par[2], strt3); + l = sprintf(out, " AQM type PIE target %s tupdate %s alpha " + "%g beta %g max_burst %s max_ecnth %.3g", + strt1, + strt2, + ep->par[4] / (float) PIE_SCALE, + ep->par[5] / (float) PIE_SCALE, + strt3, + ep->par[3] / (float) PIE_SCALE + ); + + if (ep->par[6] & PIE_ECN_ENABLED) + l += sprintf(out + l, " ECN"); + else + l += sprintf(out + l, " NoECN"); + if (ep->par[6] & PIE_CAPDROP_ENABLED) + l += sprintf(out + l, " CapDrop"); + else + l += sprintf(out + l, " NoCapDrop"); + if (ep->par[6] & PIE_ON_OFF_MODE_ENABLED) + l += sprintf(out + l, " OnOff"); + if (ep->par[6] & PIE_DEPRATEEST_ENABLED) + l += sprintf(out + l, " DRE"); + else + l += sprintf(out + l, " TS"); + if (ep->par[6] & PIE_DERAND_ENABLED) + l += sprintf(out + l, " Derand"); + else + l += sprintf(out + l, " NoDerand"); + } + break; + + case DN_SCH_PARAMS: + if (!strcasecmp(ep->name,"FQ_CODEL")) { + us_to_time(ep->par[0], strt1); + us_to_time(ep->par[1], strt2); + l = sprintf(out," FQ_CODEL target %s interval %s" + " quantum %jd limit %jd flows %jd", + strt1, strt2, + (intmax_t) ep->par[3], + (intmax_t) ep->par[4], + (intmax_t) ep->par[5] + ); + if (ep->par[2] & CODEL_ECN_ENABLED) + l += sprintf(out + l, " ECN"); + else + l += sprintf(out + l, " NoECN"); + l += sprintf(out + l, "\n"); + } else if (!strcasecmp(ep->name,"FQ_PIE")) { + us_to_time(ep->par[0], strt1); + us_to_time(ep->par[1], strt2); + us_to_time(ep->par[2], strt3); + l = sprintf(out, " FQ_PIE target %s tupdate %s alpha " + "%g beta %g max_burst %s max_ecnth %.3g" + " quantum %jd limit %jd flows %jd", + strt1, + strt2, + ep->par[4] / (float) PIE_SCALE, + ep->par[5] / (float) PIE_SCALE, + strt3, + ep->par[3] / (float) PIE_SCALE, + (intmax_t) ep->par[7], + (intmax_t) ep->par[8], + (intmax_t) ep->par[9] + ); + + if (ep->par[6] & PIE_ECN_ENABLED) + l += sprintf(out + l, " ECN"); + else + l += sprintf(out + l, " NoECN"); + if (ep->par[6] & PIE_CAPDROP_ENABLED) + l += sprintf(out + l, " CapDrop"); + else + l += sprintf(out + l, " NoCapDrop"); + if (ep->par[6] & PIE_ON_OFF_MODE_ENABLED) + l += sprintf(out + l, " OnOff"); + if (ep->par[6] & PIE_DEPRATEEST_ENABLED) + l += sprintf(out + l, " DRE"); + else + l += sprintf(out + l, " TS"); + if (ep->par[6] & PIE_DERAND_ENABLED) + l += sprintf(out + l, " Derand"); + else + l += sprintf(out + l, " NoDerand"); + l += sprintf(out + l, "\n"); + } + break; + } + + free(ep); +} +#endif + + +#if 0 +static int +sort_q(void *arg, const void *pa, const void *pb) +{ + int rev = (co.do_sort < 0); + int field = rev ? -co.do_sort : co.do_sort; + long long res = 0; + const struct dn_flow_queue *a = pa; + const struct dn_flow_queue *b = pb; + + switch (field) { + case 1: /* pkts */ + res = a->len - b->len; + break; + case 2: /* bytes */ + res = a->len_bytes - b->len_bytes; + break; + + case 3: /* tot pkts */ + res = a->tot_pkts - b->tot_pkts; + break; + + case 4: /* tot bytes */ + res = a->tot_bytes - b->tot_bytes; + break; + } + if (res < 0) + res = -1; + if (res > 0) + res = 1; + return (int)(rev ? res : -res); +} +#endif + +/* print a mask and header for the subsequent list of flows */ +static void +print_mask(struct ipfw_flow_id *id) +{ + if (!IS_IP6_FLOW_ID(id)) { + printf(" " + "mask: %s 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", + id->extra ? "queue," : "", + id->proto, + id->src_ip, id->src_port, + id->dst_ip, id->dst_port); + } else { + char buf[255]; + printf("\n mask: %sproto: 0x%02x, flow_id: 0x%08x, ", + id->extra ? "queue," : "", + id->proto, id->flow_id6); + inet_ntop(AF_INET6, &(id->src_ip6), buf, sizeof(buf)); + printf("%s/0x%04x -> ", buf, id->src_port); + inet_ntop(AF_INET6, &(id->dst_ip6), buf, sizeof(buf)); + printf("%s/0x%04x\n", buf, id->dst_port); + } +} + +static void +print_header(struct ipfw_flow_id *id) +{ + if (!IS_IP6_FLOW_ID(id)) + printf("BKT Prot ___Source IP/port____ " + "____Dest. IP/port____ " + "Tot_pkt/bytes Pkt/Byte Drp\n"); + else + printf("BKT ___Prot___ _flow-id_ " + "______________Source IPv6/port_______________ " + "_______________Dest. IPv6/port_______________ " + "Tot_pkt/bytes Pkt/Byte Drp\n"); +} + +static void +list_flow(struct buf_pr *bp, struct dn_flow *ni) +{ + char buff[255]; + struct protoent *pe = NULL; + struct in_addr ina; + struct ipfw_flow_id *id = &ni->fid; + + pe = getprotobynumber(id->proto); + /* XXX: Should check for IPv4 flows */ + bprintf(bp, "%3u%c", (ni->oid.id) & 0xff, + id->extra ? '*' : ' '); + if (!IS_IP6_FLOW_ID(id)) { + if (pe) + bprintf(bp, "%-4s ", pe->p_name); + else + bprintf(bp, "%4u ", id->proto); + ina.s_addr = htonl(id->src_ip); + bprintf(bp, "%15s/%-5d ", + inet_ntoa(ina), id->src_port); + ina.s_addr = htonl(id->dst_ip); + bprintf(bp, "%15s/%-5d ", + inet_ntoa(ina), id->dst_port); + } else { + /* Print IPv6 flows */ + if (pe != NULL) + bprintf(bp, "%9s ", pe->p_name); + else + bprintf(bp, "%9u ", id->proto); + bprintf(bp, "%7d %39s/%-5d ", id->flow_id6, + inet_ntop(AF_INET6, &(id->src_ip6), buff, sizeof(buff)), + id->src_port); + bprintf(bp, " %39s/%-5d ", + inet_ntop(AF_INET6, &(id->dst_ip6), buff, sizeof(buff)), + id->dst_port); + } + pr_u64(bp, &ni->tot_pkts, 4); + pr_u64(bp, &ni->tot_bytes, 8); + bprintf(bp, "%2u %4u %3u", + ni->length, ni->len_bytes, ni->drops); +} + +static void +print_flowset_parms(struct dn_fs *fs, char *prefix) +{ + int l; + char qs[30]; + char plr[40]; + char red[200]; /* Display RED parameters */ + + l = fs->qsize; + if (fs->flags & DN_QSIZE_BYTES) { + if (l >= 8192) + sprintf(qs, "%d KB", l / 1024); + else + sprintf(qs, "%d B", l); + } else + sprintf(qs, "%3d sl.", l); + if (fs->plr[0] || fs->plr[1]) { + if (fs->plr[1] == 0) + sprintf(plr, "plr %f", + 1.0 * fs->plr[0] / (double)(0x7fffffff)); + else + sprintf(plr, "plr %f,%f,%f,%f", + 1.0 * fs->plr[0] / (double)(0x7fffffff), + 1.0 * fs->plr[1] / (double)(0x7fffffff), + 1.0 * fs->plr[2] / (double)(0x7fffffff), + 1.0 * fs->plr[3] / (double)(0x7fffffff)); + } else + plr[0] = '\0'; + + if (fs->flags & DN_IS_RED) { /* RED parameters */ + sprintf(red, + "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", + (fs->flags & DN_IS_GENTLE_RED) ? 'G' : ' ', + 1.0 * fs->w_q / (double)(1 << SCALE_RED), + fs->min_th, + fs->max_th, + 1.0 * fs->max_p / (double)(1 << SCALE_RED)); + if (fs->flags & DN_IS_ECN) + strlcat(red, " (ecn)", sizeof(red)); +#ifdef NEW_AQM + /* get AQM parameters */ + } else if (fs->flags & DN_IS_AQM) { + get_extra_parms(fs->fs_nr, red, DN_AQM_PARAMS); +#endif + } else + sprintf(red, "droptail"); + + if (prefix[0]) { + printf("%s %s%s %d queues (%d buckets) %s\n", + prefix, qs, plr, fs->oid.id, fs->buckets, red); + prefix[0] = '\0'; + } else { + printf("q%05d %s%s %d flows (%d buckets) sched %d " + "weight %d lmax %d pri %d %s\n", + fs->fs_nr, qs, plr, fs->oid.id, fs->buckets, + fs->sched_nr, fs->par[0], fs->par[1], fs->par[2], red); + if (fs->flags & DN_HAVE_MASK) + print_mask(&fs->flow_mask); + } +} + +static void +print_extra_delay_parms(struct dn_profile *p) +{ + double loss; + if (p->samples_no <= 0) + return; + + loss = p->loss_level; + loss /= p->samples_no; + printf("\t profile: name \"%s\" loss %f samples %d\n", + p->name, loss, p->samples_no); +} + +static void +flush_buf(char *buf) +{ + if (buf[0]) + printf("%s\n", buf); + buf[0] = '\0'; +} + +/* + * generic list routine. We expect objects in a specific order, i.e. + * PIPES AND SCHEDULERS: + * link; scheduler; internal flowset if any; instances + * we can tell a pipe from the number. + * + * FLOWSETS: + * flowset; queues; + * link i (int queue); scheduler i; si(i) { flowsets() : queues } + */ +static void +list_pipes(struct dn_id *oid, struct dn_id *end) +{ + char buf[160]; /* pending buffer */ + int toPrint = 1; /* print header */ + struct buf_pr bp; + + buf[0] = '\0'; + bp_alloc(&bp, 4096); + for (; oid != end; oid = O_NEXT(oid, oid->len)) { + if (oid->len < sizeof(*oid)) + errx(1, "invalid oid len %d\n", oid->len); + + switch (oid->type) { + default: + flush_buf(buf); + printf("unrecognized object %d size %d\n", oid->type, oid->len); + break; + case DN_TEXT: /* list of attached flowsets */ + { + int i, l; + struct { + struct dn_id id; + uint32_t p[0]; + } *d = (void *)oid; + l = (oid->len - sizeof(*oid))/sizeof(d->p[0]); + if (l == 0) + break; + printf(" Children flowsets: "); + for (i = 0; i < l; i++) + printf("%u ", d->p[i]); + printf("\n"); + break; + } + case DN_CMD_GET: + if (g_co.verbose) + printf("answer for cmd %d, len %d\n", oid->type, oid->id); + break; + case DN_SCH: { + struct dn_sch *s = (struct dn_sch *)oid; + flush_buf(buf); + printf(" sched %d type %s flags 0x%x %d buckets %d active\n", + s->sched_nr, + s->name, s->flags, s->buckets, s->oid.id); +#ifdef NEW_AQM + char parms[200]; + get_extra_parms(s->sched_nr, parms, DN_SCH_PARAMS); + printf("%s",parms); +#endif + if (s->flags & DN_HAVE_MASK) + print_mask(&s->sched_mask); + } + break; + + case DN_FLOW: + if (toPrint != 0) { + print_header(&((struct dn_flow *)oid)->fid); + toPrint = 0; + } + list_flow(&bp, (struct dn_flow *)oid); + printf("%s\n", bp.buf); + bp_flush(&bp); + break; + + case DN_LINK: { + struct dn_link *p = (struct dn_link *)oid; + double b = p->bandwidth; + char bwbuf[30]; + char burst[5 + 7]; + + /* This starts a new object so flush buffer */ + flush_buf(buf); + /* data rate */ + if (b == 0) + sprintf(bwbuf, "unlimited "); + else if (b >= 1000000000) + sprintf(bwbuf, "%7.3f Gbit/s", b/1000000000); + else if (b >= 1000000) + sprintf(bwbuf, "%7.3f Mbit/s", b/1000000); + else if (b >= 1000) + sprintf(bwbuf, "%7.3f Kbit/s", b/1000); + else + sprintf(bwbuf, "%7.3f bit/s ", b); + + if (humanize_number(burst, sizeof(burst), p->burst, + "", HN_AUTOSCALE, 0) < 0 || g_co.verbose) + sprintf(burst, "%d", (int)p->burst); + sprintf(buf, "%05d: %s %4d ms burst %s", + p->link_nr % DN_MAX_ID, bwbuf, p->delay, burst); + } + break; + + case DN_FS: + print_flowset_parms((struct dn_fs *)oid, buf); + break; *** 23275 LINES SKIPPED ***home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?698b1f6d.32357.78a6474f>
