Compare commits

...
Author SHA1 Message Date
Colin Percival a456f852d1 Update in preparation for 14.4-RELEASE
- Bump BRANCH to RELEASE
- Add the anticipated RELEASE announcement date
- Set a static __FreeBSD_version

Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-03-06 00:00:00 +00:00
Colin Percival 041aa28386 14.4: Update to RC1
Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-02-27 00:00:00 +00:00
Colin Percival 12143e3e3a Switch from "quarterly" to "release" pkgs on DVD
Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-02-26 14:41:52 -08:00
Dag-Erling Smørgrav ca76ec7c4e libfetch: Fail hard if interrupted while connecting
This fixes an issue where the first address that DNS returns is blocked
by a packet filter, so we hang for a while, then the user hits Ctrl-C,
interrupting connect(2), whereupon we move on to the next address, get
a connection, request the file, and return to fetch(1), which sees that
SIGINT was caught and bails.

Note that we make no attempt to enforce fetchTimeout in the connection
phase, and never have.  It's feasible, but non-trivial, so we'll leave
it as an exercise for future us.

PR:		293312
MFC after:	1 week
Reviewed by:	imp
Differential Revision:	https://reviews.freebsd.org/D55406

(cherry picked from commit afbdcd402b)
(cherry picked from commit cca6f5eadb)
2026-02-26 10:00:38 -08:00
Ahmad Khalifa 3cf73e195a bsdinstall: fix EFI boot entry creation
update_uefi_bootentry assumes that the caller sets FREEBSD_BOOTNAME and
mntpt, which isn't the case anymore. The result is that there is no
"FreeBSD" boot entry created/updated after install. Most machines manage
to boot from the removable media path (if the loader is installed there
too), but some don't.

Take the loader's path as an argument and rename the variable used in
the ZFS mirror loop so mntpt can be reused below.

Also mark nentries as a local variable so it doesn't leak out of the
function.

PR:		293385
Fixes:		494de51bc0
MFC after:	2 days
Reviewed by:	imp
Differential Revision:	https://reviews.freebsd.org/D55469

(cherry picked from commit 0fd91c4891)
(cherry picked from commit cfdd90abab)
2026-02-26 08:50:15 -08:00
Mark Johnston 49684d7d93 nullfs: Fix handling of doomed vnodes in nullfs_unlink_lowervp()
nullfs_unlink_lowervp() is called with the lower vnode locked, so the
nullfs vnode is locked too.  The following can occur:
1. the vunref() call decrements the usecount 2->1,
2. a different thread calls vrele() on the vnode, decrements the
   usecount 0->1, then blocks on the vnode lock,
3. the first thread tests vp->v_usecount == 0 and observes that it is
   true,
4. the first thread incorrectly unlocks the lower vnode.

Fix this by testing VN_IS_DOOMED directly.  Since
nullfs_unlink_lowervp() holds the vnode lock, the value of the
VIRF_DOOMED flag is stable.

Thanks to leres@ for patiently helping to track this down.

PR:		288345
MFC after:	1 week
Reviewed by:	kib
Differential Revision:	https://reviews.freebsd.org/D55446

(cherry picked from commit 8b64d46fab)
(cherry picked from commit 6ed3732276)
2026-02-25 19:12:43 -08:00
Colin Percival 20cff160e1 pkg-stage.sh: Add ext2 and ntfs
Having these packages available on release media may help users who
need to sneakernet other packages (e.g. firmware) from systems running
Linux or Windows.

Suggested by:	vladlen, ziaee
MFC after:	3 days

(cherry picked from commit 6881fd278d)
(cherry picked from commit a2c2de82c0)
2026-02-25 16:23:37 -08:00
Colin Percival 6ecd231b9e pkg-stage.sh: Add emacs@nox and vim
We have a bit of space left on the 14.4 DVDs; add packages for two
editors, one of which is useful.

Direct commit to stable/14: These packages were added to 15.0 but
at the same time as removing kde, because shipping distribution sets
*and* a pkgbase repository on 15 significantly cuts into the space
available.  On 14 we can keep kde and still add these packages.

With hat:	re
MFC after:	3 days

(cherry picked from commit d982b7bd4e)
2026-02-25 16:23:31 -08:00
Mark Johnston 7465d0b094 rtsock: Fix stack overflow
Approved by:	so
Approved by:	re (cperciva)
Security:	FreeBSD-SA-26:05.route
Security:	CVE-2026-3038
Fixes:		92be2847e8 ("rtsock: Avoid copying uninitialized padding bytes")

(cherry picked from commit f3be7df50f)
(cherry picked from commit 1eb2beb368)
2026-02-24 16:02:21 +00:00
Colin Percival 0c49d9fafc 14.3: Update to BETA3
Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-02-20 00:00:00 +00:00
Gleb Smirnoff 7c81bf5191 ng_ksocket: use new macros to lock socket buffers
PR:		292885
Reported by:	Walker R. Thompson <[email protected]>

(cherry picked from commit 1a3d1be496)
(cherry picked from commit 4dc38e71cc)
2026-02-19 14:54:18 -08:00
Baptiste Daroussin 02138275ef usb_vendors: update to 2025.12.13
(cherry picked from commit 8d4c1043bb)
(cherry picked from commit 2f866e0547)
2026-02-19 11:22:24 -08:00
Baptiste Daroussin 7805899ed7 pci_vendors: update to 2026-02-10
(cherry picked from commit 1acfc913e6)
(cherry picked from commit b28b6c6d33)
2026-02-19 11:22:24 -08:00
Baptiste Daroussin 65338ff41f tr: fix class handling in unicode world
toupper/tolower logic was only handled for CCLASS_TOUPPER and
CCLASS_TOLOWER, add support for CCLASS ([:alpha:])

PR:		219900
MFC After: 	1 week

(cherry picked from commit 625dc44832)
(cherry picked from commit 45d84c2f06)
2026-02-19 11:22:24 -08:00
Timo Völker 28b5b653a5 icmp6: clear csum_flags on mbuf reuse
When icmp6 sends an ICMPv6 message, it reuses the mbuf of the packet
that triggered the ICMPv6 message and prepends an IPv6 and ICMPv6
header. For a locally generated packet with checksum offloading, the
mbuf still has csum_flags set indicating that a SCTP/TCP/UDP checksum
has to be computed and inserted. Since this not the case anymore,
csum_flags need to be cleared.

PR:			293227
Reviewed by:		kp, zlei, tuexen
MFC after:		3 days
Differential Revision:	https://reviews.freebsd.org/D55367

(cherry picked from commit ada4dc7757)
(cherry picked from commit 0a87ae1833)
2026-02-19 11:21:55 -08:00
Jessica Clarke 0d08a243f2 Merge commit bfb276e55c from upstream OpenZFS (by Jessica Clarke)
Once upon a time, 32-bit PowerPC did indeed have a 32-bit time_t, but
  FreeBSD 12.0 switched to a 64-bit time_t for PowerPC as an ABI break,
  which predates the addition of FreeBSD support to OpenZFS. Moreover,
  64-bit PowerPC has existed since FreeBSD 9.0, where __powerpc__ is also
  defined (alongside __powerpc64__ to disambiguate), which has always had
  a 64-bit time_t. This code has therefore always been wrong for all
  PowerPC variants. Fix this by limiting the 32-bit case to just i386,
  which is the only architecture in FreeBSD to have a 32-bit time_t and
  not have broken ABI, due to its special legacy compatibility status.

  Reviewed-by: Brian Behlendorf <[email protected]>
  Reviewed-by: Alexander Motin <[email protected]>
  Signed-off-by: Jessica Clarke <[email protected]>
  Closes #18217
  Closes #18218

Reported by:	fuz
MFC after:	1 day

(cherry picked from commit 45c1e44779)
(cherry picked from commit 354cc5e142)
2026-02-19 11:21:28 -08:00
Dag-Erling Smørgrav 8755b5f3a5 libfetch: Restore timeout functionality
PR:		293124
MFC after:	1 week
Fixes:		792ef1ae7b ("Refactor fetch_connect() and fetch_bind() to improve readability and avoid repeating the same DNS lookups.")
Reverts:	8f8a7f6fff ("libfetch: apply timeout to SSL_read()")
Reviewed by:	eugen, imp
Differential Revision:	https://reviews.freebsd.org/D55293

(cherry picked from commit 73b82d1b0a)
(insta-mfc requested by re@)
(cherry picked from commit d97c824f5b)
2026-02-19 11:21:21 -08:00
Dmitry Morozovsky 7f1e9f9451 pw: make manual page more friendly for uid/gid search
pw.8 structure is quite different from usual manual page, especially in
describing -o option usage.  Specifically, these paragraphs do not
contain "uid/gid" terms, and have "user id"/"group id" instead,
making searching for "override duplicate safety belt" difficult.
Try to simplify such searches.

Also, clarify uid/gid space between 100 and 1000 as "somewhat special",
as it actually is.

Discussed on:   russian telegram FreeBSD group
Reviewed by:	eugen, novel
MFC after:      1 week

(cherry picked from commit e89454417b)
(cherry picked from commit 8a2d04cf8c)
2026-02-18 08:28:43 -08:00
Dag-Erling Smørgrav f16fc39527 ngctl: Fix buffer overflow in config command
Keep track of our buffer length when assembling the argument list.

PR:		293075
MFC after:	1 week
Reviewed by:	zlei, markj
Differential Revision:	https://reviews.freebsd.org/D55259

(cherry picked from commit 59906a163e)
(cherry picked from commit e5bf728058)
2026-02-17 17:48:33 -08:00
Dag-Erling Smørgrav 6316ab68d3 ngctl: Check hook name length
Check the length of the hook name when copying it into the sockaddr.

MFC after:	1 week
Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D55258

(cherry picked from commit 585190dff4)
(cherry picked from commit 71c0f48ab1)
2026-02-17 17:48:33 -08:00
Konstantin Belousov 71ed9ae5e6 kern/vfs_unmount.c: promote flags to uint64_t
(cherry picked from commit 8066b8923e)
(cherry picked from commit 00095a0896)
2026-02-17 17:47:16 -08:00
Konstantin Belousov 0235e9e569 unmount(2): do not allow MNT_DEFERRED or MNT_RECURSE flags from userspace
(cherry picked from commit cd8d44173a)
(cherry picked from commit a893e8463a)
2026-02-17 17:47:16 -08:00
Konstantin Belousov 39dd0d8a0d kqtimer_proc_continue(): correct calculation of 'now'
PR:	293141

(cherry picked from commit e7f86f8b13)
(cherry picked from commit cf941029dd)
2026-02-17 17:47:15 -08:00
Konstantin Belousov 37fa2e7695 filt_timerexpire_l(): re-insert restarted timer into head instead of tail
PR:	293141

(cherry picked from commit 75a30ea09f)
(cherry picked from commit 119af90d48)
2026-02-17 17:47:15 -08:00
Dimitry Andric d2136eeb14 BSD.usr.dist: remove obsolete usr/share/examples/drivers entry
In base 8f0a6a9aad, usr/share/examples/drivers was cleaned up,
because it contained unmaintained scripts. The directory itself is
cleaned up by ObsoleteFiles.inc, but there was still an entry in
BSD.usr.dist that re-created the directory. Remove it.

Fixes:		8f0a6a9aad
MFC after:	3 days

(cherry picked from commit ac2f284258)
(cherry picked from commit c44a4859c3)
2026-02-14 13:59:15 -08:00
Colin Percival f2dc20d2d2 14.3: Update to BETA2
Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-02-13 00:00:00 +00:00
Dag-Erling Smørgrav 53e0a1d1ff libfetch: Check for failure to create SSL context
* Drop the ssl_meth member, there is no reason to hang on to it.

* Replace deprecated SSLv23_client_method() with TLS_client_method().

* Check the return value from SSL_CTX_new().

Approved by:	re (cperciva)
MFC after:	1 week
PR:		292903
Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D55098

(cherry picked from commit 4e160c6197)
(cherry picked from commit 4781aeb5b9)
2026-02-12 13:24:34 -08:00
Colin Percival e8918d58a2 release: Turn off debugging in pkg(8)
Running `pkg -d` in pkg-stage.sh results in multiple GB of network
traffic being written into the log files, which is less than helpful
when it comes to tracking down build failures.  Remove the -d flag.

Approved by:	re (cperciva)
MFC after:	5 days
X-MFC-note:	The code in 15 has diverged from 14, but the flag is
		there, just in a different place.

(cherry picked from commit 18721be356)
(cherry picked from commit 721dfa7e5a)
2026-02-12 13:24:30 -08:00
Colin Percival 8b34da3d3e Makefile.incl1: .WAIT before distribute in etc
In order to make sure that man pages are all installed before we run
makewhatis to generate mandoc.db files, we have long placed etc at the
end of the list of subdirectories being recursed into by the build.
In order to support installworld -jN, a .WAIT was more recently added
here.

With the recent adoption by the release engineering team of parallel
*release* builds (aka 'make release -jN') it is now also necessary to
add the same .WAIT before recursing for the 'distribute' target, as we
otherwise end up with distribution sets containing incomplete mandoc.db
files.

Approved by:	re (cperciva)
Reviewed by:	bdrewery
PR:		289683
MFC after:	3 days
Sponsored by:	https://www.patreon.com/cperciva
Differential Revision:	https://reviews.freebsd.org/D53533

(cherry picked from commit dcb6706ba4)
(cherry picked from commit cd8a5000b3)
2026-02-12 13:24:27 -08:00
Colin Percival fce4758b71 uart: Add ns8250 ACPI entry for SPCR rev 2
This is an MFC "in spirit" of a685a263b803; the code in this area has
been significantly restructured between 14.x and 15.x, but the general
concept of adding ACPI_DBG2_16550_WITH_GAS (aka 0x12) as a recognized
flavour of ns8250 UART which can be configured via SPCR remains.

Approved by:	re (cperciva)
Reviewed by:	imp
Tested by:	David Woodhouse
Sponsored by:	Amazon
Differential Revision:	https://reviews.freebsd.org/D55173

(cherry picked from commit 1dd5b197b7)
2026-02-12 13:24:22 -08:00
Boris Lytochkin 969e2b4068 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.

Approved by:	re (cperciva)
PR:		291562
Reviewed by:	jhb, glebius
Fixes:		4a77657cbc
MFC after:	3 days
Differential Revision:	https://reviews.freebsd.org/D54763

(cherry picked from commit 704ec5e68c)
2026-02-12 11:28:43 -08:00
Zhenlei Huang 2f47676012 qlnxe: Overhaul setting the multicast MAC filters
When operating the multicast MAC filters, the current usage of
ECORE_FILTER_ADD and ECORE_FILTER_REMOVE are rather misleading.
ECORE_FILTER_ADD reads "adding new filter", but it actually removes
any existing filters and then addes a new one. ECORE_FILTER_REMOVE
reads "removing a filter", but it actually removes all filters.
Let's use ECORE_FILTER_REPLACE and ECORE_FILTER_FLUSH instead to
avoid confusion.

In the current implementation, only one MAC address is passed to
ecore_sp_eth_filter_mcast() and any previously installed filters are
removed, hence it breaks the multicast function. That can be observed
via either assigning new IPv6 addresses to the interface or putting
the interface as a member of lagg(4) interface with LACP aggregation
protocol. Fix that by calculating the multicast filter bins directly
from multicast MAC addresses and replace the filters every time
the bins changes.

Due to the nature of the multicast filter, which is hash based, a
full 1's multicast filter bin means all multicast packets are to be
accepted. Thus there's no need to make the vport into allmulti mode
when the number of multicast MAC addresses exceeds the limit
(ECORE_MAX_MC_ADDRS, 64).

Tested with a FastLinQ QL41212HLCU 25GbE adapter, both MFW_Version
8.35.23.0 and 8.59.16.0 are tested.

Note: Currently the VF port is set to promiscuous mode unconditionally,
and the setting of the multicast MAC filters for VF ports is
short-circuited, so the VF port functions as it did.

Approved by:	re (cperciva)
PR:		265857
PR:		290973
Reviewed by:	kbowling
MFC after:	5 days
Differential Revision:	https://reviews.freebsd.org/D54892

(cherry picked from commit 70256d2b86)
(cherry picked from commit 0cfc1145cd)
(cherry picked from commit 87942d7f8f)
2026-02-11 12:29:25 -08:00
Zhenlei Huang 572d4096d3 qlnxe: Allow tapping the TX packets
Currently only the packets in the RX path can be captured by tcpdump
as the ETHER_BPF_MTAP call in the TX path is missing. Add it so that
packets in both directions can be captured.

Approved by:	re (cperciva)
PR:		290973
Reviewed by:	kbowling
MFC after:	5 days
Differential Revision:	https://reviews.freebsd.org/D54891

(cherry picked from commit 968647502e)
(cherry picked from commit 425b9cec0b)
(cherry picked from commit ddfe98e8cc)
2026-02-11 12:29:22 -08:00
Zhenlei Huang 1e23939306 qlnxe: Refactor setting the promiscuous and allmulti mode
There are two entry points to set the promiscuous and allmulti mode.
One is ioctl, and another is the init routine. Given they share almost
the identical logic, refactor a little to make the code more clear.

While here, for the ioctl, translate the error to EINVAL to avoid
confusing the net stack.

Approved by:	re (cperciva)
Reviewed by:	kbowling
MFC after:	5 days
Differential Revision:	https://reviews.freebsd.org/D54890

(cherry picked from commit 45b1718fad)
(cherry picked from commit b8d2c1c367)
(cherry picked from commit 00ab0df793)
2026-02-11 12:29:19 -08:00
Zhenlei Huang 133eae6afd qlnxev: Remove now unneeded include for opt_inet.h
Since the change [1], this is not required anymore.

This change partially reverts commit 8a84794715.

[1] 4012b63889 qlnxe: Let ether_ioctl() handle SIOCSIFADDR ioctl

Approved by:	re (cperciva)
Reviewed by:	kbowling
MFC after:	5 days
Differential Revision:	https://reviews.freebsd.org/D54889

(cherry picked from commit ec7950fe42)
(cherry picked from commit 926e44b498)
(cherry picked from commit e1a051fd53)
2026-02-11 12:29:16 -08:00
Zhenlei Huang be256934d6 qlnxe: Let ether_ioctl() handle SIOCSIFADDR ioctl
Since the change [1], the init routine qlnx_init() works as intended.
Let ether_ioctl() handle SIOCSIFADDR to simplify the code.

Combined with the change [1], this shall be a better fix for PR 287445.

[1] c10e6bc0f0 qlnxe: Avoid reinitializing the interface when it is already initialized

Approved by:	re (cperciva)
PR:		287445
Reviewed by:	kbowling
MFC after:	5 days
Differential Revision:	https://reviews.freebsd.org/D54888

(cherry picked from commit 4012b63889)
(cherry picked from commit 0f383f74b7)
(cherry picked from commit 20ffe22fcf)
2026-02-11 12:29:13 -08:00
Zhenlei Huang 7d0345d32b qlnxe: Avoid reinitializing the interface when it is already initialized
qlnx_init_locked() unconditionally uninitialize the interface thus is
actually reinitializing the interface. Well the init routine qlnx_init()
is to initialize the interface by net stack when assigned with the first
inet or inet6 address. The ioctl SIOCSIFADDR for the first inet6 address
is handled by ether_ioctl() thus the interface is reinitialized no matter
it was initialized or not.

Add a driver status check for that to avoid reinitializing. Further plan
is removing SIOCSIFADDR ioctl from the driver and let ether_ioctl() handle
it.

Approved by:	re (cperciva)
Reviewed by:	kbowling
MFC after:	5 days
Differential Revision:	https://reviews.freebsd.org/D54887

(cherry picked from commit c10e6bc0f0)
(cherry picked from commit 8731ff4871)
(cherry picked from commit ee64955809)
2026-02-11 12:29:10 -08:00
Zhenlei Huang 0671ffe268 qlnxe: Prevent potential concurrency between ioctls
The driver-managed status flags should be lock protected to be touched.
Also this can serialize ioctls those check the IFF_DRV_RUNNING status.

Approved by:	re (cperciva)
Reviewed by:	kbowling
MFC after:	5 days
Differential Revision:	https://reviews.freebsd.org/D54886

(cherry picked from commit 0df8a998a9)
(cherry picked from commit 285b25c080)
(cherry picked from commit 6e5b12acb6)
2026-02-11 12:29:07 -08:00
Zhenlei Huang f8e20e75a6 qlnxe: Fix setting the unicast MAC filter of RX path
When an Ethernet interface is added to lagg(4) as a child interface, its
type, aka if_type, is changed from IFT_ETHER to IFT_IEEE8023ADLAG. Well
changing the link-layer address of the lagg(4) interface will be
propagated to all child interfaces, hence the drivers of child interfaces
shall not presume the type of the interface will not be changed.

Meanwhile, on initializing, an ifnet has been fully attached and it is
guaranteed to have non-null link-layer address so stop NULL checking for
it.

Approved by:	re (cperciva)
Reviewed by:	kbowling
Fixes:		792226e530 qlnxe: Allow MAC address override
MFC after:	5 days
Differential Revision:	https://reviews.freebsd.org/D54885

(cherry picked from commit f250852c9a)
(cherry picked from commit 6d138e958f)
(cherry picked from commit 93719f8c83)
2026-02-11 12:29:04 -08:00
Zhenlei Huang 36ebcb4f82 qlnxe: Avoid memcpy with same source and destination
In case the device is VF, qlnx_get_mac_addr() returns ha->primary_mac
hence it ends up memcpy with same source and destination. Refactor
slightly to avoid that.

Approved by:	re (cperciva)
Reviewed by:	kbowling
MFC after:	5 days
Differential Revision:	https://reviews.freebsd.org/D54884

(cherry picked from commit 3aeeedc7e0)
(cherry picked from commit 6462189595)
(cherry picked from commit ea1143bddb)
2026-02-11 12:29:01 -08:00
Zhenlei Huang 6444869020 qlnxe: Remove a pointless copy back from the link-layer address
On ifnet attaching, ether_ifattach() makes the link-layer address by
shadow copying the ha->primary_mac. Well, the link-layer address will
not be altered during attaching, thus it is pointless to copy it back.

No functional change intended.

Approved by:	re (cperciva)
Reviewed by:	kbowling
MFC after:	5 days
Differential Revision:	https://reviews.freebsd.org/D54883

(cherry picked from commit 4ac3081b28)
(cherry picked from commit 23ffd1650c)
(cherry picked from commit 7d7cee09b9)
2026-02-11 12:28:56 -08:00
Jose Luis Duran 4690a369ff Adapt changes from blocklist 2026-02-07 (10a907f)
Also apply the fix from PR 258411.

This is a direct commit to stable/14, as blacklist has been renamed to
blocklist upstream.

Approved by:	re (cperciva)

(cherry picked from commit 30c04399f2)
2026-02-10 22:14:53 -08:00
Dag-Erling Smørgrav 3c10ed2ba3 diff: Report I/O errors in Stone algorithm
In the legacy Stone algorithm, we do a first pass over the files to
check if they're identical before we start diffing them.  That code
would correctly set the exit status if an I/O error was encountered,
but would not emit an error message.  Do so.

Approved by:	re (cperciva)
PR:		292198
MFC after:	1 week
Sponsored by:	Klara, Inc.
Reviewed by:	thj
Differential Revision:	https://reviews.freebsd.org/D55125

(cherry picked from commit f8c12e6e38)
(cherry picked from commit 37ceb8794c)
2026-02-10 22:14:50 -08:00
Dag-Erling Smørgrav 7cf7c711d9 diff: Correctly declare tests
Approved by:	re (cperciva)
Sponsored by:	Klara, Inc.
Fixes:		5fc739eb59 ("diff: Fix integer overflows in Stone algorithm")
Fixes:		270492602b ("diff: Add test case for pagination resource leak")
Fixes:		590126789c ("diff: Don't compare a file or directory to itself")

(cherry picked from commit 157d6664ae)
(cherry picked from commit b8bcf04d6d)
2026-02-10 22:14:46 -08:00
Dag-Erling Smørgrav b4139147bb diff: Don't compare a file or directory to itself
While here, stop abusing struct dirent for something we don't even need
to store.

Approved by:	re (cperciva)
PR:		254455
MFC after:	1 week
Sponsored by:	Klara, Inc.
Reviewed by:	thj, kevans
Differential Revision:	https://reviews.freebsd.org/D55113

(cherry picked from commit 590126789c)

diff: Fix build

rc must be defined first.

Fixes:		590126789c
MFC after:	1 week
X-MFC with:	590126789c

(cherry picked from commit ee44ab936e)
(cherry picked from commit 7f412c6f88)
2026-02-10 22:14:30 -08:00
Dag-Erling Smørgrav 6761e55537 diff: Fix pagination leak
* Drop an unnecessary variable and rename pidfd to procd.

* Rewinding stdout serves no purpose, so stop doing it.

* Don't bother freeing memory or setting the global status right
  before erroring out.

* Error out if dup(2) or dup2(2) fail.

* In the unlikely case that our pipe is equal to stdout, we need to
  record that information so we don't close it when cleaning up.

* Don't bother closing a descriptor before dup2(2)ing to it.

* Don't forget to close the the process descriptor after reaping the
  child process.

Approved by:	re (cperciva)
PR:		266592
MFC after:	1 week
Sponsored by:	Klara, Inc.
Reviewed by:	kevans, markj
Differential Revision:	https://reviews.freebsd.org/D55112

(cherry picked from commit c3904a7de7)
(cherry picked from commit 144455c333)
2026-02-10 22:14:26 -08:00
Dag-Erling Smørgrav 2434f3b279 diff: Add test case for pagination resource leak
The pagination code leaks either processes or descriptors or both,
depending on the exact version of the code you have.  Add a test case
which exercises this leak to facilitate fixing it.

Approved by:	re (cperciva)
MFC after:	1 week
Sponsored by:	Klara, Inc.
Reviewed by:	thj, kevans
Differential Revision:	https://reviews.freebsd.org/D55111

(cherry picked from commit 270492602b)
(cherry picked from commit 51c2384ce0)
2026-02-10 22:14:23 -08:00
Dag-Erling Smørgrav 238bf5ebf6 diff: Fix integer overflows in Stone algorithm
Fix integer overflows that may occur when the context window is very
large and add tests to exercise those conditions.

Approved by:	re (cperciva)
PR:		267032
MFC after:	1 week
Sponsored by:	Klara, Inc.
Reviewed by:	thj, kevans
Differential Revision:	https://reviews.freebsd.org/D55110

(cherry picked from commit 5fc739eb59)
(cherry picked from commit 237fd8dd96)
2026-02-10 22:14:04 -08:00
Mark Johnston 61dbfaa13c amd64/conf: Remove a config committed by accident
Approved by:	re (cperciva)
Reported by:	kib, kp
Fixes:		350ba9672a ("unix: Set O_RESOLVE_BENEATH on fds transferred between jails")

(cherry picked from commit 3ef39f58e5)
(cherry picked from commit 302120bcb9)
2026-02-09 13:37:40 -08:00
Michael Osipov 11b616d9de sockstat: Surround explicit IPv6 addresses with brackets
Approved by:	re (cperciva)
PR:		254611
Approved by:	otis, tuexen, des
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D54375

(cherry picked from commit fe81e3944c)
(cherry picked from commit 03c8e3e771)
2026-02-08 19:09:35 -08:00
Bojan Novković 5d7d22588d pmc: Import Intel Granite Rapids events
Approved by:	re (cperciva)
Reviewed by:	mhorne
Sponsored by:	Klara, Inc.
Obtained from:	Intel perfmon (JSON event definitions)
Differential Revision:	https://reviews.freebsd.org/D55081
MFC after:	2 days

(cherry picked from commit a3ff85e119)
(cherry picked from commit 625ed65183)
2026-02-08 19:09:29 -08:00
Colin Percival df3c9a8a5f Revert "release: Ship firmware from kmods repo on DVD"
While all of the net/wifi-firmware-*-kmod packages are in the "kmod" pkg
repository, the net/wifi-firmware-kmod metapackage itself is not; this
results in the DVD build failing when it can't fetch that.

I'm not sure if the correct fix here is to add kmod-related metapackages
to the kmod repository (even if they themselves do not contain kmods) or
something else; but this needs to be backed out at least temporarily so
that 14.4-BETA1 can happen.

This reverts commit 8c1de31097.

This is a direct commit to releng/14.4 since it is not yet clear whether
this should be permanently removed from other branches and there is no
urgency to do so (since DVD builds are disabled by default).

With hat:	re
Approved by:	re (cperciva)
2026-02-06 12:58:55 -08:00
Alexander Ziaee 7fa4ccb8e4 mandoc: Vendor import of upstream at 2025-09-26
Interesting changes:
+ mandoc db: Improve case sorting, found by our very own markj
+ history: Add macros for version 8 and 10 AT&T Unix
+ linter: Warn on blank lines in man(7) like mdoc(7)
+ manuals: Improve precision, man(7) syntax table, and roff(7) specifics
+ manuals: Fix PDF/PS footer regression detailed in our PR: 289786

Approved by:	re (cperciva)
PR:		289786
MFC after:	3 days

(cherry picked from commit 59fc2b0166)
(cherry picked from commit f763f12ed5)
2026-02-05 17:07:07 -08:00
Ingo Schwarze e261ea9105 mandoc: Improve width calculation for GCC compat
Avoid implicitly converting a potentially negative page offset
to size_t and then back to int.  While this was not a bug and the end
result was portably correct, Alexander Ziaee@ privately reported to me
that the GCC 14 in the FreeBSD Jenkins CI felt uneasy about it.

For clarity and readability, rewrite the truncation statement
to not mix signed and unsigned types, to not use explicit casts,
and make handling of the lower and upper cutoff more similar
to each other.

Approved by:	re (cperciva)
Fixes:  6410c1b51637 (mandoc: vendor import of upstream at 2025-07-27)
MFC after:		3 days
Reported by:		ivy
Reviewed by:		ivy
Differential Revision:	https://reviews.freebsd.org/D52127

(cherry picked from commit 93bc3d83a1)
(cherry picked from commit 0d066d2166)
2026-02-05 17:06:59 -08:00
Alexander Ziaee 8039d22f6a mandoc: Vendor import of upstream at 2025-07-27
Groff Compat Edition -- Interesting changes:
+ italics in section/subsection headers are now also bold, like groff
+ display "LOCAL" in response to invalid section numbers, like groff
+ tbl(7) rendering has been tweaked to be more like groff
+ scaling has been improved to better render poorly generated manuals
+ display "UNTITLED" in response to invalid man(7) titles, like groff
+ improve mandocd error handling of broken pipes
+ manual footers now always show NAME(SECTION) on the right, like groff

Approved by:	re (cperciva)
MFC after:	3 days

(cherry picked from commit 06410c1b51)
(cherry picked from commit a1f4ccd6c7)
2026-02-05 17:06:51 -08:00
Colin Percival 9bbe9bfc66 14.4: create releng/14.4 branch
Update from PRERELEASE to BETA1
Switch pkg(8) configuration to use the quarterly repository
Bump __FreeBSD_version

Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-02-06 00:00:00 +00:00
122 changed files with 38872 additions and 1426 deletions

No files matched your search

+1 -1
View File
@@ -437,7 +437,7 @@ SUBDIR+= ${_DIR}
# by calling 'makedb' in share/man. This is only relevant for
# install/distribute so they build the whatis file after every manpage is
# installed.
.if make(installworld) || make(install)
.if make(installworld) || make(install) || make(distributeworld) || make(distribute)
SUBDIR+=.WAIT
.endif
SUBDIR+=etc
+3
View File
@@ -12,6 +12,9 @@ Items affecting the ports and packages system can be found in
/usr/ports/UPDATING. Please read that file before updating system packages
and/or ports.
20260310:
14.4-RELEASE.
20260116:
Bump __FreeBSD_version to 1403508 for various LinuxKPI changes
so they could be detected if needed.
+15 -14
View File
@@ -339,10 +339,10 @@ addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd,
exit(EXIT_FAILURE);
if (*nfd >= *maxfd) {
*maxfd += 10;
*blp = realloc(*blp, sizeof(**blp) * *maxfd);
*blp = reallocarray(*blp, *maxfd, sizeof(**blp));
if (*blp == NULL)
err(EXIT_FAILURE, "malloc");
*pfdp = realloc(*pfdp, sizeof(**pfdp) * *maxfd);
*pfdp = reallocarray(*pfdp, *maxfd, sizeof(**pfdp));
if (*pfdp == NULL)
err(EXIT_FAILURE, "malloc");
}
@@ -366,7 +366,7 @@ uniqueadd(struct conf ***listp, size_t *nlist, size_t *mlist, struct conf *c)
}
if (*nlist == *mlist) {
*mlist += 10;
void *p = realloc(*listp, *mlist * sizeof(*list));
void *p = reallocarray(*listp, *mlist, sizeof(*list));
if (p == NULL)
err(EXIT_FAILURE, "Can't allocate for rule list");
list = *listp = p;
@@ -451,8 +451,8 @@ main(int argc, char *argv[])
case 's':
if (nblsock >= maxblsock) {
maxblsock += 10;
void *p = realloc(blsock,
sizeof(*blsock) * maxblsock);
void *p = reallocarray(blsock, maxblsock,
sizeof(*blsock));
if (p == NULL)
err(EXIT_FAILURE,
"Can't allocate memory for %zu sockets",
@@ -527,14 +527,15 @@ main(int argc, char *argv[])
state = state_open(dbfile, flags, 0600);
if (state == NULL)
state = state_open(dbfile, flags | O_CREAT, 0600);
if (state == NULL)
return EXIT_FAILURE;
if (restore) {
if (!flush)
rules_flush();
rules_restore();
else {
if (restore) {
if (!flush)
rules_flush();
rules_restore();
}
}
if (state == NULL)
exit(EXIT_FAILURE);
if (!debug) {
if (daemon(0, 0) == -1)
@@ -556,7 +557,7 @@ main(int argc, char *argv[])
if (errno == EINTR)
continue;
(*lfun)(LOG_ERR, "poll (%m)");
return EXIT_FAILURE;
exit(EXIT_FAILURE);
case 0:
state_sync(state);
break;
@@ -572,5 +573,5 @@ main(int argc, char *argv[])
update();
}
state_close(state);
return 0;
exit(EXIT_SUCCESS);
}
+2 -2
View File
@@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 18, 2020
.Dd January 13, 2026
.Dt BLACKLISTD.CONF 5
.Os
.Sh NAME
@@ -102,7 +102,7 @@ The syntax for the
.Va location
is:
.Bd -literal -offset indent
[<address>|<interface>][/<mask>][:<port>]
[<address>|<interface>[/<mask>]:]<port>
.Ed
.Pp
The
+7 -6
View File
@@ -62,10 +62,10 @@ static char *
run(const char *cmd, const char *name, ...)
{
const char *argv[20];
size_t i;
size_t i, len;
va_list ap;
FILE *fp;
char buf[10240], *res;
char *line, *res;
argv[0] = "control";
argv[1] = cmd;
@@ -77,6 +77,7 @@ run(const char *cmd, const char *name, ...)
va_end(ap);
if (debug) {
char buf[2048];
size_t z;
int r;
@@ -97,10 +98,10 @@ run(const char *cmd, const char *name, ...)
(*lfun)(LOG_ERR, "popen %s failed (%m)", controlprog);
return NULL;
}
if (fgets(buf, sizeof(buf), fp) != NULL)
res = strdup(buf);
else
res = NULL;
line = res = NULL;
len = 0;
if (getline(&line, &len, fp) >= 0)
res = line;
pclose(fp);
if (debug)
(*lfun)(LOG_DEBUG, "%s returns %s", cmd, res);
-1
View File
@@ -117,7 +117,6 @@ fmtydhms(char *b, size_t l, time_t t)
y = t;
z = 0;
o = 0;
#define APPEND(a) \
if (a) { \
+37 -34
View File
@@ -45,19 +45,19 @@ __RCSID("$NetBSD: popenve.c,v 1.2 2015/01/22 03:10:50 christos Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef __weak_alias
__weak_alias(popen,_popen)
@@ -71,8 +71,8 @@ static struct pid {
int fd;
#endif
pid_t pid;
} *pidlist;
} *pidlist;
#ifdef _REENTRANT
static rwlock_t pidlist_lock = RWLOCK_INITIALIZER;
#endif
@@ -109,11 +109,25 @@ pdes_get(int *pdes, const char **type)
#endif
}
if ((cur = malloc(sizeof(*cur))) != NULL)
return cur;
if ((cur = malloc(sizeof(*cur))) != NULL) {
if (**type == 'r') {
cur->fp = fdopen(pdes[0], *type);
#ifdef _REENTRANT
cur->fd = pdes[0];
#endif
} else {
cur->fp = fdopen(pdes[1], *type);
#ifdef _REENTRANT
cur->fd = pdes[1];
#endif
}
if (cur->fp != NULL)
return cur;
}
serrno = errno;
(void)close(pdes[0]);
(void)close(pdes[1]);
free(cur);
errno = serrno;
return NULL;
}
@@ -123,16 +137,6 @@ pdes_child(int *pdes, const char *type)
{
struct pid *old;
/* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
from previous popen() calls that remain open in the
parent process are closed in the new child process. */
for (old = pidlist; old; old = old->next)
#ifdef _REENTRANT
(void)close(old->fd); /* don't allow a flush */
#else
(void)close(fileno(old->fp)); /* don't allow a flush */
#endif
if (type[0] == 'r') {
(void)close(pdes[0]);
if (pdes[1] != STDOUT_FILENO) {
@@ -148,31 +152,30 @@ pdes_child(int *pdes, const char *type)
(void)close(pdes[0]);
}
}
/* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
from previous popen() calls that remain open in the
parent process are closed in the new child process. */
for (old = pidlist; old; old = old->next) {
#ifdef _REENTRANT
(void)close(old->fd); /* don't allow a flush */
#else
(void)close(fileno(old->fp)); /* don't allow a flush */
#endif
}
}
static void
pdes_parent(int *pdes, struct pid *cur, pid_t pid, const char *type)
{
FILE *iop;
/* Parent; assume fdopen can't fail. */
if (*type == 'r') {
iop = fdopen(pdes[0], type);
#ifdef _REENTRANT
cur->fd = pdes[0];
#endif
/* Parent */
if (*type == 'r')
(void)close(pdes[1]);
} else {
iop = fdopen(pdes[1], type);
#ifdef _REENTRANT
cur->fd = pdes[1];
#endif
else
(void)close(pdes[0]);
}
/* Link into list of file descriptors. */
cur->fp = iop;
cur->pid = pid;
cur->pid = pid;
cur->next = pidlist;
pidlist = cur;
}
@@ -198,7 +201,7 @@ popenve(const char *cmd, char *const *argv, char *const *envp, const char *type)
#ifdef _REENTRANT
(void)rwlock_rdlock(&pidlist_lock);
#endif
switch (pid = vfork()) {
switch (pid = fork()) {
case -1: /* Error. */
serrno = errno;
#ifdef _REENTRANT
+1 -1
View File
@@ -15,7 +15,7 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
VERSION = 1.14.6s20250613
VERSION = 1.14.6s20250926
# === LIST OF FILES ====================================================
+10 -1
View File
@@ -1,6 +1,6 @@
************************************************************************
* Official mandoc TODO.
* $Id: TODO,v 1.337 2025/04/08 21:53:14 schwarze Exp $
* $Id: TODO,v 1.338 2025/07/22 13:36:54 schwarze Exp $
************************************************************************
Many issues are annotated for difficulty as follows:
@@ -505,6 +505,15 @@ are mere guesses, and some may be wrong.
re-reported by tb@ Mon, 16 Mar 2015 16:47:21 +0100
loc ** exist ** algo ** size * imp **
- Check for bad line breaks caused by PostScript and PDF using variable-
width fonts, for example in .Bl -width "string". The difficulty line
below describes a naive solution by simply scaling up widths internally
or adding default spacing (like in terminal output). If fixes are
needed in width measurements, it might be a bit harder, but likely
not unreasonably so.
reported by Jan Stary 20 May 2024 10:19:01 +0200
loc * exist * algo ** size * imp **
--- HTML issues --------------------------------------------------------
- support the idiom .TP .IP .TP for multi-paragraph list item bodies
+216 -28
View File
@@ -1,6 +1,6 @@
.\" $Id: catman.8,v 1.8 2017/03/18 19:56:01 schwarze Exp $
.\" $Id: catman.8,v 1.15 2025/07/13 14:15:26 schwarze Exp $
.\"
.\" Copyright (c) 2017 Ingo Schwarze <[email protected]>
.\" Copyright (c) 2017, 2025 Ingo Schwarze <[email protected]>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: March 18 2017 $
.Dd $Mdocdate: July 13 2025 $
.Dt CATMAN 8
.Os
.Sh NAME
@@ -37,9 +37,9 @@ and
format and formats all of them, storing the formatted versions in
the same relative paths below
.Ar dstdir .
Subdirectories of
Unless they already exist,
.Ar dstdir
are created as needed.
itself and any required subdirectories are created.
Existing files are not explicitly deleted, but possibly overwritten.
.Pp
The options are as follows:
@@ -71,6 +71,18 @@ output mode, the
.Cm fragment
output option is implied.
Other output options are not supported.
.It Fl v
Verbose mode, printing additional information to standard error output.
Specifying this once prints a summary about the number of files
and directories processed at the end of the iteration.
Specifying it twice additionally prints debugging information
about the backchannel from
.Xr mandocd 8
to
.Nm
that is used to limit the number of files in flight at any given time.
For details, see
.Sx DIAGNOSTICS .
.El
.Sh IMPLEMENTATION NOTES
Since this version avoids
@@ -87,33 +99,209 @@ implementations.
.Sh EXIT STATUS
.Ex -std
.Pp
Possible errors include:
.Bl -bullet
.It
missing, invalid, or excessive command line arguments
.It
failure to change the current working directory to
.Ar srcdir
.It
failure to open
.Ar dstdir
.It
communication failure with
.Xr mandocd 8
.It
resource exhaustion, for example file descriptor, process table,
or memory exhaustion
.El
.Pp
Except for memory exhaustion and similar system-level failures,
failures while trying to open, read, parse, or format individual
manual pages, to save individual formatted files to the file system,
or even to create directories do not cause
Failures while trying to open individual manual pages for reading,
to save individual formatted files to the file system,
or even to read or create subdirectories do not cause
.Nm
to return an error exit status.
In such cases,
.Nm
will simply continue with the next file or subdirectory.
simply continues with the next file or subdirectory.
.Sh DIAGNOSTICS
Some fatal errors cause
.Nm
to exit before the iteration over input files is even started:
.Bl -tag -width Ds -offset indent
.It unknown option \-\- Ar option
An invalid option was passed on the command line.
.It missing arguments: srcdir and dstdir
No argument was provided.
Both
.Ar srcdir
and
.Ar dstdir
are mandatory.
.It missing argument: dstdir
Only one argument was provided.
The second argument,
.Ar dstdir ,
is mandatory, too.
.It too many arguments: Ar third argument
Three or more arguments were provided, but only two are supported.
.It Sy socketpair : Ar reason
The sockets needed for communication with
.Xr mandocd 8
could not be created, for example due to file descriptor or memory exhaustion.
.It Sy fork : Ar reason
The new process needed to run
.Xr mandocd 8
could not be created, for example due to process table exhaustion
or system resource limits.
.It Sy exec Ns Po Sy mandocd Pc : Ar reason
The
.Xr mandocd 8
child program could not be started, for example because it is not in the
.Ev PATH
or has no execute permission.
.It Sy mkdir No destination Ar dstdir : reason
The
.Ar dstdir
does not exist and could not be created, for example because
the parent directory does not exist or permission is denied.
.It Sy open No destination Ar dstdir : reason
The
.Ar dstdir
could not be opened for reading, for example because
it is not a directory or permission is denied.
.It Sy chdir No to source Ar srcdir : reason
The current working directory could not be changed to
.Ar srcdir ,
for example because it does not exist, it is not a directory,
or permission is denied.
.It Sy fts_open : Ar reason
Starting the iteration was attempted but failed,
for example due to memory exhaustion.
.El
.Pp
Some fatal errors cause the iteration over input files to be aborted
prematurely:
.Bl -tag -width Ds -offset indent
.It FATAL: Sy fts_read : Ar reason
A call to
.Xr fts_read 3
returned
.Dv NULL ,
meaning that the iteration failed before being complete.
.It FATAL: mandocd child died: got Ar SIGNAME
This message appears if
.Nm
gets the
.Dv SIGCHLD
or
.Dv SIGPIPE
signal, most likely due to a fatal bug in
.Xr mandocd 8 .
.It FATAL: Sy sendmsg : Ar reason
The file descriptors needed to process one of the manual pages
could not be sent to
.Xr mandocd 8 ,
for example because
.Xr mandocd 8
could not be started or died unexpectedly.
.It FATAL: Sy recv : Ar reason
Trying to read a reply message from
.Xr mandocd 8
failed, most likely because
.Xr mandocd 8
unexpectedly died or closed the socket.
.It FATAL: signal Ar SIGNAME
This message appears if
.Nm
gets a
.Dv SIGHUP ,
.Dv SIGINT ,
or
.Dv SIGTERM
signal, for example because the user deliberately killed it.
.El
.Pp
Some non-fatal errors cause a single subdirectory to be skipped.
The iteration is not aborted but continues with the next subdirectory,
and the exit status is unaffected:
.Bl -tag -width Ds -offset indent
.It directory Ar subdirectory No unreadable : Ar reason
A directory below
.Ar srcdir
could not be read and is skipped.
.It directory Ar subdirectory No causes cycle
A directory below
.Ar srcdir
is skipped because it would cause cyclic processing.
.It Sy mkdirat Ar subdirectory : reason
A required directory below
.Ar dstdir
does not exist and could not be created.
The corresponding subdirectory below
.Ar srcdir
is skipped.
.El
.Pp
Some non-fatal errors cause a single source file to be skipped.
The iteration is not aborted but continues with the next file,
and the exit status is unaffected:
.Bl -tag -width Ds -offset indent
.It file Ar filename : reason
The function
.Xr fts_read 3
reported a non-fatal error with respect to
.Ar filename .
.It file Ar filename : No not a regular file
For example, it might be a symbolic link or a device file.
.It Sy open Ar filename No for reading : Ar reason
A file below
.Ar srcdir
could not be read, for example due to permission problems.
.It Sy openat Ar filename No for writing : Ar reason
A file below
.Ar dstdir
could not be created or truncated, for example due to permission problems.
.El
.Pp
If errors occur, the applicable summary messages appear
after the end of the iteration:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It skipped Ar number No directories due to errors
.It skipped Ar number No files due to errors
.It processing aborted due to fatal error
.El
.Pp
If the
.Fl v
flag is specified, the following summary message also appears:
.Bl -tag -width Ds -offset indent
.It processed Ar nfiles No files in Ar ndirs No directories
A file is counted if it could be opened for reading and the
corresponding output file could be opened for writing;
this does not necessarily mean that it is a useful manual page.
A directory is counted if it could be opened for reading and the
corresponding output directory existed or could be created;
this does not necessarily mean that any files could be
processed inside.
.El
.Pp
If the
.Fl v
flag is specified twice, the following messages also appear:
.Bl -tag -width Ds -offset indent
.It allowing up to Ar number No files in flight
This is printed at the beginning of the iteration,
showing the maximum number of files that
.Nm
allows to be in flight at any given time.
.It files in flight: Ar old No \- Ar decrement No = Ar new
This message is printed when
.Nm
learns about
.Xr mandocd 8
accepting more than one file at the same time.
The three numbers printed are the old number of files in flight,
the amount this number is being reduced, and the resulting
new number of files in flight.
.It waiting for Ar number No files in flight
This message is printed at the end of the iteration, after
.Nm
has submitted all files to
.Xr mandocd 8
that it intends to.
THe message informs about the number of files still in flight
at this point.
The
.Nm
program then waits until
.Xr mandocd 8
has accepted them all or until an error occurs.
.El
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr mandocd 8
+205 -26
View File
@@ -1,7 +1,7 @@
/* $Id: catman.c,v 1.23 2021/10/15 15:04:02 schwarze Exp $ */
/* $Id: catman.c,v 1.30 2025/07/13 14:15:26 schwarze Exp $ */
/*
* Copyright (c) 2017, 2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -25,6 +25,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <assert.h>
#if HAVE_ERR
#include <err.h>
#endif
@@ -35,26 +36,44 @@
#else
#include "compat_fts.h"
#endif
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
int verbose_flag = 0;
sig_atomic_t got_signal = 0;
int process_manpage(int, int, const char *);
int process_tree(int, int);
void run_mandocd(int, const char *, const char *)
__attribute__((__noreturn__));
void signal_handler(int);
ssize_t sock_fd_write(int, int, int, int);
void usage(void) __attribute__((__noreturn__));
void
signal_handler(int signum)
{
got_signal = signum;
}
void
run_mandocd(int sockfd, const char *outtype, const char* defos)
{
char sockfdstr[10];
int len;
if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1)
len = snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd);
if (len >= (int)sizeof(sockfdstr)) {
errno = EOVERFLOW;
len = -1;
}
if (len < 0)
err(1, "snprintf");
if (defos == NULL)
execlp("mandocd", "mandocd", "-T", outtype,
@@ -109,10 +128,11 @@ sock_fd_write(int fd, int fd0, int fd1, int fd2)
* to neither cause more than a handful of retries
* in normal operation nor unnecessary delays.
*/
for (;;) {
if ((sz = sendmsg(fd, &msg, 0)) != -1 ||
errno != EAGAIN)
while ((sz = sendmsg(fd, &msg, 0)) == -1) {
if (errno != EAGAIN) {
warn("FATAL: sendmsg");
break;
}
nanosleep(&timeout, NULL);
}
return sz;
@@ -125,14 +145,16 @@ process_manpage(int srv_fd, int dstdir_fd, const char *path)
int irc;
if ((in_fd = open(path, O_RDONLY)) == -1) {
warn("open(%s)", path);
warn("open %s for reading", path);
fflush(stderr);
return 0;
}
if ((out_fd = openat(dstdir_fd, path,
O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
warn("openat(%s)", path);
warn("openat %s for writing", path);
fflush(stderr);
close(in_fd);
return 0;
}
@@ -142,20 +164,22 @@ process_manpage(int srv_fd, int dstdir_fd, const char *path)
close(in_fd);
close(out_fd);
if (irc < 0) {
warn("sendmsg");
return -1;
}
return 0;
return irc;
}
int
process_tree(int srv_fd, int dstdir_fd)
{
const struct timespec timeout = { 0, 10000000 }; /* 0.01 s */
const int max_inflight = 16;
FTS *ftsp;
FTSENT *entry;
const char *argv[2];
const char *path;
int inflight, irc, decr, fatal;
int gooddirs, baddirs, goodfiles, badfiles;
char dummy[1];
argv[0] = ".";
argv[1] = (char *)NULL;
@@ -166,13 +190,59 @@ process_tree(int srv_fd, int dstdir_fd)
return -1;
}
while ((entry = fts_read(ftsp)) != NULL) {
if (verbose_flag >= 2) {
warnx("allowing up to %d files in flight", max_inflight);
fflush(stderr);
}
inflight = fatal = gooddirs = baddirs = goodfiles = badfiles = 0;
while (fatal == 0 && got_signal == 0 &&
(entry = fts_read(ftsp)) != NULL) {
if (inflight >= max_inflight) {
while (recv(srv_fd, dummy, sizeof(dummy), 0) == -1) {
if (errno != EAGAIN) {
warn("FATAL: recv");
fatal = errno;
break;
}
nanosleep(&timeout, NULL);
}
if (fatal != 0)
break;
decr = 1;
while ((irc = recv(srv_fd, dummy, sizeof(dummy),
MSG_DONTWAIT)) > 0)
decr++;
assert(inflight >= decr);
if (verbose_flag >= 2 && decr > 1) {
warnx("files in flight: %d - %d = %d",
inflight, decr, inflight - decr);
fflush(stderr);
}
inflight -= decr;
if (irc == 0) {
errno = ECONNRESET;
inflight = -1;
}
if (errno != EAGAIN) {
warn("FATAL: recv");
fatal = errno;
break;
}
}
path = entry->fts_path + 2;
switch (entry->fts_info) {
case FTS_F:
if (process_manpage(srv_fd, dstdir_fd, path) == -1) {
fts_close(ftsp);
return -1;
switch (process_manpage(srv_fd, dstdir_fd, path)) {
case -1:
fatal = errno;
break;
case 0:
badfiles++;
break;
default:
goodfiles++;
inflight++;
break;
}
break;
case FTS_D:
@@ -180,25 +250,96 @@ process_tree(int srv_fd, int dstdir_fd)
mkdirat(dstdir_fd, path, S_IRWXU | S_IRGRP |
S_IXGRP | S_IROTH | S_IXOTH) == -1 &&
errno != EEXIST) {
warn("mkdirat(%s)", path);
warn("mkdirat %s", path);
fflush(stderr);
(void)fts_set(ftsp, entry, FTS_SKIP);
}
baddirs++;
} else
gooddirs++;
break;
case FTS_DP:
break;
case FTS_DNR:
warnx("directory %s unreadable: %s",
path, strerror(entry->fts_errno));
fflush(stderr);
baddirs++;
break;
case FTS_DC:
warnx("directory %s causes cycle", path);
fflush(stderr);
baddirs++;
break;
case FTS_ERR:
case FTS_NS:
warnx("file %s: %s",
path, strerror(entry->fts_errno));
fflush(stderr);
badfiles++;
break;
default:
warnx("%s: not a regular file", path);
warnx("file %s: not a regular file", path);
fflush(stderr);
badfiles++;
break;
}
}
if (got_signal != 0) {
switch (got_signal) {
case SIGCHLD:
warnx("FATAL: mandocd child died: got SIGCHLD");
break;
case SIGPIPE:
warnx("FATAL: mandocd child died: got SIGPIPE");
break;
default:
warnx("FATAL: signal SIG%s", sys_signame[got_signal]);
break;
}
inflight = -1;
fatal = 1;
} else if (fatal == 0 && (fatal = errno) != 0)
warn("FATAL: fts_read");
fts_close(ftsp);
return 0;
if (verbose_flag >= 2 && inflight > 0) {
warnx("waiting for %d files in flight", inflight);
fflush(stderr);
}
while (inflight > 0) {
irc = recv(srv_fd, dummy, sizeof(dummy), 0);
if (irc > 0)
inflight--;
else if (irc == -1 && errno == EAGAIN)
nanosleep(&timeout, NULL);
else {
if (irc == 0)
errno = ECONNRESET;
warn("recv");
inflight = -1;
}
}
if (verbose_flag)
warnx("processed %d files in %d directories",
goodfiles, gooddirs);
if (baddirs > 0)
warnx("skipped %d %s due to errors", baddirs,
baddirs == 1 ? "directory" : "directories");
if (badfiles > 0)
warnx("skipped %d %s due to errors", badfiles,
badfiles == 1 ? "file" : "files");
if (fatal != 0) {
warnx("processing aborted due to fatal error, "
"results are probably incomplete");
inflight = -1;
}
return inflight;
}
int
main(int argc, char **argv)
{
struct sigaction sa;
const char *defos, *outtype;
int srv_fds[2];
int dstdir_fd;
@@ -207,7 +348,7 @@ main(int argc, char **argv)
defos = NULL;
outtype = "ascii";
while ((opt = getopt(argc, argv, "I:T:")) != -1) {
while ((opt = getopt(argc, argv, "I:T:v")) != -1) {
switch (opt) {
case 'I':
defos = optarg;
@@ -215,6 +356,9 @@ main(int argc, char **argv)
case 'T':
outtype = optarg;
break;
case 'v':
verbose_flag += 1;
break;
default:
usage();
}
@@ -224,8 +368,36 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
}
if (argc != 2)
if (argc != 2) {
switch (argc) {
case 0:
warnx("missing arguments: srcdir and dstdir");
break;
case 1:
warnx("missing argument: dstdir");
break;
default:
warnx("too many arguments: %s", argv[2]);
break;
}
usage();
}
memset(&sa, 0, sizeof(sa));
sa.sa_handler = &signal_handler;
sa.sa_flags = SA_NOCLDWAIT;
if (sigfillset(&sa.sa_mask) == -1)
err(1, "sigfillset");
if (sigaction(SIGHUP, &sa, NULL) == -1)
err(1, "sigaction(SIGHUP)");
if (sigaction(SIGINT, &sa, NULL) == -1)
err(1, "sigaction(SIGINT)");
if (sigaction(SIGPIPE, &sa, NULL) == -1)
err(1, "sigaction(SIGPIPE)");
if (sigaction(SIGTERM, &sa, NULL) == -1)
err(1, "sigaction(SIGTERM)");
if (sigaction(SIGCHLD, &sa, NULL) == -1)
err(1, "sigaction(SIGCHLD)");
if (socketpair(AF_LOCAL, SOCK_STREAM, AF_UNSPEC, srv_fds) == -1)
err(1, "socketpair");
@@ -242,11 +414,18 @@ main(int argc, char **argv)
}
close(srv_fds[1]);
if ((dstdir_fd = open(argv[1], O_RDONLY | O_DIRECTORY)) == -1)
err(1, "open(%s)", argv[1]);
if ((dstdir_fd = open(argv[1], O_RDONLY | O_DIRECTORY)) == -1) {
if (errno != ENOENT)
err(1, "open destination %s", argv[1]);
if (mkdir(argv[1], S_IRWXU |
S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1)
err(1, "mkdir destination %s", argv[1]);
if ((dstdir_fd = open(argv[1], O_RDONLY | O_DIRECTORY)) == -1)
err(1, "open destination %s", argv[1]);
}
if (chdir(argv[0]) == -1)
err(1, "chdir(%s)", argv[0]);
err(1, "chdir to source %s", argv[0]);
return process_tree(srv_fds[0], dstdir_fd) == -1 ? 1 : 0;
}
+4 -3
View File
@@ -1,6 +1,6 @@
/* $Id: dba.c,v 1.10 2017/02/17 14:43:54 schwarze Exp $ */
/* $Id: dba.c,v 1.11 2025/09/24 13:13:30 schwarze Exp $ */
/*
* Copyright (c) 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2016, 2017, 2025 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -318,7 +318,8 @@ compare_names(const void *vp1, const void *vp2)
cp1 = *(const char * const *)vp1;
cp2 = *(const char * const *)vp2;
return (diff = *cp2 - *cp1) ? diff :
strcasecmp(cp1 + 1, cp2 + 1);
(diff = strcasecmp(cp1 + 1, cp2 + 1)) ? diff :
strcmp(cp1 + 1, cp2 + 1);
}
static int
+2 -2
View File
@@ -45,8 +45,8 @@ while [ -n "$1" ]; do
file=$1
shift
echo " ========== $file ========== "
$ROFF -mandoc $file | $COLPIPE 2> /tmp/roff.err > /tmp/roff.out
${MANDOC:=mandoc} $MOPT $file | $COLPIPE \
($ROFF -mandoc $file | $COLPIPE) 2> /tmp/roff.err > /tmp/roff.out
(${MANDOC:=mandoc} $MOPT $file | $COLPIPE) \
2> /tmp/mandoc.err > /tmp/mandoc.out
for i in roff mandoc; do
[ -s /tmp/$i.err ] && echo "$i errors:" && cat /tmp/$i.err
+10 -42
View File
@@ -1,6 +1,6 @@
/* $Id: main.c,v 1.361 2022/04/14 16:43:43 schwarze Exp $ */
/* $Id: main.c,v 1.364 2025/09/24 21:30:20 schwarze Exp $ */
/*
* Copyright (c) 2010-2012, 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010-2012,2014-2021,2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
@@ -109,7 +109,7 @@ static void parse(struct mparse *, int, const char *,
struct outstate *, struct manconf *);
static void passthrough(int, int);
static void process_onefile(struct mparse *, struct manpage *,
int, struct outstate *, struct manconf *);
struct outstate *, struct manconf *);
static void run_pager(struct outstate *, char *);
static pid_t spawn_pager(struct outstate *, char *);
static void usage(enum argmode) __attribute__((__noreturn__));
@@ -144,7 +144,6 @@ main(int argc, char *argv[])
int options; /* Parser options. */
int show_usage; /* Invalid argument: give up. */
int prio, best_prio;
int startdir;
int c;
enum mandoc_os os_e; /* Check base system conventions. */
enum outmode outmode; /* According to command line. */
@@ -514,7 +513,7 @@ main(int argc, char *argv[])
if (resnsz == 0)
(void)fs_search(&search, &conf.manpath,
*argv, &resn, &resnsz);
if (resnsz == 0 && strchr(*argv, '/') == NULL) {
if (resnsz == 0) {
if (search.arch != NULL &&
arch_valid(search.arch, OSENUM) == 0)
warnx("Unknown architecture \"%s\".",
@@ -529,20 +528,6 @@ main(int argc, char *argv[])
mandoc_msg_setrc(MANDOCLEVEL_BADARG);
continue;
}
if (resnsz == 0) {
if (access(*argv, R_OK) == -1) {
mandoc_msg_setinfilename(*argv);
mandoc_msg(MANDOCERR_BADARG_BAD,
0, 0, "%s", strerror(errno));
mandoc_msg_setinfilename(NULL);
continue;
}
resnsz = 1;
resn = mandoc_calloc(resnsz, sizeof(*res));
resn->file = mandoc_strdup(*argv);
resn->ipath = SIZE_MAX;
resn->form = FORM_SRC;
}
if (outmode != OUTMODE_ONE || resnsz == 1) {
res = mandoc_reallocarray(res,
ressz + resnsz, sizeof(*res));
@@ -559,7 +544,8 @@ main(int argc, char *argv[])
best_prio = 40;
for (ib = i = 0; i < resnsz; i++) {
sec = resn[i].file;
sec = resn[i].file +
strlen(conf.manpath.paths[resn[i].ipath]);
sec += strcspn(sec, "123456789");
if (sec[0] == '\0')
continue; /* No section at all. */
@@ -647,23 +633,13 @@ main(int argc, char *argv[])
mchars_alloc();
mp = mparse_alloc(options, os_e, os_s);
/*
* Remember the original working directory, if possible.
* This will be needed if some names on the command line
* are page names and some are relative file names.
* Do not error out if the current directory is not
* readable: Maybe it won't be needed after all.
*/
startdir = open(".", O_RDONLY | O_DIRECTORY);
for (i = 0; i < ressz; i++) {
process_onefile(mp, res + i, startdir, &outst, &conf);
if (i > 0)
mparse_reset(mp);
process_onefile(mp, res + i, &outst, &conf);
if (outst.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
break;
}
if (startdir != -1) {
(void)fchdir(startdir);
close(startdir);
}
if (conf.output.tag != NULL && conf.output.tag_found == 0) {
mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", conf.output.tag);
conf.output.tag = NULL;
@@ -909,7 +885,7 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
}
static void
process_onefile(struct mparse *mp, struct manpage *resp, int startdir,
process_onefile(struct mparse *mp, struct manpage *resp,
struct outstate *outst, struct manconf *conf)
{
int fd;
@@ -921,8 +897,6 @@ process_onefile(struct mparse *mp, struct manpage *resp, int startdir,
*/
if (resp->ipath != SIZE_MAX)
(void)chdir(conf->manpath.paths[resp->ipath]);
else if (startdir != -1)
(void)fchdir(startdir);
mandoc_msg_setinfilename(resp->file);
if (resp->file != NULL) {
@@ -982,18 +956,12 @@ parse(struct mparse *mp, int fd, const char *file,
struct outstate *outst, struct manconf *conf)
{
static struct manpaths basepaths;
static int previous;
struct roff_meta *meta;
assert(fd >= 0);
if (file == NULL)
file = "<stdin>";
if (previous)
mparse_reset(mp);
else
previous = 1;
mparse_readfd(mp, fd, file);
if (fd != STDIN_FILENO)
close(fd);
+89 -62
View File
@@ -1,7 +1,8 @@
.\" $Id: man.7,v 1.150 2023/10/23 22:57:54 schwarze Exp $
.\" $Id: man.7,v 1.154 2025/08/05 21:16:20 schwarze Exp $
.\"
.\" Copyright (c) 2011-2015, 2017-2020, 2023, 2025
.\" Ingo Schwarze <[email protected]>
.\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <[email protected]>
.\" Copyright (c) 2011-2015,2017-2020,2023 Ingo Schwarze <[email protected]>
.\" Copyright (c) 2017 Anthony Bentley <[email protected]>
.\" Copyright (c) 2010 Joerg Sonnenberger <[email protected]>
.\"
@@ -17,7 +18,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: October 23 2023 $
.Dd $Mdocdate: August 5 2025 $
.Dt MAN 7
.Os
.Sh NAME
@@ -89,7 +90,7 @@ but can be found in the alphabetical reference below.
.Ss Page header and footer meta-data
.Bl -column "RS, RE" description
.It Ic TH Ta set the title: Ar name section date Op Ar source Op Ar volume
.It Ic AT Ta display AT&T UNIX version in the page footer (<= 1 argument)
.It Ic AT Ta display AT&T UNIX version in the page footer (<= 2 arguments)
.It Ic UC Ta display BSD version in the page footer (<= 1 argument)
.El
.Ss Sections and paragraphs
@@ -99,6 +100,7 @@ but can be found in the alphabetical reference below.
.It Ic PP Ta start an undecorated paragraph (no arguments)
.It Ic IP Ta indented paragraph: Op Ar head Op Ar width
.It Ic TP Ta tagged paragraph: Op Ar width
.It Ic HP Ta hanged paragraph: Op Ar width
.It Ic PD Ta set vertical paragraph distance: Op Ar height
.It Ic EX , EE Ta display an example (no arguments)
.It Ic RS , RE Ta reset the left margin: Op Ar width
@@ -198,11 +200,6 @@ argument is a
scaling width.
If specified, it's saved for later paragraph left margins;
if unspecified, the saved or default width is used.
.Pp
This macro is portable, but deprecated
because it has no good representation in HTML output,
usually ending up indistinguishable from
.Ic PP .
.It Ic I
Text is rendered in italics.
.It Ic IB
@@ -239,6 +236,17 @@ A synonym for
End a mailto block started with
.Ic MT .
This is a GNU extension.
.It Ic MR
Reference another manual page.
This is a Plan 9 extension also supported by GNU.
It has the following syntax:
.Pp
.D1 Pf . Ic MR Ar name section Op Ar suffix
.Pp
The optional, single
.Ar suffix
argument is appended without preceding whitespace
and typically used for trailing punctuation.
.It Ic MT
Begin a mailto block.
This is a GNU extension.
@@ -250,8 +258,12 @@ link description to be shown
.Ed
.It Ic OP
Optional command-line argument.
This is a rarely used DWB extension.
It has the following syntax:
This is a deprecated GNU extension.
The name and purpose of the macro match an earlier DWB extension,
but both the syntax and semantics are incompatible.
In GNU and
.Xr mandoc 1 ,
it has the following syntax:
.Pp
.D1 Pf . Ic OP Ar key Op Ar value
.Pp
@@ -503,43 +515,56 @@ raised.
.Pp
The syntax is as follows:
.Bd -literal -offset indent
\&.YO \(lBbody...\(rB
\(lBbody...\(rB
\&.\e" current-line syntax
\&.YO \(lBbody ...\(rB
\&.\e" next-line syntax
\&.YO
body ...
.Ed
.Bl -column "MacroX" "ArgumentsX" "ScopeXXXXX" "CompatX" -offset indent
.It Em Macro Ta Em Arguments Ta Em Scope Ta Em Notes
.It Ic AT Ta <=1 Ta current Ta \&
.It Ic B Ta n Ta next-line Ta \&
.It Ic BI Ta n Ta current Ta \&
.It Ic BR Ta n Ta current Ta \&
.It Ic DT Ta 0 Ta current Ta \&
.It Ic EE Ta 0 Ta current Ta Version 9 At
.It Ic EX Ta 0 Ta current Ta Version 9 At
.It Ic I Ta n Ta next-line Ta \&
.It Ic IB Ta n Ta current Ta \&
.It Ic IR Ta n Ta current Ta \&
.It Ic OP Ta >=1 Ta current Ta DWB
.It Ic PD Ta 1 Ta current Ta \&
.It Ic RB Ta n Ta current Ta \&
.It Ic RI Ta n Ta current Ta \&
.It Ic SB Ta n Ta next-line Ta \&
.It Ic SM Ta n Ta next-line Ta \&
.It Ic TH Ta >1, <6 Ta current Ta \&
.It Ic UC Ta <=1 Ta current Ta \&
.It Ic in Ta 1 Ta current Ta Xr roff 7
.Bl -column -offset indent\
"Macro" "Arguments" "curr and next" "Version 9 AT&T UNIX"
.It Em Macro Ta Em Arguments Ta Em Line Scope Ta Em Notes
.It Ic AT Ta 0 to 2 Ta current Ta \&
.It Ic B Ta 1 or more Ta curr or next Ta \&
.It Ic BI Ta 2 or more Ta current Ta \&
.It Ic BR Ta 2 or more Ta current Ta \&
.It Ic DT Ta 0 Ta none Ta \&
.It Ic EE Ta 0 Ta none Ta Version 9 At
.It Ic EX Ta 0 Ta none Ta Version 9 At
.It Ic I Ta 1 or more Ta curr or next Ta \&
.It Ic IB Ta 2 or more Ta current Ta \&
.It Ic IR Ta 2 or more Ta current Ta \&
.It Ic MR Ta 2 or 3 Ta current Ta Plan 9
.It Ic OP Ta 1 or 2 Ta current Ta GNU
.It Ic PD Ta 0 or 1 Ta current Ta \&
.It Ic RB Ta 2 or more Ta current Ta \&
.It Ic RI Ta 2 or more Ta current Ta \&
.It Ic SB Ta 1 or more Ta curr or next Ta \&
.It Ic SM Ta 1 or more Ta curr or next Ta \&
.It Ic TH Ta 3 to 5 Ta current Ta \&
.It Ic UC Ta 0 or 1 Ta current Ta \&
.It Ic in Ta 0 or 1 Ta current Ta Xr roff 7
.El
.Ss Block Macros
Block macros comprise a head and body.
As with in-line macros, the head is scoped to the current line and, in
one circumstance, the next line (the next-line stipulations as in
As with in-line macros, the head is scoped to the current line or,
for some macros, to the next line (the next-line stipulations as in
.Sx Line Macros
apply here as well).
.Pp
The syntax is as follows:
.Bd -literal -offset indent
\&.YO \(lBhead...\(rB
\(lBhead...\(rB
\(lBbody...\(rB
\&.\e" current-line syntax
\&.YO \(lBhead ...\(rB
body ...
\&...
\&.\e" next-line syntax
\&.YO \(lBhead\(rB
head ...
body ...
\&...
.Ed
.Pp
The closure of body scope may be to the section, where a macro is closed
@@ -547,40 +572,42 @@ by
.Ic SH ;
sub-section, closed by a section or
.Ic SS ;
or paragraph, closed by a section, sub-section,
paragraph, closed by a section, sub-section,
.Ic HP ,
.Ic IP ,
.Ic LP ,
.Ic P ,
.Ic PP ,
.Ic RE ,
.Ic RS ,
.Ic SY ,
.Ic TP ,
or
.Ic TP .
No closure refers to an explicit block closing macro.
.Ic TQ ;
or to an explicit block closing macro.
.Pp
As a rule, block macros may not be nested; thus, calling a block macro
while another block macro scope is open, and the open scope is not
implicitly closed, is syntactically incorrect.
.Bl -column "MacroX" "ArgumentsX" "Head ScopeX" "sub-sectionX" "compatX" -offset indent
.It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope Ta Em Notes
.It Ic HP Ta <2 Ta current Ta paragraph Ta \&
.It Ic IP Ta <3 Ta current Ta paragraph Ta \&
.It Ic LP Ta 0 Ta current Ta paragraph Ta \&
.It Ic ME Ta 0 Ta none Ta none Ta GNU
.It Ic MT Ta 1 Ta current Ta to \&ME Ta GNU
.It Ic P Ta 0 Ta current Ta paragraph Ta \&
.It Ic PP Ta 0 Ta current Ta paragraph Ta \&
.It Ic RE Ta <=1 Ta current Ta none Ta \&
.It Ic RS Ta 1 Ta current Ta to \&RE Ta \&
.It Ic SH Ta >0 Ta next-line Ta section Ta \&
.It Ic SS Ta >0 Ta next-line Ta sub-section Ta \&
.It Ic SY Ta 1 Ta current Ta to \&YS Ta GNU
.It Ic TP Ta n Ta next-line Ta paragraph Ta \&
.It Ic TQ Ta n Ta next-line Ta paragraph Ta GNU
.It Ic UE Ta 0 Ta current Ta none Ta GNU
.It Ic UR Ta 1 Ta current Ta part Ta GNU
.It Ic YS Ta 0 Ta none Ta none Ta GNU
.Bl -column -offset indent\
"Macro" "Arguments" "curr and next" "sub-section" "Notes"
.It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope Ta Em Notes
.It Ic HP Ta 0 or 1 Ta current Ta paragraph Ta \&
.It Ic IP Ta 0 to 2 Ta current Ta paragraph Ta \&
.It Ic LP Ta 0 Ta none Ta paragraph Ta \&
.It Ic ME Ta 0 or 1 Ta current Ta none Ta GNU
.It Ic MT Ta 1 Ta current Ta to \&ME Ta GNU
.It Ic P Ta 0 Ta none Ta paragraph Ta \&
.It Ic PP Ta 0 Ta none Ta paragraph Ta \&
.It Ic RE Ta 0 or 1 Ta current Ta none Ta \&
.It Ic RS Ta 0 or 1 Ta current Ta to \&RE Ta \&
.It Ic SH Ta 1 or more Ta curr or next Ta section Ta \&
.It Ic SS Ta 1 or more Ta curr or next Ta sub-section Ta \&
.It Ic SY Ta 1 Ta current Ta to \&YS Ta GNU
.It Ic TP Ta 0 or 1 Ta curr and next Ta paragraph Ta \&
.It Ic TQ Ta 0 or 1 Ta curr and next Ta paragraph Ta GNU
.It Ic UE Ta 0 or 1 Ta current Ta none Ta GNU
.It Ic UR Ta 1 Ta current Ta to \&UE Ta GNU
.It Ic YS Ta 0 Ta none Ta none Ta GNU
.El
.Pp
If a block macro is next-line scoped, it may only be followed by in-line
+2 -1
View File
@@ -1,4 +1,4 @@
/* $Id: man.c,v 1.189 2022/08/16 23:01:09 schwarze Exp $ */
/* $Id: man.c,v 1.190 2025/08/22 13:17:06 schwarze Exp $ */
/*
* Copyright (c) 2013-2015,2017-2019,2022 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -134,6 +134,7 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
*ep = '\0';
return 1;
}
mandoc_msg(MANDOCERR_FI_BLANK, line, i, NULL);
roff_elem_alloc(man, line, offs, ROFF_sp);
man->next = ROFF_NEXT_SIBLING;
return 1;
+34 -6
View File
@@ -1,6 +1,6 @@
.\" $Id: man.options.1,v 1.7 2017/07/04 23:40:01 schwarze Exp $
.\" $Id: man.options.1,v 1.9 2025/08/28 13:46:57 schwarze Exp $
.\"
.\" Copyright (c) 2017 Ingo Schwarze <[email protected]>
.\" Copyright (c) 2017, 2025 Ingo Schwarze <[email protected]>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: July 4 2017 $
.Dd $Mdocdate: August 28 2025 $
.Dt MAN.OPTIONS 1
.Os
.Sh NAME
@@ -39,9 +39,18 @@
.de At5
.At V Pq January 1983 \\$1
..
.de At8
.No Version 8 At Pq February 1985 \\$1
..
.de Bx43
.Bx 4.3 Pq June 1986 \\$1
..
.de At9
.No Version 9 At Pq September 1986 \\$1
..
.de At10
.No Version 10 At Pq October 1989 \\$1
..
.\" option was present in groff-1.01 as contained in 4.3BSD-Net/2
.\" and no mention of it could be found in the ChangeLog,
.\" so it's probably older than groff-0.4, where the log started
@@ -49,7 +58,7 @@
.No probably before groff-0.4 Pq before July 14, 1990 \\$1
..
.de Eaton
.No Eaton Pq before July 7, 1993; 1990/91? \\$1
.No Eaton Pq before July 7, 1993; 1990/91?\& \\$1
..
.\" man-1.5e was released on July 11, 1998.
.de man15e
@@ -399,6 +408,12 @@ do not feed out paper nor stop phototypesetter
.br
.Nm troff :
.At7
.Pp
.Bq superseded by Fl l
interpret arguments as file names
.br
.Nm man :
.At10
.It Fl G
preprocess with
.Xr grap 1
@@ -549,6 +564,7 @@ mode
.br
.Nm man :
.Bx4 ,
.At10 ,
.Eaton ;
.No POSIX , Ox , Fx , Nx , No man-db , man-1.6 , illumos , Solaris 9-11
.br
@@ -720,7 +736,9 @@ specify a page number for the first page
output mode
.br
.Nm man :
.At7
.At7 ,
.At8 ,
.At10
.Pp
do not create the
.Xr whatis 1
@@ -852,6 +870,12 @@ invoke the simultaneous input-output mode of the .rd request
.Nm nroff , troff :
.At7
.Pp
quick mode: prefer preformatted page if available
.br
.Nm man :
.At8 ,
.At10
.Pp
issue no warnings
.br
.Nm manpath :
@@ -1046,6 +1070,8 @@ output mode
.Bx 2 Pq May 10, 1979 ,
.At3 ,
.At5 ,
.At8 ,
.At10 ,
.Eaton ;
.Fx , No man-db , man-1.6 , illumos , Solaris 9-11
.br
@@ -1113,7 +1139,8 @@ print version number
verbose mode
.br
.Nm catman :
.Fx Pq March 15, 1995
.Fx Pq March 15, 1995 ,
.No mandoc Pq June 30, 2025
.br
.Nm makewhatis :
.man15g
@@ -1161,6 +1188,7 @@ list pathnames
.At7 ,
.At3 ,
.At5 ,
.At8 ,
.Eaton ;
.Ox , Fx , Nx , No man-db , man-1.6
.br
+14 -5
View File
@@ -1,6 +1,6 @@
/* $Id: man_html.c,v 1.187 2023/10/24 20:53:12 schwarze Exp $ */
/* $Id: man_html.c,v 1.188 2025/06/26 17:06:34 schwarze Exp $ */
/*
* Copyright (c) 2013-15,2017-20,2022-23 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013-2020,2022-2023,2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -293,21 +293,30 @@ static void
man_root_post(const struct roff_meta *man, struct html *h)
{
struct tag *t;
char *title;
assert(man->title != NULL);
if (man->msec == NULL)
title = mandoc_strdup(man->title);
else
mandoc_asprintf(&title, "%s(%s)", man->title, man->msec);
t = print_otag(h, TAG_DIV, "cr?", "foot", "doc-pagefooter",
"aria-label", "Manual footer line");
print_otag(h, TAG_SPAN, "c", "foot-left");
if (man->os != NULL)
print_text(h, man->os);
print_stagq(h, t);
print_otag(h, TAG_SPAN, "c", "foot-date");
print_text(h, man->date);
print_stagq(h, t);
print_otag(h, TAG_SPAN, "c", "foot-os");
if (man->os != NULL)
print_text(h, man->os);
print_otag(h, TAG_SPAN, "c", "foot-right");
print_text(h, title);
print_tagq(h, t);
free(title);
}
static int
+60 -73
View File
@@ -1,6 +1,6 @@
/* $Id: man_term.c,v 1.244 2023/11/13 19:13:01 schwarze Exp $ */
/* $Id: man_term.c,v 1.248 2025/07/27 15:27:28 schwarze Exp $ */
/*
* Copyright (c) 2010-15,2017-20,2022-23 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010-2020,2022-23,2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -38,14 +38,14 @@
#include "term_tag.h"
#include "main.h"
#define MAXMARGINS 64 /* maximum number of indented scopes */
#define MAXMARGINS 64 /* Maximum number of indented scopes. */
struct mtermp {
int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */
int lmargincur; /* index of current margin */
int lmarginsz; /* actual number of nested margins */
size_t offset; /* default offset to visible page */
int pardist; /* vert. space before par., unit: [v] */
int lmargin[MAXMARGINS]; /* Margins in basic units. */
int lmargincur; /* Index of current margin. */
int lmarginsz; /* Actual number of nested margins. */
size_t offset; /* Default offset in basic units. */
int pardist; /* Vert. space before par., unit: [v]. */
};
#define DECL_ARGS struct termp *p, \
@@ -194,12 +194,10 @@ terminal_man(void *arg, const struct roff_meta *man)
}
/*
* Printing leading vertical space before a block.
* This is used for the paragraph macros.
* The rules are pretty simple, since there's very little nesting going
* on here. Basically, if we're the first within another block (SS/SH),
* then don't emit vertical space. If we are (RS), then do. If not the
* first, print it.
* Print leading vertical space before a paragraph, unless
* it is the first paragraph in a section or subsection.
* If it is the first paragraph in an .RS block, consider
* that .RS block instead of the paragraph, recursively.
*/
static void
print_bvspace(struct termp *p, struct roff_node *n, int pardist)
@@ -214,9 +212,13 @@ print_bvspace(struct termp *p, struct roff_node *n, int pardist)
nch->type == ROFFT_TBL)
return;
if (n->parent->tok != MAN_RS && roff_node_prev(n) == NULL)
return;
while (roff_node_prev(n) == NULL) {
n = n->parent;
if (n->tok != MAN_RS)
return;
if (n->type == ROFFT_BODY)
n = n->parent;
}
for (i = 0; i < pardist; i++)
term_vspace(p);
}
@@ -372,8 +374,8 @@ static int
pre_in(DECL_ARGS)
{
struct roffsu su;
const char *cp;
size_t v;
const char *cp; /* Request argument. */
size_t v; /* Indentation in basic units. */
int less;
term_newln(p);
@@ -386,17 +388,18 @@ pre_in(DECL_ARGS)
cp = n->child->string;
less = 0;
if (*cp == '-')
if (*cp == '-') {
less = -1;
else if (*cp == '+')
cp++;
} else if (*cp == '+') {
less = 1;
else
cp--;
cp++;
}
if (a2roffsu(++cp, &su, SCALE_EN) == NULL)
if (a2roffsu(cp, &su, SCALE_EN) == NULL)
return 0;
v = term_hen(p, &su);
v = term_hspan(p, &su);
if (less < 0)
p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset;
@@ -424,7 +427,7 @@ pre_HP(DECL_ARGS)
{
struct roffsu su;
const struct roff_node *nn;
int len;
int len; /* Indentation in basic units. */
switch (n->type) {
case ROFFT_BLOCK:
@@ -450,7 +453,7 @@ pre_HP(DECL_ARGS)
if ((nn = n->parent->head->child) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
len = term_hen(p, &su);
len = term_hspan(p, &su);
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
@@ -518,7 +521,7 @@ pre_IP(DECL_ARGS)
{
struct roffsu su;
const struct roff_node *nn;
int len;
int len; /* Indentation in basic units. */
switch (n->type) {
case ROFFT_BLOCK:
@@ -539,7 +542,7 @@ pre_IP(DECL_ARGS)
if ((nn = n->parent->head->child) != NULL &&
(nn = nn->next) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
len = term_hen(p, &su);
len = term_hspan(p, &su);
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
@@ -591,7 +594,7 @@ pre_TP(DECL_ARGS)
{
struct roffsu su;
struct roff_node *nn;
int len;
int len; /* Indentation in basic units. */
switch (n->type) {
case ROFFT_BLOCK:
@@ -614,7 +617,7 @@ pre_TP(DECL_ARGS)
if ((nn = n->parent->head->child) != NULL &&
nn->string != NULL && ! (NODE_LINE & nn->flags) &&
a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
len = term_hen(p, &su);
len = term_hspan(p, &su);
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
@@ -691,10 +694,11 @@ pre_SS(DECL_ARGS)
term_vspace(p);
break;
case ROFFT_HEAD:
p->fontibi = 1;
term_fontrepl(p, TERMFONT_BOLD);
p->tcol->offset = term_len(p, 3);
p->tcol->offset = term_len(p, p->defindent) / 2 + 1;
p->tcol->rmargin = mt->offset;
p->trailspace = mt->offset;
p->trailspace = mt->offset / term_len(p, 1);
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break;
case ROFFT_BODY:
@@ -732,10 +736,11 @@ pre_SH(DECL_ARGS)
term_vspace(p);
break;
case ROFFT_HEAD:
p->fontibi = 1;
term_fontrepl(p, TERMFONT_BOLD);
p->tcol->offset = 0;
p->tcol->rmargin = mt->offset;
p->trailspace = mt->offset;
p->trailspace = mt->offset / term_len(p, 1);
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break;
case ROFFT_BODY:
@@ -757,6 +762,8 @@ post_SH(DECL_ARGS)
case ROFFT_BLOCK:
break;
case ROFFT_HEAD:
p->fontibi = 0;
/* FALLTHROUGH */
case ROFFT_BODY:
term_newln(p);
break;
@@ -787,7 +794,7 @@ pre_RS(DECL_ARGS)
if (n->child == NULL)
n->aux = mt->lmargin[mt->lmargincur];
else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL)
n->aux = term_hen(p, &su);
n->aux = term_hspan(p, &su);
if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
n->aux = -mt->offset;
else if (n->aux > SHRT_MAX)
@@ -827,7 +834,7 @@ static int
pre_SY(DECL_ARGS)
{
const struct roff_node *nn;
int len;
int len; /* Indentation in basic units. */
switch (n->type) {
case ROFFT_BLOCK:
@@ -842,7 +849,9 @@ pre_SY(DECL_ARGS)
}
nn = n->parent->head->child;
len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1;
len = term_len(p, 1);
if (nn != NULL)
len += term_strlen(p, nn->string);
switch (n->type) {
case ROFFT_HEAD:
@@ -1015,40 +1024,26 @@ static void
print_man_foot(struct termp *p, const struct roff_meta *meta)
{
char *title;
size_t datelen, titlen;
size_t datelen, titlen; /* In basic units. */
assert(meta->title);
assert(meta->msec);
assert(meta->date);
assert(meta->title != NULL);
assert(meta->msec != NULL);
term_fontrepl(p, TERMFONT_NONE);
if (meta->hasbody)
term_vspace(p);
/*
* Temporary, undocumented option to imitate mdoc(7) output.
* In the bottom right corner, use the operating system
* instead of the title.
*/
if ( ! p->mdocstyle) {
mandoc_asprintf(&title, "%s(%s)",
meta->title, meta->msec);
} else if (meta->os != NULL) {
title = mandoc_strdup(meta->os);
} else {
title = mandoc_strdup("");
}
datelen = term_strlen(p, meta->date);
mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec);
titlen = term_strlen(p, title);
/* Bottom left corner: operating system. */
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
p->trailspace = 1;
p->tcol->offset = 0;
p->tcol->rmargin = p->maxrmargin > datelen ?
(p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
p->trailspace = 1;
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
if (meta->os)
term_word(p, meta->os);
@@ -1057,7 +1052,6 @@ print_man_foot(struct termp *p, const struct roff_meta *meta)
/* At the bottom in the middle: manual date. */
p->tcol->offset = p->tcol->rmargin;
titlen = term_strlen(p, title);
p->tcol->rmargin = p->maxrmargin > titlen ?
p->maxrmargin - titlen : 0;
p->flags |= TERMP_NOSPACE;
@@ -1067,11 +1061,11 @@ print_man_foot(struct termp *p, const struct roff_meta *meta)
/* Bottom right corner: manual title and section. */
p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE;
p->trailspace = 0;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE;
term_word(p, title);
term_flushln(p);
@@ -1086,7 +1080,6 @@ print_man_foot(struct termp *p, const struct roff_meta *meta)
p->tcol->offset = 0;
p->flags = 0;
free(title);
}
@@ -1095,7 +1088,7 @@ print_man_head(struct termp *p, const struct roff_meta *meta)
{
const char *volume;
char *title;
size_t vollen, titlen;
size_t vollen, titlen; /* In basic units. */
assert(meta->title);
assert(meta->msec);
@@ -1111,7 +1104,8 @@ print_man_head(struct termp *p, const struct roff_meta *meta)
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1;
p->tcol->offset = 0;
p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
p->tcol->rmargin =
titlen * 2 + term_len(p, 2) + vollen < p->maxrmargin ?
(p->maxrmargin - vollen + term_len(p, 1)) / 2 :
vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
@@ -1123,7 +1117,7 @@ print_man_head(struct termp *p, const struct roff_meta *meta)
p->flags |= TERMP_NOSPACE;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->tcol->offset + vollen + titlen <
p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
term_word(p, volume);
term_flushln(p);
@@ -1143,13 +1137,6 @@ print_man_head(struct termp *p, const struct roff_meta *meta)
p->flags &= ~TERMP_NOSPACE;
p->tcol->offset = 0;
p->tcol->rmargin = p->maxrmargin;
/*
* Groff prints three blank lines before the content.
* Do the same, except in the temporary, undocumented
* mode imitating mdoc(7) output.
*/
term_vspace(p);
free(title);
}
+13 -5
View File
@@ -1,6 +1,6 @@
/* $Id: man_validate.c,v 1.159 2023/10/24 20:53:12 schwarze Exp $ */
/* $Id: man_validate.c,v 1.161 2025/07/09 12:51:06 schwarze Exp $ */
/*
* Copyright (c) 2010, 2012-2020, 2023 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010-2020, 2023, 2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -299,6 +299,14 @@ post_SH(CHKARGS)
nc = n->child;
switch (n->type) {
case ROFFT_BLOCK:
if ((nc = n->prev) != NULL && nc->tok == ROFF_br) {
mandoc_msg(MANDOCERR_PAR_SKIP, nc->line, nc->pos,
"%s before first %s", roff_name[nc->tok],
roff_name[n->tok]);
roff_node_delete(man, nc);
}
return;
case ROFFT_HEAD:
tag = NULL;
deroff(&tag, n);
@@ -473,7 +481,7 @@ post_TH(CHKARGS)
/* ->TITLE<- MSEC DATE OS VOL */
n = n->child;
if (n != NULL && n->string != NULL) {
if (n != NULL && n->string != NULL && *n->string != '\0') {
for (p = n->string; *p != '\0'; p++) {
/* Only warn about this once... */
if (isalpha((unsigned char)*p) &&
@@ -486,8 +494,8 @@ post_TH(CHKARGS)
}
man->meta.title = mandoc_strdup(n->string);
} else {
man->meta.title = mandoc_strdup("");
mandoc_msg(MANDOCERR_TH_NOTITLE, nb->line, nb->pos, "TH");
man->meta.title = mandoc_strdup("UNTITLED");
mandoc_msg(MANDOCERR_DT_NOTITLE, nb->line, nb->pos, "TH");
}
/* TITLE ->MSEC<- DATE OS VOL */
+18 -25
View File
@@ -1,4 +1,4 @@
.\" $Id: mandoc.1,v 1.270 2025/03/03 14:07:51 schwarze Exp $
.\" $Id: mandoc.1,v 1.273 2025/08/22 13:17:06 schwarze Exp $
.\"
.\" Copyright (c) 2012, 2014-2023, 2025 Ingo Schwarze <[email protected]>
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <[email protected]>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: March 3 2025 $
.Dd $Mdocdate: August 22 2025 $
.Dt MANDOC 1
.Os
.Sh NAME
@@ -292,19 +292,6 @@ Increasing this is not recommended; it may result in degraded formatting,
for example overfull lines or ugly line breaks.
When output is to a pager on a terminal that is less than 66 columns
wide, the default is reduced to three columns.
.It Cm mdoc
Format
.Xr man 7
input files in
.Xr mdoc 7
output style.
This prints the operating system name rather than the page title
on the right side of the footer line.
One useful application is for checking that
.Fl T Cm man
output formats in the same way as the
.Xr mdoc 7
source it was generated from.
.It Cm tag Ns Op = Ns Ar term
If the formatted manual page is opened in a pager,
go to the definition of the
@@ -1015,14 +1002,14 @@ macro that could be represented using
or
.Ic \&Dx .
.It Sy "errnos out of order"
.Pq mdoc, Nx
.Pq mdoc , Nx
The
.Ic \&Er
items in a
.Ic \&Bl
list are not in alphabetical order.
.It Sy "duplicate errno"
.Pq mdoc, Nx
.Pq mdoc , Nx
A
.Ic \&Bl
list contains two consecutive
@@ -1121,17 +1108,21 @@ but leaving out the backslash might not be portable.
.Ss Warnings related to the document prologue
.Bl -ohang
.It Sy "missing manual title, using UNTITLED"
.Pq mdoc
.Pq mdoc , man
A
.Ic \&Dt
macro has no arguments, or there is no
or
.Ic \&TH
macro has no arguments, its first argument is an empty string, or there is no
.Ic \&Dt
macro before the first non-prologue macro.
macro before the first non-prologue
.Xr mdoc 7
macro.
.It Sy "missing manual title, using \(dq\(dq"
.Pq man
There is no
An input document does not contain any
.Ic \&TH
macro, or it has no arguments.
macro.
.It Sy "missing manual section, using \(dq\(dq"
.Pq mdoc , man
A
@@ -1159,7 +1150,7 @@ The
argument is used as provided anyway.
Consider checking whether the file name or the argument need a correction.
.It Sy "missing date, using \(dq\(dq"
.Pq mdoc, man
.Pq mdoc , man
The document was parsed as
.Xr mdoc 7
and it has no
@@ -1741,7 +1732,7 @@ or
macro contains an opening or closing parenthesis; that's probably wrong,
parentheses are added automatically.
.It Sy "unknown library name"
.Pq mdoc, not on Ox
.Pq mdoc , not on Ox
An
.Ic \&Lb
macro has an unknown name argument and will be rendered as
@@ -1799,7 +1790,7 @@ The last character is mapped to the blank character.
.Ss "Warnings related to plain text"
.Bl -ohang
.It Sy "blank line in fill mode, using .sp"
.Pq mdoc
.Pq mdoc , man
The meaning of blank input lines is only well-defined in non-fill mode:
In fill mode, line breaks of text input lines are not supposed to be
significant.
@@ -1809,6 +1800,8 @@ are formatted like
requests.
To request a paragraph break, use
.Ic \&Pp
or
.Ic \&PP
instead of a blank line.
.It Sy "tab in filled text"
.Pq mdoc , man
+2 -2
View File
@@ -1,4 +1,4 @@
/* $Id: mandoc.css,v 1.54 2025/01/25 03:18:55 schwarze Exp $ */
/* $Id: mandoc.css,v 1.55 2025/06/26 17:06:34 schwarze Exp $ */
/*
* Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
*
@@ -73,7 +73,7 @@ div[role=doc-pagefooter] {
.foot-left { flex: 1; }
.foot-date { flex: 0 1 auto;
text-align: center; }
.foot-os { flex: 1;
.foot-right { flex: 1;
text-align: right; }
/* Sections and paragraphs. */
+20 -6
View File
@@ -1,6 +1,6 @@
.\" $Id: mandocd.8,v 1.3 2021/09/28 15:41:41 schwarze Exp $
.\" $Id: mandocd.8,v 1.5 2025/06/30 15:07:38 schwarze Exp $
.\"
.\" Copyright (c) 2017 Ingo Schwarze <[email protected]>
.\" Copyright (c) 2017, 2025 Ingo Schwarze <[email protected]>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: September 28 2021 $
.Dd $Mdocdate: June 30 2025 $
.Dt MANDOCD 8
.Os
.Sh NAME
@@ -78,6 +78,19 @@ or
input, the second one for formatted output, and the third one
for error output.
.Pp
After accepting each message,
.Nm
replies with a one-byte message of its own,
such that the parent process can keep track of how many messages
.Nm
has already accepted and how many file descriptors
consequently are still in flight, such that the parent process
can limit the number of file descriptors in flight at any given time
in order to prevent
.Er EMFILE
failure of
.Xr sendmsg 2 .
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl I Cm os Ns = Ns Ar name
@@ -112,7 +125,7 @@ Other output options are not supported.
After exhausting one input file descriptor, all three file descriptors
are closed before reading the next dummy byte and control message.
.Pp
When a zero-byte message is read, when the
When a zero-byte message or a misformatted message is read, when the
.Ar socket_fd
is closed by the parent process,
or when an error occurs,
@@ -131,9 +144,10 @@ missing, invalid, or excessive
.Xr exec 3
arguments
.It
communication failure with the parent, for example failure in
.Xr recvmsg 2
failure, for example due to
.Er EMSGSIZE
or
.Xr send 2
.It
missing or unexpected control data, in particular a
.Fa cmsg_level
+30 -4
View File
@@ -1,7 +1,7 @@
/* $Id: mandocd.c,v 1.13 2022/04/14 16:43:44 schwarze Exp $ */
/* $Id: mandocd.c,v 1.15 2025/06/30 15:04:57 schwarze Exp $ */
/*
* Copyright (c) 2017-2019, 2022, 2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
* Copyright (c) 2017, 2019, 2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,11 +27,14 @@
#if HAVE_ERR
#include <err.h>
#endif
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "mandoc.h"
@@ -61,6 +64,7 @@ static void usage(void) __attribute__((__noreturn__));
static int
read_fds(int clientfd, int *fds)
{
const struct timespec timeout = { 0, 10000000 }; /* 0.01 s */
struct msghdr msg;
struct iovec iov[1];
unsigned char dummy[1];
@@ -98,6 +102,15 @@ read_fds(int clientfd, int *fds)
break;
}
*dummy = '\0';
while (send(clientfd, dummy, sizeof(dummy), 0) == -1) {
if (errno != EAGAIN) {
warn("send");
return -1;
}
nanosleep(&timeout, NULL);
}
if ((cmsg = CMSG_FIRSTHDR(&msg)) == NULL) {
warnx("CMSG_FIRSTHDR: missing control message");
return -1;
@@ -120,6 +133,7 @@ read_fds(int clientfd, int *fds)
int
main(int argc, char *argv[])
{
struct sigaction sa;
struct manoutput options;
struct mparse *parser;
void *formatter;
@@ -170,13 +184,25 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
}
if (argc != 1)
if (argc != 1) {
if (argc == 0)
warnx("missing argument: socket_fd");
else
warnx("too many arguments: %s", argv[1]);
usage();
}
errstr = NULL;
clientfd = strtonum(argv[0], 3, INT_MAX, &errstr);
if (errstr)
errx(1, "file descriptor %s %s", argv[1], errstr);
errx(1, "file descriptor %s is %s", argv[0], errstr);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
if (sigfillset(&sa.sa_mask) == -1)
err(1, "sigfillset");
if (sigaction(SIGPIPE, &sa, NULL) == -1)
err(1, "sigaction(SIGPIPE)");
mchars_alloc();
parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
+4 -7
View File
@@ -1,6 +1,6 @@
/* $Id: manpath.c,v 1.44 2021/11/05 18:03:08 schwarze Exp $ */
/* $Id: manpath.c,v 1.45 2025/06/26 17:26:23 schwarze Exp $ */
/*
* Copyright (c) 2011,2014,2015,2017-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011,2014,2015,2017-2021 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -218,7 +218,7 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
/* Token taking an optional argument. */
"tag",
/* Tokens not taking arguments. */
"fragment", "mdoc", "noval", "toc"
"fragment", "noval", "toc"
};
const size_t ntoks = sizeof(toks) / sizeof(toks[0]);
@@ -328,12 +328,9 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
conf->fragment = 1;
return 0;
case 10:
conf->mdoc = 1;
return 0;
case 11:
conf->noval = 1;
return 0;
case 12:
case 11:
conf->toc = 1;
return 0;
default:
+23 -12
View File
@@ -1,4 +1,4 @@
.\" $Id: mdoc.7,v 1.299 2025/06/13 16:18:28 schwarze Exp $
.\" $Id: mdoc.7,v 1.300 2025/08/19 14:08:59 schwarze Exp $
.\"
.\" Copyright (c) 2010-2021, 2024, 2025 Ingo Schwarze <[email protected]>
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <[email protected]>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: June 13 2025 $
.Dd $Mdocdate: August 19 2025 $
.Dt MDOC 7
.Os
.Sh NAME
@@ -979,7 +979,7 @@ Unless the
.Fl compact
argument is specified, list entries are separated by vertical space.
.Pp
A list must specify one of the following list types:
The following list types are commonly used:
.Bl -tag -width 12n -offset indent
.It Fl bullet
No item heads can be specified, but a bullet will be printed at the head
@@ -994,7 +994,14 @@ The
.Fl width
argument has no effect; instead, the string length of each argument
specifies the width of one column.
If the first line of the body of a
The width specification for the last column does not affect formatting.
.Pp
For two-column lists, using
.Fl tag
often results in simpler code, identical terminal output, and better HTML
output, especially when the first column contains short identifiers.
.Pp
For compatibility with legacy documents, if the first line of the body of a
.Fl column
list is not an
.Ic \&It
@@ -1016,7 +1023,7 @@ Like
except that item heads are not parsed for macro invocations.
Most often used in the
.Em DIAGNOSTICS
section with error constants in the item heads.
section with error messages in the item heads.
.It Fl enum
A numbered list.
No item heads can be specified.
@@ -1024,6 +1031,17 @@ Formatted like
.Fl bullet ,
except that ordinal numbers are used in place of bullets,
starting at 1.
.It Fl tag
Item bodies are indented according to the
.Fl width
argument.
When an item head fits inside the indentation, the item body follows
this head on the same output line.
Otherwise, the body starts on the output line following the head.
.El
.Pp
The following list types are rarely useful:
.Bl -tag -width 12n -offset indent
.It Fl hang
Like
.Fl tag ,
@@ -1050,13 +1068,6 @@ Item bodies start on the line following item heads and are not indented.
The
.Fl width
argument is ignored.
.It Fl tag
Item bodies are indented according to the
.Fl width
argument.
When an item head fits inside the indentation, the item body follows
this head on the same output line.
Otherwise, the body starts on the output line following the head.
.El
.Pp
Lists may be nested within lists and displays.
+12 -3
View File
@@ -1,4 +1,4 @@
/* $Id: mdoc_html.c,v 1.353 2025/01/25 00:22:28 schwarze Exp $ */
/* $Id: mdoc_html.c,v 1.354 2025/06/26 17:06:34 schwarze Exp $ */
/*
* Copyright (c) 2014-2022, 2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -454,20 +454,29 @@ static void
mdoc_root_post(const struct roff_meta *meta, struct html *h)
{
struct tag *t;
char *title;
assert(meta->title != NULL);
if (meta->msec == NULL)
title = mandoc_strdup(meta->title);
else
mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec);
t = print_otag(h, TAG_DIV, "cr?", "foot", "doc-pagefooter",
"aria-label", "Manual footer line");
print_otag(h, TAG_SPAN, "c", "foot-left");
print_text(h, meta->os);
print_stagq(h, t);
print_otag(h, TAG_SPAN, "c", "foot-date");
print_text(h, meta->date);
print_stagq(h, t);
print_otag(h, TAG_SPAN, "c", "foot-os");
print_text(h, meta->os);
print_otag(h, TAG_SPAN, "c", "foot-right");
print_text(h, title);
print_tagq(h, t);
free(title);
}
static int
+2 -3
View File
@@ -1,4 +1,4 @@
/* $Id: mdoc_man.c,v 1.139 2025/01/24 22:37:24 schwarze Exp $ */
/* $Id: mdoc_man.c,v 1.141 2025/07/02 19:57:48 schwarze Exp $ */
/*
* Copyright (c) 2011-2021, 2025 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -494,6 +494,7 @@ print_offs(const char *v, int keywords)
const char *end;
int sz;
outflags &= ~MMAN_PP;
print_line(".RS", MMAN_Bk_susp);
/* Convert v into a number (of characters). */
@@ -1616,9 +1617,7 @@ pre_lk(DECL_ARGS)
}
/* Link target. */
font_push('B');
print_word(link->string);
font_pop();
/* Trailing punctuation. */
while (punct != NULL) {
+9 -1
View File
@@ -1,4 +1,4 @@
/* $Id: mdoc_markdown.c,v 1.39 2025/01/20 07:01:17 schwarze Exp $ */
/* $Id: mdoc_markdown.c,v 1.40 2025/06/26 17:06:34 schwarze Exp $ */
/*
* Copyright (c) 2017, 2018, 2020, 2025 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -292,6 +292,14 @@ markdown_mdoc(void *arg, const struct roff_meta *mdoc)
md_word(mdoc->os);
md_word("-");
md_word(mdoc->date);
md_word("-");
md_word(mdoc->title);
if (mdoc->msec != NULL) {
outflags &= ~MD_spc;
md_word("(");
md_word(mdoc->msec);
md_word(")");
}
putchar('\n');
}
+68 -54
View File
@@ -1,6 +1,6 @@
/* $Id: mdoc_term.c,v 1.383 2023/11/13 19:13:01 schwarze Exp $ */
/* $Id: mdoc_term.c,v 1.387 2025/07/27 15:27:28 schwarze Exp $ */
/*
* Copyright (c) 2010, 2012-2020, 2022 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010,2012-2020,2022,2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
@@ -302,7 +302,7 @@ print_mdoc_node(DECL_ARGS)
{
const struct mdoc_term_act *act;
struct termpair npair;
size_t offset, rmargin;
size_t offset, rmargin; /* In basic units. */
int chld;
/*
@@ -441,70 +441,62 @@ print_mdoc_node(DECL_ARGS)
static void
print_mdoc_foot(struct termp *p, const struct roff_meta *meta)
{
size_t sz;
char *title;
size_t datelen, titlen; /* In basic units. */
assert(meta->title != NULL);
datelen = term_strlen(p, meta->date);
if (meta->msec == NULL)
title = mandoc_strdup(meta->title);
else
mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec);
titlen = term_strlen(p, title);
term_fontrepl(p, TERMFONT_NONE);
/*
* Output the footer in new-groff style, that is, three columns
* with the middle being the manual date and flanking columns
* being the operating system:
*
* SYSTEM DATE SYSTEM
*/
term_vspace(p);
/* Bottom left corner: operating system. */
p->tcol->offset = 0;
sz = term_strlen(p, meta->date);
p->tcol->rmargin = p->maxrmargin > sz ?
(p->maxrmargin + term_len(p, 1) - sz) / 2 : 0;
p->tcol->rmargin = p->maxrmargin > datelen ?
(p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
p->trailspace = 1;
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
term_word(p, meta->os);
term_flushln(p);
/* At the bottom in the middle: manual date. */
p->tcol->offset = p->tcol->rmargin;
sz = term_strlen(p, meta->os);
p->tcol->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0;
p->tcol->rmargin = p->maxrmargin > titlen ?
p->maxrmargin - titlen : 0;
p->flags |= TERMP_NOSPACE;
term_word(p, meta->date);
term_flushln(p);
/* Bottom right corner: manual title and section. */
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE;
term_word(p, meta->os);
term_word(p, title);
term_flushln(p);
p->tcol->offset = 0;
p->tcol->rmargin = p->maxrmargin;
p->flags = 0;
free(title);
}
static void
print_mdoc_head(struct termp *p, const struct roff_meta *meta)
{
char *volume, *title;
size_t vollen, titlen;
/*
* The header is strange. It has three components, which are
* really two with the first duplicated. It goes like this:
*
* IDENTIFIER TITLE IDENTIFIER
*
* The IDENTIFIER is NAME(SECTION), which is the command-name
* (if given, or "unknown" if not) followed by the manual page
* section. These are given in `Dt'. The TITLE is a free-form
* string depending on the manual volume. If not specified, it
* switches on the manual section.
*/
size_t vollen, titlen; /* In basic units. */
assert(meta->vol);
if (NULL == meta->arch)
@@ -514,6 +506,8 @@ print_mdoc_head(struct termp *p, const struct roff_meta *meta)
meta->vol, meta->arch);
vollen = term_strlen(p, volume);
/* Top left corner: manual title and section. */
if (NULL == meta->msec)
title = mandoc_strdup(meta->title);
else
@@ -524,13 +518,16 @@ print_mdoc_head(struct termp *p, const struct roff_meta *meta)
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1;
p->tcol->offset = 0;
p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
p->tcol->rmargin =
titlen * 2 + term_len(p, 2) + vollen < p->maxrmargin ?
(p->maxrmargin - vollen + term_len(p, 1)) / 2 :
vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
term_word(p, title);
term_flushln(p);
/* At the top in the middle: manual volume. */
p->flags |= TERMP_NOSPACE;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->tcol->offset + vollen + titlen <
@@ -539,6 +536,8 @@ print_mdoc_head(struct termp *p, const struct roff_meta *meta)
term_word(p, volume);
term_flushln(p);
/* Top right corner: title and section, again. */
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
if (p->tcol->rmargin + titlen <= p->maxrmargin) {
@@ -556,6 +555,11 @@ print_mdoc_head(struct termp *p, const struct roff_meta *meta)
free(volume);
}
/*
* Interpret the string v as a scaled width or, if the syntax is invalid,
* measure how much width it takes up when printed. In both cases,
* return the width in basic units.
*/
static int
a2width(const struct termp *p, const char *v)
{
@@ -564,10 +568,10 @@ a2width(const struct termp *p, const char *v)
end = a2roffsu(v, &su, SCALE_MAX);
if (end == NULL || *end != '\0') {
su.unit = SCALE_EN;
su.scale = term_strlen(p, v) / term_strlen(p, "0");
su.unit = SCALE_BU;
su.scale = term_strlen(p, v);
}
return term_hen(p, &su);
return term_hspan(p, &su);
}
/*
@@ -623,8 +627,11 @@ termp_it_pre(DECL_ARGS)
struct roffsu su;
char buf[24];
const struct roff_node *bl, *nn;
size_t ncols, dcol;
int i, offset, width;
size_t ncols; /* Number of columns in .Bl -column. */
size_t dcol; /* Column spacing in basic units. */
int i; /* Zero-based column index. */
int offset; /* Start of column in basic units. */
int width; /* Column width in basic units. */
enum mdoc_list type;
if (n->type == ROFFT_BLOCK) {
@@ -701,10 +708,9 @@ termp_it_pre(DECL_ARGS)
for (i = 0, nn = n->prev;
nn->prev && i < (int)ncols;
nn = nn->prev, i++) {
su.unit = SCALE_EN;
su.scale = term_strlen(p, bl->norm->Bl.cols[i]) /
term_strlen(p, "0");
offset += term_hen(p, &su) + dcol;
su.unit = SCALE_BU;
su.scale = term_strlen(p, bl->norm->Bl.cols[i]);
offset += term_hspan(p, &su) + dcol;
}
/*
@@ -720,10 +726,9 @@ termp_it_pre(DECL_ARGS)
* Use the declared column widths, extended as explained
* in the preceding paragraph.
*/
su.unit = SCALE_EN;
su.scale = term_strlen(p, bl->norm->Bl.cols[i]) /
term_strlen(p, "0");
width = term_hen(p, &su) + dcol;
su.unit = SCALE_BU;
su.scale = term_strlen(p, bl->norm->Bl.cols[i]);
width = term_hspan(p, &su) + dcol;
break;
default:
if (NULL == bl->norm->Bl.width)
@@ -1274,6 +1279,7 @@ termp_sh_pre(DECL_ARGS)
term_vspace(p);
break;
case ROFFT_HEAD:
p->fontibi = 1;
return termp_bold_pre(p, pair, meta, n);
case ROFFT_BODY:
p->tcol->offset = term_len(p, p->defindent);
@@ -1294,6 +1300,7 @@ termp_sh_post(DECL_ARGS)
{
switch (n->type) {
case ROFFT_HEAD:
p->fontibi = 0;
term_newln(p);
break;
case ROFFT_BODY:
@@ -1421,7 +1428,7 @@ termp_fa_pre(DECL_ARGS)
static int
termp_bd_pre(DECL_ARGS)
{
int offset;
int offset; /* In basic units. */
if (n->type == ROFFT_BLOCK) {
print_bvspace(p, n, n);
@@ -1509,7 +1516,8 @@ termp_ss_pre(DECL_ARGS)
term_vspace(p);
break;
case ROFFT_HEAD:
p->tcol->offset = term_len(p, (p->defindent+1)/2);
p->tcol->offset = term_len(p, p->defindent) / 2 + 1;
p->fontibi = 1;
return termp_bold_pre(p, pair, meta, n);
case ROFFT_BODY:
p->tcol->offset = term_len(p, p->defindent);
@@ -1526,8 +1534,16 @@ termp_ss_pre(DECL_ARGS)
static void
termp_ss_post(DECL_ARGS)
{
if (n->type == ROFFT_HEAD || n->type == ROFFT_BODY)
switch (n->type) {
case ROFFT_HEAD:
p->fontibi = 0;
/* FALLTHROUGH */
case ROFFT_BODY:
term_newln(p);
break;
default:
break;
}
}
static int
@@ -1888,9 +1904,7 @@ termp_lk_pre(DECL_ARGS)
}
/* Link target. */
term_fontpush(p, TERMFONT_BOLD);
term_word(p, link->string);
term_fontpop(p);
/* Trailing punctuation. */
while (punct != NULL) {
+4 -6
View File
@@ -1,4 +1,4 @@
/* $Id: mdoc_validate.c,v 1.393 2025/06/05 12:38:26 schwarze Exp $ */
/* $Id: mdoc_validate.c,v 1.396 2025/07/26 12:23:16 schwarze Exp $ */
/*
* Copyright (c) 2010-2022, 2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -1714,7 +1714,7 @@ post_xx(POST_ARGS)
os = "OpenBSD";
break;
case MDOC_Ux:
os = "UNIX";
os = "Unix";
break;
default:
abort();
@@ -2777,7 +2777,7 @@ post_dd(POST_ARGS)
mandoc_msg(MANDOCERR_PROLOG_ORDER,
n->line, n->pos, "Dd after Os");
if (mdoc->quick && n != NULL)
if (mdoc->quick)
mdoc->meta.date = mandoc_strdup("");
else
mdoc->meta.date = mandoc_normdate(n->child, n);
@@ -2842,8 +2842,7 @@ post_dt(POST_ARGS)
if (nn == NULL) {
mandoc_msg(MANDOCERR_MSEC_MISSING, n->line, n->pos,
"Dt %s", mdoc->meta.title);
mdoc->meta.vol = mandoc_strdup("LOCAL");
return; /* msec and arch remain NULL. */
return; /* msec, vol, and arch remain NULL. */
}
mdoc->meta.msec = mandoc_strdup(nn->string);
@@ -2854,7 +2853,6 @@ post_dt(POST_ARGS)
if (cp == NULL) {
mandoc_msg(MANDOCERR_MSEC_BAD,
nn->line, nn->pos, "Dt ... %s", nn->string);
mdoc->meta.vol = mandoc_strdup(nn->string);
} else {
mdoc->meta.vol = mandoc_strdup(cp);
if (mdoc->filesec != '\0' &&
+42 -21
View File
@@ -1,8 +1,8 @@
/* $Id: out.c,v 1.86 2025/01/05 18:14:39 schwarze Exp $ */
/* $Id: out.c,v 1.87 2025/07/16 14:33:08 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2014, 2015, 2017, 2018, 2019, 2021
* Copyright (c) 2011, 2014, 2015, 2017, 2018, 2019, 2021, 2025
* Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -122,9 +122,23 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
const struct tbl_dat *dp;
struct roffcol *col;
struct tbl_colgroup *first_group, **gp, *g;
size_t *colwidth;
size_t ewidth, min1, min2, wanted, width, xwidth;
int done, icol, maxcol, necol, nxcol, quirkcol;
/* Widths in basic units. */
size_t *colwidth; /* Widths of all columns. */
size_t min1; /* Width of the narrowest column. */
size_t min2; /* Width of the second narrowest column. */
size_t wanted; /* For any of the narrowest columns. */
size_t xwidth; /* Total width of columns not to expand. */
size_t ewidth; /* Width of widest column to equalize. */
size_t width; /* Width of the data in basic units. */
size_t enw; /* Width of one EN unit. */
int icol; /* Column number, starting at zero. */
int maxcol; /* Number of last column. */
int necol; /* Number of columns to equalize. */
int nxcol; /* Number of columns to expand. */
int done; /* Boolean: this group is wide enough. */
int quirkcol;
/*
* Allocate the master column specifiers. These will hold the
@@ -139,6 +153,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
maxcol = -1;
first_group = NULL;
enw = (*tbl->len)(1, tbl->arg);
for (sp = sp_first; sp != NULL; sp = sp->next) {
if (sp->pos != TBL_SPAN_DATA)
continue;
@@ -175,8 +190,8 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
opts, dp,
dp->block == 0 ? 0 :
dp->layout->width ? dp->layout->width :
rmargin ? (rmargin + sp->opts->cols / 2)
/ (sp->opts->cols + 1) : 0);
rmargin ? (rmargin / enw + sp->opts->cols / 2) /
(sp->opts->cols + 1) * enw : 0);
if (dp->hspans == 0)
continue;
@@ -211,8 +226,8 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
maxcol = sp_first->opts->cols - 1;
for (icol = 0; icol <= maxcol; icol++) {
col = tbl->cols + icol;
if (col->width < 1)
col->width = 1;
if (col->width < enw)
col->width = enw;
/*
* Column spacings are needed for span width
@@ -234,7 +249,8 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
for (icol = g->startcol; icol <= g->endcol; icol++) {
width = tbl->cols[icol].width;
if (icol < g->endcol)
width += tbl->cols[icol].spacing;
width += (*tbl->len)(tbl->cols[icol].spacing,
tbl->arg);
if (g->wanted <= width) {
done = 1;
break;
@@ -372,9 +388,9 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
*/
if (nxcol && rmargin) {
xwidth += 3*maxcol +
xwidth += (*tbl->len)(3 * maxcol +
(opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ?
2 : !!opts->lvert + !!opts->rvert);
2 : !!opts->lvert + !!opts->rvert), tbl->arg);
if (rmargin <= offset + xwidth)
return;
xwidth = rmargin - offset - xwidth;
@@ -387,7 +403,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
*/
if (nxcol == 5) {
quirkcol = xwidth % nxcol + 2;
quirkcol = xwidth / enw % nxcol + 2;
if (quirkcol != 3 && quirkcol != 4)
quirkcol = -1;
} else
@@ -402,7 +418,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
col->width = (double)xwidth * ++necol / nxcol
- ewidth + 0.4995;
if (necol == quirkcol)
col->width--;
col->width -= enw;
ewidth += col->width;
}
}
@@ -444,9 +460,12 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
const char *str; /* Beginning of the first line. */
const char *beg; /* Beginning of the current line. */
char *end; /* End of the current line. */
size_t lsz; /* Length of the current line. */
size_t wsz; /* Length of the current word. */
size_t msz; /* Length of the longest line. */
/* Widths in basic units. */
size_t lsz; /* Of the current line. */
size_t wsz; /* Of the current word. */
size_t msz; /* Of the longest line. */
size_t enw; /* Of one EN unit. */
if (dp->string == NULL || *dp->string == '\0')
return 0;
@@ -460,8 +479,9 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
end++;
}
wsz = (*tbl->slen)(beg, tbl->arg);
if (mw && lsz && lsz + 1 + wsz <= mw)
lsz += 1 + wsz;
enw = (*tbl->len)(1, tbl->arg);
if (mw && lsz && lsz + enw + wsz <= mw)
lsz += enw + wsz;
else
lsz = wsz;
if (msz < lsz)
@@ -479,7 +499,8 @@ tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
const struct tbl_opts *opts, const struct tbl_dat *dp)
{
const char *cp, *lastdigit, *lastpoint;
size_t intsz, totsz;
size_t totsz; /* Total width of the number in basic units. */
size_t intsz; /* Width of the integer part in basic units. */
char buf[2];
if (dp->string == NULL || *dp->string == '\0')
+11 -13
View File
@@ -1,7 +1,7 @@
/* $Id: out.h,v 1.35 2022/09/11 09:13:48 schwarze Exp $ */
/* $Id: out.h,v 1.36 2025/07/16 14:33:08 schwarze Exp $ */
/*
* Copyright (c) 2011,2014,2017,2018,2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -33,11 +33,11 @@ enum roffscale {
};
struct roffcol {
size_t width; /* width of cell */
size_t nwidth; /* max. width of number in cell */
size_t decimal; /* decimal position in cell */
size_t spacing; /* spacing after the column */
int flags; /* layout flags, see tbl_cell */
size_t width; /* Width of cell [BU]. */
size_t nwidth; /* Maximum width of number [BU]. */
size_t decimal; /* Decimal position [BU]. */
size_t spacing; /* Spacing after the column [EN]. */
int flags; /* Layout flags, see tbl_cell. */
};
struct roffsu {
@@ -45,16 +45,14 @@ struct roffsu {
double scale;
};
typedef size_t (*tbl_sulen)(const struct roffsu *, void *);
typedef size_t (*tbl_strlen)(const char *, void *);
typedef size_t (*tbl_len)(size_t, void *);
struct rofftbl {
tbl_sulen sulen; /* calculate scaling unit length */
tbl_strlen slen; /* calculate string length */
tbl_len len; /* produce width of empty space */
struct roffcol *cols; /* master column specifiers */
void *arg; /* passed to sulen, slen, and len */
tbl_strlen slen; /* Calculate string length [BU]. */
tbl_len len; /* Produce width of empty space [BU]. */
struct roffcol *cols; /* Master column specifiers. */
void *arg; /* Passed to slen() and len(). */
};
+148 -47
View File
@@ -1,6 +1,6 @@
.\" $Id: roff.7,v 1.121 2023/10/23 20:25:02 schwarze Exp $
.\" $Id: roff.7,v 1.123 2025/08/04 23:12:08 schwarze Exp $
.\"
.\" Copyright (c) 2010-2019, 2022-2023 Ingo Schwarze <[email protected]>
.\" Copyright (c) 2010-2019,2022-2023,2025 Ingo Schwarze <[email protected]>
.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <[email protected]>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: October 23 2023 $
.Dd $Mdocdate: August 4 2025 $
.Dt ROFF 7
.Os
.Sh NAME
@@ -79,8 +79,10 @@ They provide free-form text to be printed; the formatting of the text
depends on the respective processing context.
.Sh LANGUAGE SYNTAX
.Nm
documents may contain only graphable 7-bit ASCII characters, the space
character, and, in certain circumstances, the tab character.
documents are text files containing only printable
.Xr ascii 7
characters, the space character,
and, in certain circumstances, the tab character.
The backslash character
.Sq \e
indicates the start of an escape sequence, used for example for
@@ -180,7 +182,7 @@ Italic font.
Return to the previous font.
If a macro caused a font change since the last
.Ic \ef
eascape sequence or
escape sequence or
.Ic \&ft
request, this returns to the font before the last font change in
the macro rather than to the font before the last manual font change.
@@ -267,7 +269,7 @@ width of rendered
.Pq en
character
.It u
default horizontal span for the terminal
device-dependent basic units
.It M
mini-em (1/100 em)
.El
@@ -289,7 +291,7 @@ for vertical spaces and
for horizontal ones.
.Pp
Examples:
.Bl -tag -width ".Bl -tag -width 2i" -offset indent -compact
.Bl -tag -width "xBl -tag -width 2i" -offset indent -compact
.It Li \&.Bl -tag -width 2i
two-inch tagged list indentation in
.Xr mdoc 7
@@ -1319,10 +1321,16 @@ among others because it overrides the
.Xr mandoc 1
.Fl O Cm width
command line option.
.It Ic \&lnr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar value Op Ar increment
.It Ic \&lnr Ar registername Xo
.Oo Cm + Ns | Ns Cm \- Oc Ns Ar value
.Op Ar increment
.Xc
Set local number register.
This is a Heirloom extension and currently unsupported.
.It Ic \&lnrf Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar value Op Ar increment
.It Ic \&lnrf Ar registername Xo
.Oo Cm + Ns | Ns Cm \- Oc Ns Ar value
.Op Ar increment
.Xc
Set local floating-point register.
This is a Heirloom extension and currently unsupported.
.It Ic \&lpfx Ar string
@@ -1398,10 +1406,13 @@ skipping the
.Ic \&nop
request and any space characters immediately following it.
This is mostly used to indent text lines inside macro definitions.
.It Ic \&nr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression Op Ar stepsize
Define or change a register.
A register is an arbitrary string value that defines some sort of state,
which influences parsing and/or formatting.
.It Ic \&nr Ar registername Xo
.Oo Cm + Ns | Ns Cm \- Oc Ns Ar expression
.Op Ar stepsize
.Xc
Define or change the number register with the given
.Ar registername .
A register can store an integer number.
For the syntax of
.Ar expression ,
see
@@ -1410,6 +1421,9 @@ below.
If it is prefixed by a sign, the register will be
incremented or decremented instead of assigned to.
.Pp
Once set, the value of a number register can be interpolated using the
.Ic \en
escape sequence.
The
.Ar stepsize
is used by the
@@ -1418,29 +1432,13 @@ auto-increment feature.
It remains unchanged when omitted while changing an existing register,
and it defaults to 0 when defining a new register.
.Pp
The following
.Ar register
is handled specially:
.Bl -tag -width Ds
.It Cm nS
If set to a positive integer value, certain
.Xr mdoc 7
macros will behave in the same way as in the
.Em SYNOPSIS
section.
If set to 0, these macros will behave in the same way as outside the
.Em SYNOPSIS
section, even when called within the
.Em SYNOPSIS
section itself.
Note that starting a new
.Xr mdoc 7
section with the
.Ic \&Sh
macro will reset this register.
.El
Some number registers can be read to inspect parser state,
and some can be changed to influence formatting.
For details about individual registers, see the
.Sx NUMBER REGISTER REFERENCE
below.
.It Xo
.Ic \&nrf Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression
.Ic \&nrf Ar registername Oo Cm + Ns | Ns Cm \- Oc Ns Ar expression
.Op Ar increment
.Xc
Define or change a floating-point register.
@@ -1569,7 +1567,7 @@ requests is not supported, and diversions are not implemented at all.
Rename a number register.
Currently unsupported.
.It Ic \&rr Ar register
Remove a register.
Remove a number register.
.It Ic \&rs
End no-space mode.
Currently ignored.
@@ -2152,6 +2150,8 @@ on the current font.
.It Ic \en Ns Oo +|- Oc Ns Ic \&[ Ns Ar name Ns Ic \&]
Interpolate the number register
.Ar name .
If the register is not yet defined,
it is automatically initialised to zero before interpolation.
For short names, there are variants
.Ic \en Ns Ar c
and
@@ -2162,6 +2162,9 @@ the register is first incremented or decremented by the
that was specified in the relevant
.Ic \&nr
request, and the changed value is interpolated.
For the names of predefined registers, see the
.Sx NUMBER REGISTER REFERENCE
below.
.It Ic \eO Ns Ar digit , Ic \eO[5 Ns arguments Ns Ic \&]
Suppress output.
This is a groff extension and currently unsupported.
@@ -2250,6 +2253,83 @@ with zero width and height; ignored by
.It Ic \ez
Output the next character without advancing the cursor position.
.El
.Sh NUMBER REGISTER REFERENCE
In
.Xr mdoc 7
and
.Xr man 7
documents, using registers is discouraged.
For compatibility with legacy documents, the
.Xr mandoc 1
.Nm
parser recognises the following names of read-only registers:
.Bl -tag -width Ds
.It Cm .$
The number of arguments of the innermost user-defined macro
currently being called, or 0 by default.
The
.Ic shift
request decrements the value of this register.
.It Cm .A
Whether ASCII approximation mode is on;
.Xr mandoc 1
always returns 0, meaning off.
.It Cm .g
Whether the formatter claims groff compatibility;
.Xr mandoc 1
always returns 1, meaning yes.
.It Cm .H
The minimum horizontal movement in basic units;
.Xr mandoc 1
always returns 24, corresponding to one character position.
.It Cm .j
The current line adjustment mode;
.Xr mandoc 1
always returns 0, meaning flush left.
.It Cm .l
The line length in basic units;
.Xr mandoc 1
always returns 78 * 24, corresponding to 78 characters per line.
.It Cm \&.T
Whether an output device has been selected;
.Xr mandoc 1
always returns 1, meaning yes.
.It Cm .V
The minimum vertical movement in basic units;
.Xr mandoc 1
always returns 40, corresponding to one line height.
.El
.Pp
The
.Cm nS
register is handled specially.
If set to a positive integer value, certain
.Xr mdoc 7
macros behave in the same way as in the
.Em SYNOPSIS
section.
If set to 0, these macros behave in the same way as outside the
.Em SYNOPSIS
section, even when called within the
.Em SYNOPSIS
section itself.
Starting a new
.Xr mdoc 7
section with the
.Ic \&Sh
macro resets this register.
.Pp
Full
.Nm
implementations support large numbers of additional predefined registers.
While the
.Ic \&nr
request supports setting and the
.Ic \en
escape sequence supports inspecting arbitrary registers,
.Xr mandoc 1
only defines the few registers listed above by default.
All other registers are undefined by default and yield 0 when interpolated.
.Sh COMPATIBILITY
The
.Xr mandoc 1
@@ -2266,17 +2346,29 @@ never reads or writes external files except via
.Ic \&so
requests with safe relative paths.
.It
There is no automatic hyphenation, no adjustment to the right margin,
and very limited support for centering; the output is always set flush-left.
There is no automatic hyphenation and no support for the
.Ic \&ad
line adjustment request.
Except when the
.Ic \&ce
or
.Ic \&rj
requests or the
.Xr tbl 7
cell specifications
.Cm c ,
.Cm n ,
or
.Cm r
or the table option
.Cm center
are used, output is always set flush-left.
.It
Support for setting tabulator and leader characters is missing,
and support for manually changing indentation is limited.
.It
The
.Sq u
scaling unit is the default terminal unit.
In traditional troff systems, this unit changes depending on the
output media.
Support for setting tabulator and leader characters is missing, and the
.Ic \&in
indentation request is not supported in
.Xr mdoc 7
input files.
.It
Width measurements are implemented in a crude way
and often yield wrong results.
@@ -2336,6 +2428,15 @@ implementations.
.%D September 17, 2007
.%U http://heirloom.sourceforge.net/doctools/troff.pdf
.Re
.Rs
.%A James Clark
.%A Werner Lemberg
.%A G. Branden Robinson
.%I Free Software Foundation, Inc.
.%T The GNU Troff Manual
.%D 1999\(en2023
.%U https://www.gnu.org/software/groff/manual/
.Re
.Sh HISTORY
The RUNOFF typesetting system, whose input forms the basis for
.Nm ,
+21 -11
View File
@@ -1,6 +1,7 @@
/* $Id: roff_term.c,v 1.25 2023/04/28 19:11:04 schwarze Exp $ */
/* $Id: roff_term.c,v 1.27 2025/08/21 15:38:51 schwarze Exp $ */
/*
* Copyright (c) 2010,2014,2015,2017-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2014, 2015, 2017-2021, 2025
* Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -159,8 +160,14 @@ static void
roff_term_pre_po(ROFF_TERM_ARGS)
{
struct roffsu su;
static int po, pouse, polast;
int ponew;
/* Page offsets in basic units. */
static int polast; /* Previously requested. */
static int po; /* Currently requested. */
static int pouse; /* Currently used. */
int pomin; /* Minimum to be used. */
int pomax; /* Maximum to be used. */
int ponew; /* Newly requested. */
/* Revert the currently active page offset. */
p->tcol->offset -= pouse;
@@ -168,7 +175,7 @@ roff_term_pre_po(ROFF_TERM_ARGS)
/* Determine the requested page offset. */
if (n->child != NULL &&
a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
ponew = term_hen(p, &su);
ponew = term_hspan(p, &su);
if (*n->child->string == '+' ||
*n->child->string == '-')
ponew += po;
@@ -180,8 +187,9 @@ roff_term_pre_po(ROFF_TERM_ARGS)
po = ponew;
/* Truncate to the range [-offset, 60], remember, and apply it. */
pouse = po >= 60 ? 60 :
po < -(int)p->tcol->offset ? -(int)p->tcol->offset : po;
pomin = -p->tcol->offset;
pomax = term_len(p, 60);
pouse = po > pomax ? pomax : po < pomin ? pomin : po;
p->tcol->offset += pouse;
}
@@ -219,9 +227,10 @@ static void
roff_term_pre_ti(ROFF_TERM_ARGS)
{
struct roffsu su;
const char *cp;
const size_t maxoff = 72;
int len, sign;
const char *cp; /* Request argument. */
size_t maxoff; /* Maximum indentation in basic units. */
int len; /* Request argument in basic units. */
int sign;
roff_term_pre_br(p, n);
@@ -239,7 +248,8 @@ roff_term_pre_ti(ROFF_TERM_ARGS)
if (a2roffsu(cp, &su, SCALE_EM) == NULL)
return;
len = term_hen(p, &su);
len = term_hspan(p, &su);
maxoff = term_len(p, 72);
switch (sign) {
case 1:
+8 -8
View File
@@ -1,7 +1,7 @@
/* $Id: tbl.h,v 1.3 2025/01/05 18:14:39 schwarze Exp $ */
/* $Id: tbl.h,v 1.4 2025/07/16 14:33:08 schwarze Exp $ */
/*
* Copyright (c) 2014-2018, 2021, 2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014,2015,2017,2018,2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,8 +27,8 @@ struct tbl_opts {
#define TBL_OPT_NOSPACE (1 << 6) /* Option "nospaces". */
#define TBL_OPT_NOWARN (1 << 7) /* Option "nowarn". */
int cols; /* Number of columns. */
int lvert; /* Width of left vertical line. */
int rvert; /* Width of right vertical line. */
int lvert; /* Width of left vertical line in EN. */
int rvert; /* Width of right vertical line in EN. */
char tab; /* Option "tab": cell separator. */
char decimal; /* Option "decimalpoint". */
};
@@ -51,9 +51,9 @@ enum tbl_cellt {
*/
struct tbl_cell {
struct tbl_cell *next; /* Layout cell to the right. */
size_t width; /* Minimum column width. */
size_t spacing; /* To the right of the column. */
int vert; /* Width of subsequent vertical line. */
size_t width; /* Minimum column width in basic units. */
size_t spacing; /* To the right of the column in EN. */
int vert; /* Width of subseq. vertical line in EN. */
int col; /* Column number, starting from 0. */
int flags;
#define TBL_CELL_TALIGN (1 << 2) /* t, T */
@@ -73,7 +73,7 @@ struct tbl_row {
struct tbl_row *next; /* Layout row below. */
struct tbl_cell *first; /* Leftmost layout cell. */
struct tbl_cell *last; /* Rightmost layout cell. */
int vert; /* Width of left vertical line. */
int vert; /* Width of left vertical line in EN. */
};
enum tbl_datt {
+1 -33
View File
@@ -1,4 +1,4 @@
/* $Id: tbl_html.c,v 1.41 2022/04/23 14:02:17 schwarze Exp $ */
/* $Id: tbl_html.c,v 1.42 2025/07/16 14:33:08 schwarze Exp $ */
/*
* Copyright (c) 2014, 2015, 2017, 2018, 2021, 2022
* Ingo Schwarze <schwarze@openbsd.org>
@@ -37,7 +37,6 @@
static void html_tblopen(struct html *, const struct tbl_span *);
static size_t html_tbl_len(size_t, void *);
static size_t html_tbl_strlen(const char *, void *);
static size_t html_tbl_sulen(const struct roffsu *, void *);
static size_t
@@ -52,36 +51,6 @@ html_tbl_strlen(const char *p, void *arg)
return strlen(p);
}
static size_t
html_tbl_sulen(const struct roffsu *su, void *arg)
{
if (su->scale < 0.0)
return 0;
switch (su->unit) {
case SCALE_FS: /* 2^16 basic units */
return su->scale * 65536.0 / 24.0;
case SCALE_IN: /* 10 characters per inch */
return su->scale * 10.0;
case SCALE_CM: /* 2.54 cm per inch */
return su->scale * 10.0 / 2.54;
case SCALE_PC: /* 6 pica per inch */
case SCALE_VS:
return su->scale * 10.0 / 6.0;
case SCALE_EN:
case SCALE_EM:
return su->scale;
case SCALE_PT: /* 12 points per pica */
return su->scale * 10.0 / 6.0 / 12.0;
case SCALE_BU: /* 24 basic units per character */
return su->scale / 24.0;
case SCALE_MM: /* 1/1000 inch */
return su->scale / 100.0;
default:
abort();
}
}
static void
html_tblopen(struct html *h, const struct tbl_span *sp)
{
@@ -89,7 +58,6 @@ html_tblopen(struct html *h, const struct tbl_span *sp)
if (h->tbl.cols == NULL) {
h->tbl.len = html_tbl_len;
h->tbl.slen = html_tbl_strlen;
h->tbl.sulen = html_tbl_sulen;
tblcalc(&h->tbl, sp, 0, 0);
}
assert(NULL == h->tblt);
+5 -5
View File
@@ -1,4 +1,4 @@
/* $Id: tbl_layout.c,v 1.51 2025/01/05 18:14:39 schwarze Exp $ */
/* $Id: tbl_layout.c,v 1.52 2025/07/16 14:33:08 schwarze Exp $ */
/*
* Copyright (c) 2012, 2014, 2015, 2017, 2020, 2021, 2025
* Ingo Schwarze <schwarze@openbsd.org>
@@ -66,8 +66,8 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
int ln, const char *p, int *pos)
{
char *endptr;
unsigned long spacing;
int isz;
unsigned long spacing; /* Column spacing in EN units. */
int isz; /* Width in basic units. */
enum mandoc_esc fontesc;
mod:
@@ -145,8 +145,7 @@ mod:
mandoc_msg(MANDOCERR_TBLLAYOUT_WIDTH,
ln, *pos, "%s", p + *pos);
else {
/* Convert from BU to EN and round. */
cp->width = (isz + 11) /24;
cp->width = isz;
(*pos)++;
}
} else {
@@ -155,6 +154,7 @@ mod:
cp->width *= 10;
cp->width += p[(*pos)++] - '0';
}
cp->width *= 24;
if (cp->width == 0)
mandoc_msg(MANDOCERR_TBLLAYOUT_WIDTH,
ln, *pos, "%s", p + *pos);
+165 -122
View File
@@ -1,6 +1,6 @@
/* $Id: tbl_term.c,v 1.79 2022/08/28 10:58:31 schwarze Exp $ */
/* $Id: tbl_term.c,v 1.81 2025/07/24 17:54:48 schwarze Exp $ */
/*
* Copyright (c) 2011-2022 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011-2022, 2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -39,23 +39,23 @@
static size_t term_tbl_len(size_t, void *);
static size_t term_tbl_strlen(const char *, void *);
static size_t term_tbl_sulen(const struct roffsu *, void *);
static void tbl_data(struct termp *, const struct tbl_opts *,
const struct tbl_cell *,
const struct tbl_dat *,
const struct roffcol *);
const struct roffcol *, size_t *);
static void tbl_direct_border(struct termp *, int, size_t);
static void tbl_fill_border(struct termp *, int, size_t);
static void tbl_fill_char(struct termp *, char, size_t);
static void tbl_fill_string(struct termp *, const char *, size_t);
static void tbl_fill_border(struct termp *, int, size_t *, size_t);
static void tbl_fill_char(struct termp *, char, size_t *, size_t);
static void tbl_fill_string(struct termp *, const char *,
size_t *, size_t);
static void tbl_hrule(struct termp *, const struct tbl_span *,
const struct tbl_span *, const struct tbl_span *,
int);
static void tbl_literal(struct termp *, const struct tbl_dat *,
const struct roffcol *);
const struct roffcol *, size_t *);
static void tbl_number(struct termp *, const struct tbl_opts *,
const struct tbl_dat *,
const struct roffcol *);
const struct roffcol *, size_t *);
static void tbl_word(struct termp *, const struct tbl_dat *);
@@ -139,15 +139,6 @@ static const int borders_ascii[81] = {
static const int *borders_locale;
static size_t
term_tbl_sulen(const struct roffsu *su, void *arg)
{
int i;
i = term_hen((const struct termp *)arg, su);
return i > 0 ? i : 0;
}
static size_t
term_tbl_strlen(const char *p, void *arg)
{
@@ -166,16 +157,29 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
{
const struct tbl_cell *cp, *cpn, *cpp, *cps;
const struct tbl_dat *dp;
static size_t offset;
size_t save_offset;
size_t coloff, tsz;
int hspans, ic, more;
int dvert, fc, horiz, lhori, rhori, uvert;
/* Positions and widths in basic units. */
static size_t offset; /* Of the table as a whole. */
size_t save_offset; /* Of the surrounding text. */
size_t coloff; /* Of this cell. */
size_t tsz; /* Total width of the table. */
size_t enw; /* Width of one EN unit. */
int ic; /* Column number. */
int hspans; /* Number of spans following this cell. */
int horiz; /* Boolean: this row only contains a line. */
int lhori; /* Number of horizontal lines pointing left. */
int rhori; /* Number of horizontal lines pointing right. */
int dvert; /* Number of vertical lines pointing down. */
int uvert; /* Number of vertical lines pointing up. */
int fc; /* Frame character index in borders_locale[]. */
int more; /* Boolean: there are more columns to print. */
/* Inhibit printing of spaces: we do padding ourselves. */
tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE;
save_offset = tp->tcol->offset;
enw = term_len(tp, 1);
/*
* The first time we're invoked for a given table block,
@@ -188,7 +192,6 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->tbl.len = term_tbl_len;
tp->tbl.slen = term_tbl_strlen;
tp->tbl.sulen = term_tbl_sulen;
tp->tbl.arg = tp;
tblcalc(&tp->tbl, sp, tp->tcol->offset, tp->tcol->rmargin);
@@ -197,17 +200,36 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
offset = tp->tcol->offset;
if (sp->opts->opts & TBL_OPT_CENTRE) {
tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)
? 2 : !!sp->opts->lvert + !!sp->opts->rvert;
/*
* Vertical lines on the edges of the table make the
* table wider; take that into account for centering.
* The following assignment essentially says that a
* line on the right side occupies two columns (which
* matches reality) and a line on the left side three
* columns (which does not match reality; in fact,
* it only occupies two columns). But this is how
* groff does centering, so for compatibility, use
* the same numbers as groff.
*/
tsz = term_len(tp,
sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ?
5 : 3 * !!sp->opts->lvert + 2 * !!sp->opts->rvert);
/* Column widths and column spacing. */
for (ic = 0; ic + 1 < sp->opts->cols; ic++)
tsz += tp->tbl.cols[ic].width +
tp->tbl.cols[ic].spacing;
term_len(tp, tp->tbl.cols[ic].spacing);
if (sp->opts->cols)
tsz += tp->tbl.cols[sp->opts->cols - 1].width;
if (offset + tsz > tp->tcol->rmargin)
tsz -= 1;
tsz -= enw;
offset = offset + tp->tcol->rmargin > tsz ?
(offset + tp->tcol->rmargin - tsz) / 2 : 0;
((offset + tp->tcol->rmargin - tsz) / enw / 2) *
enw : 0;
tp->tcol->offset = offset;
}
@@ -239,7 +261,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
if (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ||
sp->opts->lvert)
coloff++;
coloff += enw * 2;
tp->tcol->rmargin = coloff;
/* Set up the data columns. */
@@ -254,7 +276,8 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
coloff += tp->tbl.cols[ic].width;
tp->tcol->rmargin = coloff;
if (ic + 1 < sp->opts->cols)
coloff += tp->tbl.cols[ic].spacing;
coloff += term_len(tp,
tp->tbl.cols[ic].spacing);
if (hspans) {
hspans--;
continue;
@@ -269,7 +292,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
/* Set up a column for a right vertical frame. */
tp->tcol++;
tp->tcol->offset = coloff + 1;
tp->tcol->offset = coloff + enw;
tp->tcol->rmargin = tp->maxrmargin;
/* Spans may have reduced the number of columns. */
@@ -279,6 +302,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
/* Fill the buffers for all data columns. */
tp->tcol = tp->tcols;
coloff = tp->tcols[1].offset;
cp = cpn = sp->layout->first;
dp = sp->first;
hspans = 0;
@@ -294,7 +318,9 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->tcol++;
tp->col = 0;
tp->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE);
tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic);
tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic,
&coloff);
coloff += term_len(tp, tp->tbl.cols[ic].spacing);
if (dp != NULL &&
(ic || sp->layout->first->pos != TBL_CELL_SPAN)) {
hspans = dp->hspans;
@@ -328,8 +354,8 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
fc = BUP * uvert + BDOWN * dvert + BRIGHT * rhori;
if (uvert > 0 || dvert > 0 || (horiz && sp->opts->lvert)) {
(*tp->advance)(tp, tp->tcols->offset);
tp->viscol = tp->tcol->offset;
tbl_direct_border(tp, fc, 1);
tbl_direct_border(tp, fc, enw);
tbl_direct_border(tp, BHORIZ * rhori, enw);
}
/* Print the data cells. */
@@ -348,6 +374,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
for (ic = 0; ic < sp->opts->cols; ic++) {
/*
* Handle horizontal alignment.
* Figure out whether to print a
* vertical line after this cell
* and advance to next layout cell.
@@ -362,6 +389,16 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
if (sp->pos == TBL_SPAN_DATA)
uvert = dvert = cps->vert;
switch (cp->pos) {
case TBL_CELL_CENTRE:
tp->flags |= TERMP_CENTER;
break;
case TBL_CELL_RIGHT:
tp->flags |= TERMP_RIGHT;
break;
case TBL_CELL_LONG:
if (hspans == 0)
tp->tcol->offset += enw;
break;
case TBL_CELL_HORIZ:
fc = BHORIZ;
break;
@@ -432,6 +469,9 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->tcol++;
if (tp->tcol->col < tp->tcol->lastcol)
term_flushln(tp);
tp->flags &= ~(TERMP_CENTER | TERMP_RIGHT);
if (cp != NULL && cp->pos == TBL_CELL_LONG)
tp->tcol->offset -= enw;
if (tp->tcol->col < tp->tcol->lastcol)
more = 1;
@@ -451,15 +491,13 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
continue;
}
if (tp->viscol < tp->tcol->rmargin) {
(*tp->advance)(tp, tp->tcol->rmargin
- tp->viscol);
tp->viscol = tp->tcol->rmargin;
}
if (tp->viscol < tp->tcol->rmargin)
(*tp->advance)(tp,
tp->tcol->rmargin - tp->viscol);
while (tp->viscol < tp->tcol->rmargin +
tp->tbl.cols[ic].spacing / 2)
term_len(tp, tp->tbl.cols[ic].spacing / 2))
tbl_direct_border(tp,
BHORIZ * lhori, 1);
BHORIZ * lhori, enw);
if (tp->tcol + 1 == tp->tcols + tp->lasttcol)
continue;
@@ -479,7 +517,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
if (tp->tbl.cols[ic].spacing)
tbl_direct_border(tp,
BLEFT * lhori + BRIGHT * rhori +
BUP * uvert + BDOWN * dvert, 1);
BUP * uvert + BDOWN * dvert, enw);
if (tp->enc == TERMENC_UTF8)
uvert = dvert = 0;
@@ -489,7 +527,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tbl_direct_border(tp,
BHORIZ * rhori +
BUP * (uvert > 1) +
BDOWN * (dvert > 1), 1);
BDOWN * (dvert > 1), enw);
}
}
@@ -528,15 +566,14 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 ||
sp->layout->last->col + 1 < sp->opts->cols)) {
tp->tcol++;
do {
if (tp->tcol->offset > tp->viscol)
tbl_direct_border(tp,
BHORIZ * lhori, 1);
} while (tp->viscol < tp->tcol->offset);
BHORIZ * lhori,
tp->tcol->offset - tp->viscol);
}
tbl_direct_border(tp, fc, 1);
tbl_direct_border(tp, fc, enw);
}
(*tp->endline)(tp);
tp->viscol = 0;
} while (more);
/*
@@ -575,6 +612,7 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp,
const struct tbl_cell *cpn; /* Layout cell below this line. */
const struct tbl_dat *dpn; /* Data cell below this line. */
const struct roffcol *col; /* Contains width and spacing. */
size_t enw; /* Width of one EN unit. */
int opts; /* For the table as a whole. */
int bw; /* Box line width. */
int hw; /* Horizontal line width. */
@@ -599,16 +637,19 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp,
/* Print the left end of the line. */
if (tp->viscol == 0) {
enw = term_len(tp, 1);
if (tp->viscol == 0)
(*tp->advance)(tp, tp->tcols->offset);
tp->viscol = tp->tcols->offset;
}
if (flags != 0)
if (flags != 0) {
tbl_direct_border(tp,
(spp == NULL ? 0 : BUP * bw) +
(spn == NULL ? 0 : BDOWN * bw) +
(spp == NULL || cpn == NULL ||
cpn->pos != TBL_CELL_DOWN ? BRIGHT * hw : 0), 1);
cpn->pos != TBL_CELL_DOWN ? BRIGHT * hw : 0), enw);
tbl_direct_border(tp,
(spp == NULL || cpn == NULL ||
cpn->pos != TBL_CELL_DOWN ? BHORIZ * hw : 0), enw);
}
col = tp->tbl.cols;
for (;;) {
@@ -625,7 +666,7 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp,
strcmp(dpn->string, "\\^") != 0))
? hw : 0;
tbl_direct_border(tp, BHORIZ * lw,
col->width + col->spacing / 2);
col->width + term_len(tp, col->spacing / 2));
/*
* Figure out whether a vertical line is crossing
@@ -678,7 +719,7 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp,
if (col->spacing)
tbl_direct_border(tp, BLEFT * lw +
BRIGHT * rw + BUP * uw + BDOWN * dw, 1);
BRIGHT * rw + BUP * uw + BDOWN * dw, enw);
/*
* In ASCII output, a crossing may print two characters.
@@ -688,13 +729,14 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp,
uw = dw = 0;
if (col->spacing > 2)
tbl_direct_border(tp,
BHORIZ * rw + BUP * uw + BDOWN * dw, 1);
BHORIZ * rw + BUP * uw + BDOWN * dw, enw);
/* Padding before the start of the next column. */
if (col->spacing > 4)
tbl_direct_border(tp,
BHORIZ * rw, (col->spacing - 3) / 2);
BHORIZ * rw,
term_len(tp, (col->spacing - 3) / 2));
}
/* Print the right end of the line. */
@@ -705,23 +747,22 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp,
(spn == NULL ? 0 : BDOWN * bw) +
(spp == NULL || spn == NULL ||
spn->layout->last->pos != TBL_CELL_DOWN ?
BLEFT * hw : 0), 1);
BLEFT * hw : 0), enw);
(*tp->endline)(tp);
tp->viscol = 0;
}
}
static void
tbl_data(struct termp *tp, const struct tbl_opts *opts,
const struct tbl_cell *cp, const struct tbl_dat *dp,
const struct roffcol *col)
const struct roffcol *col, size_t *coloff)
{
switch (cp->pos) {
case TBL_CELL_HORIZ:
tbl_fill_border(tp, BHORIZ, col->width);
tbl_fill_border(tp, BHORIZ, coloff, col->width);
return;
case TBL_CELL_DHORIZ:
tbl_fill_border(tp, BHORIZ * 2, col->width);
tbl_fill_border(tp, BHORIZ * 2, coloff, col->width);
return;
default:
break;
@@ -735,11 +776,11 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
return;
case TBL_DATA_HORIZ:
case TBL_DATA_NHORIZ:
tbl_fill_border(tp, BHORIZ, col->width);
tbl_fill_border(tp, BHORIZ, coloff, col->width);
return;
case TBL_DATA_NDHORIZ:
case TBL_DATA_DHORIZ:
tbl_fill_border(tp, BHORIZ * 2, col->width);
tbl_fill_border(tp, BHORIZ * 2, coloff, col->width);
return;
default:
break;
@@ -750,10 +791,10 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
case TBL_CELL_CENTRE:
case TBL_CELL_LEFT:
case TBL_CELL_RIGHT:
tbl_literal(tp, dp, col);
tbl_literal(tp, dp, col, coloff);
break;
case TBL_CELL_NUMBER:
tbl_number(tp, opts, dp, col);
tbl_number(tp, opts, dp, col, coloff);
break;
case TBL_CELL_DOWN:
case TBL_CELL_SPAN:
@@ -763,46 +804,72 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
}
}
/*
* Print multiple copies of the string cp to advance to
* len basic units from the left edge of the current column.
*/
static void
tbl_fill_string(struct termp *tp, const char *cp, size_t len)
tbl_fill_string(struct termp *tp, const char *cp, size_t *coloff, size_t len)
{
size_t i, sz;
size_t sz; /* Width of the string cp in basic units. */
size_t target; /* Distance from the left margin in basic units. */
if (len == 0)
return;
sz = term_strlen(tp, cp);
for (i = 0; i < len; i += sz)
target = tp->tcol->offset + len;
while (*coloff < target) {
term_word(tp, cp);
*coloff += sz;
}
}
/*
* Print multiple copies of the ASCII character c to advance to
* len basic units from the left edge of the current column.
*/
static void
tbl_fill_char(struct termp *tp, char c, size_t len)
tbl_fill_char(struct termp *tp, char c, size_t *coloff, size_t len)
{
char cp[2];
cp[0] = c;
cp[1] = '\0';
tbl_fill_string(tp, cp, len);
tbl_fill_string(tp, cp, coloff, len);
}
/*
* Print multiple copies of the border c to fill len basic units.
* Used for horizontal lines inside table cells.
*/
static void
tbl_fill_border(struct termp *tp, int c, size_t len)
tbl_fill_border(struct termp *tp, int c, size_t *coloff, size_t len)
{
char buf[12];
if ((c = borders_locale[c]) > 127) {
(void)snprintf(buf, sizeof(buf), "\\[u%04x]", c);
tbl_fill_string(tp, buf, len);
tbl_fill_string(tp, buf, coloff, len);
} else
tbl_fill_char(tp, c, len);
tbl_fill_char(tp, c, coloff, len);
}
/*
* The same, but bypassing term_flushln().
* Used for horizontal and vertical lines at the edges of table cells.
*/
static void
tbl_direct_border(struct termp *tp, int c, size_t len)
{
size_t i, sz;
size_t sz; /* Width of the character in basic units. */
size_t enw2; /* Width of half an EN in basic units. */
size_t target; /* Distance from the left margin in basic units. */
c = borders_locale[c];
sz = (*tp->width)(tp, c);
for (i = 0; i < len; i += sz) {
sz = (*tp->getwidth)(tp, c);
enw2 = (*tp->getwidth)(tp, ' ') / 2;
target = tp->viscol + len;
while (tp->viscol + enw2 < target) {
(*tp->letter)(tp, c);
tp->viscol += sz;
}
@@ -810,56 +877,36 @@ tbl_direct_border(struct termp *tp, int c, size_t len)
static void
tbl_literal(struct termp *tp, const struct tbl_dat *dp,
const struct roffcol *col)
const struct roffcol *col, size_t *coloff)
{
size_t len, padl, padr, width;
int ic, hspans;
size_t width; /* Of the cell including following spans [BU]. */
int ic; /* Column number of the cell. */
int hspans; /* Number of horizontal spans that follow. */
assert(dp->string);
len = term_strlen(tp, dp->string);
width = col->width;
ic = dp->layout->col;
hspans = dp->hspans;
while (hspans--) {
width += tp->tbl.cols[ic].spacing;
width += term_len(tp, tp->tbl.cols[ic].spacing);
ic++;
width += tp->tbl.cols[ic].width;
}
padr = width > len ? width - len : 0;
padl = 0;
switch (dp->layout->pos) {
case TBL_CELL_LONG:
padl = term_len(tp, 1);
padr = padr > padl ? padr - padl : 0;
break;
case TBL_CELL_CENTRE:
if (2 > padr)
break;
padl = padr / 2;
padr -= padl;
break;
case TBL_CELL_RIGHT:
padl = padr;
padr = 0;
break;
default:
break;
}
tbl_fill_char(tp, ASCII_NBRSP, padl);
tbl_word(tp, dp);
tbl_fill_char(tp, ASCII_NBRSP, padr);
*coloff += width;
}
static void
tbl_number(struct termp *tp, const struct tbl_opts *opts,
const struct tbl_dat *dp,
const struct roffcol *col)
const struct roffcol *col, size_t *coloff)
{
const char *cp, *lastdigit, *lastpoint;
size_t intsz, padl, totsz;
/* Widths in basic units. */
size_t pad; /* Padding before the number. */
size_t totsz; /* Of the number to be printed. */
size_t intsz; /* Of the integer part. */
char buf[2];
/*
@@ -883,7 +930,7 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts,
/* Then measure both widths. */
padl = 0;
pad = 0;
totsz = term_strlen(tp, dp->string);
if (lastdigit != NULL) {
if (lastpoint == NULL)
@@ -901,23 +948,19 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts,
*/
if (col->decimal > intsz && col->width > totsz) {
padl = col->decimal - intsz;
if (padl + totsz > col->width)
padl = col->width - totsz;
pad = col->decimal - intsz;
if (pad + totsz > col->width)
pad = col->width - totsz;
}
/* If it is not a number, simply center the string. */
} else if (col->width > totsz)
padl = (col->width - totsz) / 2;
pad = (col->width - totsz) / 2;
tbl_fill_char(tp, ASCII_NBRSP, padl);
tbl_fill_char(tp, ASCII_NBRSP, coloff, pad);
tbl_word(tp, dp);
/* Pad right to fill the column. */
if (col->width > padl + totsz)
tbl_fill_char(tp, ASCII_NBRSP, col->width - padl - totsz);
*coloff += col->width;
}
static void
+108 -93
View File
@@ -1,6 +1,6 @@
/* $Id: term.c,v 1.291 2023/04/28 19:11:04 schwarze Exp $ */
/* $Id: term.c,v 1.294 2025/08/01 14:59:39 schwarze Exp $ */
/*
* Copyright (c) 2010-2022 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010-2022, 2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -94,12 +94,15 @@ term_end(struct termp *p)
void
term_flushln(struct termp *p)
{
size_t vbl; /* Number of blanks to prepend to the output. */
/* Widths in basic units. */
size_t vbl; /* Whitespace to prepend to the output. */
size_t vbr; /* Actual visual position of the end of field. */
size_t vfield; /* Desired visual field width. */
size_t vtarget; /* Desired visual position of the right margin. */
size_t ic; /* Character position in the input buffer. */
size_t nbr; /* Number of characters to print in this field. */
/* Bytes. */
size_t ic; /* Byte index in the input buffer. */
size_t nbr; /* Number of bytes to print in this field. */
/*
* Normally, start writing at the left margin, but with the
@@ -108,8 +111,8 @@ term_flushln(struct termp *p)
vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ?
0 : p->tcol->offset - p->viscol;
if (p->minbl && vbl < p->minbl)
vbl = p->minbl;
if (p->minbl > 0 && vbl < term_len(p, p->minbl))
vbl = term_len(p, p->minbl);
if ((p->flags & TERMP_MULTICOL) == 0)
p->tcol->col = 0;
@@ -137,7 +140,7 @@ term_flushln(struct termp *p)
*/
term_fill(p, &nbr, &vbr,
p->flags & TERMP_BRNEVER ? SIZE_MAX : vtarget);
p->flags & TERMP_BRNEVER ? SIZE_MAX / 2 : vtarget);
if (nbr == 0)
break;
@@ -161,7 +164,7 @@ term_flushln(struct termp *p)
p->tcol->taboff += vbr;
else
p->tcol->taboff += vtarget;
p->tcol->taboff += (*p->width)(p, ' ');
p->tcol->taboff += term_len(p, 1);
/*
* If there is no text left in the field, exit the loop.
@@ -178,7 +181,7 @@ term_flushln(struct termp *p)
continue;
case ' ':
if (p->flags & TERMP_BRTRSP)
vbr += (*p->width)(p, ' ');
vbr += term_len(p, 1);
continue;
case '\n':
case ASCII_NBRZW:
@@ -245,13 +248,13 @@ term_flushln(struct termp *p)
if ((p->flags & TERMP_HANG) == 0 &&
((p->flags & TERMP_NOBREAK) == 0 ||
vbr + term_len(p, p->trailspace) > vfield))
vbr + term_len(p, p->trailspace) > vfield + term_len(p, 1) / 2))
endline(p);
}
/*
* Store the number of input characters to print in this field in *nbr
* and their total visual width to print in *vbr.
* Store the number of input bytes to print in this field in *nbr
* and their total visual width in basic units in *vbr.
* If there is only whitespace in the field, both remain zero.
* The desired visual width of the field is provided by vtarget.
* If the first word is longer, the field will be overrun.
@@ -259,28 +262,33 @@ term_flushln(struct termp *p)
static void
term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget)
{
size_t ic; /* Character position in the input buffer. */
/* Widths in basic units. */
size_t vis; /* Visual position of the current character. */
size_t vn; /* Visual position of the next character. */
size_t enw; /* Width of an EN unit. */
int taboff; /* Temporary offset for literal tabs. */
size_t ic; /* Byte index in the input buffer. */
int breakline; /* Break at the end of this word. */
int graph; /* Last character was non-blank. */
int taboff; /* Temporary offset for literal tabs. */
*nbr = *vbr = vis = 0;
breakline = graph = 0;
taboff = p->tcol->taboff;
enw = (*p->getwidth)(p, ' ');
vtarget += enw / 2;
for (ic = p->tcol->col; ic < p->tcol->lastcol; ic++) {
switch (p->tcol->buf[ic]) {
case '\b': /* Escape \o (overstrike) or backspace markup. */
assert(ic > 0);
vis -= (*p->width)(p, p->tcol->buf[ic - 1]);
vis -= (*p->getwidth)(p, p->tcol->buf[ic - 1]);
continue;
case ' ':
case ASCII_BREAK: /* Escape \: (breakpoint). */
vn = vis;
if (p->tcol->buf[ic] == ' ')
vn += (*p->width)(p, ' ');
vn += enw;
/* Can break at the end of a word. */
if (breakline || vn > vtarget)
break;
@@ -305,7 +313,7 @@ term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget)
* hyphen such that we get the correct width.
*/
p->tcol->buf[ic] = '-';
vis += (*p->width)(p, '-');
vis += (*p->getwidth)(p, '-');
if (vis > vtarget) {
ic++;
break;
@@ -315,7 +323,7 @@ term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget)
continue;
case ASCII_TABREF:
taboff = -vis - (*p->width)(p, ' ');
taboff = -vis - enw;
continue;
default:
@@ -334,7 +342,7 @@ term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget)
p->tcol->buf[ic] = ' ';
/* FALLTHROUGH */
default: /* Printable character. */
vis += (*p->width)(p, p->tcol->buf[ic]);
vis += (*p->getwidth)(p, p->tcol->buf[ic]);
break;
}
graph = 1;
@@ -359,18 +367,20 @@ term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget)
/*
* Print the contents of one field
* with an indentation of vbl visual columns,
* and an input string length of nbr characters.
* with an indentation of vbl basic units
* and an input string length of nbr bytes.
*/
static void
term_field(struct termp *p, size_t vbl, size_t nbr)
{
size_t ic; /* Character position in the input buffer. */
/* Widths in basic units. */
size_t vis; /* Visual position of the current character. */
size_t vt; /* Visual position including tab offset. */
size_t dv; /* Visual width of the current character. */
int taboff; /* Temporary offset for literal tabs. */
size_t ic; /* Byte position in the input buffer. */
vis = 0;
taboff = p->tcol->taboff;
for (ic = p->tcol->col; ic < nbr; ic++) {
@@ -386,7 +396,7 @@ term_field(struct termp *p, size_t vbl, size_t nbr)
case ASCII_NBRZW:
continue;
case ASCII_TABREF:
taboff = -vis - (*p->width)(p, ' ');
taboff = -vis - (*p->getwidth)(p, ' ');
continue;
case '\t':
case ' ':
@@ -398,7 +408,7 @@ term_field(struct termp *p, size_t vbl, size_t nbr)
vt = vis + taboff;
dv = term_tab_next(vt) - vt;
} else
dv = (*p->width)(p, ' ');
dv = (*p->getwidth)(p, ' ');
vbl += dv;
vis += dv;
continue;
@@ -413,7 +423,6 @@ term_field(struct termp *p, size_t vbl, size_t nbr)
if (vbl > 0) {
(*p->advance)(p, vbl);
p->viscol += vbl;
vbl = 0;
}
@@ -421,11 +430,11 @@ term_field(struct termp *p, size_t vbl, size_t nbr)
(*p->letter)(p, p->tcol->buf[ic]);
if (p->tcol->buf[ic] == '\b') {
dv = (*p->width)(p, p->tcol->buf[ic - 1]);
dv = (*p->getwidth)(p, p->tcol->buf[ic - 1]);
p->viscol -= dv;
vis -= dv;
} else {
dv = (*p->width)(p, p->tcol->buf[ic]);
dv = (*p->getwidth)(p, p->tcol->buf[ic]);
p->viscol += dv;
vis += dv;
}
@@ -433,6 +442,10 @@ term_field(struct termp *p, size_t vbl, size_t nbr)
p->tcol->col = nbr;
}
/*
* Print the margin character, if one is configured,
* and end the output line.
*/
static void
endline(struct termp *p)
{
@@ -441,14 +454,13 @@ endline(struct termp *p)
p->flags &= ~TERMP_ENDMC;
}
if (p->mc != NULL) {
if (p->viscol && p->maxrmargin >= p->viscol)
(*p->advance)(p, p->maxrmargin - p->viscol + 1);
if (p->viscol > 0 && p->viscol <= p->maxrmargin)
(*p->advance)(p,
p->maxrmargin - p->viscol + term_len(p, 1));
p->flags |= TERMP_NOBUF | TERMP_NOSPACE;
term_word(p, p->mc);
p->flags &= ~(TERMP_NOBUF | TERMP_NEWMC);
}
p->viscol = 0;
p->minbl = 0;
(*p->endline)(p);
}
@@ -477,8 +489,6 @@ term_vspace(struct termp *p)
{
term_newln(p);
p->viscol = 0;
p->minbl = 0;
if (0 < p->skipvsp)
p->skipvsp--;
else
@@ -496,34 +506,36 @@ term_fontlast(struct termp *p)
p->fontq[p->fonti] = f;
}
/* Set font, save current, discard previous; for \f, .ft, .B etc. */
/* Set font, save current, discard previous; for \f, .ft, and man(7). */
void
term_fontrepl(struct termp *p, enum termfont f)
{
p->fontl = p->fontq[p->fonti];
if (p->fontibi && f == TERMFONT_UNDER)
f = TERMFONT_BI;
p->fontq[p->fonti] = f;
}
/* Set font, save previous. */
/* Set font, save previous; for mdoc(7), eqn(7), and tbl(7). */
void
term_fontpush(struct termp *p, enum termfont f)
{
enum termfont fl;
p->fontl = p->fontq[p->fonti];
fl = p->fontq[p->fonti];
if (++p->fonti == p->fontsz) {
p->fontsz += 8;
p->fontq = mandoc_reallocarray(p->fontq,
p->fontsz, sizeof(*p->fontq));
}
p->fontq[p->fonti] = f;
p->fontq[p->fonti] = fl;
term_fontrepl(p, f);
}
/* Flush to make the saved pointer current again. */
void
term_fontpopq(struct termp *p, int i)
{
assert(i >= 0);
if (p->fonti > i)
p->fonti = i;
@@ -533,8 +545,7 @@ term_fontpopq(struct termp *p, int i)
void
term_fontpop(struct termp *p)
{
assert(p->fonti);
assert(p->fonti > 0);
p->fonti--;
}
@@ -548,9 +559,14 @@ term_word(struct termp *p, const char *word)
{
struct roffsu su;
const char nbrsp[2] = { ASCII_NBRSP, 0 };
const char *seq, *cp;
int sz, uc;
size_t csz, lsz, ssz;
const char *seq; /* Escape sequence argument. */
const char *cp; /* String to be printed. */
size_t csz; /* String length in basic units. */
size_t lsz; /* Line width in basic units. */
size_t ssz; /* Substring length in bytes. */
int sz; /* Argument length in bytes. */
int uc; /* Unicode codepoint number. */
int bu; /* Width in basic units. */
enum mandoc_esc esc;
if ((p->flags & TERMP_NOBUF) == 0) {
@@ -663,15 +679,15 @@ term_word(struct termp *p, const char *word)
}
if (*seq == '|') {
seq++;
uc = -p->col;
bu = -term_len(p, p->col);
} else
uc = 0;
bu = 0;
if (a2roffsu(seq, &su, SCALE_EM) == NULL)
continue;
uc += term_hen(p, &su);
if (uc >= 0) {
while (uc > 0) {
uc -= term_len(p, 1);
bu += term_hspan(p, &su);
if (bu >= 0) {
while (bu > 0) {
bu -= term_len(p, 1);
if (p->flags & TERMP_BACKBEFORE)
p->flags &= ~TERMP_BACKBEFORE;
else
@@ -681,17 +697,17 @@ term_word(struct termp *p, const char *word)
}
if (p->flags & TERMP_BACKBEFORE) {
p->flags &= ~TERMP_BACKBEFORE;
assert(p->col > 0);
assert(p->col > 1);
p->col--;
}
if (p->col >= (size_t)(-uc)) {
p->col += uc;
if (term_len(p, p->col) >= (size_t)(-bu)) {
p->col -= -bu / term_len(p, 1);
} else {
uc += p->col;
bu += term_len(p, p->col);
p->col = 0;
if (p->tcol->offset > (size_t)(-uc)) {
p->ti += uc;
p->tcol->offset += uc;
if (p->tcol->offset > (size_t)(-bu)) {
p->ti += bu;
p->tcol->offset += bu;
} else {
p->ti -= p->tcol->offset;
p->tcol->offset = 0;
@@ -701,13 +717,13 @@ term_word(struct termp *p, const char *word)
case ESCAPE_HLINE:
if ((cp = a2roffsu(seq, &su, SCALE_EM)) == NULL)
continue;
uc = term_hen(p, &su);
if (uc <= 0) {
bu = term_hspan(p, &su);
if (bu <= 0) {
if (p->tcol->rmargin <= p->tcol->offset)
continue;
lsz = p->tcol->rmargin - p->tcol->offset;
} else
lsz = uc;
lsz = bu;
if (*cp == seq[-1])
uc = -1;
else if (*cp == '\\') {
@@ -739,13 +755,16 @@ term_word(struct termp *p, const char *word)
csz = term_strlen(p, cp);
ssz = strlen(cp);
} else
csz = (*p->width)(p, uc);
while (lsz >= csz) {
csz = (*p->getwidth)(p, uc);
while (lsz > 0) {
if (p->enc == TERMENC_ASCII)
encode(p, cp, ssz);
else
encode1(p, uc);
lsz -= csz;
if (lsz > csz)
lsz -= csz;
else
lsz = 0;
}
continue;
case ESCAPE_SKIPCHAR:
@@ -954,28 +973,39 @@ term_setwidth(struct termp *p, const char *wstr)
size_t
term_len(const struct termp *p, size_t sz)
{
return (*p->width)(p, ' ') * sz;
return (*p->getwidth)(p, ' ') * sz;
}
static size_t
cond_width(const struct termp *p, int c, int *skip)
{
if (*skip) {
(*skip) = 0;
return 0;
} else
return (*p->width)(p, c);
return (*p->getwidth)(p, c);
}
size_t
term_strlen(const struct termp *p, const char *cp)
{
size_t sz, rsz, i;
int ssz, skip, uc;
const char *seq, *rhs;
const char *seq; /* Escape sequence argument. */
const char *rhs; /* String to be printed. */
/* Widths in basic units. */
size_t sz; /* Return value. */
size_t this_sz; /* Individual char for overstrike. */
size_t max_sz; /* Result of overstrike. */
/* Numbers of bytes. */
size_t rsz; /* Substring length in bytes. */
size_t i; /* Byte index in substring. */
int ssz; /* Argument length in bytes. */
int skip; /* Number of bytes to skip. */
int uc; /* Unicode codepoint number. */
enum mandoc_esc esc;
static const char rej[] = { '\\', ASCII_NBRSP, ASCII_NBRZW,
ASCII_BREAK, ASCII_HYPH, ASCII_TABREF, '\0' };
@@ -1039,18 +1069,18 @@ term_strlen(const struct termp *p, const char *cp)
skip = 1;
continue;
case ESCAPE_OVERSTRIKE:
rsz = 0;
max_sz = 0;
rhs = seq + ssz;
while (seq < rhs) {
if (*seq == '\\') {
mandoc_escape(&seq, NULL, NULL);
continue;
}
i = (*p->width)(p, *seq++);
if (rsz < i)
rsz = i;
this_sz = (*p->getwidth)(p, *seq++);
if (max_sz < this_sz)
max_sz = this_sz;
}
sz += rsz;
sz += max_sz;
continue;
default:
continue;
@@ -1085,7 +1115,7 @@ term_strlen(const struct termp *p, const char *cp)
*/
for (i = 0; i < rsz; i++)
sz += (*p->width)(p, *rhs++);
sz += (*p->getwidth)(p, *rhs++);
break;
case ASCII_NBRSP:
sz += cond_width(p, ' ', &skip);
@@ -1146,25 +1176,10 @@ term_vspan(const struct termp *p, const struct roffsu *su)
}
/*
* Convert a scaling width to basic units, rounding towards 0.
* Convert a scaling width to basic units.
*/
int
term_hspan(const struct termp *p, const struct roffsu *su)
{
return (*p->hspan)(p, su);
}
/*
* Convert a scaling width to basic units, rounding to closest.
*/
int
term_hen(const struct termp *p, const struct roffsu *su)
{
int bu;
if ((bu = (*p->hspan)(p, su)) >= 0)
return (bu + 11) / 24;
else
return -((-bu + 11) / 24);
}
+16 -22
View File
@@ -1,6 +1,7 @@
/* $Id: term.h,v 1.134 2022/08/16 17:45:55 schwarze Exp $ */
/* $Id: term.h,v 1.138 2025/07/27 15:27:28 schwarze Exp $ */
/*
* Copyright (c) 2011-2015,2017,2019,2022 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011-2015, 2017, 2019, 2021, 2022, 2025
* Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -44,19 +45,14 @@ struct termp;
typedef void (*term_margin)(struct termp *, const struct roff_meta *);
struct termp_tbl {
int width; /* width in fixed chars */
int decimal; /* decimal point position */
};
struct termp_col {
int *buf; /* Output buffer. */
size_t maxcols; /* Allocated bytes in buf. */
size_t lastcol; /* Last byte in buf. */
size_t col; /* Byte in buf to be written. */
size_t rmargin; /* Current right margin. */
size_t offset; /* Current left margin. */
size_t taboff; /* Offset for literal tabs. */
size_t rmargin; /* Current right margin [BU]. */
size_t offset; /* Current left margin [BU]. */
size_t taboff; /* Offset for literal tabs [BU]. */
};
struct termp {
@@ -66,17 +62,16 @@ struct termp {
size_t maxtcol; /* Allocated table columns. */
size_t lasttcol; /* Last column currently used. */
size_t line; /* Current output line number. */
size_t defindent; /* Default indent for text. */
size_t defrmargin; /* Right margin of the device. */
size_t lastrmargin; /* Right margin before the last ll. */
size_t maxrmargin; /* Max right margin. */
size_t defindent; /* Default indent for text [EN]. */
size_t defrmargin; /* Right margin of the device [BU]. */
size_t lastrmargin; /* Right margin before last ll [BU]. */
size_t maxrmargin; /* Maximum right margin [BU]. */
size_t col; /* Byte position in buf. */
size_t viscol; /* Chars on current line. */
size_t trailspace; /* See term_flushln(). */
size_t minbl; /* Minimum blanks before next field. */
size_t viscol; /* Width of the current line [BU]. */
size_t trailspace; /* Whitespace after field [EN]. */
size_t minbl; /* Whitespace before field [EN]. */
int synopsisonly; /* Print the synopsis only. */
int mdocstyle; /* Imitate mdoc(7) output. */
int ti; /* Temporary indent for one line. */
int ti; /* Temporary indent for line [BU]. */
int skipvsp; /* Vertical space to skip. */
int flags;
#define TERMP_SENTENCE (1 << 0) /* Space before a sentence. */
@@ -108,6 +103,7 @@ struct termp {
enum termfont *fontq; /* Symmetric fonts. */
int fontsz; /* Allocated size of font stack */
int fonti; /* Index of font stack. */
int fontibi; /* Map font I to BI. */
term_margin headf; /* invoked to print head */
term_margin footf; /* invoked to print foot */
void (*letter)(struct termp *, int);
@@ -116,7 +112,7 @@ struct termp {
void (*endline)(struct termp *);
void (*advance)(struct termp *, size_t);
void (*setwidth)(struct termp *, int, int);
size_t (*width)(const struct termp *, int);
size_t (*getwidth)(const struct termp *, int);
int (*hspan)(const struct termp *,
const struct roffsu *);
const void *argf; /* arg for headf/footf */
@@ -143,13 +139,11 @@ void term_end(struct termp *);
void term_setwidth(struct termp *, const char *);
int term_hspan(const struct termp *, const struct roffsu *);
int term_hen(const struct termp *, const struct roffsu *);
int term_vspan(const struct termp *, const struct roffsu *);
size_t term_strlen(const struct termp *, const char *);
size_t term_len(const struct termp *, size_t);
void term_tab_set(const struct termp *, const char *);
void term_tab_iset(size_t);
void term_tab_ref(struct termp *);
size_t term_tab_next(size_t);
void term_tab_free(void);
+51 -40
View File
@@ -1,7 +1,7 @@
/* $Id: term_ascii.c,v 1.69 2023/11/13 19:13:01 schwarze Exp $ */
/* $Id: term_ascii.c,v 1.71 2025/07/16 14:33:08 schwarze Exp $ */
/*
* Copyright (c) 2014,2015,2017-2020,2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014,2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -43,7 +43,7 @@
static struct termp *ascii_init(enum termenc, const struct manoutput *);
static int ascii_hspan(const struct termp *,
const struct roffsu *);
static size_t ascii_width(const struct termp *, int);
static size_t ascii_getwidth(const struct termp *, int);
static void ascii_advance(struct termp *, size_t);
static void ascii_begin(struct termp *);
static void ascii_end(struct termp *);
@@ -55,7 +55,7 @@ static void ascii_setwidth(struct termp *, int, int);
static void locale_advance(struct termp *, size_t);
static void locale_endline(struct termp *);
static void locale_letter(struct termp *, int);
static size_t locale_width(const struct termp *, int);
static size_t locale_getwidth(const struct termp *, int);
#endif
@@ -73,7 +73,6 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
p->line = 1;
p->defindent = 5;
p->defrmargin = p->lastrmargin = 78;
p->fontq = mandoc_reallocarray(NULL,
(p->fontsz = 8), sizeof(*p->fontq));
p->fontq[0] = p->fontl = TERMFONT_NONE;
@@ -82,13 +81,12 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
p->end = ascii_end;
p->hspan = ascii_hspan;
p->type = TERMTYPE_CHAR;
p->enc = TERMENC_ASCII;
p->advance = ascii_advance;
p->endline = ascii_endline;
p->letter = ascii_letter;
p->setwidth = ascii_setwidth;
p->width = ascii_width;
p->getwidth = ascii_getwidth;
#if HAVE_WCHAR
if (enc != TERMENC_ASCII) {
@@ -118,17 +116,15 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
p->advance = locale_advance;
p->endline = locale_endline;
p->letter = locale_letter;
p->width = locale_width;
p->getwidth = locale_getwidth;
}
}
#endif
p->defrmargin = term_len(p, outopts->width ? outopts->width : 78);
p->lastrmargin = p->defrmargin;
if (outopts->mdoc)
p->mdocstyle = 1;
if (outopts->indent)
p->defindent = outopts->indent;
if (outopts->width)
p->defrmargin = outopts->width;
if (outopts->synopsisonly)
p->synopsisonly = 1;
@@ -140,29 +136,24 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
void *
ascii_alloc(const struct manoutput *outopts)
{
return ascii_init(TERMENC_ASCII, outopts);
}
void *
utf8_alloc(const struct manoutput *outopts)
{
return ascii_init(TERMENC_UTF8, outopts);
}
void *
locale_alloc(const struct manoutput *outopts)
{
return ascii_init(TERMENC_LOCALE, outopts);
}
static void
ascii_setwidth(struct termp *p, int iop, int width)
{
width /= 24;
p->tcol->rmargin = p->defrmargin;
if (iop > 0)
p->defrmargin += width;
@@ -172,8 +163,8 @@ ascii_setwidth(struct termp *p, int iop, int width)
p->defrmargin -= width;
else
p->defrmargin = 0;
if (p->defrmargin > 1000)
p->defrmargin = 1000;
if (p->defrmargin > term_len(p, 1000))
p->defrmargin = term_len(p, 1000);
p->lastrmargin = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin = p->defrmargin;
}
@@ -182,67 +173,76 @@ void
terminal_sepline(void *arg)
{
struct termp *p;
size_t i;
size_t i; /* Printed width in basic units. */
size_t sz; /* Width of a dash in basic units. */
p = (struct termp *)arg;
(*p->endline)(p);
for (i = 0; i < p->defrmargin; i++)
sz = (*p->getwidth)(p, '-');
for (i = 0; i < p->defrmargin; i += sz)
(*p->letter)(p, '-');
(*p->endline)(p);
(*p->endline)(p);
}
static size_t
ascii_width(const struct termp *p, int c)
ascii_getwidth(const struct termp *p, int c)
{
return c != ASCII_BREAK && c != ASCII_NBRZW && c != ASCII_TABREF;
switch (c) {
case ASCII_BREAK:
case ASCII_NBRZW:
case ASCII_TABREF:
return 0;
default:
return 24;
}
}
void
ascii_free(void *arg)
{
term_free((struct termp *)arg);
}
static void
ascii_letter(struct termp *p, int c)
{
putchar(c);
}
static void
ascii_begin(struct termp *p)
{
(*p->headf)(p, p->argf);
}
static void
ascii_end(struct termp *p)
{
(*p->footf)(p, p->argf);
}
static void
ascii_endline(struct termp *p)
{
p->line++;
if ((int)p->tcol->offset > p->ti)
p->tcol->offset -= p->ti;
else
p->tcol->offset = 0;
p->ti = 0;
p->minbl = 0;
p->viscol = 0;
putchar('\n');
}
static void
ascii_advance(struct termp *p, size_t len)
{
size_t i;
size_t dst; /* Destination column in basic units. */
size_t sz; /* Width of a space in basic units. */
sz = (*p->getwidth)(p, ' ');
/*
* XXX We used to have "assert(len < UINT16_MAX)" here.
@@ -250,10 +250,14 @@ ascii_advance(struct termp *p, size_t len)
* can trigger that by merely providing large input.
* For now, simply truncate.
*/
if (len > 256)
len = 256;
for (i = 0; i < len; i++)
if (len > 256 * sz)
len = 256 * sz;
dst = p->viscol + len;
while (p->viscol + sz / 2 < dst) {
putchar(' ');
p->viscol += sz;
}
}
static int
@@ -372,7 +376,7 @@ ascii_uc2str(int uc)
#if HAVE_WCHAR
static size_t
locale_width(const struct termp *p, int c)
locale_getwidth(const struct termp *p, int c)
{
int rc;
@@ -381,13 +385,16 @@ locale_width(const struct termp *p, int c)
rc = wcwidth(c);
if (rc < 0)
rc = 0;
return rc;
return rc * 24;
}
static void
locale_advance(struct termp *p, size_t len)
{
size_t i;
size_t dst; /* Destination column in basic units. */
size_t sz; /* Width of a space in basic units. */
sz = (*p->getwidth)(p, ' ');
/*
* XXX We used to have "assert(len < UINT16_MAX)" here.
@@ -395,29 +402,33 @@ locale_advance(struct termp *p, size_t len)
* can trigger that by merely providing large input.
* For now, simply truncate.
*/
if (len > 256)
len = 256;
for (i = 0; i < len; i++)
if (len > 256 * sz)
len = 256 * sz;
dst = p->viscol + len;
while (p->viscol + sz / 2 < dst) {
putwchar(L' ');
p->viscol += sz;
}
}
static void
locale_endline(struct termp *p)
{
p->line++;
if ((int)p->tcol->offset > p->ti)
p->tcol->offset -= p->ti;
else
p->tcol->offset = 0;
p->ti = 0;
p->minbl = 0;
p->viscol = 0;
putwchar(L'\n');
}
static void
locale_letter(struct termp *p, int c)
{
putwchar(c);
}
#endif
+10 -8
View File
@@ -1,7 +1,7 @@
/* $Id: term_ps.c,v 1.92 2020/09/06 14:45:22 schwarze Exp $ */
/* $Id: term_ps.c,v 1.95 2025/09/26 12:17:12 schwarze Exp $ */
/*
* Copyright (c) 2014-2017, 2020, 2025 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014,2015,2016,2017,2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2017 Marc Espie <espie@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -95,7 +95,7 @@ struct termp_ps {
static int ps_hspan(const struct termp *,
const struct roffsu *);
static size_t ps_width(const struct termp *, int);
static size_t ps_getwidth(const struct termp *, int);
static void ps_advance(struct termp *, size_t);
static void ps_begin(struct termp *);
static void ps_closepage(struct termp *);
@@ -549,7 +549,7 @@ pspdf_alloc(const struct manoutput *outopts, enum termtype type)
p->hspan = ps_hspan;
p->letter = ps_letter;
p->setwidth = ps_setwidth;
p->width = ps_width;
p->getwidth = ps_getwidth;
/* Default to US letter (millimetres). */
@@ -1211,6 +1211,7 @@ ps_advance(struct termp *p, size_t len)
ps_plast(p);
ps_pclose(p);
p->ps->pscol += len;
p->viscol += len;
}
static void
@@ -1221,6 +1222,8 @@ ps_endline(struct termp *p)
ps_plast(p);
ps_pclose(p);
p->viscol = 0;
p->minbl = 0;
/*
* If we're in the margin, don't try to recalculate our current
@@ -1282,7 +1285,7 @@ ps_setfont(struct termp *p, enum termfont f)
}
static size_t
ps_width(const struct termp *p, int c)
ps_getwidth(const struct termp *p, int c)
{
if (c <= 32 || c - 32 >= MAXCHAR)
@@ -1311,7 +1314,7 @@ ps_hspan(const struct termp *p, const struct roffsu *su)
* scaling unit so that output is the same regardless
* the media.
*/
r = PNT2AFM(p, su->scale * 72.0 / 240.0);
r = PNT2AFM(p, su->scale * 72.0 / 10.0);
break;
case SCALE_CM:
r = PNT2AFM(p, su->scale * 72.0 / 2.54);
@@ -1344,8 +1347,7 @@ ps_hspan(const struct termp *p, const struct roffsu *su)
r = su->scale;
break;
}
return r * 24.0;
return r;
}
static void
+6 -21
View File
@@ -1,6 +1,6 @@
/* $Id: term_tab.c,v 1.7 2021/10/04 18:56:31 schwarze Exp $ */
/* $Id: term_tab.c,v 1.9 2025/07/16 14:33:08 schwarze Exp $ */
/*
* Copyright (c) 2017, 2021 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2017, 2021, 2025 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,7 +27,7 @@
#include "term.h"
struct tablist {
size_t *t; /* Allocated array of tab positions. */
size_t *t; /* Allocated array of tab positions [BU]. */
size_t s; /* Allocated number of positions. */
size_t n; /* Currently used number of positions. */
};
@@ -36,7 +36,7 @@ static struct {
struct tablist a; /* All tab positions for lookup. */
struct tablist p; /* Periodic tab positions to add. */
struct tablist *r; /* Tablist currently being recorded. */
size_t d; /* Default tab width in units of n. */
size_t d; /* Default tab width in basic units. */
} tabs;
@@ -55,7 +55,7 @@ term_tab_set(const struct termp *p, const char *arg)
tabs.r = &tabs.a;
if (tabs.d == 0) {
a2roffsu(".8i", &su, SCALE_IN);
tabs.d = term_hen(p, &su);
tabs.d = term_hspan(p, &su);
}
return;
}
@@ -84,28 +84,13 @@ term_tab_set(const struct termp *p, const char *arg)
/* Append the new position. */
pos = term_hen(p, &su);
pos = term_hspan(p, &su);
tl->t[tl->n] = pos;
if (add && tl->n)
tl->t[tl->n] += tl->t[tl->n - 1];
tl->n++;
}
/*
* Simplified version without a parser,
* never incremental, never periodic, for use by tbl(7).
*/
void
term_tab_iset(size_t inc)
{
if (tabs.a.n >= tabs.a.s) {
tabs.a.s += 8;
tabs.a.t = mandoc_reallocarray(tabs.a.t, tabs.a.s,
sizeof(*tabs.a.t));
}
tabs.a.t[tabs.a.n++] = inc;
}
size_t
term_tab_next(size_t prev)
{
-2
View File
@@ -274,8 +274,6 @@
..
dma
..
drivers
..
dwatch
..
etc
+1 -1
View File
@@ -43,7 +43,7 @@
.4byte NT_FREEBSD_ABI_TAG
1: .asciz NOTE_FREEBSD_VENDOR
2: .p2align 2
3: .4byte __FreeBSD_version
3: .4byte 1404000
4:
.section .note.GNU-stack,"",%progbits
+17 -12
View File
@@ -287,6 +287,9 @@ fetch_reopen(int sd)
flags = fcntl(sd, F_GETFD);
if (flags != -1 && (flags & FD_CLOEXEC) == 0)
(void)fcntl(sd, F_SETFD, flags | FD_CLOEXEC);
flags = fcntl(sd, F_GETFL);
if (flags != -1 && (flags & O_NONBLOCK) == 0)
(void)fcntl(sd, F_SETFL, flags | O_NONBLOCK);
(void)setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
conn->sd = sd;
++conn->ref;
@@ -655,7 +658,13 @@ fetch_connect(const char *host, int port, int af, int verbose)
goto syserr;
}
/* attempt to connect to server address */
if ((err = connect(sd, sai->ai_addr, sai->ai_addrlen)) == 0)
while ((err = connect(sd, sai->ai_addr, sai->ai_addrlen)) < 0) {
if (errno == EINTR && fetchRestartCalls)
continue;
break;
}
/* success? */
if (err == 0)
break;
/* clean up before next attempt */
close(sd);
@@ -1183,8 +1192,11 @@ fetch_ssl(conn_t *conn, const struct url *URL, int verbose)
X509_NAME *name;
char *str;
conn->ssl_meth = SSLv23_client_method();
conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth);
if ((conn->ssl_ctx = SSL_CTX_new(TLS_client_method())) == NULL) {
fprintf(stderr, "SSL context creation failed\n");
ERR_print_errors_fp(stderr);
return (-1);
}
SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY);
fetch_ssl_setup_transport_layer(conn->ssl_ctx, verbose);
@@ -1195,7 +1207,8 @@ fetch_ssl(conn_t *conn, const struct url *URL, int verbose)
conn->ssl = SSL_new(conn->ssl_ctx);
if (conn->ssl == NULL) {
fprintf(stderr, "SSL context creation failed\n");
fprintf(stderr, "SSL connection creation failed\n");
ERR_print_errors_fp(stderr);
return (-1);
}
SSL_set_fd(conn->ssl, conn->sd);
@@ -1268,14 +1281,6 @@ fetch_ssl_read(SSL *ssl, char *buf, size_t len)
{
ssize_t rlen;
int ssl_err;
struct timeval tv;
if (fetchTimeout > 0) {
tv.tv_sec = fetchTimeout;
tv.tv_usec = 0;
setsockopt(SSL_get_fd(ssl), SOL_SOCKET, SO_RCVTIMEO,
&tv, sizeof(tv));
}
rlen = SSL_read(ssl, buf, len);
if (rlen < 0) {
-1
View File
@@ -56,7 +56,6 @@ struct fetchconn {
SSL *ssl; /* SSL handle */
SSL_CTX *ssl_ctx; /* SSL context */
X509 *ssl_cert; /* server certificate */
const SSL_METHOD *ssl_meth; /* SSL method */
#endif
int ref; /* reference count */
};
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,242 @@
[
{
"BriefDescription": "This event counts the cycles the floating point divider is busy.",
"Counter": "0,1,2,3,4,5,6,7",
"CounterMask": "1",
"EventCode": "0xb0",
"EventName": "ARITH.FPDIV_ACTIVE",
"SampleAfterValue": "1000003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts all microcode FP assists.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc1",
"EventName": "ASSISTS.FP",
"PublicDescription": "Counts all microcode Floating Point assists.",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "ASSISTS.SSE_AVX_MIX",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc1",
"EventName": "ASSISTS.SSE_AVX_MIX",
"SampleAfterValue": "1000003",
"UMask": "0x10"
},
{
"BriefDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0]",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xb3",
"EventName": "FP_ARITH_DISPATCHED.PORT_0",
"SampleAfterValue": "2000003",
"UMask": "0x1"
},
{
"BriefDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1]",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xb3",
"EventName": "FP_ARITH_DISPATCHED.PORT_1",
"SampleAfterValue": "2000003",
"UMask": "0x2"
},
{
"BriefDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2]",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xb3",
"EventName": "FP_ARITH_DISPATCHED.PORT_5",
"SampleAfterValue": "2000003",
"UMask": "0x4"
},
{
"BriefDescription": "FP_ARITH_DISPATCHED.V0 [This event is alias to FP_ARITH_DISPATCHED.PORT_0]",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xb3",
"EventName": "FP_ARITH_DISPATCHED.V0",
"SampleAfterValue": "2000003",
"UMask": "0x1"
},
{
"BriefDescription": "FP_ARITH_DISPATCHED.V1 [This event is alias to FP_ARITH_DISPATCHED.PORT_1]",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xb3",
"EventName": "FP_ARITH_DISPATCHED.V1",
"SampleAfterValue": "2000003",
"UMask": "0x2"
},
{
"BriefDescription": "FP_ARITH_DISPATCHED.V2 [This event is alias to FP_ARITH_DISPATCHED.PORT_5]",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xb3",
"EventName": "FP_ARITH_DISPATCHED.V2",
"SampleAfterValue": "2000003",
"UMask": "0x4"
},
{
"BriefDescription": "Counts number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE",
"PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "100003",
"UMask": "0x4"
},
{
"BriefDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE",
"PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "100003",
"UMask": "0x8"
},
{
"BriefDescription": "Counts number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE",
"PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "100003",
"UMask": "0x10"
},
{
"BriefDescription": "Counts number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE",
"PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "100003",
"UMask": "0x20"
},
{
"BriefDescription": "Number of SSE/AVX computational 128-bit packed single and 256-bit packed double precision FP instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, 1 for each element. Applies to SSE* and AVX* packed single precision and packed double precision FP instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB count twice as they perform 2 calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.4_FLOPS",
"PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "100003",
"UMask": "0x18"
},
{
"BriefDescription": "Counts number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE",
"PublicDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "100003",
"UMask": "0x40"
},
{
"BriefDescription": "Counts number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE",
"PublicDescription": "Number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "100003",
"UMask": "0x80"
},
{
"BriefDescription": "Number of SSE/AVX computational 256-bit packed single precision and 512-bit packed double precision FP instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, 1 for each element. Applies to SSE* and AVX* packed single precision and double precision FP instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RSQRT14 RCP RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB count twice as they perform 2 calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.8_FLOPS",
"PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision and 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision and double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RSQRT14 RCP RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "100003",
"UMask": "0x60"
},
{
"BriefDescription": "Number of SSE/AVX computational scalar floating-point instructions retired; some instructions will count twice as noted below. Applies to SSE* and AVX* scalar, double and single precision floating-point: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 RANGE SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform multiple calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.SCALAR",
"PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "1000003",
"UMask": "0x3"
},
{
"BriefDescription": "Counts number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.SCALAR_DOUBLE",
"PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.SCALAR_SINGLE",
"PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "Number of any Vector retired FP arithmetic instructions",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc7",
"EventName": "FP_ARITH_INST_RETIRED.VECTOR",
"PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.",
"SampleAfterValue": "1000003",
"UMask": "0xfc"
},
{
"BriefDescription": "FP_ARITH_INST_RETIRED2.128B_PACKED_HALF",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xcf",
"EventName": "FP_ARITH_INST_RETIRED2.128B_PACKED_HALF",
"SampleAfterValue": "100003",
"UMask": "0x4"
},
{
"BriefDescription": "FP_ARITH_INST_RETIRED2.256B_PACKED_HALF",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xcf",
"EventName": "FP_ARITH_INST_RETIRED2.256B_PACKED_HALF",
"SampleAfterValue": "100003",
"UMask": "0x8"
},
{
"BriefDescription": "FP_ARITH_INST_RETIRED2.512B_PACKED_HALF",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xcf",
"EventName": "FP_ARITH_INST_RETIRED2.512B_PACKED_HALF",
"SampleAfterValue": "100003",
"UMask": "0x10"
},
{
"BriefDescription": "FP_ARITH_INST_RETIRED2.COMPLEX_SCALAR_HALF",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xcf",
"EventName": "FP_ARITH_INST_RETIRED2.COMPLEX_SCALAR_HALF",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "Number of all Scalar Half-Precision FP arithmetic instructions(1) retired - regular and complex.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xcf",
"EventName": "FP_ARITH_INST_RETIRED2.SCALAR",
"PublicDescription": "FP_ARITH_INST_RETIRED2.SCALAR",
"SampleAfterValue": "100003",
"UMask": "0x3"
},
{
"BriefDescription": "FP_ARITH_INST_RETIRED2.SCALAR_HALF",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xcf",
"EventName": "FP_ARITH_INST_RETIRED2.SCALAR_HALF",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Number of all Vector (also called packed) Half-Precision FP arithmetic instructions(1) retired.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xcf",
"EventName": "FP_ARITH_INST_RETIRED2.VECTOR",
"PublicDescription": "FP_ARITH_INST_RETIRED2.VECTOR",
"SampleAfterValue": "100003",
"UMask": "0x1c"
}
]
@@ -0,0 +1,476 @@
[
{
"BriefDescription": "Clears due to Unknown Branches.",
"Counter": "0,1,2,3",
"EventCode": "0x60",
"EventName": "BACLEARS.ANY",
"PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore.",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Stalls caused by changing prefix length of the instruction.",
"Counter": "0,1,2,3",
"EventCode": "0x87",
"EventName": "DECODE.LCP",
"PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk.",
"SampleAfterValue": "500009",
"UMask": "0x1"
},
{
"BriefDescription": "Cycles the Microcode Sequencer is busy.",
"Counter": "0,1,2,3",
"EventCode": "0x87",
"EventName": "DECODE.MS_BUSY",
"SampleAfterValue": "500009",
"UMask": "0x2"
},
{
"BriefDescription": "DSB-to-MITE switch true penalty cycles.",
"Counter": "0,1,2,3",
"EventCode": "0x61",
"EventName": "DSB2MITE_SWITCHES.PENALTY_CYCLES",
"PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE.",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "Retired ANT branches",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.ANY_ANT",
"MSRIndex": "0x3F7",
"MSRValue": "0x9",
"PublicDescription": "Always Not Taken (ANT) conditional retired branches (no BTB entry and not mispredicted) Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired Instructions who experienced DSB miss.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.ANY_DSB_MISS",
"MSRIndex": "0x3F7",
"MSRValue": "0x1",
"PublicDescription": "Counts retired Instructions that experienced DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Available PDIST counters: 0",
"RetirementLatencyMax": "65535",
"RetirementLatencyMean": "2.46",
"RetirementLatencyMin": "0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired Instructions who experienced a critical DSB miss.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.DSB_MISS",
"MSRIndex": "0x3F7",
"MSRValue": "0x11",
"PublicDescription": "Number of retired Instructions that experienced a critical DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Critical means stalls were exposed to the back-end as a result of the DSB miss. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired Instructions who experienced iTLB true miss.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.ITLB_MISS",
"MSRIndex": "0x3F7",
"MSRValue": "0x14",
"PublicDescription": "Counts retired Instructions that experienced iTLB (Instruction TLB) true miss. Available PDIST counters: 0",
"RetirementLatencyMax": "980",
"RetirementLatencyMean": "41.96",
"RetirementLatencyMin": "0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired Instructions who experienced Instruction L1 Cache true miss.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.L1I_MISS",
"MSRIndex": "0x3F7",
"MSRValue": "0x12",
"PublicDescription": "Counts retired Instructions who experienced Instruction L1 Cache true miss. Available PDIST counters: 0",
"RetirementLatencyMax": "1785",
"RetirementLatencyMean": "9.83",
"RetirementLatencyMin": "0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired Instructions who experienced Instruction L2 Cache true miss.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.L2_MISS",
"MSRIndex": "0x3F7",
"MSRValue": "0x13",
"PublicDescription": "Counts retired Instructions who experienced Instruction L2 Cache true miss. Available PDIST counters: 0",
"RetirementLatencyMax": "2854",
"RetirementLatencyMean": "137.41",
"RetirementLatencyMin": "0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions after front-end starvation of at least 1 cycle",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_1",
"MSRIndex": "0x3F7",
"MSRValue": "0x600106",
"PublicDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of at least 1 cycle which was not interrupted by a back-end stall. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_128",
"MSRIndex": "0x3F7",
"MSRValue": "0x608006",
"PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 16 cycles which was not interrupted by a back-end stall.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_16",
"MSRIndex": "0x3F7",
"MSRValue": "0x601006",
"PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 16 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions after front-end starvation of at least 2 cycles",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_2",
"MSRIndex": "0x3F7",
"MSRValue": "0x600206",
"PublicDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of at least 2 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_256",
"MSRIndex": "0x3F7",
"MSRValue": "0x610006",
"PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions that are fetched after an interval where the front-end had at least 1 bubble-slot for a period of 2 cycles which was not interrupted by a back-end stall.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_2_BUBBLES_GE_1",
"MSRIndex": "0x3F7",
"MSRValue": "0x100206",
"PublicDescription": "Counts retired instructions that are delivered to the back-end after the front-end had at least 1 bubble-slot for a period of 2 cycles. A bubble-slot is an empty issue-pipeline slot while there was no RAT stall. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 32 cycles which was not interrupted by a back-end stall.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_32",
"MSRIndex": "0x3F7",
"MSRValue": "0x602006",
"PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 32 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_4",
"MSRIndex": "0x3F7",
"MSRValue": "0x600406",
"PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_512",
"MSRIndex": "0x3F7",
"MSRValue": "0x620006",
"PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_64",
"MSRIndex": "0x3F7",
"MSRValue": "0x604006",
"PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 8 cycles which was not interrupted by a back-end stall.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATENCY_GE_8",
"MSRIndex": "0x3F7",
"MSRValue": "0x600806",
"PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 8 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "I-Cache miss too close to Code Prefetch Instruction",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.LATE_SWPF",
"MSRIndex": "0x3F7",
"MSRValue": "0xA",
"PublicDescription": "Number of Instruction Cache demand miss in shadow of an on-going i-fetch cache-line triggered by PREFETCHIT0/1 instructions Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Mispredicted Retired ANT branches",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.MISP_ANT",
"MSRIndex": "0x3F7",
"MSRValue": "0x9",
"PublicDescription": "ANT retired branches that got just mispredicted Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x2"
},
{
"BriefDescription": "FRONTEND_RETIRED.MS_FLOWS",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.MS_FLOWS",
"MSRIndex": "0x3F7",
"MSRValue": "0x8",
"PublicDescription": "FRONTEND_RETIRED.MS_FLOWS Available PDIST counters: 0",
"RetirementLatencyMax": "65535",
"RetirementLatencyMean": "77.14",
"RetirementLatencyMin": "0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Retired Instructions who experienced STLB (2nd level TLB) true miss.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.STLB_MISS",
"MSRIndex": "0x3F7",
"MSRValue": "0x15",
"PublicDescription": "Counts retired Instructions that experienced STLB (2nd level TLB) true miss. Available PDIST counters: 0",
"RetirementLatencyMax": "754",
"RetirementLatencyMean": "206.85",
"RetirementLatencyMin": "0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "FRONTEND_RETIRED.UNKNOWN_BRANCH",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc6",
"EventName": "FRONTEND_RETIRED.UNKNOWN_BRANCH",
"MSRIndex": "0x3F7",
"MSRValue": "0x17",
"PublicDescription": "FRONTEND_RETIRED.UNKNOWN_BRANCH Available PDIST counters: 0",
"RetirementLatencyMax": "532",
"RetirementLatencyMean": "3.85",
"RetirementLatencyMin": "0",
"SampleAfterValue": "100007",
"UMask": "0x3"
},
{
"BriefDescription": "Cycles where a code fetch is stalled due to L1 instruction cache miss.",
"Counter": "0,1,2,3",
"EventCode": "0x80",
"EventName": "ICACHE_DATA.STALLS",
"PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity.",
"SampleAfterValue": "500009",
"UMask": "0x4"
},
{
"BriefDescription": "ICACHE_DATA.STALL_PERIODS",
"Counter": "0,1,2,3",
"CounterMask": "1",
"EdgeDetect": "1",
"EventCode": "0x80",
"EventName": "ICACHE_DATA.STALL_PERIODS",
"SampleAfterValue": "500009",
"UMask": "0x4"
},
{
"BriefDescription": "Cycles where a code fetch is stalled due to L1 instruction cache tag miss.",
"Counter": "0,1,2,3",
"EventCode": "0x83",
"EventName": "ICACHE_TAG.STALLS",
"PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss.",
"SampleAfterValue": "200003",
"UMask": "0x4"
},
{
"BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering any Uop",
"Counter": "0,1,2,3",
"CounterMask": "1",
"EventCode": "0x79",
"EventName": "IDQ.DSB_CYCLES_ANY",
"PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.",
"SampleAfterValue": "2000003",
"UMask": "0x8"
},
{
"BriefDescription": "Cycles DSB is delivering optimal number of Uops",
"Counter": "0,1,2,3",
"CounterMask": "6",
"EventCode": "0x79",
"EventName": "IDQ.DSB_CYCLES_OK",
"PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.",
"SampleAfterValue": "2000003",
"UMask": "0x8"
},
{
"BriefDescription": "Uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path",
"Counter": "0,1,2,3",
"EventCode": "0x79",
"EventName": "IDQ.DSB_UOPS",
"PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.",
"SampleAfterValue": "2000003",
"UMask": "0x8"
},
{
"BriefDescription": "Cycles MITE is delivering any Uop",
"Counter": "0,1,2,3",
"CounterMask": "1",
"EventCode": "0x79",
"EventName": "IDQ.MITE_CYCLES_ANY",
"PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).",
"SampleAfterValue": "2000003",
"UMask": "0x4"
},
{
"BriefDescription": "Cycles MITE is delivering optimal number of Uops",
"Counter": "0,1,2,3",
"CounterMask": "6",
"EventCode": "0x79",
"EventName": "IDQ.MITE_CYCLES_OK",
"PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).",
"SampleAfterValue": "2000003",
"UMask": "0x4"
},
{
"BriefDescription": "Uops delivered to Instruction Decode Queue (IDQ) from MITE path",
"Counter": "0,1,2,3",
"EventCode": "0x79",
"EventName": "IDQ.MITE_UOPS",
"PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB).",
"SampleAfterValue": "2000003",
"UMask": "0x4"
},
{
"BriefDescription": "Cycles when uops are being delivered to IDQ while MS is busy",
"Counter": "0,1,2,3",
"CounterMask": "1",
"EventCode": "0x79",
"EventName": "IDQ.MS_CYCLES_ANY",
"PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE.",
"SampleAfterValue": "2000003",
"UMask": "0x20"
},
{
"BriefDescription": "Number of switches from DSB or MITE to the MS",
"Counter": "0,1,2,3",
"CounterMask": "1",
"EdgeDetect": "1",
"EventCode": "0x79",
"EventName": "IDQ.MS_SWITCHES",
"PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer.",
"SampleAfterValue": "100003",
"UMask": "0x20"
},
{
"BriefDescription": "Uops initiated by MITE or Decode Stream Buffer (DSB) and delivered to Instruction Decode Queue (IDQ) while Microcode Sequencer (MS) is busy",
"Counter": "0,1,2,3",
"EventCode": "0x79",
"EventName": "IDQ.MS_UOPS",
"PublicDescription": "Counts the number of uops initiated by MITE or Decode Stream Buffer (DSB) and delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Counting includes uops that may 'bypass' the IDQ.",
"SampleAfterValue": "1000003",
"UMask": "0x20"
},
{
"BriefDescription": "This event counts a subset of the Topdown Slots event that when no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0x9c",
"EventName": "IDQ_BUBBLES.CORE",
"PublicDescription": "This event counts a subset of the Topdown Slots event that when no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations. The count may be distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Frontend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.",
"SampleAfterValue": "1000003",
"UMask": "0x1"
},
{
"BriefDescription": "Cycles when no uops are not delivered by the IDQ when backend of the machine is not stalled [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE]",
"Counter": "0,1,2,3,4,5,6,7",
"CounterMask": "6",
"EventCode": "0x9c",
"EventName": "IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE",
"PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE]",
"SampleAfterValue": "1000003",
"UMask": "0x1"
},
{
"BriefDescription": "Cycles when optimal number of uops was delivered to the back-end when the back-end is not stalled [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK]",
"Counter": "0,1,2,3,4,5,6,7",
"CounterMask": "1",
"EventCode": "0x9c",
"EventName": "IDQ_BUBBLES.CYCLES_FE_WAS_OK",
"Invert": "1",
"PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK]",
"SampleAfterValue": "1000003",
"UMask": "0x1"
},
{
"BriefDescription": "Uops not delivered by IDQ when backend of the machine is not stalled",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0x9c",
"EventName": "IDQ_UOPS_NOT_DELIVERED.CORE",
"PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle.",
"SampleAfterValue": "1000003",
"UMask": "0x1"
},
{
"BriefDescription": "Cycles when no uops are not delivered by the IDQ when backend of the machine is not stalled [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE]",
"Counter": "0,1,2,3,4,5,6,7",
"CounterMask": "6",
"EventCode": "0x9c",
"EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE",
"PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE]",
"SampleAfterValue": "1000003",
"UMask": "0x1"
},
{
"BriefDescription": "Cycles when optimal number of uops was delivered to the back-end when the back-end is not stalled [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK]",
"Counter": "0,1,2,3,4,5,6,7",
"CounterMask": "1",
"EventCode": "0x9c",
"EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK",
"Invert": "1",
"PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK]",
"SampleAfterValue": "1000003",
"UMask": "0x1"
}
]
@@ -0,0 +1,523 @@
[
{
"BriefDescription": "Cycles while L3 cache miss demand load is outstanding.",
"Counter": "0,1,2,3",
"CounterMask": "2",
"EventCode": "0xa3",
"EventName": "CYCLE_ACTIVITY.CYCLES_L3_MISS",
"SampleAfterValue": "1000003",
"UMask": "0x2"
},
{
"BriefDescription": "Execution stalls while L3 cache miss demand load is outstanding.",
"Counter": "0,1,2,3",
"CounterMask": "6",
"EventCode": "0xa3",
"EventName": "CYCLE_ACTIVITY.STALLS_L3_MISS",
"SampleAfterValue": "1000003",
"UMask": "0x6"
},
{
"BriefDescription": "Number of machine clears due to memory ordering conflicts.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc3",
"EventName": "MACHINE_CLEARS.MEMORY_ORDERING",
"PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "Cycles while L1 cache miss demand load is outstanding.",
"Counter": "0,1,2,3",
"CounterMask": "2",
"EventCode": "0x47",
"EventName": "MEMORY_ACTIVITY.CYCLES_L1D_MISS",
"SampleAfterValue": "1000003",
"UMask": "0x2"
},
{
"BriefDescription": "Execution stalls while L1 cache miss demand load is outstanding.",
"Counter": "0,1,2,3",
"CounterMask": "3",
"EventCode": "0x47",
"EventName": "MEMORY_ACTIVITY.STALLS_L1D_MISS",
"SampleAfterValue": "1000003",
"UMask": "0x3"
},
{
"BriefDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding.",
"Counter": "0,1,2,3",
"CounterMask": "5",
"EventCode": "0x47",
"EventName": "MEMORY_ACTIVITY.STALLS_L2_MISS",
"PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).",
"SampleAfterValue": "1000003",
"UMask": "0x5"
},
{
"BriefDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding.",
"Counter": "0,1,2,3",
"CounterMask": "9",
"EventCode": "0x47",
"EventName": "MEMORY_ACTIVITY.STALLS_L3_MISS",
"PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).",
"SampleAfterValue": "1000003",
"UMask": "0x9"
},
{
"BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles.",
"Counter": "1,2,3,4,5,6,7",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_1024",
"MSRIndex": "0x3F6",
"MSRValue": "0x400",
"PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0",
"SampleAfterValue": "53",
"UMask": "0x1"
},
{
"BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles.",
"Counter": "1,2,3,4,5,6,7",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_128",
"MSRIndex": "0x3F6",
"MSRValue": "0x80",
"PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0",
"SampleAfterValue": "1009",
"UMask": "0x1"
},
{
"BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles.",
"Counter": "1,2,3,4,5,6,7",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_16",
"MSRIndex": "0x3F6",
"MSRValue": "0x10",
"PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0",
"SampleAfterValue": "20011",
"UMask": "0x1"
},
{
"BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles.",
"Counter": "1,2,3,4,5,6,7",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_2048",
"MSRIndex": "0x3F6",
"MSRValue": "0x800",
"PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0",
"SampleAfterValue": "23",
"UMask": "0x1"
},
{
"BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles.",
"Counter": "1,2,3,4,5,6,7",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_256",
"MSRIndex": "0x3F6",
"MSRValue": "0x100",
"PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0",
"SampleAfterValue": "503",
"UMask": "0x1"
},
{
"BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles.",
"Counter": "1,2,3,4,5,6,7",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_32",
"MSRIndex": "0x3F6",
"MSRValue": "0x20",
"PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0",
"SampleAfterValue": "100007",
"UMask": "0x1"
},
{
"BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles.",
"Counter": "1,2,3,4,5,6,7",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_4",
"MSRIndex": "0x3F6",
"MSRValue": "0x4",
"PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles.",
"Counter": "1,2,3,4,5,6,7",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_512",
"MSRIndex": "0x3F6",
"MSRValue": "0x200",
"PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0",
"SampleAfterValue": "101",
"UMask": "0x1"
},
{
"BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles.",
"Counter": "1,2,3,4,5,6,7",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_64",
"MSRIndex": "0x3F6",
"MSRValue": "0x40",
"PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0",
"SampleAfterValue": "2003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles.",
"Counter": "1,2,3,4,5,6,7",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_8",
"MSRIndex": "0x3F6",
"MSRValue": "0x8",
"PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0",
"SampleAfterValue": "50021",
"UMask": "0x1"
},
{
"BriefDescription": "Retired memory store access operations. A PDist event for PEBS Store Latency Facility.",
"Counter": "0",
"Data_LA": "1",
"EventCode": "0xcd",
"EventName": "MEM_TRANS_RETIRED.STORE_SAMPLE",
"PublicDescription": "Counts Retired memory accesses with at least 1 store operation. This PEBS event is the precisely-distributed (PDist) trigger covering all stores uops for sampling by the PEBS Store Latency Facility. The facility is described in Intel SDM Volume 3 section 19.9.8 Available PDIST counters: 0",
"SampleAfterValue": "1000003",
"UMask": "0x2"
},
{
"BriefDescription": "Counts demand instruction fetches and L1 instruction cache prefetches that were supplied by DRAM.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.DEMAND_CODE_RD.DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x73C000004",
"PublicDescription": "Counts demand instruction fetches and L1 instruction cache prefetches that were supplied by DRAM. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts demand instruction fetches and L1 instruction cache prefetches that were not supplied by the local socket's L1, L2, or L3 caches.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.DEMAND_CODE_RD.L3_MISS",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x3FBFC00004",
"PublicDescription": "Counts demand instruction fetches and L1 instruction cache prefetches that were not supplied by the local socket's L1, L2, or L3 caches. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts demand instruction fetches and L1 instruction cache prefetches that were supplied by DRAM attached to this socket, unless in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts only those DRAM accesses that are controlled by the close SNC Cluster.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.DEMAND_CODE_RD.LOCAL_DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x104000004",
"PublicDescription": "Counts demand instruction fetches and L1 instruction cache prefetches that were supplied by DRAM attached to this socket, unless in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts only those DRAM accesses that are controlled by the close SNC Cluster. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts demand data reads that were supplied by DRAM.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.DEMAND_DATA_RD.DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x73C000001",
"PublicDescription": "Counts demand data reads that were supplied by DRAM. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts demand data reads that were not supplied by the local socket's L1, L2, or L3 caches.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.DEMAND_DATA_RD.L3_MISS",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x3FBFC00001",
"PublicDescription": "Counts demand data reads that were not supplied by the local socket's L1, L2, or L3 caches. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts demand data reads that were supplied by DRAM attached to this socket, unless in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts only those DRAM accesses that are controlled by the close SNC Cluster.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.DEMAND_DATA_RD.LOCAL_DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x104000001",
"PublicDescription": "Counts demand data reads that were supplied by DRAM attached to this socket, unless in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts only those DRAM accesses that are controlled by the close SNC Cluster. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts demand data reads that were supplied by DRAM attached to another socket.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.DEMAND_DATA_RD.REMOTE_DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x730000001",
"PublicDescription": "Counts demand data reads that were supplied by DRAM attached to another socket. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by DRAM.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.DEMAND_RFO.DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x73C000002",
"PublicDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by DRAM. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were not supplied by the local socket's L1, L2, or L3 caches.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.DEMAND_RFO.L3_MISS",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x3F3FC00002",
"PublicDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were not supplied by the local socket's L1, L2, or L3 caches. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by DRAM attached to this socket, unless in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts only those DRAM accesses that are controlled by the close SNC Cluster.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.DEMAND_RFO.LOCAL_DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x104000002",
"PublicDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by DRAM attached to this socket, unless in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts only those DRAM accesses that are controlled by the close SNC Cluster. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by DRAM.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.READS_TO_CORE.DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x73C004477",
"PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by DRAM. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were not supplied by the local socket's L1, L2, or L3 caches.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.READS_TO_CORE.L3_MISS",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x3F3FC04477",
"PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were not supplied by the local socket's L1, L2, or L3 caches. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were not supplied by the local socket's L1, L2, or L3 caches and the cacheline is homed locally.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.READS_TO_CORE.L3_MISS_LOCAL",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x3F04C04477",
"PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were not supplied by the local socket's L1, L2, or L3 caches and the cacheline is homed locally. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that missed the L3 Cache and were supplied by the local socket (DRAM or PMM), whether or not in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts PMM or DRAM accesses that are controlled by the close or distant SNC Cluster. It does not count misses to the L3 which go to Local CXL Type 2 Memory or Local Non DRAM.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.READS_TO_CORE.L3_MISS_LOCAL_SOCKET",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x70CC04477",
"PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that missed the L3 Cache and were supplied by the local socket (DRAM or PMM), whether or not in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts PMM or DRAM accesses that are controlled by the close or distant SNC Cluster. It does not count misses to the L3 which go to Local CXL Type 2 Memory or Local Non DRAM. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by DRAM attached to this socket, unless in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts only those DRAM accesses that are controlled by the close SNC Cluster.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.READS_TO_CORE.LOCAL_DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x104004477",
"PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by DRAM attached to this socket, unless in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts only those DRAM accesses that are controlled by the close SNC Cluster. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by DRAM attached to this socket, whether or not in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts DRAM accesses that are controlled by the close or distant SNC Cluster.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.READS_TO_CORE.LOCAL_SOCKET_DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x70C004477",
"PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by DRAM attached to this socket, whether or not in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts DRAM accesses that are controlled by the close or distant SNC Cluster. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by DRAM attached to another socket.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.READS_TO_CORE.REMOTE_DRAM",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x730004477",
"PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by DRAM attached to another socket. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by DRAM or PMM attached to another socket.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.READS_TO_CORE.REMOTE_MEMORY",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x733004477",
"PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by DRAM or PMM attached to another socket. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts Demand RFOs, ItoM's, PREFECTHW's, Hardware RFO Prefetches to the L1/L2 and Streaming stores that likely resulted in a store to Memory (DRAM or PMM)",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.WRITE_ESTIMATE.MEMORY",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0xFBFF80822",
"PublicDescription": "Counts Demand RFOs, ItoM's, PREFECTHW's, Hardware RFO Prefetches to the L1/L2 and Streaming stores that likely resulted in a store to Memory (DRAM or PMM) Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Counts demand data read requests that miss the L3 cache.",
"Counter": "0,1,2,3",
"EventCode": "0x21",
"EventName": "OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD",
"SampleAfterValue": "100003",
"UMask": "0x10"
},
{
"BriefDescription": "Cycles where data return is pending for a Demand Data Read request who miss L3 cache.",
"Counter": "0,1,2,3",
"CounterMask": "1",
"EventCode": "0x20",
"EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_L3_MISS_DEMAND_DATA_RD",
"PublicDescription": "Cycles with at least 1 Demand Data Read requests who miss L3 cache in the superQ.",
"SampleAfterValue": "1000003",
"UMask": "0x10"
},
{
"BriefDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache.",
"Counter": "0,1,2,3",
"EventCode": "0x20",
"EventName": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD",
"PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache.",
"SampleAfterValue": "2000003",
"UMask": "0x10"
},
{
"BriefDescription": "Number of times an RTM execution aborted.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc9",
"EventName": "RTM_RETIRED.ABORTED",
"PublicDescription": "Counts the number of times RTM abort was triggered. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x4"
},
{
"BriefDescription": "Number of times an RTM execution aborted due to none of the previous 3 categories (e.g. interrupt)",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc9",
"EventName": "RTM_RETIRED.ABORTED_EVENTS",
"PublicDescription": "Counts the number of times an RTM execution aborted due to none of the previous 3 categories (e.g. interrupt).",
"SampleAfterValue": "100003",
"UMask": "0x80"
},
{
"BriefDescription": "Number of times an RTM execution aborted due to various memory events (e.g. read/write capacity and conflicts)",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc9",
"EventName": "RTM_RETIRED.ABORTED_MEM",
"PublicDescription": "Counts the number of times an RTM execution aborted due to various memory events (e.g. read/write capacity and conflicts).",
"SampleAfterValue": "100003",
"UMask": "0x8"
},
{
"BriefDescription": "Number of times an RTM execution aborted due to incompatible memory type",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc9",
"EventName": "RTM_RETIRED.ABORTED_MEMTYPE",
"PublicDescription": "Counts the number of times an RTM execution aborted due to incompatible memory type.",
"SampleAfterValue": "100003",
"UMask": "0x40"
},
{
"BriefDescription": "Number of times an RTM execution aborted due to HLE-unfriendly instructions",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc9",
"EventName": "RTM_RETIRED.ABORTED_UNFRIENDLY",
"PublicDescription": "Counts the number of times an RTM execution aborted due to HLE-unfriendly instructions.",
"SampleAfterValue": "100003",
"UMask": "0x20"
},
{
"BriefDescription": "Number of times an RTM execution successfully committed",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc9",
"EventName": "RTM_RETIRED.COMMIT",
"PublicDescription": "Counts the number of times RTM commit succeeded.",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "Number of times an RTM execution started.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc9",
"EventName": "RTM_RETIRED.START",
"PublicDescription": "Counts the number of times we entered an RTM region. Does not count nested transactions.",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Speculatively counts the number of TSX aborts due to a data capacity limitation for transactional reads",
"Counter": "0,1,2,3",
"EventCode": "0x54",
"EventName": "TX_MEM.ABORT_CAPACITY_READ",
"PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional reads",
"SampleAfterValue": "100003",
"UMask": "0x80"
},
{
"BriefDescription": "Speculatively counts the number of TSX aborts due to a data capacity limitation for transactional writes.",
"Counter": "0,1,2,3",
"EventCode": "0x54",
"EventName": "TX_MEM.ABORT_CAPACITY_WRITE",
"PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional writes.",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "Number of times a transactional abort was signaled due to a data conflict on a transactionally accessed address",
"Counter": "0,1,2,3",
"EventCode": "0x54",
"EventName": "TX_MEM.ABORT_CONFLICT",
"PublicDescription": "Counts the number of times a TSX line had a cache conflict.",
"SampleAfterValue": "100003",
"UMask": "0x1"
}
]
@@ -0,0 +1,65 @@
[
{
"BriefDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events. the event also counts for Machine Ordering count.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc1",
"EventName": "ASSISTS.HARDWARE",
"PublicDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events. This includes, but not limited to, assists at EXE or MEM uop writeback like AVX* load/store/gather/scatter (non-FP GSSE-assist ) , assists generated by ROB like PEBS and RTIT, Uncore trap, RAR (Remote Action Request) and CET (Control flow Enforcement Technology) assists. the event also counts for Machine Ordering count.",
"SampleAfterValue": "100003",
"UMask": "0x4"
},
{
"BriefDescription": "ASSISTS.PAGE_FAULT",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xc1",
"EventName": "ASSISTS.PAGE_FAULT",
"SampleAfterValue": "1000003",
"UMask": "0x8"
},
{
"BriefDescription": "HW_INTERRUPTS.MASKED",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xcb",
"EventName": "HW_INTERRUPTS.MASKED",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "HW_INTERRUPTS.PENDING_AND_MASKED",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xcb",
"EventName": "HW_INTERRUPTS.PENDING_AND_MASKED",
"SampleAfterValue": "100003",
"UMask": "0x4"
},
{
"BriefDescription": "Number of hardware interrupts received by the processor.",
"Counter": "0,1,2,3,4,5,6,7",
"EventCode": "0xcb",
"EventName": "HW_INTERRUPTS.RECEIVED",
"PublicDescription": "Counts the number of hardware interruptions received by the processor.",
"SampleAfterValue": "203",
"UMask": "0x1"
},
{
"BriefDescription": "Counts streaming stores that have any type of response.",
"Counter": "0,1,2,3",
"EventCode": "0x2A,0x2B",
"EventName": "OCR.STREAMING_WR.ANY_RESPONSE",
"MSRIndex": "0x1a6,0x1a7",
"MSRValue": "0x10800",
"PublicDescription": "Counts streaming stores that have any type of response. Available PDIST counters: 0",
"SampleAfterValue": "100003",
"UMask": "0x1"
},
{
"BriefDescription": "Cycles the uncore cannot take further requests",
"Counter": "0,1,2,3",
"CounterMask": "1",
"EventCode": "0x2d",
"EventName": "XQ.FULL_CYCLES",
"PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache).",
"SampleAfterValue": "1000003",
"UMask": "0x1"
}
]
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,29 @@
[
{
"BriefDescription": "B2CXL Clockticks",
"Counter": "0,1,2,3",
"EventCode": "0x01",
"EventName": "UNC_B2CXL_CLOCKTICKS",
"PerPkg": "1",
"PortMask": "0x000",
"Unit": "B2CXL"
},
{
"BriefDescription": "Number of Allocation to Mem Data Packing buffer",
"Counter": "4,5,6,7",
"EventCode": "0x41",
"EventName": "UNC_CXLCM_RxC_PACK_BUF_INSERTS.MEM_DATA",
"PerPkg": "1",
"UMask": "0x10",
"Unit": "CXLCM"
},
{
"BriefDescription": "Number of Allocation to M2S Data AGF",
"Counter": "0,1,2,3",
"EventCode": "0x02",
"EventName": "UNC_CXLDP_TxC_AGF_INSERTS.M2S_DATA",
"PerPkg": "1",
"UMask": "0x20",
"Unit": "CXLDP"
}
]
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,890 @@
[
{
"BriefDescription": "DRAM Activate Count : Counts the number of DRAM Activate commands sent on this channel. Activate commands are issued to open up a page on the DRAM devices so that it can be read or written to with a CAS. One can calculate the number of Page Misses by subtracting the number of Page Miss precharges from the number of Activates.",
"Counter": "0,1,2,3",
"EventCode": "0x02",
"EventName": "UNC_M_ACT_COUNT.ALL",
"PerPkg": "1",
"UMask": "0xf7",
"Unit": "IMC"
},
{
"BriefDescription": "DRAM Activate Count : Read transaction on Page Empty or Page Miss : Counts the number of DRAM Activate commands sent on this channel. Activate commands are issued to open up a page on the DRAM devices so that it can be read or written to with a CAS. One can calculate the number of Page Misses by subtracting the number of Page Miss precharges from the number of Activates.",
"Counter": "0,1,2,3",
"EventCode": "0x02",
"EventName": "UNC_M_ACT_COUNT.RD",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xf1",
"Unit": "IMC"
},
{
"BriefDescription": "DRAM Activate Count : Underfill Read transaction on Page Empty or Page Miss : Counts the number of DRAM Activate commands sent on this channel. Activate commands are issued to open up a page on the DRAM devices so that it can be read or written to with a CAS. One can calculate the number of Page Misses by subtracting the number of Page Miss precharges from the number of Activates.",
"Counter": "0,1,2,3",
"EventCode": "0x02",
"EventName": "UNC_M_ACT_COUNT.UFILL",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xf4",
"Unit": "IMC"
},
{
"BriefDescription": "DRAM Activate Count : Write transaction on Page Empty or Page Miss : Counts the number of DRAM Activate commands sent on this channel. Activate commands are issued to open up a page on the DRAM devices so that it can be read or written to with a CAS. One can calculate the number of Page Misses by subtracting the number of Page Miss precharges from the number of Activates.",
"Counter": "0,1,2,3",
"EventCode": "0x02",
"EventName": "UNC_M_ACT_COUNT.WR",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xf2",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0, all CAS operations",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.ALL",
"PerPkg": "1",
"UMask": "0xff",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0, all reads",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.RD",
"PerPkg": "1",
"UMask": "0xcf",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0 regular reads",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.RD_NON_UNDERFILL",
"PerPkg": "1",
"UMask": "0xc3",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0 auto-precharge reads",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.RD_PRE_REG",
"PerPkg": "1",
"UMask": "0xc2",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0 auto-precharge underfill reads",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.RD_PRE_UNDERFILL",
"PerPkg": "1",
"UMask": "0xc8",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0 regular reads",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.RD_REG",
"PerPkg": "1",
"UMask": "0xc1",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0 underfill reads",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.RD_UNDERFILL",
"PerPkg": "1",
"UMask": "0xc4",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0 underfill reads",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.RD_UNDERFILL_ALL",
"PerPkg": "1",
"UMask": "0xcc",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0, all writes",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.WR",
"PerPkg": "1",
"UMask": "0xf0",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0 regular writes",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.WR_NONPRE",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xd0",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 0 auto-precharge writes",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_M_CAS_COUNT_SCH0.WR_PRE",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xe0",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1, all CAS operations",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.ALL",
"PerPkg": "1",
"UMask": "0xff",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1, all reads",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.RD",
"PerPkg": "1",
"UMask": "0xcf",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1 regular reads",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.RD_NON_UNDERFILL",
"PerPkg": "1",
"UMask": "0xc3",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1 auto-precharge reads",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.RD_PRE_REG",
"PerPkg": "1",
"UMask": "0xc2",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1 auto-precharge underfill reads",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.RD_PRE_UNDERFILL",
"PerPkg": "1",
"UMask": "0xc8",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1 regular reads",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.RD_REG",
"PerPkg": "1",
"UMask": "0xc1",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1 underfill reads",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.RD_UNDERFILL",
"PerPkg": "1",
"UMask": "0xc4",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1 underfill reads",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.RD_UNDERFILL_ALL",
"PerPkg": "1",
"UMask": "0xcc",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1, all writes",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.WR",
"PerPkg": "1",
"UMask": "0xf0",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1 regular writes",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.WR_NONPRE",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xd0",
"Unit": "IMC"
},
{
"BriefDescription": "CAS count for SubChannel 1 auto-precharge writes",
"Counter": "0,1,2,3",
"EventCode": "0x06",
"EventName": "UNC_M_CAS_COUNT_SCH1.WR_PRE",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xe0",
"Unit": "IMC"
},
{
"BriefDescription": "Number of DRAM DCLK clock cycles while the event is enabled. DCLK is 1/4 of DRAM data rate.",
"Counter": "0,1,2,3",
"EventCode": "0x01",
"EventName": "UNC_M_CLOCKTICKS",
"PerPkg": "1",
"PublicDescription": "DRAM Clockticks",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "Number of DRAM HCLK clock cycles while the event is enabled",
"Counter": "0,1,2,3",
"EventCode": "0x01",
"EventName": "UNC_M_HCLOCKTICKS",
"Experimental": "1",
"PerPkg": "1",
"PublicDescription": "DRAM Clockticks",
"Unit": "IMC"
},
{
"BriefDescription": "PMMNT is sending REF* commands while being in specified Refresh rate",
"Counter": "0,1,2,3",
"EventCode": "0x72",
"EventName": "UNC_M_MNTCMD_REFRATE.REFAB1X",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "PMMNT is sending REF* commands while being in specified Refresh rate",
"Counter": "0,1,2,3",
"EventCode": "0x72",
"EventName": "UNC_M_MNTCMD_REFRATE.REFAB2X",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x4",
"Unit": "IMC"
},
{
"BriefDescription": "PMMNT is sending REF* commands while being in specified Refresh rate",
"Counter": "0,1,2,3",
"EventCode": "0x72",
"EventName": "UNC_M_MNTCMD_REFRATE.REFSB1X",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "PMMNT is sending REF* commands while being in specified Refresh rate",
"Counter": "0,1,2,3",
"EventCode": "0x72",
"EventName": "UNC_M_MNTCMD_REFRATE.REFSB2X",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x8",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles MR4 temp readings forced 2x refresh",
"Counter": "0,1,2,3",
"EventCode": "0xA7",
"EventName": "UNC_M_MR4_2XREF_CYCLES.SCH0_DIMM0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles MR4 temp readings forced 2x refresh",
"Counter": "0,1,2,3",
"EventCode": "0xA7",
"EventName": "UNC_M_MR4_2XREF_CYCLES.SCH0_DIMM1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles MR4 temp readings forced 2x refresh",
"Counter": "0,1,2,3",
"EventCode": "0xA7",
"EventName": "UNC_M_MR4_2XREF_CYCLES.SCH1_DIMM0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x4",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles MR4 temp readings forced 2x refresh",
"Counter": "0,1,2,3",
"EventCode": "0xA7",
"EventName": "UNC_M_MR4_2XREF_CYCLES.SCH1_DIMM1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x8",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles MR4 MRRs was triggered/running",
"Counter": "0,1,2,3",
"EventCode": "0xA6",
"EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH0_DIMM0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles MR4 MRRs was triggered/running",
"Counter": "0,1,2,3",
"EventCode": "0xA6",
"EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH0_DIMM1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles MR4 MRRs was triggered/running",
"Counter": "0,1,2,3",
"EventCode": "0xA6",
"EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH1_DIMM0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x4",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles MR4 MRRs was triggered/running",
"Counter": "0,1,2,3",
"EventCode": "0xA6",
"EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH1_DIMM1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x8",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles a given rank is in Power Down Mode",
"Counter": "0,1,2,3",
"EventCode": "0x47",
"EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles a given rank is in Power Down Mode",
"Counter": "0,1,2,3",
"EventCode": "0x47",
"EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles a given rank is in Power Down Mode",
"Counter": "0,1,2,3",
"EventCode": "0x47",
"EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK2",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x4",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles a given rank is in Power Down Mode",
"Counter": "0,1,2,3",
"EventCode": "0x47",
"EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK3",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x8",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles a given rank is in Power Down Mode",
"Counter": "0,1,2,3",
"EventCode": "0x47",
"EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x10",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles a given rank is in Power Down Mode",
"Counter": "0,1,2,3",
"EventCode": "0x47",
"EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x20",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles a given rank is in Power Down Mode",
"Counter": "0,1,2,3",
"EventCode": "0x47",
"EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK2",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x40",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles a given rank is in Power Down Mode",
"Counter": "0,1,2,3",
"EventCode": "0x47",
"EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK3",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x80",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles a given rank is in Power Down Mode and all pages are closed",
"Counter": "0,1,2,3",
"EventCode": "0x88",
"EventName": "UNC_M_POWER_CHANNEL_PPD_CYCLES",
"Experimental": "1",
"PerPkg": "1",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles Throttling at Critical level on specified DIMM and throttle level is zero.",
"Counter": "0,1,2,3",
"EventCode": "0x89",
"EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES.SLOT0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles Throttling at Critical level on specified DIMM and throttle level is zero.",
"Counter": "0,1,2,3",
"EventCode": "0x89",
"EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES.SLOT1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "UNC_M_POWER_THROTTLE_CYCLES.BW_SLOT0",
"Counter": "0,1,2,3",
"EventCode": "0x46",
"EventName": "UNC_M_POWER_THROTTLE_CYCLES.BW_SLOT0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "UNC_M_POWER_THROTTLE_CYCLES.BW_SLOT1",
"Counter": "0,1,2,3",
"EventCode": "0x46",
"EventName": "UNC_M_POWER_THROTTLE_CYCLES.BW_SLOT1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "MR4 temp reading is throttling",
"Counter": "0,1,2,3",
"EventCode": "0x46",
"EventName": "UNC_M_POWER_THROTTLE_CYCLES.MR4BLKEN",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x8",
"Unit": "IMC"
},
{
"BriefDescription": "RAPL is throttling",
"Counter": "0,1,2,3",
"EventCode": "0x46",
"EventName": "UNC_M_POWER_THROTTLE_CYCLES.RAPLBLK",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x4",
"Unit": "IMC"
},
{
"BriefDescription": "DRAM Precharge commands. : Counts the number of DRAM Precharge commands sent on this channel.",
"Counter": "0,1,2,3",
"EventCode": "0x03",
"EventName": "UNC_M_PRE_COUNT.ALL",
"PerPkg": "1",
"UMask": "0xff",
"Unit": "IMC"
},
{
"BriefDescription": "DRAM Precharge commands. : Precharge due to (?) : Counts the number of DRAM Precharge commands sent on this channel.",
"Counter": "0,1,2,3",
"EventCode": "0x03",
"EventName": "UNC_M_PRE_COUNT.PGT",
"PerPkg": "1",
"UMask": "0xf8",
"Unit": "IMC"
},
{
"BriefDescription": "DRAM Precharge commands. : Counts the number of DRAM Precharge commands sent on this channel.",
"Counter": "0,1,2,3",
"EventCode": "0x03",
"EventName": "UNC_M_PRE_COUNT.RD",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xf1",
"Unit": "IMC"
},
{
"BriefDescription": "DRAM Precharge commands. : Counts the number of DRAM Precharge commands sent on this channel.",
"Counter": "0,1,2,3",
"EventCode": "0x03",
"EventName": "UNC_M_PRE_COUNT.UFILL",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xf4",
"Unit": "IMC"
},
{
"BriefDescription": "DRAM Precharge commands. : Counts the number of DRAM Precharge commands sent on this channel.",
"Counter": "0,1,2,3",
"EventCode": "0x03",
"EventName": "UNC_M_PRE_COUNT.WR",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xf2",
"Unit": "IMC"
},
{
"BriefDescription": "Read buffer inserts on subchannel 0",
"Counter": "0,1,2,3",
"EventCode": "0x17",
"EventName": "UNC_M_RDB_INSERTS.SCH0",
"PerPkg": "1",
"UMask": "0x40",
"Unit": "IMC"
},
{
"BriefDescription": "Read buffer inserts on subchannel 1",
"Counter": "0,1,2,3",
"EventCode": "0x17",
"EventName": "UNC_M_RDB_INSERTS.SCH1",
"PerPkg": "1",
"UMask": "0x80",
"Unit": "IMC"
},
{
"BriefDescription": "Read buffer occupancy on subchannel 0",
"Counter": "0,1,2,3",
"EventCode": "0x1a",
"EventName": "UNC_M_RDB_OCCUPANCY_SCH0",
"PerPkg": "1",
"Unit": "IMC"
},
{
"BriefDescription": "Read buffer occupancy on subchannel 1",
"Counter": "0,1,2,3",
"EventCode": "0x1b",
"EventName": "UNC_M_RDB_OCCUPANCY_SCH1",
"PerPkg": "1",
"Unit": "IMC"
},
{
"BriefDescription": "Read Pending Queue Allocations : Counts the number of allocations into the Read Pending Queue. This queue is used to schedule reads out to the memory controller and to track the requests. Requests allocate into the RPQ soon after they enter the memory controller, and need credits for an entry in this buffer before being sent from the HA to the iMC. They deallocate after the CAS command has been issued to memory. This includes both ISOCH and non-ISOCH requests.",
"Counter": "0,1,2,3",
"EventCode": "0x10",
"EventName": "UNC_M_RPQ_INSERTS.PCH0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x50",
"Unit": "IMC"
},
{
"BriefDescription": "Read Pending Queue Allocations : Counts the number of allocations into the Read Pending Queue. This queue is used to schedule reads out to the memory controller and to track the requests. Requests allocate into the RPQ soon after they enter the memory controller, and need credits for an entry in this buffer before being sent from the HA to the iMC. They deallocate after the CAS command has been issued to memory. This includes both ISOCH and non-ISOCH requests.",
"Counter": "0,1,2,3",
"EventCode": "0x10",
"EventName": "UNC_M_RPQ_INSERTS.PCH1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xa0",
"Unit": "IMC"
},
{
"BriefDescription": "Read Pending Queue inserts for subchannel 0, pseudochannel 0",
"Counter": "0,1,2,3",
"EventCode": "0x10",
"EventName": "UNC_M_RPQ_INSERTS.SCH0_PCH0",
"PerPkg": "1",
"UMask": "0x10",
"Unit": "IMC"
},
{
"BriefDescription": "Read Pending Queue inserts for subchannel 0, pseudochannel 1",
"Counter": "0,1,2,3",
"EventCode": "0x10",
"EventName": "UNC_M_RPQ_INSERTS.SCH0_PCH1",
"PerPkg": "1",
"UMask": "0x20",
"Unit": "IMC"
},
{
"BriefDescription": "Read Pending Queue inserts for subchannel 1, pseudochannel 0",
"Counter": "0,1,2,3",
"EventCode": "0x10",
"EventName": "UNC_M_RPQ_INSERTS.SCH1_PCH0",
"PerPkg": "1",
"UMask": "0x40",
"Unit": "IMC"
},
{
"BriefDescription": "Read Pending Queue inserts for subchannel 1, pseudochannel 1",
"Counter": "0,1,2,3",
"EventCode": "0x10",
"EventName": "UNC_M_RPQ_INSERTS.SCH1_PCH1",
"PerPkg": "1",
"UMask": "0x80",
"Unit": "IMC"
},
{
"BriefDescription": "Read pending queue occupancy for subchannel 0, pseudochannel 0",
"Counter": "0,1,2,3",
"EventCode": "0x80",
"EventName": "UNC_M_RPQ_OCCUPANCY_SCH0_PCH0",
"PerPkg": "1",
"Unit": "IMC"
},
{
"BriefDescription": "Read pending queue occupancy for subchannel 0, pseudochannel 1",
"Counter": "0,1,2,3",
"EventCode": "0x81",
"EventName": "UNC_M_RPQ_OCCUPANCY_SCH0_PCH1",
"PerPkg": "1",
"Unit": "IMC"
},
{
"BriefDescription": "Read pending queue occupancy for subchannel 1, pseudochannel 0",
"Counter": "0,1,2,3",
"EventCode": "0x82",
"EventName": "UNC_M_RPQ_OCCUPANCY_SCH1_PCH0",
"PerPkg": "1",
"Unit": "IMC"
},
{
"BriefDescription": "Read pending queue occupancy for subchannel 1, pseudochannel 1",
"Counter": "0,1,2,3",
"EventCode": "0x83",
"EventName": "UNC_M_RPQ_OCCUPANCY_SCH1_PCH1",
"PerPkg": "1",
"Unit": "IMC"
},
{
"BriefDescription": "subevent0 - # of cycles all ranks were in SR subevent1 - # of times all ranks went into SR subevent2 -# of times ps_sr_active asserted (SRE) subevent3 - # of times ps_sr_active deasserted (SRX) subevent4 - # of times PS-&>Refresh ps_sr_req asserted (SRE) subevent5 - # of times PS-&>Refresh ps_sr_req deasserted (SRX) subevent6 - # of cycles PSCtrlr FSM was in FATAL",
"Counter": "0,1,2,3",
"EventCode": "0x43",
"EventName": "UNC_M_SELF_REFRESH.ENTER_SUCCESS",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles all ranks were in SR",
"Counter": "0,1,2,3",
"EventCode": "0x43",
"EventName": "UNC_M_SELF_REFRESH.ENTER_SUCCESS_CYCLES",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles Throttling at Critical level on specified DIMM",
"Counter": "0,1,2,3",
"EventCode": "0x8e",
"EventName": "UNC_M_THROTTLE_CRIT_CYCLES.SLOT0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles Throttling at Critical level on specified DIMM",
"Counter": "0,1,2,3",
"EventCode": "0x8e",
"EventName": "UNC_M_THROTTLE_CRIT_CYCLES.SLOT1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles Throttling at High level on specified DIMM",
"Counter": "0,1,2,3",
"EventCode": "0x8d",
"EventName": "UNC_M_THROTTLE_HIGH_CYCLES.SLOT0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles Throttling at High level on specified DIMM",
"Counter": "0,1,2,3",
"EventCode": "0x8d",
"EventName": "UNC_M_THROTTLE_HIGH_CYCLES.SLOT1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles Throttling at Normal level on specified DIMM",
"Counter": "0,1,2,3",
"EventCode": "0x8b",
"EventName": "UNC_M_THROTTLE_LOW_CYCLES.SLOT0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles Throttling at Normal level on specified DIMM",
"Counter": "0,1,2,3",
"EventCode": "0x8b",
"EventName": "UNC_M_THROTTLE_LOW_CYCLES.SLOT1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles Throttling at Mid level on specified DIMM",
"Counter": "0,1,2,3",
"EventCode": "0x8c",
"EventName": "UNC_M_THROTTLE_MID_CYCLES.SLOT0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x1",
"Unit": "IMC"
},
{
"BriefDescription": "# of cycles Throttling at Mid level on specified DIMM",
"Counter": "0,1,2,3",
"EventCode": "0x8c",
"EventName": "UNC_M_THROTTLE_MID_CYCLES.SLOT1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x2",
"Unit": "IMC"
},
{
"BriefDescription": "Write Pending Queue Allocations",
"Counter": "0,1,2,3",
"EventCode": "0x22",
"EventName": "UNC_M_WPQ_INSERTS.PCH0",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0x50",
"Unit": "IMC"
},
{
"BriefDescription": "Write Pending Queue Allocations",
"Counter": "0,1,2,3",
"EventCode": "0x22",
"EventName": "UNC_M_WPQ_INSERTS.PCH1",
"Experimental": "1",
"PerPkg": "1",
"UMask": "0xa0",
"Unit": "IMC"
},
{
"BriefDescription": "Write Pending Queue inserts for subchannel 0, pseudochannel 0",
"Counter": "0,1,2,3",
"EventCode": "0x22",
"EventName": "UNC_M_WPQ_INSERTS.SCH0_PCH0",
"PerPkg": "1",
"UMask": "0x10",
"Unit": "IMC"
},
{
"BriefDescription": "Write Pending Queue inserts for subchannel 0, pseudochannel 1",
"Counter": "0,1,2,3",
"EventCode": "0x22",
"EventName": "UNC_M_WPQ_INSERTS.SCH0_PCH1",
"PerPkg": "1",
"UMask": "0x20",
"Unit": "IMC"
},
{
"BriefDescription": "Write Pending Queue inserts for subchannel 1, pseudochannel 0",
"Counter": "0,1,2,3",
"EventCode": "0x22",
"EventName": "UNC_M_WPQ_INSERTS.SCH1_PCH0",
"PerPkg": "1",
"UMask": "0x40",
"Unit": "IMC"
},
{
"BriefDescription": "Write Pending Queue inserts for subchannel 1, pseudochannel 1",
"Counter": "0,1,2,3",
"EventCode": "0x22",
"EventName": "UNC_M_WPQ_INSERTS.SCH1_PCH1",
"PerPkg": "1",
"UMask": "0x80",
"Unit": "IMC"
},
{
"BriefDescription": "Write pending queue occupancy for subchannel 0, pseudochannel 0",
"Counter": "0,1,2,3",
"EventCode": "0x84",
"EventName": "UNC_M_WPQ_OCCUPANCY_SCH0_PCH0",
"PerPkg": "1",
"Unit": "IMC"
},
{
"BriefDescription": "Write pending queue occupancy for subchannel 0, pseudochannel 1",
"Counter": "0,1,2,3",
"EventCode": "0x85",
"EventName": "UNC_M_WPQ_OCCUPANCY_SCH0_PCH1",
"PerPkg": "1",
"Unit": "IMC"
},
{
"BriefDescription": "Write pending queue occupancy for subchannel 1, pseudochannel 0",
"Counter": "0,1,2,3",
"EventCode": "0x86",
"EventName": "UNC_M_WPQ_OCCUPANCY_SCH1_PCH0",
"PerPkg": "1",
"Unit": "IMC"
},
{
"BriefDescription": "Write pending queue occupancy for subchannel 1, pseudochannel 1",
"Counter": "0,1,2,3",
"EventCode": "0x87",
"EventName": "UNC_M_WPQ_OCCUPANCY_SCH1_PCH1",
"PerPkg": "1",
"Unit": "IMC"
}
]
@@ -0,0 +1,109 @@
[
{
"BriefDescription": "PCU Clockticks",
"Counter": "0,1,2,3",
"EventCode": "0x01",
"EventName": "UNC_P_CLOCKTICKS",
"PerPkg": "1",
"PublicDescription": "PCU Clockticks: The PCU runs off a fixed 1 GHz clock. This event counts the number of pclk cycles measured while the counter was enabled. The pclk, like the Memory Controller's dclk, counts at a constant rate making it a good measure of actual wall time.",
"Unit": "PCU"
},
{
"BriefDescription": "Thermal Strongest Upper Limit Cycles",
"Counter": "0,1,2,3",
"EventCode": "0x04",
"EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES",
"Experimental": "1",
"PerPkg": "1",
"PublicDescription": "Thermal Strongest Upper Limit Cycles : Number of cycles any frequency is reduced due to a thermal limit. Count only if throttling is occurring.",
"Unit": "PCU"
},
{
"BriefDescription": "Power Strongest Upper Limit Cycles",
"Counter": "0,1,2,3",
"EventCode": "0x05",
"EventName": "UNC_P_FREQ_MAX_POWER_CYCLES",
"Experimental": "1",
"PerPkg": "1",
"PublicDescription": "Power Strongest Upper Limit Cycles : Counts the number of cycles when power is the upper limit on frequency.",
"Unit": "PCU"
},
{
"BriefDescription": "Cycles spent changing Frequency",
"Counter": "0,1,2,3",
"EventCode": "0x74",
"EventName": "UNC_P_FREQ_TRANS_CYCLES",
"Experimental": "1",
"PerPkg": "1",
"PublicDescription": "Cycles spent changing Frequency : Counts the number of cycles when the system is changing frequency. This can not be filtered by thread ID. One can also use it with the occupancy counter that monitors number of threads in C0 to estimate the performance impact that frequency transitions had on the system.",
"Unit": "PCU"
},
{
"BriefDescription": "Package C State Residency - C2E",
"Counter": "0,1,2,3",
"EventCode": "0x2b",
"EventName": "UNC_P_PKG_RESIDENCY_C2E_CYCLES",
"Experimental": "1",
"PerPkg": "1",
"PublicDescription": "Package C State Residency - C2E : Counts the number of cycles when the package was in C2E. This event can be used in conjunction with edge detect to count C2E entrances (or exits using invert). Residency events do not include transition times.",
"Unit": "PCU"
},
{
"BriefDescription": "Package C State Residency - C6",
"Counter": "0,1,2,3",
"EventCode": "0x2d",
"EventName": "UNC_P_PKG_RESIDENCY_C6_CYCLES",
"Experimental": "1",
"PerPkg": "1",
"PublicDescription": "Package C State Residency - C6 : Counts the number of cycles when the package was in C6. This event can be used in conjunction with edge detect to count C6 entrances (or exits using invert). Residency events do not include transition times.",
"Unit": "PCU"
},
{
"BriefDescription": "Number of cores in C0",
"Counter": "0,1,2,3",
"EventCode": "0x35",
"EventName": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C0",
"PerPkg": "1",
"PublicDescription": "Number of cores in C0 : This is an occupancy event that tracks the number of cores that are in the chosen C-State. It can be used by itself to get the average number of cores in that C-state with thresholding to generate histograms, or with other PCU events and occupancy triggering to capture other details.",
"Unit": "PCU"
},
{
"BriefDescription": "Number of cores in C3",
"Counter": "0,1,2,3",
"EventCode": "0x36",
"EventName": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C3",
"Experimental": "1",
"PerPkg": "1",
"PublicDescription": "Number of cores in C3 : This is an occupancy event that tracks the number of cores that are in the chosen C-State. It can be used by itself to get the average number of cores in that C-state with thresholding to generate histograms, or with other PCU events and occupancy triggering to capture other details.",
"Unit": "PCU"
},
{
"BriefDescription": "Number of cores in C6",
"Counter": "0,1,2,3",
"EventCode": "0x37",
"EventName": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C6",
"PerPkg": "1",
"PublicDescription": "Number of cores in C6 : This is an occupancy event that tracks the number of cores that are in the chosen C-State. It can be used by itself to get the average number of cores in that C-state with thresholding to generate histograms, or with other PCU events and occupancy triggering to capture other details.",
"Unit": "PCU"
},
{
"BriefDescription": "External Prochot",
"Counter": "0,1,2,3",
"EventCode": "0x0a",
"EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES",
"Experimental": "1",
"PerPkg": "1",
"PublicDescription": "External Prochot : Counts the number of cycles that we are in external PROCHOT mode. This mode is triggered when a sensor off the die determines that something off-die (like DRAM) is too hot and must throttle to avoid damaging the chip.",
"Unit": "PCU"
},
{
"BriefDescription": "Internal Prochot",
"Counter": "0,1,2,3",
"EventCode": "0x09",
"EventName": "UNC_P_PROCHOT_INTERNAL_CYCLES",
"Experimental": "1",
"PerPkg": "1",
"PublicDescription": "Internal Prochot : Counts the number of cycles that we are in Internal PROCHOT mode. This mode is triggered when a sensor on the die determines that we are too hot and must throttle to avoid damaging the chip.",
"Unit": "PCU"
}
]
@@ -0,0 +1,185 @@
[
{
"BriefDescription": "Loads that miss the DTLB and hit the STLB.",
"Counter": "0,1,2,3",
"EventCode": "0x12",
"EventName": "DTLB_LOAD_MISSES.STLB_HIT",
"PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB).",
"SampleAfterValue": "100003",
"UMask": "0x20"
},
{
"BriefDescription": "Cycles when at least one PMH is busy with a page walk for a demand load.",
"Counter": "0,1,2,3",
"CounterMask": "1",
"EventCode": "0x12",
"EventName": "DTLB_LOAD_MISSES.WALK_ACTIVE",
"PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load.",
"SampleAfterValue": "100003",
"UMask": "0x10"
},
{
"BriefDescription": "Load miss in all TLB levels causes a page walk that completes. (All page sizes)",
"Counter": "0,1,2,3",
"EventCode": "0x12",
"EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED",
"PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0xe"
},
{
"BriefDescription": "Page walks completed due to a demand data load to a 1G page.",
"Counter": "0,1,2,3",
"EventCode": "0x12",
"EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_1G",
"PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0x8"
},
{
"BriefDescription": "Page walks completed due to a demand data load to a 2M/4M page.",
"Counter": "0,1,2,3",
"EventCode": "0x12",
"EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M",
"PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0x4"
},
{
"BriefDescription": "Page walks completed due to a demand data load to a 4K page.",
"Counter": "0,1,2,3",
"EventCode": "0x12",
"EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K",
"PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "Number of page walks outstanding for a demand load in the PMH each cycle.",
"Counter": "0,1,2,3",
"EventCode": "0x12",
"EventName": "DTLB_LOAD_MISSES.WALK_PENDING",
"PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle.",
"SampleAfterValue": "100003",
"UMask": "0x10"
},
{
"BriefDescription": "Stores that miss the DTLB and hit the STLB.",
"Counter": "0,1,2,3",
"EventCode": "0x13",
"EventName": "DTLB_STORE_MISSES.STLB_HIT",
"PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB).",
"SampleAfterValue": "100003",
"UMask": "0x20"
},
{
"BriefDescription": "Cycles when at least one PMH is busy with a page walk for a store.",
"Counter": "0,1,2,3",
"CounterMask": "1",
"EventCode": "0x13",
"EventName": "DTLB_STORE_MISSES.WALK_ACTIVE",
"PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store.",
"SampleAfterValue": "100003",
"UMask": "0x10"
},
{
"BriefDescription": "Store misses in all TLB levels causes a page walk that completes. (All page sizes)",
"Counter": "0,1,2,3",
"EventCode": "0x13",
"EventName": "DTLB_STORE_MISSES.WALK_COMPLETED",
"PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0xe"
},
{
"BriefDescription": "Page walks completed due to a demand data store to a 1G page.",
"Counter": "0,1,2,3",
"EventCode": "0x13",
"EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_1G",
"PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0x8"
},
{
"BriefDescription": "Page walks completed due to a demand data store to a 2M/4M page.",
"Counter": "0,1,2,3",
"EventCode": "0x13",
"EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M",
"PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0x4"
},
{
"BriefDescription": "Page walks completed due to a demand data store to a 4K page.",
"Counter": "0,1,2,3",
"EventCode": "0x13",
"EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K",
"PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "Number of page walks outstanding for a store in the PMH each cycle.",
"Counter": "0,1,2,3",
"EventCode": "0x13",
"EventName": "DTLB_STORE_MISSES.WALK_PENDING",
"PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle.",
"SampleAfterValue": "100003",
"UMask": "0x10"
},
{
"BriefDescription": "Instruction fetch requests that miss the ITLB and hit the STLB.",
"Counter": "0,1,2,3",
"EventCode": "0x11",
"EventName": "ITLB_MISSES.STLB_HIT",
"PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB).",
"SampleAfterValue": "100003",
"UMask": "0x20"
},
{
"BriefDescription": "Cycles when at least one PMH is busy with a page walk for code (instruction fetch) request.",
"Counter": "0,1,2,3",
"CounterMask": "1",
"EventCode": "0x11",
"EventName": "ITLB_MISSES.WALK_ACTIVE",
"PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request.",
"SampleAfterValue": "100003",
"UMask": "0x10"
},
{
"BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (All page sizes)",
"Counter": "0,1,2,3",
"EventCode": "0x11",
"EventName": "ITLB_MISSES.WALK_COMPLETED",
"PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0xe"
},
{
"BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (2M/4M)",
"Counter": "0,1,2,3",
"EventCode": "0x11",
"EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M",
"PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0x4"
},
{
"BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (4K)",
"Counter": "0,1,2,3",
"EventCode": "0x11",
"EventName": "ITLB_MISSES.WALK_COMPLETED_4K",
"PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.",
"SampleAfterValue": "100003",
"UMask": "0x2"
},
{
"BriefDescription": "Number of page walks outstanding for an outstanding code request in the PMH each cycle.",
"Counter": "0,1,2,3",
"EventCode": "0x11",
"EventName": "ITLB_MISSES.WALK_PENDING",
"PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle.",
"SampleAfterValue": "100003",
"UMask": "0x10"
}
]
@@ -11,6 +11,7 @@ GenuineIntel-6-35,v4,bonnell,core
GenuineIntel-6-5C,v8,goldmont,core
GenuineIntel-6-5F,v8,goldmont,core
GenuineIntel-6-7A,v1,goldmontplus,core
GenuineIntel-6-A[DE],v1,graniterapids,core
GenuineIntel-6-CF,v1,emeraldrapids,core
GenuineIntel-6-3C,v24,haswell,core
GenuineIntel-6-45,v24,haswell,core
1 Family-model Version Filename EventType
11 GenuineIntel-6-5C v8 goldmont core
12 GenuineIntel-6-5F v8 goldmont core
13 GenuineIntel-6-7A v1 goldmontplus core
14 GenuineIntel-6-A[DE] v1 graniterapids core
15 GenuineIntel-6-CF v1 emeraldrapids core
16 GenuineIntel-6-3C v24 haswell core
17 GenuineIntel-6-45 v24 haswell core
+1 -8
View File
@@ -1,12 +1,5 @@
release: {
url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",
mirror_type: "srv",
signature_type: "fingerprints",
fingerprints: "/usr/share/keys/pkg",
enabled: yes
}
release-kmods: {
url: "pkg+http://pkg.FreeBSD.org/${ABI}/kmods_latest",
url: "pkg+http://pkg.FreeBSD.org/${ABI}/release_4",
mirror_type: "srv",
signature_type: "fingerprints",
fingerprints: "/usr/share/keys/pkg",
+12 -19
View File
@@ -9,15 +9,20 @@ export PKG_DBDIR="/tmp/pkg"
export PERMISSIVE="YES"
export REPO_AUTOUPDATE="NO"
export ROOTDIR="$PWD/dvd"
export PKGCMD="/usr/sbin/pkg -d --rootdir ${ROOTDIR}"
export PKGCMD="/usr/sbin/pkg --rootdir ${ROOTDIR}"
export PORTSDIR="${PORTSDIR:-/usr/ports}"
_DVD_PACKAGES_MAIN="
_DVD_PACKAGES="
comms/usbmuxd
devel/git@lite
editors/emacs@nox
editors/vim
filesystems/ext2
filesystems/ntfs
misc/freebsd-doc-all
net/mpd5
net/rsync
net/wifi-firmware-kmod@release
ports-mgmt/pkg
shells/bash
shells/zsh
@@ -34,10 +39,6 @@ x11/xorg
x11-wm/sway
"
_DVD_PACKAGES_KMODS="
net/wifi-firmware-kmod@release
"
# If NOPORTS is set for the release, do not attempt to build pkg(8).
if [ ! -f ${PORTSDIR}/Makefile ]; then
echo "*** ${PORTSDIR} is missing! ***"
@@ -60,25 +61,18 @@ if [ ! -z "${PKG_ALTABI}" ]; then
ln -s ${PKG_ABI} ${ROOTDIR}/packages/${PKG_ALTABI}
fi
# Ensure the ports listed in _DVD_PACKAGES_* exist to sanitize the
# Ensure the ports listed in _DVD_PACKAGES exist to sanitize the
# final list.
for _P in ${_DVD_PACKAGES_MAIN}; do
for _P in ${_DVD_PACKAGES}; do
if [ -d "${PORTSDIR}/${_P%%@*}" ]; then
DVD_PACKAGES_MAIN="${DVD_PACKAGES_MAIN} ${_P}"
else
echo "*** Skipping nonexistent port: ${_P%%@*}"
fi
done
for _P in ${_DVD_PACKAGES_KMODS}; do
if [ -d "${PORTSDIR}/${_P%%@*}" ]; then
DVD_PACKAGES_KMODS="${DVD_PACKAGES_KMODS} ${_P}"
DVD_PACKAGES="${DVD_PACKAGES} ${_P}"
else
echo "*** Skipping nonexistent port: ${_P%%@*}"
fi
done
# Make sure the package list is not empty.
if [ -z "${DVD_PACKAGES_MAIN}${DVD_PACKAGES_KMODS}" ]; then
if [ -z "${DVD_PACKAGES}" ]; then
echo "*** The package list is empty."
echo "*** Something is very wrong."
# Exit '0' so the rest of the build process continues
@@ -89,8 +83,7 @@ fi
# Print pkg(8) information to make debugging easier.
${PKGCMD} -vv
${PKGCMD} update -f
${PKGCMD} fetch -o ${PKG_REPODIR} -r release -d ${DVD_PACKAGES_MAIN}
${PKGCMD} fetch -o ${PKG_REPODIR} -r release-kmods -d ${DVD_PACKAGES_KMODS}
${PKGCMD} fetch -o ${PKG_REPODIR} -d ${DVD_PACKAGES}
# Create the 'Latest/pkg.txz' symlink so 'pkg bootstrap' works
# using the on-disc packages.
+1
View File
@@ -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
+26
View File
@@ -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.
+23
View File
@@ -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
+19
View File
@@ -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
+152
View File
@@ -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);
}
}
File diff suppressed because it is too large. Load diff
+259
View File
@@ -0,0 +1,259 @@
/* lint -save -library Flexelint comment for external headers */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Charles Mott <cm@linktel.net>
* 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 THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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.
*/
/*
* Alias.h defines the outside world interfaces for the packet aliasing
* software.
*
* This software is placed into the public domain with no restrictions on its
* distribution.
*/
#ifndef _ALIAS_H_
#define _ALIAS_H_
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define LIBALIAS_BUF_SIZE 128
#ifdef _KERNEL
/*
* The kernel version of libalias does not support these features.
*/
#define NO_FW_PUNCH
#define NO_USE_SOCKETS
#endif
/*
* The external interface to libalias, the packet aliasing engine.
*
* There are two sets of functions:
*
* PacketAlias*() the old API which doesn't take an instance pointer
* and therefore can only have one packet engine at a time.
*
* LibAlias*() the new API which takes as first argument a pointer to
* the instance of the packet aliasing engine.
*
* The functions otherwise correspond to each other one for one, except
* for the LibAliasUnaliasOut()/PacketUnaliasOut() function which were
* were misnamed in the old API.
*/
/*
* The instance structure
*/
struct libalias;
/*
* An anonymous structure, a pointer to which is returned from
* PacketAliasRedirectAddr(), PacketAliasRedirectPort() or
* PacketAliasRedirectProto(), passed to PacketAliasAddServer(),
* and freed by PacketAliasRedirectDelete().
*/
struct alias_link;
/* Initialization and control functions. */
struct libalias *LibAliasInit(struct libalias *);
void LibAliasSetAddress(struct libalias *, struct in_addr _addr);
void LibAliasSetAliasPortRange(struct libalias *la, u_short port_low, u_short port_hi);
void LibAliasSetFWBase(struct libalias *, unsigned int _base, unsigned int _num);
void LibAliasSetSkinnyPort(struct libalias *, unsigned int _port);
unsigned int LibAliasSetMode(struct libalias *, unsigned int _flags, unsigned int _mask);
void LibAliasUninit(struct libalias *);
/* Packet Handling functions. */
int LibAliasIn (struct libalias *, void *_ptr, int _maxpacketsize);
int LibAliasOut(struct libalias *, void *_ptr, int _maxpacketsize);
int LibAliasOutTry(struct libalias *, void *_ptr, int _maxpacketsize, int _create);
int LibAliasUnaliasOut(struct libalias *, void *_ptr, int _maxpacketsize);
/* Port and address redirection functions. */
int LibAliasAddServer(struct libalias *, struct alias_link *_lnk,
struct in_addr _addr, unsigned short _port);
struct alias_link * LibAliasRedirectAddr(struct libalias *, struct in_addr _src_addr,
struct in_addr _alias_addr);
int LibAliasRedirectDynamic(struct libalias *, struct alias_link *_lnk);
void LibAliasRedirectDelete(struct libalias *, struct alias_link *_lnk);
struct alias_link * LibAliasRedirectPort(struct libalias *, struct in_addr _src_addr,
unsigned short _src_port, struct in_addr _dst_addr,
unsigned short _dst_port, struct in_addr _alias_addr,
unsigned short _alias_port, unsigned char _proto);
struct alias_link * LibAliasRedirectProto(struct libalias *, struct in_addr _src_addr,
struct in_addr _dst_addr, struct in_addr _alias_addr,
unsigned char _proto);
/* Fragment Handling functions. */
void LibAliasFragmentIn(struct libalias *, void *_ptr, void *_ptr_fragment);
void *LibAliasGetFragment(struct libalias *, void *_ptr);
int LibAliasSaveFragment(struct libalias *, void *_ptr);
/* Miscellaneous functions. */
unsigned short LibAliasInternetChecksum(struct libalias *, unsigned short *_ptr, int _nbytes);
void LibAliasSetTarget(struct libalias *, struct in_addr _target_addr);
/* Transparent proxying routines. */
int LibAliasProxyRule(struct libalias *, const char *_cmd);
/* Module handling API */
int LibAliasLoadModule(char *);
int LibAliasUnLoadAllModule(void);
int LibAliasRefreshModules(void);
/* Mbuf helper function. */
struct mbuf *m_megapullup(struct mbuf *, int);
/*
* Mode flags and other constants.
*/
/* Mode flags, set using PacketAliasSetMode() */
/*
* If PKT_ALIAS_LOG is set, a message will be printed to /var/log/alias.log
* every time a link is created or deleted. This is useful for debugging.
*/
#define PKT_ALIAS_LOG 0x01
/*
* If PKT_ALIAS_DENY_INCOMING is set, then incoming connections (e.g. to ftp,
* telnet or web servers will be prevented by the aliasing mechanism.
*/
#define PKT_ALIAS_DENY_INCOMING 0x02
/*
* If PKT_ALIAS_SAME_PORTS is set, packets will be attempted sent from the
* same port as they originated on. This allows e.g. rsh to work *99% of the
* time*, but _not_ 100% (it will be slightly flakey instead of not working
* at all). This mode bit is set by PacketAliasInit(), so it is a default
* mode of operation.
*/
#define PKT_ALIAS_SAME_PORTS 0x04
/*
* If PKT_ALIAS_USE_SOCKETS is set, then when partially specified links (e.g.
* destination port and/or address is zero), the packet aliasing engine will
* attempt to allocate a socket for the aliasing port it chooses. This will
* avoid interference with the host machine. Fully specified links do not
* require this. This bit is set after a call to PacketAliasInit(), so it is
* a default mode of operation.
*/
#ifndef NO_USE_SOCKETS
#define PKT_ALIAS_USE_SOCKETS 0x08
#endif
/*-
* If PKT_ALIAS_UNREGISTERED_ONLY is set, then only packets with
* unregistered source addresses will be aliased. Private
* addresses are those in the following ranges:
*
* 10.0.0.0 -> 10.255.255.255
* 172.16.0.0 -> 172.31.255.255
* 192.168.0.0 -> 192.168.255.255
*/
#define PKT_ALIAS_UNREGISTERED_ONLY 0x10
/*
* If PKT_ALIAS_RESET_ON_ADDR_CHANGE is set, then the table of dynamic
* aliasing links will be reset whenever PacketAliasSetAddress() changes the
* default aliasing address. If the default aliasing address is left
* unchanged by this function call, then the table of dynamic aliasing links
* will be left intact. This bit is set after a call to PacketAliasInit().
*/
#define PKT_ALIAS_RESET_ON_ADDR_CHANGE 0x20
/*
* If PKT_ALIAS_PROXY_ONLY is set, then NAT will be disabled and only
* transparent proxying is performed.
*/
#define PKT_ALIAS_PROXY_ONLY 0x40
/*
* If PKT_ALIAS_REVERSE is set, the actions of PacketAliasIn() and
* PacketAliasOut() are reversed.
*/
#define PKT_ALIAS_REVERSE 0x80
#ifndef NO_FW_PUNCH
/*
* If PKT_ALIAS_PUNCH_FW is set, active FTP and IRC DCC connections will
* create a 'hole' in the firewall to allow the transfers to work. The
* ipfw rule number that the hole is created with is controlled by
* PacketAliasSetFWBase(). The hole will be attached to that
* particular alias_link, so when the link goes away the hole is deleted.
*/
#define PKT_ALIAS_PUNCH_FW 0x100
#endif
/*
* If PKT_ALIAS_SKIP_GLOBAL is set, nat instance is not checked for matching
* states in 'ipfw nat global' rule.
*/
#define PKT_ALIAS_SKIP_GLOBAL 0x200
/*
* Like PKT_ALIAS_UNREGISTERED_ONLY, but includes the RFC 6598
* (Carrier Grade NAT) address range as follows:
*
* 100.64.0.0 -> 100.127.255.255
*/
#define PKT_ALIAS_UNREGISTERED_CGN 0x400
/*
* When this bit is set, UDP uses endpoint-independent mapping (EIM), as per
* RFC 4787 ("full cone" NAT of RFC 3489). All packets from the same internal
* address:port are mapped to the same NAT address:port, regardless of their
* destination address:port. If filtering rules allow, and if
* PKT_ALIAS_DENY_INCOMING is unset, any other external address:port can also
* send to the internal address:port through its mapped NAT address:port. This
* is more compatible with applications, and can reduce the need for port
* forwarding, but less scalable as each NAT address:port can only be
* concurrently used by at most one internal address:port.
*
* When this bit is unset, UDP packets use endpoint-dependent mapping (EDM)
* ("symmetric" NAT). Each connection from a particular internal address:port
* to different external addresses:ports is mapped to a random and
* unpredictable NAT address:port. Two appplications behind EDM NATs can only
* connect to each other by port forwarding on the NAT, or tunnelling through
* an in-between server.
*/
#define PKT_ALIAS_UDP_EIM 0x800
/* Function return codes. */
#define PKT_ALIAS_ERROR -1
#define PKT_ALIAS_OK 1
#define PKT_ALIAS_IGNORED 2
#define PKT_ALIAS_UNRESOLVED_FRAGMENT 3
#define PKT_ALIAS_FOUND_HEADER_FRAGMENT 4
#endif /* !_ALIAS_H_ */
/* lint -restore */
@@ -0,0 +1,284 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1998-2010 Luigi Rizzo, Universita` di Pisa
* Portions Copyright (c) 2000 Akamba Corp.
* 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 THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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.
*/
#ifndef _IP_DUMMYNET_H
#define _IP_DUMMYNET_H
#define NEW_AQM
/*
* Definition of the kernel-userland API for dummynet.
*
* Setsockopt() and getsockopt() pass a batch of objects, each
* of them starting with a "struct dn_id" which should fully identify
* the object and its relation with others in the sequence.
* The first object in each request should have
* type= DN_CMD_*, id = DN_API_VERSION.
* For other objects, type and subtype specify the object, len indicates
* the total length including the header, and 'id' identifies the specific
* object.
*
* Most objects are numbered with an identifier in the range 1..65535.
* DN_MAX_ID indicates the first value outside the range.
*/
#define DN_API_VERSION 12500000
#define DN_MAX_ID 0x10000
struct dn_id {
uint16_t len; /* total obj len including this header */
uint8_t type;
uint8_t subtype;
uint32_t id; /* generic id */
};
/*
* These values are in the type field of struct dn_id.
* To preserve the ABI, never rearrange the list or delete
* entries with the exception of DN_LAST
*/
enum {
DN_NONE = 0,
DN_LINK = 1,
DN_FS,
DN_SCH,
DN_SCH_I,
DN_QUEUE,
DN_DELAY_LINE,
DN_PROFILE,
DN_FLOW, /* struct dn_flow */
DN_TEXT, /* opaque text is the object */
DN_CMD_CONFIG = 0x80, /* objects follow */
DN_CMD_DELETE, /* subtype + list of entries */
DN_CMD_GET, /* subtype + list of entries */
DN_CMD_FLUSH,
/* for compatibility with FreeBSD 7.2/8 */
DN_COMPAT_PIPE,
DN_COMPAT_QUEUE,
DN_GET_COMPAT,
/* special commands for emulation of sysctl variables */
DN_SYSCTL_GET,
DN_SYSCTL_SET,
#ifdef NEW_AQM
/* subtypes used for setting/getting extra parameters.
* these subtypes used with IP_DUMMYNET3 command (get)
* and DN_TEXT (set). */
DN_AQM_PARAMS, /* AQM extra params */
DN_SCH_PARAMS, /* scheduler extra params */
#endif
DN_LAST,
};
enum { /* subtype for schedulers, flowset and the like */
DN_SCHED_UNKNOWN = 0,
DN_SCHED_FIFO = 1,
DN_SCHED_WF2QP = 2,
/* others are in individual modules */
};
enum { /* user flags */
DN_HAVE_MASK = 0x0001, /* fs or sched has a mask */
DN_NOERROR = 0x0002, /* do not report errors */
DN_QHT_HASH = 0x0004, /* qht is a hash table */
DN_QSIZE_BYTES = 0x0008, /* queue size is in bytes */
DN_HAS_PROFILE = 0x0010, /* a link has a profile */
DN_IS_RED = 0x0020,
DN_IS_GENTLE_RED= 0x0040,
DN_IS_ECN = 0x0080,
#ifdef NEW_AQM
DN_IS_AQM = 0x0100, /* AQMs: e.g Codel & PIE */
#endif
DN_PIPE_CMD = 0x1000, /* pipe config... */
};
/*
* link template.
*/
struct dn_link {
struct dn_id oid;
/*
* Userland sets bw and delay in bits/s and milliseconds.
* The kernel converts this back and forth to bits/tick and ticks.
* XXX what about burst ?
*/
int32_t link_nr;
uint32_t bandwidth; /* bit/s or bits/tick. */
int delay; /* ms and ticks */
uint64_t burst; /* scaled. bits*Hz XXX */
};
/*
* A flowset, which is a template for flows. Contains parameters
* from the command line: id, target scheduler, queue sizes, plr,
* flow masks, buckets for the flow hash, and possibly scheduler-
* specific parameters (weight, quantum and so on).
*/
struct dn_fs {
struct dn_id oid;
uint32_t fs_nr; /* the flowset number */
uint32_t flags; /* userland flags */
int qsize; /* queue size in slots or bytes */
int32_t pl_state; /* packet loss state */
uint32_t buckets; /* buckets used for the queue hash table */
struct ipfw_flow_id flow_mask;
uint32_t sched_nr; /* the scheduler we attach to */
/* generic scheduler parameters. Leave them at -1 if unset.
* Now we use 0: weight, 1: lmax, 2: priority
*/
int par[4];
/* RED/GRED parameters.
* weight and probabilities are in the range 0..1 represented
* in fixed point arithmetic with SCALE_RED decimal bits.
*/
#define SCALE_RED 16
#define SCALE(x) ( (x) << SCALE_RED )
#define SCALE_VAL(x) ( (x) >> SCALE_RED )
#define SCALE_MUL(x,y) ( ( (x) * (y) ) >> SCALE_RED )
int w_q ; /* queue weight (scaled) */
int max_th ; /* maximum threshold for queue (scaled) */
int min_th ; /* minimum threshold for queue (scaled) */
int max_p ; /* maximum value for p_b (scaled) */
int32_t plr[4]; /* PLR, pkt loss rate (2^31-1 means 100%) */
};
/*
* dn_flow collects flow_id and stats for queues and scheduler
* instances, and is used to pass these info to userland.
* oid.type/oid.subtype describe the object, oid.id is number
* of the parent object.
*/
struct dn_flow {
struct dn_id oid;
struct ipfw_flow_id fid;
uint64_t tot_pkts; /* statistics counters */
uint64_t tot_bytes;
uint32_t length; /* Queue length, in packets */
uint32_t len_bytes; /* Queue length, in bytes */
uint32_t drops;
};
/*
* Scheduler template, mostly indicating the name, number,
* sched_mask and buckets.
*/
struct dn_sch {
struct dn_id oid;
uint32_t sched_nr; /* N, scheduler number */
uint32_t buckets; /* number of buckets for the instances */
uint32_t flags; /* have_mask, ... */
char name[16]; /* null terminated */
/* mask to select the appropriate scheduler instance */
struct ipfw_flow_id sched_mask; /* M */
};
/* A delay profile is attached to a link.
* Note that a profile, as any other object, cannot be longer than 2^16
*/
#define ED_MAX_SAMPLES_NO 1024
struct dn_profile {
struct dn_id oid;
/* fields to simulate a delay profile */
#define ED_MAX_NAME_LEN 32
char name[ED_MAX_NAME_LEN];
int link_nr;
int loss_level;
uint32_t bandwidth; // XXX use link bandwidth?
int samples_no; /* actual len of samples[] */
int samples[ED_MAX_SAMPLES_NO]; /* may be shorter */
};
#ifdef NEW_AQM
/* Extra parameters for AQM and scheduler.
* This struct is used to pass and retrieve parameters (configurations)
* to/from AQM and Scheduler.
*/
struct dn_extra_parms {
struct dn_id oid;
char name[16];
uint32_t nr;
#define DN_MAX_EXTRA_PARM 10
int64_t par[DN_MAX_EXTRA_PARM];
};
#endif
/*
* Overall structure of dummynet
In dummynet, packets are selected with the firewall rules, and passed
to two different objects: PIPE or QUEUE (bad name).
A QUEUE defines a classifier, which groups packets into flows
according to a 'mask', puts them into independent queues (one
per flow) with configurable size and queue management policy,
and passes flows to a scheduler:
(flow_mask|sched_mask) sched_mask
+---------+ weight Wx +-------------+
| |->-[flow]-->--| |-+
-->--| QUEUE x | ... | | |
| |->-[flow]-->--| SCHEDuler N | |
+---------+ | | |
... | +--[LINK N]-->--
+---------+ weight Wy | | +--[LINK N]-->--
| |->-[flow]-->--| | |
-->--| QUEUE y | ... | | |
| |->-[flow]-->--| | |
+---------+ +-------------+ |
+-------------+
Many QUEUE objects can connect to the same scheduler, each
QUEUE object can have its own set of parameters.
In turn, the SCHEDuler 'forks' multiple instances according
to a 'sched_mask', each instance manages its own set of queues
and transmits on a private instance of a configurable LINK.
A PIPE is a simplified version of the above, where there
is no flow_mask, and each scheduler instance handles a single queue.
The following data structures (visible from userland) describe
the objects used by dummynet:
+ dn_link, contains the main configuration parameters related
to delay and bandwidth;
+ dn_profile describes a delay profile;
+ dn_flow describes the flow status (flow id, statistics)
+ dn_sch describes a scheduler
+ dn_fs describes a flowset (msk, weight, queue parameters)
*
*/
#endif /* _IP_DUMMYNET_H */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,212 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2015-2019 Yandex LLC
* Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
* Copyright (c) 2015-2019 Andrey V. Elsukov <ae@FreeBSD.org>
*
* 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 THE AUTHOR ``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 THE AUTHOR 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.
*/
#ifndef _NETINET6_IP_FW_NAT64_H_
#define _NETINET6_IP_FW_NAT64_H_
struct ipfw_nat64stl_stats {
uint64_t opcnt64; /* 6to4 of packets translated */
uint64_t opcnt46; /* 4to6 of packets translated */
uint64_t ofrags; /* number of fragments generated */
uint64_t ifrags; /* number of fragments received */
uint64_t oerrors; /* number of output errors */
uint64_t noroute4;
uint64_t noroute6;
uint64_t noproto; /* Protocol not supported */
uint64_t nomem; /* mbuf allocation failed */
uint64_t dropped; /* dropped due to some errors */
};
struct ipfw_nat64clat_stats {
uint64_t opcnt64; /* 6to4 of packets translated */
uint64_t opcnt46; /* 4to6 of packets translated */
uint64_t ofrags; /* number of fragments generated */
uint64_t ifrags; /* number of fragments received */
uint64_t oerrors; /* number of output errors */
uint64_t noroute4;
uint64_t noroute6;
uint64_t noproto; /* Protocol not supported */
uint64_t nomem; /* mbuf allocation failed */
uint64_t dropped; /* dropped due to some errors */
};
struct ipfw_nat64lsn_stats {
uint64_t opcnt64; /* 6to4 of packets translated */
uint64_t opcnt46; /* 4to6 of packets translated */
uint64_t ofrags; /* number of fragments generated */
uint64_t ifrags; /* number of fragments received */
uint64_t oerrors; /* number of output errors */
uint64_t noroute4;
uint64_t noroute6;
uint64_t noproto; /* Protocol not supported */
uint64_t nomem; /* mbuf allocation failed */
uint64_t dropped; /* dropped due to some errors */
uint64_t nomatch4; /* No addr/port match */
uint64_t jcalls; /* Number of job handler calls */
uint64_t jrequests; /* Number of job requests */
uint64_t jhostsreq; /* Number of job host requests */
uint64_t jportreq; /* Number of portgroup requests */
uint64_t jhostfails; /* Number of failed host allocs */
uint64_t jportfails; /* Number of failed portgroup allocs */
uint64_t jreinjected; /* Number of packets reinjected to q */
uint64_t jmaxlen; /* Max queue length reached */
uint64_t jnomem; /* No memory to alloc queue item */
uint64_t screated; /* Number of states created */
uint64_t sdeleted; /* Number of states deleted */
uint64_t spgcreated; /* Number of portgroups created */
uint64_t spgdeleted; /* Number of portgroups deleted */
uint64_t hostcount; /* Number of hosts */
uint64_t tcpchunks; /* Number of TCP portgroups */
uint64_t udpchunks; /* Number of UDP portgroups */
uint64_t icmpchunks; /* Number of ICMP portgroups */
uint64_t _reserved[4];
};
#define NAT64_LOG 0x0001 /* Enable logging via BPF */
#define NAT64_ALLOW_PRIVATE 0x0002 /* Allow private IPv4 address
* translation
*/
#define NAT64LSN_ALLOW_SWAPCONF 0x0004 /* Allow configuration exchange
* between NAT64LSN instances
* during the sets swapping.
*/
typedef struct _ipfw_nat64stl_cfg {
char name[64]; /* NAT name */
ipfw_obj_ntlv ntlv6; /* object name tlv */
ipfw_obj_ntlv ntlv4; /* object name tlv */
struct in6_addr prefix6; /* NAT64 prefix */
uint8_t plen6; /* Prefix length */
uint8_t set; /* Named instance set [0..31] */
uint8_t spare[2];
uint32_t flags;
} ipfw_nat64stl_cfg;
typedef struct _ipfw_nat64clat_cfg {
char name[64]; /* NAT name */
struct in6_addr plat_prefix; /* NAT64 (PLAT) prefix */
struct in6_addr clat_prefix; /* Client (CLAT) prefix */
uint8_t plat_plen; /* PLAT Prefix length */
uint8_t clat_plen; /* CLAT Prefix length */
uint8_t set; /* Named instance set [0..31] */
uint8_t spare;
uint32_t flags;
} ipfw_nat64clat_cfg;
/*
* NAT64LSN default configuration values
*/
#define NAT64LSN_MAX_PORTS 2048 /* Unused */
#define NAT64LSN_JMAXLEN 2048 /* Max outstanding requests. */
#define NAT64LSN_TCP_SYN_AGE 10 /* State's TTL after SYN received. */
#define NAT64LSN_TCP_EST_AGE (2 * 3600) /* TTL for established connection */
#define NAT64LSN_TCP_FIN_AGE 180 /* State's TTL after FIN/RST received */
#define NAT64LSN_UDP_AGE 120 /* TTL for UDP states */
#define NAT64LSN_ICMP_AGE 60 /* TTL for ICMP states */
#define NAT64LSN_HOST_AGE 3600 /* TTL for stale host entry */
#define NAT64LSN_PG_AGE 900 /* TTL for stale ports groups */
typedef struct _ipfw_nat64lsn_cfg {
char name[64]; /* NAT name */
uint32_t flags;
uint32_t max_ports; /* Unused */
uint32_t agg_prefix_len; /* Unused */
uint32_t agg_prefix_max; /* Unused */
struct in_addr prefix4;
uint16_t plen4; /* Prefix length */
uint16_t plen6; /* Prefix length */
struct in6_addr prefix6; /* NAT64 prefix */
uint32_t jmaxlen; /* Max jobqueue length */
uint16_t min_port; /* Unused */
uint16_t max_port; /* Unused */
uint16_t nh_delete_delay;/* Stale host delete delay */
uint16_t pg_delete_delay;/* Stale portgroup delete delay */
uint16_t st_syn_ttl; /* TCP syn expire */
uint16_t st_close_ttl; /* TCP fin expire */
uint16_t st_estab_ttl; /* TCP established expire */
uint16_t st_udp_ttl; /* UDP expire */
uint16_t st_icmp_ttl; /* ICMP expire */
uint8_t set; /* Named instance set [0..31] */
uint8_t states_chunks; /* Number of states chunks per PG */
} ipfw_nat64lsn_cfg;
typedef struct _ipfw_nat64lsn_state {
struct in_addr daddr; /* Remote IPv4 address */
uint16_t dport; /* Remote destination port */
uint16_t aport; /* Local alias port */
uint16_t sport; /* Source port */
uint8_t flags; /* State flags */
uint8_t spare[3];
uint16_t idle; /* Last used time */
} ipfw_nat64lsn_state;
typedef struct _ipfw_nat64lsn_stg {
uint64_t next_idx; /* next state index */
struct in_addr alias4; /* IPv4 alias address */
uint8_t proto; /* protocol */
uint8_t flags;
uint16_t spare;
struct in6_addr host6; /* Bound IPv6 host */
uint32_t count; /* Number of states */
uint32_t spare2;
} ipfw_nat64lsn_stg;
typedef struct _ipfw_nat64lsn_state_v1 {
struct in6_addr host6; /* Bound IPv6 host */
struct in_addr daddr; /* Remote IPv4 address */
uint16_t dport; /* Remote destination port */
uint16_t aport; /* Local alias port */
uint16_t sport; /* Source port */
uint16_t spare;
uint16_t idle; /* Last used time */
uint8_t flags; /* State flags */
uint8_t proto; /* protocol */
} ipfw_nat64lsn_state_v1;
typedef struct _ipfw_nat64lsn_stg_v1 {
union nat64lsn_pgidx {
uint64_t index;
struct {
uint8_t chunk; /* states chunk */
uint8_t proto; /* protocol */
uint16_t port; /* base port */
in_addr_t addr; /* alias address */
};
} next; /* next state index */
struct in_addr alias4; /* IPv4 alias address */
uint32_t count; /* Number of states */
} ipfw_nat64lsn_stg_v1;
#endif /* _NETINET6_IP_FW_NAT64_H_ */
@@ -0,0 +1,52 @@
/*-
* Copyright (c) 2016 Yandex LLC
* Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
* 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 THE AUTHOR ``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 THE AUTHOR 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.
*/
#ifndef _NETINET6_IP_FW_NPTV6_H_
#define _NETINET6_IP_FW_NPTV6_H_
struct ipfw_nptv6_stats {
uint64_t in2ex; /* Int->Ext packets translated */
uint64_t ex2in; /* Ext->Int packets translated */
uint64_t dropped; /* dropped due to some errors */
uint64_t reserved[5];
};
typedef struct _ipfw_nptv6_cfg {
char name[64]; /* NPTv6 instance name */
struct in6_addr internal; /* NPTv6 internal prefix */
union {
struct in6_addr external; /* NPTv6 external prefix */
char if_name[IF_NAMESIZE];
};
uint8_t plen; /* Prefix length */
uint8_t set; /* Named instance set [0..31] */
uint8_t spare[2];
uint32_t flags;
#define NPTV6_DYNAMIC_PREFIX 1 /* Use dynamic external prefix */
} ipfw_nptv6_cfg;
#endif /* _NETINET6_IP_FW_NPTV6_H_ */
File diff suppressed because it is too large. Load diff
+5094
View File
File diff suppressed because it is too large. Load diff
+6129
View File
File diff suppressed because it is too large. Load diff
+470
View File
@@ -0,0 +1,470 @@
/*-
* 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
*/
enum cmdline_prog {
cmdline_prog_ipfw,
cmdline_prog_dnctl
};
/*
* Options that can be set on the command line.
* When reading commands from a file, a subset of the options can also
* be applied globally by specifying them before the file name.
* After that, each line can contain its own option that changes
* the global value.
* XXX The context is not restored after each line.
*/
struct cmdline_opts {
/* boolean options: */
int do_value_as_ip; /* show table value as IP */
int do_resolv; /* try to resolve all ip to names */
int do_time; /* Show time stamps */
int do_quiet; /* Be quiet in add and flush */
int do_pipe; /* this cmd refers to a pipe/queue/sched */
int do_nat; /* this cmd refers to a nat config */
int do_compact; /* show rules in compact mode */
int do_force; /* do not ask for confirmation */
int show_sets; /* display the set each rule belongs to */
int test_only; /* only check syntax */
int comment_only; /* only print action and comment */
int verbose; /* be verbose on some commands */
int debug_only; /* output ioctl i/o on stdout */
/* The options below can have multiple values. */
int do_dynamic; /* 1 - display dynamic rules */
/* 2 - display/delete only dynamic rules */
int do_sort; /* field to sort results (0 = no) */
/* valid fields are 1 and above */
uint32_t use_set; /* work with specified set number */
/* 0 means all sets, otherwise apply to set use_set - 1 */
enum cmdline_prog prog; /* Are we ipfw or dnctl? */
};
int is_ipfw(void);
enum {
TIMESTAMP_NONE = 0,
TIMESTAMP_STRING,
TIMESTAMP_NUMERIC,
};
extern struct cmdline_opts g_co;
/*
* _s_x is a structure that stores a string <-> token pairs, used in
* various places in the parser. Entries are stored in arrays,
* with an entry with s=NULL as terminator.
* The search routines are match_token() and match_value().
* Often, an element with x=0 contains an error string.
*
*/
struct _s_x {
char const *s;
int x;
};
extern struct _s_x f_ipdscp[];
enum tokens {
TOK_NULL=0,
TOK_OR,
TOK_NOT,
TOK_STARTBRACE,
TOK_ENDBRACE,
TOK_ABORT6,
TOK_ABORT,
TOK_ACCEPT,
TOK_COUNT,
TOK_EACTION,
TOK_PIPE,
TOK_LINK,
TOK_QUEUE,
TOK_FLOWSET,
TOK_SCHED,
TOK_DIVERT,
TOK_TEE,
TOK_NETGRAPH,
TOK_NGTEE,
TOK_FORWARD,
TOK_SKIPTO,
TOK_DENY,
TOK_REJECT,
TOK_RESET,
TOK_UNREACH,
TOK_CHECKSTATE,
TOK_NAT,
TOK_REASS,
TOK_CALL,
TOK_RETURN,
TOK_ALTQ,
TOK_LOG,
TOK_TAG,
TOK_UNTAG,
TOK_TAGGED,
TOK_UID,
TOK_GID,
TOK_JAIL,
TOK_IN,
TOK_LIMIT,
TOK_SETLIMIT,
TOK_KEEPSTATE,
TOK_RECORDSTATE,
TOK_LAYER2,
TOK_OUT,
TOK_DIVERTED,
TOK_DIVERTEDLOOPBACK,
TOK_DIVERTEDOUTPUT,
TOK_XMIT,
TOK_RECV,
TOK_VIA,
TOK_FRAG,
TOK_IPOPTS,
TOK_IPLEN,
TOK_IPID,
TOK_IPPRECEDENCE,
TOK_DSCP,
TOK_IPTOS,
TOK_IPTTL,
TOK_IPVER,
TOK_ESTAB,
TOK_SETUP,
TOK_TCPDATALEN,
TOK_TCPFLAGS,
TOK_TCPOPTS,
TOK_TCPSEQ,
TOK_TCPACK,
TOK_TCPMSS,
TOK_TCPWIN,
TOK_ICMPTYPES,
TOK_MAC,
TOK_MACTYPE,
TOK_VERREVPATH,
TOK_VERSRCREACH,
TOK_ANTISPOOF,
TOK_IPSEC,
TOK_COMMENT,
TOK_PLR,
TOK_NOERROR,
TOK_BUCKETS,
TOK_DSTIP,
TOK_SRCIP,
TOK_DSTPORT,
TOK_SRCPORT,
TOK_DSTMAC,
TOK_SRCMAC,
TOK_ALL,
TOK_MASK,
TOK_FLOW_MASK,
TOK_SCHED_MASK,
TOK_BW,
TOK_DELAY,
TOK_PROFILE,
TOK_BURST,
TOK_RED,
TOK_GRED,
TOK_ECN,
TOK_DROPTAIL,
TOK_PROTO,
#ifdef NEW_AQM
/* AQM tokens*/
TOK_NO_ECN,
TOK_CODEL,
TOK_FQ_CODEL,
TOK_TARGET,
TOK_INTERVAL,
TOK_FLOWS,
TOK_QUANTUM,
TOK_PIE,
TOK_FQ_PIE,
TOK_TUPDATE,
TOK_MAX_BURST,
TOK_MAX_ECNTH,
TOK_ALPHA,
TOK_BETA,
TOK_CAPDROP,
TOK_NO_CAPDROP,
TOK_ONOFF,
TOK_DRE,
TOK_TS,
TOK_DERAND,
TOK_NO_DERAND,
#endif
/* dummynet tokens */
TOK_WEIGHT,
TOK_LMAX,
TOK_PRI,
TOK_TYPE,
TOK_SLOTSIZE,
TOK_IP,
TOK_IF,
TOK_ALOG,
TOK_DENY_INC,
TOK_SAME_PORTS,
TOK_UNREG_ONLY,
TOK_UNREG_CGN,
TOK_SKIP_GLOBAL,
TOK_RESET_ADDR,
TOK_ALIAS_REV,
TOK_PROXY_ONLY,
TOK_REDIR_ADDR,
TOK_REDIR_PORT,
TOK_REDIR_PROTO,
TOK_IPV6,
TOK_FLOWID,
TOK_ICMP6TYPES,
TOK_EXT6HDR,
TOK_DSTIP6,
TOK_SRCIP6,
TOK_IPV4,
TOK_UNREACH6,
TOK_RESET6,
TOK_FIB,
TOK_SETFIB,
TOK_LOOKUP,
TOK_SOCKARG,
TOK_SETDSCP,
TOK_FLOW,
TOK_IFLIST,
/* Table tokens */
TOK_CREATE,
TOK_DESTROY,
TOK_LIST,
TOK_INFO,
TOK_DETAIL,
TOK_MODIFY,
TOK_FLUSH,
TOK_SWAP,
TOK_ADD,
TOK_DEL,
TOK_VALTYPE,
TOK_ALGO,
TOK_TALIST,
TOK_ATOMIC,
TOK_LOCK,
TOK_UNLOCK,
TOK_VLIST,
TOK_OLIST,
TOK_MONITOR,
TOK_MISSING,
TOK_ORFLUSH,
/* NAT64 tokens */
TOK_NAT64STL,
TOK_NAT64LSN,
TOK_STATS,
TOK_STATES,
TOK_CONFIG,
TOK_TABLE4,
TOK_TABLE6,
TOK_PREFIX4,
TOK_PREFIX6,
TOK_AGG_LEN,
TOK_AGG_COUNT,
TOK_MAX_PORTS,
TOK_STATES_CHUNKS,
TOK_JMAXLEN,
TOK_PORT_RANGE,
TOK_PORT_ALIAS,
TOK_HOST_DEL_AGE,
TOK_PG_DEL_AGE,
TOK_TCP_SYN_AGE,
TOK_TCP_CLOSE_AGE,
TOK_TCP_EST_AGE,
TOK_UDP_AGE,
TOK_ICMP_AGE,
TOK_LOGOFF,
TOK_PRIVATE,
TOK_PRIVATEOFF,
TOK_SWAPCONF,
TOK_SWAPCONFOFF,
/* NAT64 CLAT tokens */
TOK_NAT64CLAT,
TOK_PLAT_PREFIX,
TOK_CLAT_PREFIX,
/* NPTv6 tokens */
TOK_NPTV6,
TOK_INTPREFIX,
TOK_EXTPREFIX,
TOK_PREFIXLEN,
TOK_EXTIF,
TOK_TCPSETMSS,
TOK_MARK,
TOK_SETMARK,
TOK_SKIPACTION,
TOK_UDP_EIM,
};
/*
* the following macro returns an error message if we run out of
* arguments.
*/
#define NEED(_p, msg) {if (!_p) errx(EX_USAGE, msg);}
#define NEED1(msg) {if (!(*av)) errx(EX_USAGE, msg);}
struct buf_pr {
char *buf; /* allocated buffer */
char *ptr; /* current pointer */
size_t size; /* total buffer size */
size_t avail; /* available storage */
size_t needed; /* length needed */
};
int pr_u64(struct buf_pr *bp, void *pd, int width);
int bp_alloc(struct buf_pr *b, size_t size);
void bp_free(struct buf_pr *b);
int bprintf(struct buf_pr *b, const char *format, ...) __printflike(2, 3);
/* memory allocation support */
void *safe_calloc(size_t number, size_t size);
void *safe_realloc(void *ptr, size_t size);
/* string comparison functions used for historical compatibility */
int _substrcmp(const char *str1, const char* str2);
int _substrcmp2(const char *str1, const char* str2, const char* str3);
int stringnum_cmp(const char *a, const char *b);
/* utility functions */
int match_token(struct _s_x *table, const char *string);
int match_token_relaxed(struct _s_x *table, const char *string);
int get_token(struct _s_x *table, const char *string, const char *errbase);
char const *match_value(struct _s_x *p, int value);
size_t concat_tokens(char *buf, size_t bufsize, struct _s_x *table,
const char *delimiter);
int fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set,
uint32_t *clear);
void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set);
struct _ip_fw3_opheader;
int do_cmd(int optname, void *optval, uintptr_t optlen);
int do_set3(int optname, struct _ip_fw3_opheader *op3, size_t optlen);
int do_get3(int optname, struct _ip_fw3_opheader *op3, size_t *optlen);
struct in6_addr;
void n2mask(struct in6_addr *mask, int n);
int contigmask(const uint8_t *p, int len);
/*
* Forward declarations to avoid include way too many headers.
* C does not allow duplicated typedefs, so we use the base struct
* that the typedef points to.
* Should the typedefs use a different type, the compiler will
* still detect the change when compiling the body of the
* functions involved, so we do not lose error checking.
*/
struct _ipfw_insn;
struct _ipfw_insn_altq;
struct _ipfw_insn_u32;
struct _ipfw_insn_ip6;
struct _ipfw_insn_icmp6;
/*
* The reserved set numer. This is a constant in ip_fw.h
* but we store it in a variable so other files do not depend
* in that header just for one constant.
*/
extern int resvd_set_number;
/* first-level command handlers */
void ipfw_add(char *av[]);
void ipfw_show_nat(int ac, char **av);
int ipfw_delete_nat(int i);
void ipfw_config_pipe(int ac, char **av);
void ipfw_config_nat(int ac, char **av);
void ipfw_sets_handler(char *av[]);
void ipfw_table_handler(int ac, char *av[]);
void ipfw_sysctl_handler(char *av[], int which);
void ipfw_delete(char *av[]);
void ipfw_flush(int force);
void ipfw_zero(int ac, char *av[], int optname);
void ipfw_list(int ac, char *av[], int show_counters);
void ipfw_internal_handler(int ac, char *av[]);
void ipfw_nat64clat_handler(int ac, char *av[]);
void ipfw_nat64lsn_handler(int ac, char *av[]);
void ipfw_nat64stl_handler(int ac, char *av[]);
void ipfw_nptv6_handler(int ac, char *av[]);
int ipfw_check_object_name(const char *name);
int ipfw_check_nat64prefix(const struct in6_addr *prefix, int length);
#ifdef PF
/* altq.c */
void altq_set_enabled(int enabled);
u_int32_t altq_name_to_qid(const char *name);
void print_altq_cmd(struct buf_pr *bp, const struct _ipfw_insn_altq *altqptr);
#else
#define NO_ALTQ
#endif
/* dummynet.c */
void dummynet_list(int ac, char *av[], int show_counters);
void dummynet_flush(void);
int ipfw_delete_pipe(int pipe_or_queue, int n);
/* ipv6.c */
void print_unreach6_code(struct buf_pr *bp, uint16_t code);
void print_ip6(struct buf_pr *bp, const struct _ipfw_insn_ip6 *cmd);
void print_flow6id(struct buf_pr *bp, const struct _ipfw_insn_u32 *cmd);
void print_icmp6types(struct buf_pr *bp, const struct _ipfw_insn_u32 *cmd);
void print_ext6hdr(struct buf_pr *bp, const struct _ipfw_insn *cmd);
struct tidx;
struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av, int cblen,
struct tidx *tstate);
struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av, int cblen,
struct tidx *tstate);
void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av, int cblen);
uint16_t get_unreach6_code(const char *str);
void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
/* ipfw2.c */
void bp_flush(struct buf_pr *b);
void fill_table(struct _ipfw_insn *cmd, char *av, uint8_t opcode,
struct tidx *tstate);
/* tables.c */
struct _ipfw_obj_ctlv;
struct _ipfw_obj_ntlv;
int table_check_name(const char *tablename);
void ipfw_list_ta(int ac, char *av[]);
void ipfw_list_values(int ac, char *av[]);
void table_fill_ntlv(struct _ipfw_obj_ntlv *ntlv, const char *name,
uint8_t set, uint32_t uidx);
+519
View File
@@ -0,0 +1,519 @@
/*-
* 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
*
* ipv6 support
*/
#include <sys/types.h>
#include <sys/socket.h>
#include "ipfw2.h"
#include <err.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/in_systm.h>
#include <netinet/ip.h>
#include <netinet/icmp6.h>
#include <netinet/ip_fw15.h>
#include <arpa/inet.h>
#define CHECK_LENGTH(v, len) do { \
if ((v) < (len)) \
errx(EX_DATAERR, "Rule too long"); \
} while (0)
static struct _s_x icmp6codes[] = {
{ "no-route", ICMP6_DST_UNREACH_NOROUTE },
{ "admin-prohib", ICMP6_DST_UNREACH_ADMIN },
{ "address", ICMP6_DST_UNREACH_ADDR },
{ "port", ICMP6_DST_UNREACH_NOPORT },
{ NULL, 0 }
};
uint16_t
get_unreach6_code(const char *str)
{
int val;
char *s;
val = strtoul(str, &s, 0);
if (s == str || *s != '\0' || val >= 0x100)
val = match_token(icmp6codes, str);
if (val < 0)
errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str);
return (val);
}
void
print_unreach6_code(struct buf_pr *bp, uint16_t code)
{
char const *s = match_value(icmp6codes, code);
if (s != NULL)
bprintf(bp, "unreach6 %s", s);
else
bprintf(bp, "unreach6 %u", code);
}
/*
* Print the ip address contained in a command.
*/
void
print_ip6(struct buf_pr *bp, const ipfw_insn_ip6 *cmd)
{
char trad[255];
struct hostent *he = NULL;
const struct in6_addr *a = &(cmd->addr6);
int len, mb;
len = F_LEN((const ipfw_insn *)cmd) - 1;
if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) {
bprintf(bp, " me6");
return;
}
if (cmd->o.opcode == O_IP6) {
bprintf(bp, " ip6");
return;
}
/*
* len == 4 indicates a single IP, whereas lists of 1 or more
* addr/mask pairs have len = (2n+1). We convert len to n so we
* use that to count the number of entries.
*/
bprintf(bp, " ");
for (len = len / 4; len > 0; len -= 2, a += 2) {
/* mask length */
mb = (cmd->o.opcode == O_IP6_SRC ||
cmd->o.opcode == O_IP6_DST) ? 128:
contigmask((const uint8_t *)&(a[1]), 128);
if (mb == 128 && g_co.do_resolv)
he = gethostbyaddr((const char *)a, sizeof(*a),
AF_INET6);
if (he != NULL) /* resolved to name */
bprintf(bp, "%s", he->h_name);
else if (mb == 0) /* any */
bprintf(bp, "any");
else { /* numeric IP followed by some kind of mask */
if (inet_ntop(AF_INET6, a, trad,
sizeof(trad)) == NULL)
bprintf(bp, "Error ntop in print_ip6\n");
bprintf(bp, "%s", trad );
if (mb < 0) /* mask not contiguous */
bprintf(bp, "/%s", inet_ntop(AF_INET6, &a[1],
trad, sizeof(trad)));
else if (mb < 128)
bprintf(bp, "/%d", mb);
}
if (len > 2)
bprintf(bp, ",");
}
}
void
fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen)
{
uint8_t type;
CHECK_LENGTH(cblen, (int)F_INSN_SIZE(ipfw_insn_icmp6));
memset(cmd, 0, sizeof(*cmd));
while (*av) {
if (*av == ',')
av++;
type = strtoul(av, &av, 0);
if (*av != ',' && *av != '\0')
errx(EX_DATAERR, "invalid ICMP6 type");
/*
* XXX: shouldn't this be 0xFF? I can't see any reason why
* we shouldn't be able to filter all possiable values
* regardless of the ability of the rest of the kernel to do
* anything useful with them.
*/
if (type > ICMP6_MAXTYPE)
errx(EX_DATAERR, "ICMP6 type out of range");
cmd->d[type / 32] |= ( 1 << (type % 32));
}
cmd->o.opcode = O_ICMP6TYPE;
cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6);
}
void
print_icmp6types(struct buf_pr *bp, const ipfw_insn_u32 *cmd)
{
int i, j;
char sep= ' ';
bprintf(bp, " icmp6types");
for (i = 0; i < 7; i++)
for (j=0; j < 32; ++j) {
if ( (cmd->d[i] & (1 << (j))) == 0)
continue;
bprintf(bp, "%c%d", sep, (i*32 + j));
sep = ',';
}
}
void
print_flow6id(struct buf_pr *bp, const ipfw_insn_u32 *cmd)
{
uint16_t i, limit = cmd->o.arg1;
char sep = ',';
bprintf(bp, " flow-id ");
for( i=0; i < limit; ++i) {
if (i == limit - 1)
sep = ' ';
bprintf(bp, "%d%c", cmd->d[i], sep);
}
}
/* structure and define for the extension header in ipv6 */
static struct _s_x ext6hdrcodes[] = {
{ "frag", EXT_FRAGMENT },
{ "hopopt", EXT_HOPOPTS },
{ "route", EXT_ROUTING },
{ "dstopt", EXT_DSTOPTS },
{ "ah", EXT_AH },
{ "esp", EXT_ESP },
{ "rthdr0", EXT_RTHDR0 },
{ "rthdr2", EXT_RTHDR2 },
{ NULL, 0 }
};
/* fills command for the extension header filtering */
int
fill_ext6hdr( ipfw_insn *cmd, char *av)
{
int tok;
char *s = av;
cmd->arg1 = 0;
while(s) {
av = strsep( &s, ",") ;
tok = match_token(ext6hdrcodes, av);
switch (tok) {
case EXT_FRAGMENT:
cmd->arg1 |= EXT_FRAGMENT;
break;
case EXT_HOPOPTS:
cmd->arg1 |= EXT_HOPOPTS;
break;
case EXT_ROUTING:
cmd->arg1 |= EXT_ROUTING;
break;
case EXT_DSTOPTS:
cmd->arg1 |= EXT_DSTOPTS;
break;
case EXT_AH:
cmd->arg1 |= EXT_AH;
break;
case EXT_ESP:
cmd->arg1 |= EXT_ESP;
break;
case EXT_RTHDR0:
cmd->arg1 |= EXT_RTHDR0;
break;
case EXT_RTHDR2:
cmd->arg1 |= EXT_RTHDR2;
break;
default:
errx(EX_DATAERR,
"invalid option for ipv6 exten header");
break;
}
}
if (cmd->arg1 == 0)
return (0);
cmd->opcode = O_EXT_HDR;
cmd->len |= F_INSN_SIZE(ipfw_insn);
return (1);
}
void
print_ext6hdr(struct buf_pr *bp, const ipfw_insn *cmd )
{
char sep = ' ';
bprintf(bp, " extension header:");
if (cmd->arg1 & EXT_FRAGMENT) {
bprintf(bp, "%cfragmentation", sep);
sep = ',';
}
if (cmd->arg1 & EXT_HOPOPTS) {
bprintf(bp, "%chop options", sep);
sep = ',';
}
if (cmd->arg1 & EXT_ROUTING) {
bprintf(bp, "%crouting options", sep);
sep = ',';
}
if (cmd->arg1 & EXT_RTHDR0) {
bprintf(bp, "%crthdr0", sep);
sep = ',';
}
if (cmd->arg1 & EXT_RTHDR2) {
bprintf(bp, "%crthdr2", sep);
sep = ',';
}
if (cmd->arg1 & EXT_DSTOPTS) {
bprintf(bp, "%cdestination options", sep);
sep = ',';
}
if (cmd->arg1 & EXT_AH) {
bprintf(bp, "%cauthentication header", sep);
sep = ',';
}
if (cmd->arg1 & EXT_ESP) {
bprintf(bp, "%cencapsulating security payload", sep);
}
}
/* Try to find ipv6 address by hostname */
static int
lookup_host6 (char *host, struct in6_addr *ip6addr)
{
struct hostent *he;
if (!inet_pton(AF_INET6, host, ip6addr)) {
if ((he = gethostbyname2(host, AF_INET6)) == NULL)
return(-1);
memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr));
}
return (0);
}
/*
* fill the addr and mask fields in the instruction as appropriate from av.
* Update length as appropriate.
* The following formats are allowed:
* any matches any IP6. Actually returns an empty instruction.
* me returns O_IP6_*_ME
*
* 03f1::234:123:0342 single IP6 address
* 03f1::234:123:0342/24 address/masklen
* 03f1::234:123:0342/ffff::ffff:ffff address/mask
* 03f1::234:123:0342/24,03f1::234:123:0343/ List of address
*
* Set of address (as in ipv6) not supported because ipv6 address
* are typically random past the initial prefix.
* Return 1 on success, 0 on failure.
*/
static int
fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen, struct tidx *tstate)
{
int len = 0;
struct in6_addr *d = &(cmd->addr6);
char *oav;
/*
* Needed for multiple address.
* Note d[1] points to struct in6_add r mask6 of cmd
*/
cmd->o.len &= ~F_LEN_MASK; /* zero len */
if (strcmp(av, "any") == 0)
return (1);
/* Set the data for "me" opt */
if (strcmp(av, "me") == 0 || strcmp(av, "me6") == 0) {
cmd->o.len |= F_INSN_SIZE(ipfw_insn);
return (1);
}
if (strncmp(av, "table(", 6) == 0) {
fill_table(&cmd->o, av, O_IP_DST_LOOKUP, tstate);
return (1);
}
oav = av = strdup(av);
while (av) {
/*
* After the address we can have '/' indicating a mask,
* or ',' indicating another address follows.
*/
char *p, *q;
int masklen;
char md = '\0';
CHECK_LENGTH(cblen,
1 + len + 2 * (int)F_INSN_SIZE(struct in6_addr));
if ((q = strchr(av, ',')) ) {
*q = '\0';
q++;
}
if ((p = strchr(av, '/')) ) {
md = *p; /* save the separator */
*p = '\0'; /* terminate address string */
p++; /* and skip past it */
}
/* now p points to NULL, mask or next entry */
/* lookup stores address in *d as a side effect */
if (lookup_host6(av, d) != 0) {
/* XXX: failed. Free memory and go */
errx(EX_DATAERR, "bad address \"%s\"", av);
}
/* next, look at the mask, if any */
if (md == '/' && strchr(p, ':')) {
if (!inet_pton(AF_INET6, p, &d[1]))
errx(EX_DATAERR, "bad mask \"%s\"", p);
masklen = contigmask((uint8_t *)&(d[1]), 128);
} else {
masklen = (md == '/') ? atoi(p) : 128;
if (masklen > 128 || masklen < 0)
errx(EX_DATAERR, "bad width \"%s\''", p);
else
n2mask(&d[1], masklen);
}
APPLY_MASK(d, &d[1]); /* mask base address with mask */
av = q;
/* Check this entry */
if (masklen == 0) {
/*
* 'any' turns the entire list into a NOP.
* 'not any' never matches, so it is removed from the
* list unless it is the only item, in which case we
* report an error.
*/
if (cmd->o.len & F_NOT && av == NULL && len == 0)
errx(EX_DATAERR, "not any never matches");
continue;
}
/*
* A single IP can be stored alone
*/
if (masklen == 128 && av == NULL && len == 0) {
len = F_INSN_SIZE(struct in6_addr);
break;
}
/* Update length and pointer to arguments */
len += F_INSN_SIZE(struct in6_addr)*2;
d += 2;
} /* end while */
/*
* Total length of the command, remember that 1 is the size of
* the base command.
*/
if (len + 1 > F_LEN_MASK)
errx(EX_DATAERR, "address list too long");
cmd->o.len |= len+1;
free(oav);
return (1);
}
/*
* fills command for ipv6 flow-id filtering
* note that the 20 bit flow number is stored in a array of u_int32_t
* it's supported lists of flow-id, so in the o.arg1 we store how many
* additional flow-id we want to filter, the basic is 1
*/
void
fill_flow6( ipfw_insn_u32 *cmd, char *av, int cblen)
{
u_int32_t type; /* Current flow number */
u_int16_t nflow = 0; /* Current flow index */
char *s = av;
cmd->d[0] = 0; /* Initializing the base number*/
while (s) {
CHECK_LENGTH(cblen,
(int)F_INSN_SIZE(ipfw_insn_u32) + nflow + 1);
av = strsep( &s, ",") ;
type = strtoul(av, &av, 0);
if (*av != ',' && *av != '\0')
errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
if (type > 0xfffff)
errx(EX_DATAERR, "flow number out of range %s", av);
cmd->d[nflow] |= type;
nflow++;
}
if( nflow > 0 ) {
cmd->o.opcode = O_FLOW6ID;
cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow;
cmd->o.arg1 = nflow;
}
else {
errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
}
}
ipfw_insn *
add_srcip6(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate)
{
fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen, tstate);
if (cmd->opcode == O_IP_DST_SET) /* set */
cmd->opcode = O_IP_SRC_SET;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
cmd->opcode = O_IP_SRC_LOOKUP;
else if (F_LEN(cmd) == 0) { /* any */
} else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
cmd->opcode = O_IP6_SRC_ME;
} else if (F_LEN(cmd) ==
(F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
/* single IP, no mask*/
cmd->opcode = O_IP6_SRC;
} else { /* addr/mask opt */
cmd->opcode = O_IP6_SRC_MASK;
}
return cmd;
}
ipfw_insn *
add_dstip6(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate)
{
fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen, tstate);
if (cmd->opcode == O_IP_DST_SET) /* set */
;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
;
else if (F_LEN(cmd) == 0) { /* any */
} else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
cmd->opcode = O_IP6_DST_ME;
} else if (F_LEN(cmd) ==
(F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
/* single IP, no mask*/
cmd->opcode = O_IP6_DST;
} else { /* addr/mask opt */
cmd->opcode = O_IP6_DST_MASK;
}
return cmd;
}
+716
View File
@@ -0,0 +1,716 @@
/*-
* Copyright (c) 2002-2003,2010 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.
*
* Command line interface for IP firewall facility
*/
#include <sys/wait.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include <libgen.h>
#include "ipfw2.h"
static void
help(void)
{
if (is_ipfw()) {
fprintf(stderr,
"IPFW compatibility binary from RELENG_15\n\n"
"ipfw syntax summary (but please do read the ipfw(8) manpage):\n\n"
"\tipfw [-abcdefhnNqStTv] <command>\n\n"
"where <command> is one of the following:\n\n"
"add [num] [set N] [prob x] RULE-BODY\n"
"{pipe|queue} N config PIPE-BODY\n"
"[pipe|queue] {zero|delete|show} [N{,N}]\n"
"nat N config {ip IPADDR|if IFNAME|log|deny_in|same_ports|unreg_only|unreg_cgn|udp_eim|\n"
" reset|reverse|proxy_only|redirect_addr linkspec|\n"
" redirect_port linkspec|redirect_proto linkspec|\n"
" port_range lower-upper}\n"
"set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n"
"set N {show|list|zero|resetlog|delete} [N{,N}] | flush\n"
"table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n"
"table all {flush | list}\n"
"\n"
"RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n"
"ACTION: check-state | allow | count | deny | unreach{,6} CODE |\n"
" skipto N | {divert|tee} PORT | forward ADDR |\n"
" pipe N | queue N | nat N | setfib FIB | reass\n"
"PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n"
"ADDR: [ MAC dst src ether_type ] \n"
" [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
" [ ipv6|ip6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n"
"IPADDR: [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n"
"IP6ADDR: [not] { any | me | me6 | ip6/bits | IP6LIST }\n"
"IP6LIST: { ip6 | ip6/bits }[,IP6LIST]\n"
"IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n"
"OPTION_LIST: OPTION [OPTION_LIST]\n"
"OPTION: bridged | diverted | diverted-loopback | diverted-output |\n"
" {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n"
" {dst-port|src-port} LIST |\n"
" estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
" iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
" ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
" icmp6types LIST | ext6hdr LIST | flow-id N[,N] | fib FIB |\n"
" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
" tcpdatalen LIST | verrevpath | versrcreach | antispoof\n"
);
} else {
fprintf(stderr,
"IPFW compatibility binary from RELENG_15\n\n"
"dnctl syntax summary (but please do read the dnctl(8) manpage):\n\n"
"\tdnctl [-hnsv] <command>\n\n"
"where <command> is one of the following:\n\n"
"[pipe|queue|sched] N config PIPE-BODY\n"
"[pipe|queue|sched] {delete|list|show} [N{,N}]\n"
"\n"
);
}
exit(0);
}
/*
* Called with the arguments, including program name because getopt
* wants it to be present.
* Returns 0 if successful, 1 if empty command, errx() in case of errors.
* First thing we do is process parameters creating an argv[] array
* which includes the program name and a NULL entry at the end.
* If we are called with a single string, we split it on whitespace.
* Also, arguments with a trailing ',' are joined to the next one.
* The pointers (av[]) and data are in a single chunk of memory.
* av[0] points to the original program name, all other entries
* point into the allocated chunk.
*/
static int
ipfw_main(int oldac, char **oldav)
{
int ch, ac;
const char *errstr;
char **av, **save_av;
int do_acct = 0; /* Show packet/byte count */
int try_next = 0; /* set if pipe cmd not found */
int av_size; /* compute the av size */
char *av_p; /* used to build the av list */
#define WHITESP " \t\f\v\n\r"
if (oldac < 2)
return 1; /* need at least one argument */
if (oldac == 2) {
/*
* If we are called with one argument, try to split it into
* words for subsequent parsing. Spaces after a ',' are
* removed by copying the string in-place.
*/
char *arg = oldav[1]; /* The string is the first arg. */
int l = strlen(arg);
int copy = 0; /* 1 if we need to copy, 0 otherwise */
int i, j;
for (i = j = 0; i < l; i++) {
if (arg[i] == '#') /* comment marker */
break;
if (copy) {
arg[j++] = arg[i];
copy = !strchr("," WHITESP, arg[i]);
} else {
copy = !strchr(WHITESP, arg[i]);
if (copy)
arg[j++] = arg[i];
}
}
if (!copy && j > 0) /* last char was a 'blank', remove it */
j--;
l = j; /* the new argument length */
arg[j++] = '\0';
if (l == 0) /* empty string! */
return 1;
/*
* First, count number of arguments. Because of the previous
* processing, this is just the number of blanks plus 1.
*/
for (i = 0, ac = 1; i < l; i++)
if (strchr(WHITESP, arg[i]) != NULL)
ac++;
/*
* Allocate the argument list structure as a single block
* of memory, containing pointers and the argument
* strings. We include one entry for the program name
* because getopt expects it, and a NULL at the end
* to simplify further parsing.
*/
ac++; /* add 1 for the program name */
av_size = (ac+1) * sizeof(char *) + l + 1;
av = safe_calloc(av_size, 1);
/*
* Init the argument pointer to the end of the array
* and copy arguments from arg[] to av[]. For each one,
* j is the initial character, i is the one past the end.
*/
av_p = (char *)&av[ac+1];
for (ac = 1, i = j = 0; i < l; i++) {
if (strchr(WHITESP, arg[i]) != NULL || i == l-1) {
if (i == l-1)
i++;
bcopy(arg+j, av_p, i-j);
av[ac] = av_p;
av_p += i-j; /* the length of the string */
*av_p++ = '\0';
ac++;
j = i + 1;
}
}
} else {
/*
* If an argument ends with ',' join with the next one.
*/
int first, i, l=0;
/*
* Allocate the argument list structure as a single block
* of memory, containing both pointers and the argument
* strings. We include some space for the program name
* because getopt expects it.
* We add an extra pointer to the end of the array,
* to make simpler further parsing.
*/
for (i=0; i<oldac; i++)
l += strlen(oldav[i]);
av_size = (oldac+1) * sizeof(char *) + l + oldac;
av = safe_calloc(av_size, 1);
/*
* Init the argument pointer to the end of the array
* and copy arguments from arg[] to av[]
*/
av_p = (char *)&av[oldac+1];
for (first = i = ac = 1, l = 0; i < oldac; i++) {
char *arg = oldav[i];
int k = strlen(arg);
l += k;
if (arg[k-1] != ',' || i == oldac-1) {
/* Time to copy. */
av[ac] = av_p;
for (l=0; first <= i; first++) {
strcat(av_p, oldav[first]);
av_p += strlen(oldav[first]);
}
*av_p++ = '\0';
ac++;
l = 0;
first = i+1;
}
}
}
/*
* set the progname pointer to the original string
* and terminate the array with null
*/
av[0] = oldav[0];
av[ac] = NULL;
/* Set the force flag for non-interactive processes */
if (!g_co.do_force)
g_co.do_force = !isatty(STDIN_FILENO);
#ifdef EMULATE_SYSCTL /* sysctl emulation */
if (is_ipfw() && ac >= 2 &&
!strcmp(av[1], "sysctl")) {
char *s;
int i;
if (ac != 3) {
printf( "sysctl emulation usage:\n"
" ipfw sysctl name[=value]\n"
" ipfw sysctl -a\n");
return 0;
}
s = strchr(av[2], '=');
if (s == NULL) {
s = !strcmp(av[2], "-a") ? NULL : av[2];
sysctlbyname(s, NULL, NULL, NULL, 0);
} else { /* ipfw sysctl x.y.z=value */
/* assume an INT value, will extend later */
if (s[1] == '\0') {
printf("ipfw sysctl: missing value\n\n");
return 0;
}
*s = '\0';
i = strtol(s+1, NULL, 0);
sysctlbyname(av[2], NULL, NULL, &i, sizeof(int));
}
return 0;
}
#endif
/* Save arguments for final freeing of memory. */
save_av = av;
optind = optreset = 1; /* restart getopt() */
if (is_ipfw()) {
while ((ch = getopt(ac, av, "abcdDefhinNp:qs:STtvx")) != -1)
switch (ch) {
case 'a':
do_acct = 1;
break;
case 'b':
g_co.comment_only = 1;
g_co.do_compact = 1;
break;
case 'c':
g_co.do_compact = 1;
break;
case 'd':
g_co.do_dynamic = 1;
break;
case 'D':
g_co.do_dynamic = 2;
break;
case 'e':
/* nop for compatibility */
break;
case 'f':
g_co.do_force = 1;
break;
case 'h': /* help */
free(save_av);
help();
break; /* NOTREACHED */
case 'i':
g_co.do_value_as_ip = 1;
break;
case 'n':
g_co.test_only = 1;
break;
case 'N':
g_co.do_resolv = 1;
break;
case 'p':
errx(EX_USAGE, "An absolute pathname must be used "
"with -p option.");
/* NOTREACHED */
case 'q':
g_co.do_quiet = 1;
break;
case 's': /* sort */
g_co.do_sort = atoi(optarg);
break;
case 'S':
g_co.show_sets = 1;
break;
case 't':
g_co.do_time = TIMESTAMP_STRING;
break;
case 'T':
g_co.do_time = TIMESTAMP_NUMERIC;
break;
case 'v': /* verbose */
g_co.verbose = 1;
break;
case 'x': /* debug output */
g_co.debug_only = 1;
break;
default:
free(save_av);
return 1;
}
} else {
while ((ch = getopt(ac, av, "hns:v")) != -1)
switch (ch) {
case 'h': /* help */
free(save_av);
help();
break; /* NOTREACHED */
case 'n':
g_co.test_only = 1;
break;
case 's': /* sort */
g_co.do_sort = atoi(optarg);
break;
case 'v': /* verbose */
g_co.verbose = 1;
break;
default:
free(save_av);
return 1;
}
}
ac -= optind;
av += optind;
NEED1("bad arguments, for usage summary ``ipfw''");
/*
* An undocumented behaviour of ipfw1 was to allow rule numbers first,
* e.g. "100 add allow ..." instead of "add 100 allow ...".
* In case, swap first and second argument to get the normal form.
*/
if (ac > 1 && isdigit(*av[0])) {
char *p = av[0];
av[0] = av[1];
av[1] = p;
}
/*
* Optional: pipe, queue or nat.
*/
g_co.do_nat = 0;
g_co.do_pipe = 0;
g_co.use_set = 0;
if (is_ipfw() && !strncmp(*av, "nat", strlen(*av)))
g_co.do_nat = 1;
else if (!strncmp(*av, "pipe", strlen(*av)))
g_co.do_pipe = 1;
else if (_substrcmp(*av, "queue") == 0)
g_co.do_pipe = 2;
else if (_substrcmp(*av, "flowset") == 0)
g_co.do_pipe = 2;
else if (_substrcmp(*av, "sched") == 0)
g_co.do_pipe = 3;
else if (is_ipfw() && !strncmp(*av, "set", strlen(*av))) {
if (ac > 1 && isdigit(av[1][0])) {
g_co.use_set = strtonum(av[1], 0, resvd_set_number,
&errstr);
if (errstr)
errx(EX_DATAERR,
"invalid set number %s\n", av[1]);
ac -= 2; av += 2; g_co.use_set++;
}
}
if (g_co.do_pipe || g_co.do_nat) {
ac--;
av++;
}
NEED1("missing command");
/*
* For pipes, queues and nats we normally say 'nat|pipe NN config'
* but the code is easier to parse as 'nat|pipe config NN'
* so we swap the two arguments.
*/
if ((g_co.do_pipe || g_co.do_nat) && ac > 1 && isdigit(*av[0])) {
char *p = av[0];
av[0] = av[1];
av[1] = p;
}
if (! is_ipfw() && g_co.do_pipe == 0) {
help();
}
if (g_co.use_set == 0) {
if (is_ipfw() && _substrcmp(*av, "add") == 0)
ipfw_add(av);
else if (g_co.do_nat && _substrcmp(*av, "show") == 0)
ipfw_show_nat(ac, av);
else if (g_co.do_pipe && _substrcmp(*av, "config") == 0)
ipfw_config_pipe(ac, av);
else if (g_co.do_nat && _substrcmp(*av, "config") == 0)
ipfw_config_nat(ac, av);
else if (is_ipfw() && _substrcmp(*av, "set") == 0)
ipfw_sets_handler(av);
else if (is_ipfw() && _substrcmp(*av, "table") == 0)
ipfw_table_handler(ac, av);
else if (is_ipfw() && _substrcmp(*av, "enable") == 0)
ipfw_sysctl_handler(av, 1);
else if (is_ipfw() && _substrcmp(*av, "disable") == 0)
ipfw_sysctl_handler(av, 0);
else
try_next = 1;
}
if (g_co.use_set || try_next) {
if (_substrcmp(*av, "delete") == 0)
ipfw_delete(av);
else if (is_ipfw() && !strncmp(*av, "nat64clat", strlen(*av)))
ipfw_nat64clat_handler(ac, av);
else if (is_ipfw() && !strncmp(*av, "nat64stl", strlen(*av)))
ipfw_nat64stl_handler(ac, av);
else if (is_ipfw() && !strncmp(*av, "nat64lsn", strlen(*av)))
ipfw_nat64lsn_handler(ac, av);
else if (is_ipfw() && !strncmp(*av, "nptv6", strlen(*av)))
ipfw_nptv6_handler(ac, av);
else if (_substrcmp(*av, "flush") == 0)
ipfw_flush(g_co.do_force);
else if (is_ipfw() && _substrcmp(*av, "zero") == 0)
ipfw_zero(ac, av, 0 /* IP_FW_ZERO */);
else if (is_ipfw() && _substrcmp(*av, "resetlog") == 0)
ipfw_zero(ac, av, 1 /* IP_FW_RESETLOG */);
else if (_substrcmp(*av, "print") == 0 ||
_substrcmp(*av, "list") == 0)
ipfw_list(ac, av, do_acct);
else if (_substrcmp(*av, "show") == 0)
ipfw_list(ac, av, 1 /* show counters */);
else if (is_ipfw() && _substrcmp(*av, "table") == 0)
ipfw_table_handler(ac, av);
else if (is_ipfw() && _substrcmp(*av, "internal") == 0)
ipfw_internal_handler(ac, av);
else
errx(EX_USAGE, "bad command `%s'", *av);
}
/* Free memory allocated in the argument parsing. */
free(save_av);
return 0;
}
static void
ipfw_readfile(int ac, char *av[])
{
#define MAX_ARGS 32
char buf[4096];
char *progname = av[0]; /* original program name */
const char *cmd = NULL; /* preprocessor name, if any */
const char *filename = av[ac-1]; /* file to read */
int c, lineno=0;
FILE *f = NULL;
pid_t preproc = 0;
if (is_ipfw()) {
while ((c = getopt(ac, av, "cfNnp:qS")) != -1) {
switch(c) {
case 'c':
g_co.do_compact = 1;
break;
case 'f':
g_co.do_force = 1;
break;
case 'N':
g_co.do_resolv = 1;
break;
case 'n':
g_co.test_only = 1;
break;
case 'p':
/*
* ipfw -p cmd [args] filename
*
* We are done with getopt(). All arguments
* except the filename go to the preprocessor,
* so we need to do the following:
* - check that a filename is actually present;
* - advance av by optind-1 to skip arguments
* already processed;
* - decrease ac by optind, to remove the args
* already processed and the final filename;
* - set the last entry in av[] to NULL so
* popen() can detect the end of the array;
* - set optind=ac to let getopt() terminate.
*/
if (optind == ac)
errx(EX_USAGE, "no filename argument");
cmd = optarg;
av[ac-1] = NULL;
av += optind - 1;
ac -= optind;
optind = ac;
break;
case 'q':
g_co.do_quiet = 1;
break;
case 'S':
g_co.show_sets = 1;
break;
default:
errx(EX_USAGE, "bad arguments, for usage"
" summary ``ipfw''");
}
}
} else {
while ((c = getopt(ac, av, "nq")) != -1) {
switch(c) {
case 'n':
g_co.test_only = 1;
break;
case 'q':
g_co.do_quiet = 1;
break;
default:
errx(EX_USAGE, "bad arguments, for usage"
" summary ``dnctl''");
}
}
}
if (cmd == NULL && ac != optind + 1)
errx(EX_USAGE, "extraneous filename arguments %s", av[ac-1]);
if ((f = fopen(filename, "r")) == NULL)
err(EX_UNAVAILABLE, "fopen: %s", filename);
if (cmd != NULL) { /* pipe through preprocessor */
int pipedes[2];
if (pipe(pipedes) == -1)
err(EX_OSERR, "cannot create pipe");
preproc = fork();
if (preproc == -1)
err(EX_OSERR, "cannot fork");
if (preproc == 0) {
/*
* Child, will run the preprocessor with the
* file on stdin and the pipe on stdout.
*/
if (dup2(fileno(f), 0) == -1
|| dup2(pipedes[1], 1) == -1)
err(EX_OSERR, "dup2()");
fclose(f);
close(pipedes[1]);
close(pipedes[0]);
execvp(cmd, av);
err(EX_OSERR, "execvp(%s) failed", cmd);
} else { /* parent, will reopen f as the pipe */
fclose(f);
close(pipedes[1]);
if ((f = fdopen(pipedes[0], "r")) == NULL) {
int savederrno = errno;
(void)kill(preproc, SIGTERM);
errno = savederrno;
err(EX_OSERR, "fdopen()");
}
}
}
while (fgets(buf, sizeof(buf), f)) { /* read commands */
char linename[20];
char *args[2];
lineno++;
snprintf(linename, sizeof(linename), "Line %d", lineno);
setprogname(linename); /* XXX */
args[0] = progname;
args[1] = buf;
ipfw_main(2, args);
}
fclose(f);
if (cmd != NULL) {
int status;
if (waitpid(preproc, &status, 0) == -1)
errx(EX_OSERR, "waitpid()");
if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
errx(EX_UNAVAILABLE,
"preprocessor exited with status %d",
WEXITSTATUS(status));
else if (WIFSIGNALED(status))
errx(EX_UNAVAILABLE,
"preprocessor exited with signal %d",
WTERMSIG(status));
}
}
int
main(int ac, char *av[])
{
#if defined(_WIN32) && defined(TCC)
{
WSADATA wsaData;
int ret=0;
unsigned short wVersionRequested = MAKEWORD(2, 2);
ret = WSAStartup(wVersionRequested, &wsaData);
if (ret != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", ret);
return 1;
}
}
#endif
if (strcmp("dnctl", basename(av[0])) == 0)
g_co.prog = cmdline_prog_dnctl;
else if (strcmp("dnctl15", basename(av[0])) == 0)
g_co.prog = cmdline_prog_dnctl;
else
g_co.prog = cmdline_prog_ipfw;
/*
* If the last argument is an absolute pathname, interpret it
* as a file to be preprocessed.
*/
if (ac > 1 && av[ac - 1][0] == '/') {
if (access(av[ac - 1], R_OK) == 0)
ipfw_readfile(ac, av);
else
err(EX_USAGE, "pathname: %s", av[ac - 1]);
} else {
if (ipfw_main(ac, av)) {
errx(EX_USAGE,
"usage: %s [options]\n"
"do \"%s -h\" or \"man %s\" for details", av[0],
av[0], av[0]);
}
}
return EX_OK;
}
+1196
View File
File diff suppressed because it is too large. Load diff
+536
View File
@@ -0,0 +1,536 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Yandex LLC
* Copyright (c) 2019 Andrey V. Elsukov <ae@FreeBSD.org>
* Copyright (c) 2019 Boris N. Lytochkin <lytboris@gmail.com>
*
* 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 THE AUTHOR ``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 THE AUTHOR 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/types.h>
#include <sys/socket.h>
#include "ipfw2.h"
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <inttypes.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 <netinet6/ip_fw_nat64.h>
#include <arpa/inet.h>
typedef int (nat64clat_cb_t)(ipfw_nat64clat_cfg *i, const char *name,
uint8_t set);
static int nat64clat_foreach(nat64clat_cb_t *f, const char *name, uint8_t set,
int sort);
static void nat64clat_create(const char *name, uint8_t set, int ac, char **av);
static void nat64clat_config(const char *name, uint8_t set, int ac, char **av);
static void nat64clat_destroy(const char *name, uint8_t set);
static void nat64clat_stats(const char *name, uint8_t set);
static void nat64clat_reset_stats(const char *name, uint8_t set);
static int nat64clat_show_cb(ipfw_nat64clat_cfg *cfg, const char *name,
uint8_t set);
static int nat64clat_destroy_cb(ipfw_nat64clat_cfg *cfg, const char *name,
uint8_t set);
static struct _s_x nat64cmds[] = {
{ "create", TOK_CREATE },
{ "config", TOK_CONFIG },
{ "destroy", TOK_DESTROY },
{ "list", TOK_LIST },
{ "show", TOK_LIST },
{ "stats", TOK_STATS },
{ NULL, 0 }
};
static struct _s_x nat64statscmds[] = {
{ "reset", TOK_RESET },
{ NULL, 0 }
};
/*
* This one handles all nat64clat-related commands
* ipfw [set N] nat64clat NAME {create | config} ...
* ipfw [set N] nat64clat NAME stats [reset]
* ipfw [set N] nat64clat {NAME | all} destroy
* ipfw [set N] nat64clat {NAME | all} {list | show}
*/
#define nat64clat_check_name table_check_name
void
ipfw_nat64clat_handler(int ac, char *av[])
{
const char *name;
int tcmd;
uint8_t set;
if (g_co.use_set != 0)
set = g_co.use_set - 1;
else
set = 0;
ac--; av++;
NEED1("nat64clat needs instance name");
name = *av;
if (nat64clat_check_name(name) != 0) {
if (strcmp(name, "all") == 0)
name = NULL;
else
errx(EX_USAGE, "nat64clat instance name %s is invalid",
name);
}
ac--; av++;
NEED1("nat64clat needs command");
tcmd = get_token(nat64cmds, *av, "nat64clat command");
if (name == NULL && tcmd != TOK_DESTROY && tcmd != TOK_LIST)
errx(EX_USAGE, "nat64clat instance name required");
switch (tcmd) {
case TOK_CREATE:
ac--; av++;
nat64clat_create(name, set, ac, av);
break;
case TOK_CONFIG:
ac--; av++;
nat64clat_config(name, set, ac, av);
break;
case TOK_LIST:
nat64clat_foreach(nat64clat_show_cb, name, set, 1);
break;
case TOK_DESTROY:
if (name == NULL)
nat64clat_foreach(nat64clat_destroy_cb, NULL, set, 0);
else
nat64clat_destroy(name, set);
break;
case TOK_STATS:
ac--; av++;
if (ac == 0) {
nat64clat_stats(name, set);
break;
}
tcmd = get_token(nat64statscmds, *av, "stats command");
if (tcmd == TOK_RESET)
nat64clat_reset_stats(name, set);
}
}
static void
nat64clat_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set)
{
ntlv->head.type = IPFW_TLV_EACTION_NAME(1); /* it doesn't matter */
ntlv->head.length = sizeof(ipfw_obj_ntlv);
ntlv->idx = 1;
ntlv->set = set;
strlcpy(ntlv->name, name, sizeof(ntlv->name));
}
static struct _s_x nat64newcmds[] = {
{ "plat_prefix", TOK_PLAT_PREFIX },
{ "clat_prefix", TOK_CLAT_PREFIX },
{ "log", TOK_LOG },
{ "-log", TOK_LOGOFF },
{ "allow_private", TOK_PRIVATE },
{ "-allow_private", TOK_PRIVATEOFF },
{ NULL, 0 }
};
/*
* Creates new nat64clat instance
* ipfw nat64clat <NAME> create clat_prefix <prefix> plat_prefix <prefix>
* Request: [ ipfw_obj_lheader ipfw_nat64clat_cfg ]
*/
#define NAT64CLAT_HAS_CLAT_PREFIX 0x01
#define NAT64CLAT_HAS_PLAT_PREFIX 0x02
static void
nat64clat_create(const char *name, uint8_t set, int ac, char *av[])
{
char buf[sizeof(ipfw_obj_lheader) + sizeof(ipfw_nat64clat_cfg)];
ipfw_nat64clat_cfg *cfg;
ipfw_obj_lheader *olh;
int tcmd, flags;
char *p;
struct in6_addr prefix;
uint8_t plen;
memset(buf, 0, sizeof(buf));
olh = (ipfw_obj_lheader *)buf;
cfg = (ipfw_nat64clat_cfg *)(olh + 1);
/* Some reasonable defaults */
inet_pton(AF_INET6, "64:ff9b::", &cfg->plat_prefix);
cfg->plat_plen = 96;
cfg->set = set;
flags = NAT64CLAT_HAS_PLAT_PREFIX;
while (ac > 0) {
tcmd = get_token(nat64newcmds, *av, "option");
ac--; av++;
switch (tcmd) {
case TOK_PLAT_PREFIX:
case TOK_CLAT_PREFIX:
if (tcmd == TOK_PLAT_PREFIX) {
NEED1("IPv6 plat_prefix required");
} else {
NEED1("IPv6 clat_prefix required");
}
if ((p = strchr(*av, '/')) != NULL)
*p++ = '\0';
if (inet_pton(AF_INET6, *av, &prefix) != 1)
errx(EX_USAGE,
"Bad prefix: %s", *av);
plen = strtol(p, NULL, 10);
if (ipfw_check_nat64prefix(&prefix, plen) != 0)
errx(EX_USAGE,
"Bad prefix length: %s", p);
if (tcmd == TOK_PLAT_PREFIX) {
flags |= NAT64CLAT_HAS_PLAT_PREFIX;
cfg->plat_prefix = prefix;
cfg->plat_plen = plen;
} else {
flags |= NAT64CLAT_HAS_CLAT_PREFIX;
cfg->clat_prefix = prefix;
cfg->clat_plen = plen;
}
ac--; av++;
break;
case TOK_LOG:
cfg->flags |= NAT64_LOG;
break;
case TOK_LOGOFF:
cfg->flags &= ~NAT64_LOG;
break;
case TOK_PRIVATE:
cfg->flags |= NAT64_ALLOW_PRIVATE;
break;
case TOK_PRIVATEOFF:
cfg->flags &= ~NAT64_ALLOW_PRIVATE;
break;
}
}
/* Check validness */
if ((flags & NAT64CLAT_HAS_PLAT_PREFIX) != NAT64CLAT_HAS_PLAT_PREFIX)
errx(EX_USAGE, "plat_prefix required");
if ((flags & NAT64CLAT_HAS_CLAT_PREFIX) != NAT64CLAT_HAS_CLAT_PREFIX)
errx(EX_USAGE, "clat_prefix required");
olh->count = 1;
olh->objsize = sizeof(*cfg);
olh->size = sizeof(buf);
strlcpy(cfg->name, name, sizeof(cfg->name));
if (do_set3(IP_FW_NAT64CLAT_CREATE, &olh->opheader, sizeof(buf)) != 0)
err(EX_OSERR, "nat64clat instance creation failed");
}
/*
* Configures existing nat64clat instance
* ipfw nat64clat <NAME> config <options>
* Request: [ ipfw_obj_header ipfw_nat64clat_cfg ]
*/
static void
nat64clat_config(const char *name, uint8_t set, int ac, char **av)
{
char buf[sizeof(ipfw_obj_header) + sizeof(ipfw_nat64clat_cfg)];
ipfw_nat64clat_cfg *cfg;
ipfw_obj_header *oh;
char *opt;
char *p;
size_t sz;
int tcmd;
struct in6_addr prefix;
uint8_t plen;
if (ac == 0)
errx(EX_USAGE, "config options required");
memset(&buf, 0, sizeof(buf));
oh = (ipfw_obj_header *)buf;
cfg = (ipfw_nat64clat_cfg *)(oh + 1);
sz = sizeof(buf);
nat64clat_fill_ntlv(&oh->ntlv, name, set);
if (do_get3(IP_FW_NAT64CLAT_CONFIG, &oh->opheader, &sz) != 0)
err(EX_OSERR, "failed to get config for instance %s", name);
while (ac > 0) {
tcmd = get_token(nat64newcmds, *av, "option");
opt = *av;
ac--; av++;
switch (tcmd) {
case TOK_PLAT_PREFIX:
case TOK_CLAT_PREFIX:
if (tcmd == TOK_PLAT_PREFIX) {
NEED1("IPv6 plat_prefix required");
} else {
NEED1("IPv6 clat_prefix required");
}
if ((p = strchr(*av, '/')) != NULL)
*p++ = '\0';
else
errx(EX_USAGE,
"Prefix length required: %s", *av);
if (inet_pton(AF_INET6, *av, &prefix) != 1)
errx(EX_USAGE,
"Bad prefix: %s", *av);
plen = strtol(p, NULL, 10);
if (ipfw_check_nat64prefix(&prefix, plen) != 0)
errx(EX_USAGE,
"Bad prefix length: %s", p);
if (tcmd == TOK_PLAT_PREFIX) {
cfg->plat_prefix = prefix;
cfg->plat_plen = plen;
} else {
cfg->clat_prefix = prefix;
cfg->clat_plen = plen;
}
ac--; av++;
break;
case TOK_LOG:
cfg->flags |= NAT64_LOG;
break;
case TOK_LOGOFF:
cfg->flags &= ~NAT64_LOG;
break;
case TOK_PRIVATE:
cfg->flags |= NAT64_ALLOW_PRIVATE;
break;
case TOK_PRIVATEOFF:
cfg->flags &= ~NAT64_ALLOW_PRIVATE;
break;
default:
errx(EX_USAGE, "Can't change %s option", opt);
}
}
if (do_set3(IP_FW_NAT64CLAT_CONFIG, &oh->opheader, sizeof(buf)) != 0)
err(EX_OSERR, "nat64clat instance configuration failed");
}
/*
* Destroys nat64clat instance.
* Request: [ ipfw_obj_header ]
*/
static void
nat64clat_destroy(const char *name, uint8_t set)
{
ipfw_obj_header oh;
memset(&oh, 0, sizeof(oh));
nat64clat_fill_ntlv(&oh.ntlv, name, set);
if (do_set3(IP_FW_NAT64CLAT_DESTROY, &oh.opheader, sizeof(oh)) != 0)
err(EX_OSERR, "failed to destroy nat instance %s", name);
}
/*
* Get nat64clat instance statistics.
* Request: [ ipfw_obj_header ]
* Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ] ]
*/
static int
nat64clat_get_stats(const char *name, uint8_t set,
struct ipfw_nat64clat_stats *stats)
{
ipfw_obj_header *oh;
ipfw_obj_ctlv *oc;
size_t sz;
sz = sizeof(*oh) + sizeof(*oc) + sizeof(*stats);
oh = calloc(1, sz);
nat64clat_fill_ntlv(&oh->ntlv, name, set);
if (do_get3(IP_FW_NAT64CLAT_STATS, &oh->opheader, &sz) == 0) {
oc = (ipfw_obj_ctlv *)(oh + 1);
memcpy(stats, oc + 1, sizeof(*stats));
free(oh);
return (0);
}
free(oh);
return (-1);
}
static void
nat64clat_stats(const char *name, uint8_t set)
{
struct ipfw_nat64clat_stats stats;
if (nat64clat_get_stats(name, set, &stats) != 0)
err(EX_OSERR, "Error retrieving stats");
if (g_co.use_set != 0 || set != 0)
printf("set %u ", set);
printf("nat64clat %s\n", name);
printf("\t%ju packets translated from IPv6 to IPv4\n",
(uintmax_t)stats.opcnt64);
printf("\t%ju packets translated from IPv4 to IPv6\n",
(uintmax_t)stats.opcnt46);
printf("\t%ju IPv6 fragments created\n",
(uintmax_t)stats.ofrags);
printf("\t%ju IPv4 fragments received\n",
(uintmax_t)stats.ifrags);
printf("\t%ju output packets dropped due to no bufs, etc.\n",
(uintmax_t)stats.oerrors);
printf("\t%ju output packets discarded due to no IPv4 route\n",
(uintmax_t)stats.noroute4);
printf("\t%ju output packets discarded due to no IPv6 route\n",
(uintmax_t)stats.noroute6);
printf("\t%ju packets discarded due to unsupported protocol\n",
(uintmax_t)stats.noproto);
printf("\t%ju packets discarded due to memory allocation problems\n",
(uintmax_t)stats.nomem);
printf("\t%ju packets discarded due to some errors\n",
(uintmax_t)stats.dropped);
}
/*
* Reset nat64clat instance statistics specified by @oh->ntlv.
* Request: [ ipfw_obj_header ]
*/
static void
nat64clat_reset_stats(const char *name, uint8_t set)
{
ipfw_obj_header oh;
memset(&oh, 0, sizeof(oh));
nat64clat_fill_ntlv(&oh.ntlv, name, set);
if (do_set3(IP_FW_NAT64CLAT_RESET_STATS, &oh.opheader, sizeof(oh)) != 0)
err(EX_OSERR, "failed to reset stats for instance %s", name);
}
static int
nat64clat_show_cb(ipfw_nat64clat_cfg *cfg, const char *name, uint8_t set)
{
char plat_buf[INET6_ADDRSTRLEN], clat_buf[INET6_ADDRSTRLEN];
if (name != NULL && strcmp(cfg->name, name) != 0)
return (ESRCH);
if (g_co.use_set != 0 && cfg->set != set)
return (ESRCH);
if (g_co.use_set != 0 || cfg->set != 0)
printf("set %u ", cfg->set);
inet_ntop(AF_INET6, &cfg->clat_prefix, clat_buf, sizeof(clat_buf));
inet_ntop(AF_INET6, &cfg->plat_prefix, plat_buf, sizeof(plat_buf));
printf("nat64clat %s clat_prefix %s/%u plat_prefix %s/%u",
cfg->name, clat_buf, cfg->clat_plen, plat_buf, cfg->plat_plen);
if (cfg->flags & NAT64_LOG)
printf(" log");
if (cfg->flags & NAT64_ALLOW_PRIVATE)
printf(" allow_private");
printf("\n");
return (0);
}
static int
nat64clat_destroy_cb(ipfw_nat64clat_cfg *cfg, const char *name __unused,
uint8_t set)
{
if (g_co.use_set != 0 && cfg->set != set)
return (ESRCH);
nat64clat_destroy(cfg->name, cfg->set);
return (0);
}
/*
* Compare nat64clat instances names.
* Honor number comparison.
*/
static int
nat64name_cmp(const void *a, const void *b)
{
const ipfw_nat64clat_cfg *ca, *cb;
ca = (const ipfw_nat64clat_cfg *)a;
cb = (const ipfw_nat64clat_cfg *)b;
if (ca->set > cb->set)
return (1);
else if (ca->set < cb->set)
return (-1);
return (stringnum_cmp(ca->name, cb->name));
}
/*
* Retrieves nat64clat instance list from kernel,
* optionally sorts it and calls requested function for each instance.
*
* Request: [ ipfw_obj_lheader ]
* Reply: [ ipfw_obj_lheader ipfw_nat64clat_cfg x N ]
*/
static int
nat64clat_foreach(nat64clat_cb_t *f, const char *name, uint8_t set, int sort)
{
ipfw_obj_lheader *olh;
ipfw_nat64clat_cfg *cfg;
size_t sz;
uint32_t i;
/* Start with reasonable default */
sz = sizeof(*olh) + 16 * sizeof(*cfg);
for (;;) {
if ((olh = calloc(1, sz)) == NULL)
return (ENOMEM);
olh->size = sz;
if (do_get3(IP_FW_NAT64CLAT_LIST, &olh->opheader, &sz) != 0) {
sz = olh->size;
free(olh);
if (errno != ENOMEM)
return (errno);
continue;
}
if (sort != 0)
qsort(olh + 1, olh->count, olh->objsize,
nat64name_cmp);
cfg = (ipfw_nat64clat_cfg *)(olh + 1);
for (i = 0; i < olh->count; i++) {
(void)f(cfg, name, set); /* Ignore errors for now */
cfg = (ipfw_nat64clat_cfg *)((caddr_t)cfg +
olh->objsize);
}
free(olh);
break;
}
return (0);
}
+901
View File
@@ -0,0 +1,901 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2015-2019 Yandex LLC
* Copyright (c) 2015-2016 Alexander V. Chernikov <melifaro@FreeBSD.org>
* Copyright (c) 2015-2019 Andrey V. Elsukov <ae@FreeBSD.org>
*
* 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 THE AUTHOR ``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 THE AUTHOR 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/types.h>
#include <sys/socket.h>
#include "ipfw2.h"
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <inttypes.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 <netinet6/ip_fw_nat64_15.h>
#include <arpa/inet.h>
static void nat64lsn_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name,
uint8_t set);
typedef int (nat64lsn_cb_t)(ipfw_nat64lsn_cfg *cfg, const char *name,
uint8_t set);
static int nat64lsn_foreach(nat64lsn_cb_t *f, const char *name, uint8_t set,
int sort);
static void nat64lsn_create(const char *name, uint8_t set, int ac, char **av);
static void nat64lsn_config(const char *name, uint8_t set, int ac, char **av);
static void nat64lsn_destroy(const char *name, uint8_t set);
static void nat64lsn_stats(const char *name, uint8_t set);
static void nat64lsn_reset_stats(const char *name, uint8_t set);
static int nat64lsn_show_cb(ipfw_nat64lsn_cfg *cfg, const char *name,
uint8_t set);
static int nat64lsn_destroy_cb(ipfw_nat64lsn_cfg *cfg, const char *name,
uint8_t set);
static int nat64lsn_states_cb(ipfw_nat64lsn_cfg *cfg, const char *name,
uint8_t set);
static struct _s_x nat64cmds[] = {
{ "create", TOK_CREATE },
{ "config", TOK_CONFIG },
{ "destroy", TOK_DESTROY },
{ "list", TOK_LIST },
{ "show", TOK_LIST },
{ "stats", TOK_STATS },
{ NULL, 0 }
};
static uint64_t
nat64lsn_print_states(void *buf)
{
char s[INET6_ADDRSTRLEN], a[INET_ADDRSTRLEN], f[INET_ADDRSTRLEN];
const char *proto;
char sflags[4], *sf;
ipfw_obj_header *oh;
ipfw_obj_data *od;
ipfw_nat64lsn_stg_v1 *stg;
ipfw_nat64lsn_state_v1 *ste;
uint64_t next_idx;
uint32_t i;
int sz;
oh = (ipfw_obj_header *)buf;
od = (ipfw_obj_data *)(oh + 1);
stg = (ipfw_nat64lsn_stg_v1 *)(od + 1);
sz = od->head.length - sizeof(*od);
next_idx = 0;
proto = NULL;
while (sz > 0 && next_idx != 0xFF) {
next_idx = stg->next.index;
sz -= sizeof(*stg);
if (stg->count == 0) {
stg++;
continue;
}
/*
* NOTE: addresses are in network byte order,
* ports are in host byte order.
*/
inet_ntop(AF_INET, &stg->alias4, a, sizeof(a));
ste = (ipfw_nat64lsn_state_v1 *)(stg + 1);
for (i = 0; i < stg->count && sz > 0; i++) {
sf = sflags;
inet_ntop(AF_INET6, &ste->host6, s, sizeof(s));
inet_ntop(AF_INET, &ste->daddr, f, sizeof(f));
switch (ste->proto) {
case IPPROTO_TCP:
proto = "TCP";
if (ste->flags & 0x02)
*sf++ = 'S';
if (ste->flags & 0x04)
*sf++ = 'E';
if (ste->flags & 0x01)
*sf++ = 'F';
break;
case IPPROTO_UDP:
proto = "UDP";
break;
case IPPROTO_ICMP:
proto = "ICMPv6";
break;
}
*sf = '\0';
switch (ste->proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
printf("%s:%d\t%s:%d\t%s\t%s\t%d\t%s:%d\n",
s, ste->sport, a, ste->aport, proto,
sflags, ste->idle, f, ste->dport);
break;
case IPPROTO_ICMP:
printf("%s\t%s\t%s\t\t%d\t%s\n",
s, a, proto, ste->idle, f);
break;
default:
printf("%s\t%s\t%d\t\t%d\t%s\n",
s, a, ste->proto, ste->idle, f);
}
ste++;
sz -= sizeof(*ste);
}
stg = (ipfw_nat64lsn_stg_v1 *)ste;
}
return (next_idx);
}
static int
nat64lsn_states_cb(ipfw_nat64lsn_cfg *cfg, const char *name, uint8_t set)
{
ipfw_obj_header *oh;
ipfw_obj_data *od;
void *buf;
uint64_t next_idx;
size_t sz;
if (name != NULL && strcmp(cfg->name, name) != 0)
return (ESRCH);
if (set != 0 && cfg->set != set)
return (ESRCH);
next_idx = 0;
sz = 4096;
if ((buf = calloc(1, sz)) == NULL)
err(EX_OSERR, NULL);
do {
oh = (ipfw_obj_header *)buf;
oh->opheader.version = 1; /* Force using ov new API */
od = (ipfw_obj_data *)(oh + 1);
nat64lsn_fill_ntlv(&oh->ntlv, cfg->name, set);
od->head.type = IPFW_TLV_OBJDATA;
od->head.length = sizeof(*od) + sizeof(next_idx);
*((uint64_t *)(od + 1)) = next_idx;
if (do_get3(IP_FW_NAT64LSN_LIST_STATES, &oh->opheader, &sz))
err(EX_OSERR, "Error reading nat64lsn states");
next_idx = nat64lsn_print_states(buf);
sz = 4096;
memset(buf, 0, sz);
} while (next_idx != 0xFF);
free(buf);
return (0);
}
static struct _s_x nat64statscmds[] = {
{ "reset", TOK_RESET },
{ NULL, 0 }
};
static void
ipfw_nat64lsn_stats_handler(const char *name, uint8_t set, int ac, char *av[])
{
int tcmd;
if (ac == 0) {
nat64lsn_stats(name, set);
return;
}
NEED1("nat64lsn stats needs command");
tcmd = get_token(nat64statscmds, *av, "nat64lsn stats command");
switch (tcmd) {
case TOK_RESET:
nat64lsn_reset_stats(name, set);
}
}
static struct _s_x nat64listcmds[] = {
{ "states", TOK_STATES },
{ "config", TOK_CONFIG },
{ NULL, 0 }
};
static void
ipfw_nat64lsn_list_handler(const char *name, uint8_t set, int ac, char *av[])
{
int tcmd;
if (ac == 0) {
nat64lsn_foreach(nat64lsn_show_cb, name, set, 1);
return;
}
NEED1("nat64lsn list needs command");
tcmd = get_token(nat64listcmds, *av, "nat64lsn list command");
switch (tcmd) {
case TOK_STATES:
nat64lsn_foreach(nat64lsn_states_cb, name, set, 1);
break;
case TOK_CONFIG:
nat64lsn_foreach(nat64lsn_show_cb, name, set, 1);
}
}
/*
* This one handles all nat64lsn-related commands
* ipfw [set N] nat64lsn NAME {create | config} ...
* ipfw [set N] nat64lsn NAME stats
* ipfw [set N] nat64lsn {NAME | all} destroy
* ipfw [set N] nat64lsn {NAME | all} {list | show} [config | states]
*/
#define nat64lsn_check_name table_check_name
void
ipfw_nat64lsn_handler(int ac, char *av[])
{
const char *name;
int tcmd;
uint8_t set;
if (g_co.use_set != 0)
set = g_co.use_set - 1;
else
set = 0;
ac--; av++;
NEED1("nat64lsn needs instance name");
name = *av;
if (nat64lsn_check_name(name) != 0) {
if (strcmp(name, "all") == 0)
name = NULL;
else
errx(EX_USAGE, "nat64lsn instance name %s is invalid",
name);
}
ac--; av++;
NEED1("nat64lsn needs command");
tcmd = get_token(nat64cmds, *av, "nat64lsn command");
if (name == NULL && tcmd != TOK_DESTROY && tcmd != TOK_LIST)
errx(EX_USAGE, "nat64lsn instance name required");
switch (tcmd) {
case TOK_CREATE:
ac--; av++;
nat64lsn_create(name, set, ac, av);
break;
case TOK_CONFIG:
ac--; av++;
nat64lsn_config(name, set, ac, av);
break;
case TOK_LIST:
ac--; av++;
ipfw_nat64lsn_list_handler(name, set, ac, av);
break;
case TOK_DESTROY:
if (name == NULL)
nat64lsn_foreach(nat64lsn_destroy_cb, NULL, set, 0);
else
nat64lsn_destroy(name, set);
break;
case TOK_STATS:
ac--; av++;
ipfw_nat64lsn_stats_handler(name, set, ac, av);
}
}
static void
nat64lsn_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set)
{
ntlv->head.type = IPFW_TLV_EACTION_NAME(1); /* it doesn't matter */
ntlv->head.length = sizeof(ipfw_obj_ntlv);
ntlv->idx = 1;
ntlv->set = set;
strlcpy(ntlv->name, name, sizeof(ntlv->name));
}
static void
nat64lsn_apply_mask(int af, void *prefix, uint16_t plen)
{
struct in6_addr mask6, *p6;
struct in_addr mask4, *p4;
if (af == AF_INET) {
p4 = (struct in_addr *)prefix;
mask4.s_addr = htonl(~((1 << (32 - plen)) - 1));
p4->s_addr &= mask4.s_addr;
} else if (af == AF_INET6) {
p6 = (struct in6_addr *)prefix;
n2mask(&mask6, plen);
APPLY_MASK(p6, &mask6);
}
}
static void
nat64lsn_parse_prefix(const char *arg, int af, void *prefix, uint16_t *plen)
{
char *p, *l;
p = strdup(arg);
if (p == NULL)
err(EX_OSERR, NULL);
if ((l = strchr(p, '/')) != NULL)
*l++ = '\0';
if (l == NULL)
errx(EX_USAGE, "Prefix length required");
if (inet_pton(af, p, prefix) != 1)
errx(EX_USAGE, "Bad prefix: %s", p);
*plen = (uint16_t)strtol(l, &l, 10);
if (*l != '\0' || *plen == 0 || (af == AF_INET && *plen > 32) ||
(af == AF_INET6 && *plen > 96))
errx(EX_USAGE, "Bad prefix length: %s", arg);
nat64lsn_apply_mask(af, prefix, *plen);
free(p);
}
static uint32_t
nat64lsn_parse_int(const char *arg, const char *desc)
{
char *p;
uint32_t val;
val = (uint32_t)strtol(arg, &p, 10);
if (*p != '\0')
errx(EX_USAGE, "Invalid %s value: %s\n", desc, arg);
return (val);
}
static struct _s_x nat64newcmds[] = {
{ "prefix6", TOK_PREFIX6 },
{ "jmaxlen", TOK_JMAXLEN },
{ "prefix4", TOK_PREFIX4 },
{ "host_del_age", TOK_HOST_DEL_AGE },
{ "pg_del_age", TOK_PG_DEL_AGE },
{ "tcp_syn_age", TOK_TCP_SYN_AGE },
{ "tcp_close_age",TOK_TCP_CLOSE_AGE },
{ "tcp_est_age", TOK_TCP_EST_AGE },
{ "udp_age", TOK_UDP_AGE },
{ "icmp_age", TOK_ICMP_AGE },
{ "states_chunks",TOK_STATES_CHUNKS },
{ "log", TOK_LOG },
{ "-log", TOK_LOGOFF },
{ "allow_private", TOK_PRIVATE },
{ "-allow_private", TOK_PRIVATEOFF },
{ "swap_conf", TOK_SWAPCONF },
{ "-swap_conf", TOK_SWAPCONFOFF },
/* for compatibility with old configurations */
{ "max_ports", TOK_MAX_PORTS }, /* unused */
{ NULL, 0 }
};
/*
* Creates new nat64lsn instance
* ipfw nat64lsn <NAME> create
* [ max_ports <N> ]
* Request: [ ipfw_obj_lheader ipfw_nat64lsn_cfg ]
*/
#define NAT64LSN_HAS_PREFIX4 0x01
#define NAT64LSN_HAS_PREFIX6 0x02
static void
nat64lsn_create(const char *name, uint8_t set, int ac, char **av)
{
char buf[sizeof(ipfw_obj_lheader) + sizeof(ipfw_nat64lsn_cfg)];
ipfw_nat64lsn_cfg *cfg;
ipfw_obj_lheader *olh;
int tcmd, flags;
char *opt;
memset(&buf, 0, sizeof(buf));
olh = (ipfw_obj_lheader *)buf;
cfg = (ipfw_nat64lsn_cfg *)(olh + 1);
/* Some reasonable defaults */
inet_pton(AF_INET6, "64:ff9b::", &cfg->prefix6);
cfg->plen6 = 96;
cfg->set = set;
cfg->max_ports = NAT64LSN_MAX_PORTS;
cfg->jmaxlen = NAT64LSN_JMAXLEN;
cfg->nh_delete_delay = NAT64LSN_HOST_AGE;
cfg->pg_delete_delay = NAT64LSN_PG_AGE;
cfg->st_syn_ttl = NAT64LSN_TCP_SYN_AGE;
cfg->st_estab_ttl = NAT64LSN_TCP_EST_AGE;
cfg->st_close_ttl = NAT64LSN_TCP_FIN_AGE;
cfg->st_udp_ttl = NAT64LSN_UDP_AGE;
cfg->st_icmp_ttl = NAT64LSN_ICMP_AGE;
flags = NAT64LSN_HAS_PREFIX6;
while (ac > 0) {
tcmd = get_token(nat64newcmds, *av, "option");
opt = *av;
ac--; av++;
switch (tcmd) {
case TOK_PREFIX4:
NEED1("IPv4 prefix required");
nat64lsn_parse_prefix(*av, AF_INET, &cfg->prefix4,
&cfg->plen4);
flags |= NAT64LSN_HAS_PREFIX4;
ac--; av++;
break;
case TOK_PREFIX6:
NEED1("IPv6 prefix required");
nat64lsn_parse_prefix(*av, AF_INET6, &cfg->prefix6,
&cfg->plen6);
if (ipfw_check_nat64prefix(&cfg->prefix6,
cfg->plen6) != 0 &&
!IN6_IS_ADDR_UNSPECIFIED(&cfg->prefix6))
errx(EX_USAGE, "Bad prefix6 %s", *av);
ac--; av++;
break;
case TOK_JMAXLEN:
NEED1("job queue length required");
cfg->jmaxlen = nat64lsn_parse_int(*av, opt);
ac--; av++;
break;
case TOK_MAX_PORTS:
NEED1("Max per-user ports required");
cfg->max_ports = nat64lsn_parse_int(*av, opt);
ac--; av++;
break;
case TOK_HOST_DEL_AGE:
NEED1("host delete delay required");
cfg->nh_delete_delay = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_PG_DEL_AGE:
NEED1("portgroup delete delay required");
cfg->pg_delete_delay = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_TCP_SYN_AGE:
NEED1("tcp syn age required");
cfg->st_syn_ttl = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_TCP_CLOSE_AGE:
NEED1("tcp close age required");
cfg->st_close_ttl = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_TCP_EST_AGE:
NEED1("tcp est age required");
cfg->st_estab_ttl = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_UDP_AGE:
NEED1("udp age required");
cfg->st_udp_ttl = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_ICMP_AGE:
NEED1("icmp age required");
cfg->st_icmp_ttl = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_STATES_CHUNKS:
NEED1("number of chunks required");
cfg->states_chunks = (uint8_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_LOG:
cfg->flags |= NAT64_LOG;
break;
case TOK_LOGOFF:
cfg->flags &= ~NAT64_LOG;
break;
case TOK_PRIVATE:
cfg->flags |= NAT64_ALLOW_PRIVATE;
break;
case TOK_PRIVATEOFF:
cfg->flags &= ~NAT64_ALLOW_PRIVATE;
break;
case TOK_SWAPCONF:
cfg->flags |= NAT64LSN_ALLOW_SWAPCONF;
break;
case TOK_SWAPCONFOFF:
cfg->flags &= ~NAT64LSN_ALLOW_SWAPCONF;
break;
}
}
/* Check validness */
if ((flags & NAT64LSN_HAS_PREFIX4) != NAT64LSN_HAS_PREFIX4)
errx(EX_USAGE, "prefix4 required");
olh->count = 1;
olh->objsize = sizeof(*cfg);
olh->size = sizeof(buf);
strlcpy(cfg->name, name, sizeof(cfg->name));
if (do_set3(IP_FW_NAT64LSN_CREATE, &olh->opheader, sizeof(buf)) != 0)
err(EX_OSERR, "nat64lsn instance creation failed");
}
/*
* Configures existing nat64lsn instance
* ipfw nat64lsn <NAME> config <options>
* Request: [ ipfw_obj_header ipfw_nat64lsn_cfg ]
*/
static void
nat64lsn_config(const char *name, uint8_t set, int ac, char **av)
{
char buf[sizeof(ipfw_obj_header) + sizeof(ipfw_nat64lsn_cfg)];
ipfw_nat64lsn_cfg *cfg;
ipfw_obj_header *oh;
size_t sz;
char *opt;
int tcmd;
if (ac == 0)
errx(EX_USAGE, "config options required");
memset(&buf, 0, sizeof(buf));
oh = (ipfw_obj_header *)buf;
cfg = (ipfw_nat64lsn_cfg *)(oh + 1);
sz = sizeof(buf);
nat64lsn_fill_ntlv(&oh->ntlv, name, set);
if (do_get3(IP_FW_NAT64LSN_CONFIG, &oh->opheader, &sz) != 0)
err(EX_OSERR, "failed to get config for instance %s", name);
while (ac > 0) {
tcmd = get_token(nat64newcmds, *av, "option");
opt = *av;
ac--; av++;
switch (tcmd) {
case TOK_MAX_PORTS:
NEED1("Max per-user ports required");
cfg->max_ports = nat64lsn_parse_int(*av, opt);
ac--; av++;
break;
case TOK_JMAXLEN:
NEED1("job queue length required");
cfg->jmaxlen = nat64lsn_parse_int(*av, opt);
ac--; av++;
break;
case TOK_HOST_DEL_AGE:
NEED1("host delete delay required");
cfg->nh_delete_delay = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_PG_DEL_AGE:
NEED1("portgroup delete delay required");
cfg->pg_delete_delay = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_TCP_SYN_AGE:
NEED1("tcp syn age required");
cfg->st_syn_ttl = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_TCP_CLOSE_AGE:
NEED1("tcp close age required");
cfg->st_close_ttl = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_TCP_EST_AGE:
NEED1("tcp est age required");
cfg->st_estab_ttl = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_UDP_AGE:
NEED1("udp age required");
cfg->st_udp_ttl = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_ICMP_AGE:
NEED1("icmp age required");
cfg->st_icmp_ttl = (uint16_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_STATES_CHUNKS:
NEED1("number of chunks required");
cfg->states_chunks = (uint8_t)nat64lsn_parse_int(
*av, opt);
ac--; av++;
break;
case TOK_LOG:
cfg->flags |= NAT64_LOG;
break;
case TOK_LOGOFF:
cfg->flags &= ~NAT64_LOG;
break;
case TOK_PRIVATE:
cfg->flags |= NAT64_ALLOW_PRIVATE;
break;
case TOK_PRIVATEOFF:
cfg->flags &= ~NAT64_ALLOW_PRIVATE;
break;
case TOK_SWAPCONF:
cfg->flags |= NAT64LSN_ALLOW_SWAPCONF;
break;
case TOK_SWAPCONFOFF:
cfg->flags &= ~NAT64LSN_ALLOW_SWAPCONF;
break;
default:
errx(EX_USAGE, "Can't change %s option", opt);
}
}
if (do_set3(IP_FW_NAT64LSN_CONFIG, &oh->opheader, sizeof(buf)) != 0)
err(EX_OSERR, "nat64lsn instance configuration failed");
}
/*
* Reset nat64lsn instance statistics specified by @oh->ntlv.
* Request: [ ipfw_obj_header ]
*/
static void
nat64lsn_reset_stats(const char *name, uint8_t set)
{
ipfw_obj_header oh;
memset(&oh, 0, sizeof(oh));
nat64lsn_fill_ntlv(&oh.ntlv, name, set);
if (do_set3(IP_FW_NAT64LSN_RESET_STATS, &oh.opheader, sizeof(oh)) != 0)
err(EX_OSERR, "failed to reset stats for instance %s", name);
}
/*
* Destroys nat64lsn instance specified by @oh->ntlv.
* Request: [ ipfw_obj_header ]
*/
static void
nat64lsn_destroy(const char *name, uint8_t set)
{
ipfw_obj_header oh;
memset(&oh, 0, sizeof(oh));
nat64lsn_fill_ntlv(&oh.ntlv, name, set);
if (do_set3(IP_FW_NAT64LSN_DESTROY, &oh.opheader, sizeof(oh)) != 0)
err(EX_OSERR, "failed to destroy nat instance %s", name);
}
/*
* Get nat64lsn instance statistics.
* Request: [ ipfw_obj_header ]
* Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ] ]
*/
static int
nat64lsn_get_stats(const char *name, uint8_t set,
struct ipfw_nat64lsn_stats *stats)
{
ipfw_obj_header *oh;
ipfw_obj_ctlv *oc;
size_t sz;
sz = sizeof(*oh) + sizeof(*oc) + sizeof(*stats);
oh = calloc(1, sz);
nat64lsn_fill_ntlv(&oh->ntlv, name, set);
if (do_get3(IP_FW_NAT64LSN_STATS, &oh->opheader, &sz) == 0) {
oc = (ipfw_obj_ctlv *)(oh + 1);
memcpy(stats, oc + 1, sizeof(*stats));
free(oh);
return (0);
}
free(oh);
return (-1);
}
static void
nat64lsn_stats(const char *name, uint8_t set)
{
struct ipfw_nat64lsn_stats stats;
if (nat64lsn_get_stats(name, set, &stats) != 0)
err(EX_OSERR, "Error retrieving stats");
if (g_co.use_set != 0 || set != 0)
printf("set %u ", set);
printf("nat64lsn %s\n", name);
printf("\t%ju packets translated from IPv6 to IPv4\n",
(uintmax_t)stats.opcnt64);
printf("\t%ju packets translated from IPv4 to IPv6\n",
(uintmax_t)stats.opcnt46);
printf("\t%ju IPv6 fragments created\n",
(uintmax_t)stats.ofrags);
printf("\t%ju IPv4 fragments received\n",
(uintmax_t)stats.ifrags);
printf("\t%ju output packets dropped due to no bufs, etc.\n",
(uintmax_t)stats.oerrors);
printf("\t%ju output packets discarded due to no IPv4 route\n",
(uintmax_t)stats.noroute4);
printf("\t%ju output packets discarded due to no IPv6 route\n",
(uintmax_t)stats.noroute6);
printf("\t%ju packets discarded due to unsupported protocol\n",
(uintmax_t)stats.noproto);
printf("\t%ju packets discarded due to memory allocation problems\n",
(uintmax_t)stats.nomem);
printf("\t%ju packets discarded due to some errors\n",
(uintmax_t)stats.dropped);
printf("\t%ju packets not matched with IPv4 prefix\n",
(uintmax_t)stats.nomatch4);
printf("\t%ju mbufs queued for post processing\n",
(uintmax_t)stats.jreinjected);
printf("\t%ju times the job queue was processed\n",
(uintmax_t)stats.jcalls);
printf("\t%ju job requests queued\n",
(uintmax_t)stats.jrequests);
printf("\t%ju job requests queue limit reached\n",
(uintmax_t)stats.jmaxlen);
printf("\t%ju job requests failed due to memory allocation problems\n",
(uintmax_t)stats.jnomem);
printf("\t%ju hosts allocated\n", (uintmax_t)stats.hostcount);
printf("\t%ju hosts requested\n", (uintmax_t)stats.jhostsreq);
printf("\t%ju host requests failed\n", (uintmax_t)stats.jhostfails);
printf("\t%ju portgroups requested\n", (uintmax_t)stats.jportreq);
printf("\t%ju portgroups allocated\n", (uintmax_t)stats.spgcreated);
printf("\t%ju portgroups deleted\n", (uintmax_t)stats.spgdeleted);
printf("\t%ju portgroup requests failed\n",
(uintmax_t)stats.jportfails);
printf("\t%ju portgroups allocated for TCP\n",
(uintmax_t)stats.tcpchunks);
printf("\t%ju portgroups allocated for UDP\n",
(uintmax_t)stats.udpchunks);
printf("\t%ju portgroups allocated for ICMP\n",
(uintmax_t)stats.icmpchunks);
printf("\t%ju states created\n", (uintmax_t)stats.screated);
printf("\t%ju states deleted\n", (uintmax_t)stats.sdeleted);
}
static int
nat64lsn_show_cb(ipfw_nat64lsn_cfg *cfg, const char *name, uint8_t set)
{
char abuf[INET6_ADDRSTRLEN];
if (name != NULL && strcmp(cfg->name, name) != 0)
return (ESRCH);
if (g_co.use_set != 0 && cfg->set != set)
return (ESRCH);
if (g_co.use_set != 0 || cfg->set != 0)
printf("set %u ", cfg->set);
inet_ntop(AF_INET, &cfg->prefix4, abuf, sizeof(abuf));
printf("nat64lsn %s prefix4 %s/%u", cfg->name, abuf, cfg->plen4);
inet_ntop(AF_INET6, &cfg->prefix6, abuf, sizeof(abuf));
printf(" prefix6 %s/%u", abuf, cfg->plen6);
if (g_co.verbose || cfg->states_chunks > 1)
printf(" states_chunks %u", cfg->states_chunks);
if (g_co.verbose || cfg->nh_delete_delay != NAT64LSN_HOST_AGE)
printf(" host_del_age %u", cfg->nh_delete_delay);
if (g_co.verbose || cfg->pg_delete_delay != NAT64LSN_PG_AGE)
printf(" pg_del_age %u", cfg->pg_delete_delay);
if (g_co.verbose || cfg->st_syn_ttl != NAT64LSN_TCP_SYN_AGE)
printf(" tcp_syn_age %u", cfg->st_syn_ttl);
if (g_co.verbose || cfg->st_close_ttl != NAT64LSN_TCP_FIN_AGE)
printf(" tcp_close_age %u", cfg->st_close_ttl);
if (g_co.verbose || cfg->st_estab_ttl != NAT64LSN_TCP_EST_AGE)
printf(" tcp_est_age %u", cfg->st_estab_ttl);
if (g_co.verbose || cfg->st_udp_ttl != NAT64LSN_UDP_AGE)
printf(" udp_age %u", cfg->st_udp_ttl);
if (g_co.verbose || cfg->st_icmp_ttl != NAT64LSN_ICMP_AGE)
printf(" icmp_age %u", cfg->st_icmp_ttl);
if (g_co.verbose || cfg->jmaxlen != NAT64LSN_JMAXLEN)
printf(" jmaxlen %u", cfg->jmaxlen);
if (cfg->flags & NAT64LSN_ALLOW_SWAPCONF)
printf(" swap_conf");
if (cfg->flags & NAT64_LOG)
printf(" log");
if (cfg->flags & NAT64_ALLOW_PRIVATE)
printf(" allow_private");
printf("\n");
return (0);
}
static int
nat64lsn_destroy_cb(ipfw_nat64lsn_cfg *cfg, const char *name __unused,
uint8_t set)
{
if (g_co.use_set != 0 && cfg->set != set)
return (ESRCH);
nat64lsn_destroy(cfg->name, cfg->set);
return (0);
}
/*
* Compare nat64lsn instances names.
* Honor number comparison.
*/
static int
nat64name_cmp(const void *a, const void *b)
{
const ipfw_nat64lsn_cfg *ca, *cb;
ca = (const ipfw_nat64lsn_cfg *)a;
cb = (const ipfw_nat64lsn_cfg *)b;
if (ca->set > cb->set)
return (1);
else if (ca->set < cb->set)
return (-1);
return (stringnum_cmp(ca->name, cb->name));
}
/*
* Retrieves nat64lsn instance list from kernel,
* optionally sorts it and calls requested function for each instance.
*
* Request: [ ipfw_obj_lheader ]
* Reply: [ ipfw_obj_lheader ipfw_nat64lsn_cfg x N ]
*/
static int
nat64lsn_foreach(nat64lsn_cb_t *f, const char *name, uint8_t set, int sort)
{
ipfw_obj_lheader *olh;
ipfw_nat64lsn_cfg *cfg;
size_t sz;
uint32_t i;
/* Start with reasonable default */
sz = sizeof(*olh) + 16 * sizeof(ipfw_nat64lsn_cfg);
for (;;) {
if ((olh = calloc(1, sz)) == NULL)
return (ENOMEM);
olh->size = sz;
if (do_get3(IP_FW_NAT64LSN_LIST, &olh->opheader, &sz) != 0) {
sz = olh->size;
free(olh);
if (errno != ENOMEM)
return (errno);
continue;
}
if (sort != 0)
qsort(olh + 1, olh->count, olh->objsize,
nat64name_cmp);
cfg = (ipfw_nat64lsn_cfg *)(olh + 1);
for (i = 0; i < olh->count; i++) {
(void)f(cfg, name, set); /* Ignore errors for now */
cfg = (ipfw_nat64lsn_cfg *)((caddr_t)cfg +
olh->objsize);
}
free(olh);
break;
}
return (0);
}
+552
View File
@@ -0,0 +1,552 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2015-2019 Yandex LLC
* Copyright (c) 2015-2019 Andrey V. Elsukov <ae@FreeBSD.org>
*
* 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 THE AUTHOR ``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 THE AUTHOR 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/types.h>
#include <sys/socket.h>
#include "ipfw2.h"
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <inttypes.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 <netinet6/ip_fw_nat64_15.h>
#include <arpa/inet.h>
typedef int (nat64stl_cb_t)(ipfw_nat64stl_cfg *i, const char *name,
uint8_t set);
static int nat64stl_foreach(nat64stl_cb_t *f, const char *name, uint8_t set,
int sort);
static void nat64stl_create(const char *name, uint8_t set, int ac, char **av);
static void nat64stl_config(const char *name, uint8_t set, int ac, char **av);
static void nat64stl_destroy(const char *name, uint8_t set);
static void nat64stl_stats(const char *name, uint8_t set);
static void nat64stl_reset_stats(const char *name, uint8_t set);
static int nat64stl_show_cb(ipfw_nat64stl_cfg *cfg, const char *name,
uint8_t set);
static int nat64stl_destroy_cb(ipfw_nat64stl_cfg *cfg, const char *name,
uint8_t set);
static struct _s_x nat64cmds[] = {
{ "create", TOK_CREATE },
{ "config", TOK_CONFIG },
{ "destroy", TOK_DESTROY },
{ "list", TOK_LIST },
{ "show", TOK_LIST },
{ "stats", TOK_STATS },
{ NULL, 0 }
};
#define IPV6_ADDR_INT32_WKPFX htonl(0x64ff9b)
#define IN6_IS_ADDR_WKPFX(a) \
((a)->__u6_addr.__u6_addr32[0] == IPV6_ADDR_INT32_WKPFX && \
(a)->__u6_addr.__u6_addr32[1] == 0 && \
(a)->__u6_addr.__u6_addr32[2] == 0)
int
ipfw_check_nat64prefix(const struct in6_addr *prefix, int length)
{
switch (length) {
case 32:
case 40:
case 48:
case 56:
case 64:
/* Well-known prefix has 96 prefix length */
if (IN6_IS_ADDR_WKPFX(prefix))
return (EINVAL);
/* FALLTHROUGH */
case 96:
/* Bits 64 to 71 must be set to zero */
if (prefix->__u6_addr.__u6_addr8[8] != 0)
return (EINVAL);
/* XXX: looks incorrect */
if (IN6_IS_ADDR_MULTICAST(prefix) ||
IN6_IS_ADDR_UNSPECIFIED(prefix) ||
IN6_IS_ADDR_LOOPBACK(prefix))
return (EINVAL);
return (0);
}
return (EINVAL);
}
static struct _s_x nat64statscmds[] = {
{ "reset", TOK_RESET },
{ NULL, 0 }
};
/*
* This one handles all nat64stl-related commands
* ipfw [set N] nat64stl NAME {create | config} ...
* ipfw [set N] nat64stl NAME stats [reset]
* ipfw [set N] nat64stl {NAME | all} destroy
* ipfw [set N] nat64stl {NAME | all} {list | show}
*/
#define nat64stl_check_name table_check_name
void
ipfw_nat64stl_handler(int ac, char *av[])
{
const char *name;
int tcmd;
uint8_t set;
if (g_co.use_set != 0)
set = g_co.use_set - 1;
else
set = 0;
ac--; av++;
NEED1("nat64stl needs instance name");
name = *av;
if (nat64stl_check_name(name) != 0) {
if (strcmp(name, "all") == 0)
name = NULL;
else
errx(EX_USAGE, "nat64stl instance name %s is invalid",
name);
}
ac--; av++;
NEED1("nat64stl needs command");
tcmd = get_token(nat64cmds, *av, "nat64stl command");
if (name == NULL && tcmd != TOK_DESTROY && tcmd != TOK_LIST)
errx(EX_USAGE, "nat64stl instance name required");
switch (tcmd) {
case TOK_CREATE:
ac--; av++;
nat64stl_create(name, set, ac, av);
break;
case TOK_CONFIG:
ac--; av++;
nat64stl_config(name, set, ac, av);
break;
case TOK_LIST:
nat64stl_foreach(nat64stl_show_cb, name, set, 1);
break;
case TOK_DESTROY:
if (name == NULL)
nat64stl_foreach(nat64stl_destroy_cb, NULL, set, 0);
else
nat64stl_destroy(name, set);
break;
case TOK_STATS:
ac--; av++;
if (ac == 0) {
nat64stl_stats(name, set);
break;
}
tcmd = get_token(nat64statscmds, *av, "stats command");
if (tcmd == TOK_RESET)
nat64stl_reset_stats(name, set);
}
}
static void
nat64stl_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set)
{
ntlv->head.type = IPFW_TLV_EACTION_NAME(1); /* it doesn't matter */
ntlv->head.length = sizeof(ipfw_obj_ntlv);
ntlv->idx = 1;
ntlv->set = set;
strlcpy(ntlv->name, name, sizeof(ntlv->name));
}
static struct _s_x nat64newcmds[] = {
{ "table4", TOK_TABLE4 },
{ "table6", TOK_TABLE6 },
{ "prefix6", TOK_PREFIX6 },
{ "log", TOK_LOG },
{ "-log", TOK_LOGOFF },
{ "allow_private", TOK_PRIVATE },
{ "-allow_private", TOK_PRIVATEOFF },
{ NULL, 0 }
};
/*
* Creates new nat64stl instance
* ipfw nat64stl <NAME> create table4 <name> table6 <name> [ prefix6 <prefix>]
* Request: [ ipfw_obj_lheader ipfw_nat64stl_cfg ]
*/
#define NAT64STL_HAS_TABLE4 0x01
#define NAT64STL_HAS_TABLE6 0x02
#define NAT64STL_HAS_PREFIX6 0x04
static void
nat64stl_create(const char *name, uint8_t set, int ac, char *av[])
{
char buf[sizeof(ipfw_obj_lheader) + sizeof(ipfw_nat64stl_cfg)];
ipfw_nat64stl_cfg *cfg;
ipfw_obj_lheader *olh;
int tcmd, flags;
char *p;
memset(buf, 0, sizeof(buf));
olh = (ipfw_obj_lheader *)buf;
cfg = (ipfw_nat64stl_cfg *)(olh + 1);
/* Some reasonable defaults */
inet_pton(AF_INET6, "64:ff9b::", &cfg->prefix6);
cfg->plen6 = 96;
cfg->set = set;
flags = NAT64STL_HAS_PREFIX6;
while (ac > 0) {
tcmd = get_token(nat64newcmds, *av, "option");
ac--; av++;
switch (tcmd) {
case TOK_TABLE4:
NEED1("table name required");
table_fill_ntlv(&cfg->ntlv4, *av, set, 4);
flags |= NAT64STL_HAS_TABLE4;
ac--; av++;
break;
case TOK_TABLE6:
NEED1("table name required");
table_fill_ntlv(&cfg->ntlv6, *av, set, 6);
flags |= NAT64STL_HAS_TABLE6;
ac--; av++;
break;
case TOK_PREFIX6:
NEED1("IPv6 prefix6 required");
if ((p = strchr(*av, '/')) != NULL)
*p++ = '\0';
else
errx(EX_USAGE,
"Prefix length required: %s", *av);
if (inet_pton(AF_INET6, *av, &cfg->prefix6) != 1)
errx(EX_USAGE,
"Bad prefix: %s", *av);
cfg->plen6 = strtol(p, NULL, 10);
if (ipfw_check_nat64prefix(&cfg->prefix6,
cfg->plen6) != 0)
errx(EX_USAGE,
"Bad prefix length: %s", p);
flags |= NAT64STL_HAS_PREFIX6;
ac--; av++;
break;
case TOK_LOG:
cfg->flags |= NAT64_LOG;
break;
case TOK_LOGOFF:
cfg->flags &= ~NAT64_LOG;
break;
case TOK_PRIVATE:
cfg->flags |= NAT64_ALLOW_PRIVATE;
break;
case TOK_PRIVATEOFF:
cfg->flags &= ~NAT64_ALLOW_PRIVATE;
break;
}
}
/* Check validness */
if ((flags & NAT64STL_HAS_TABLE4) != NAT64STL_HAS_TABLE4)
errx(EX_USAGE, "table4 required");
if ((flags & NAT64STL_HAS_TABLE6) != NAT64STL_HAS_TABLE6)
errx(EX_USAGE, "table6 required");
if ((flags & NAT64STL_HAS_PREFIX6) != NAT64STL_HAS_PREFIX6)
errx(EX_USAGE, "prefix6 required");
olh->count = 1;
olh->objsize = sizeof(*cfg);
olh->size = sizeof(buf);
strlcpy(cfg->name, name, sizeof(cfg->name));
if (do_set3(IP_FW_NAT64STL_CREATE, &olh->opheader, sizeof(buf)) != 0)
err(EX_OSERR, "nat64stl instance creation failed");
}
/*
* Configures existing nat64stl instance
* ipfw nat64stl <NAME> config <options>
* Request: [ ipfw_obj_header ipfw_nat64stl_cfg ]
*/
static void
nat64stl_config(const char *name, uint8_t set, int ac, char **av)
{
char buf[sizeof(ipfw_obj_header) + sizeof(ipfw_nat64stl_cfg)];
ipfw_nat64stl_cfg *cfg;
ipfw_obj_header *oh;
char *opt;
size_t sz;
int tcmd;
if (ac == 0)
errx(EX_USAGE, "config options required");
memset(&buf, 0, sizeof(buf));
oh = (ipfw_obj_header *)buf;
cfg = (ipfw_nat64stl_cfg *)(oh + 1);
sz = sizeof(buf);
nat64stl_fill_ntlv(&oh->ntlv, name, set);
if (do_get3(IP_FW_NAT64STL_CONFIG, &oh->opheader, &sz) != 0)
err(EX_OSERR, "failed to get config for instance %s", name);
while (ac > 0) {
tcmd = get_token(nat64newcmds, *av, "option");
opt = *av;
ac--; av++;
switch (tcmd) {
#if 0
case TOK_TABLE4:
NEED1("table name required");
table_fill_ntlv(&cfg->ntlv4, *av, set, 4);
ac--; av++;
break;
case TOK_TABLE6:
NEED1("table name required");
table_fill_ntlv(&cfg->ntlv6, *av, set, 6);
ac--; av++;
break;
#endif
case TOK_LOG:
cfg->flags |= NAT64_LOG;
break;
case TOK_LOGOFF:
cfg->flags &= ~NAT64_LOG;
break;
case TOK_PRIVATE:
cfg->flags |= NAT64_ALLOW_PRIVATE;
break;
case TOK_PRIVATEOFF:
cfg->flags &= ~NAT64_ALLOW_PRIVATE;
break;
default:
errx(EX_USAGE, "Can't change %s option", opt);
}
}
if (do_set3(IP_FW_NAT64STL_CONFIG, &oh->opheader, sizeof(buf)) != 0)
err(EX_OSERR, "nat64stl instance configuration failed");
}
/*
* Destroys nat64stl instance.
* Request: [ ipfw_obj_header ]
*/
static void
nat64stl_destroy(const char *name, uint8_t set)
{
ipfw_obj_header oh;
memset(&oh, 0, sizeof(oh));
nat64stl_fill_ntlv(&oh.ntlv, name, set);
if (do_set3(IP_FW_NAT64STL_DESTROY, &oh.opheader, sizeof(oh)) != 0)
err(EX_OSERR, "failed to destroy nat instance %s", name);
}
/*
* Get nat64stl instance statistics.
* Request: [ ipfw_obj_header ]
* Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ] ]
*/
static int
nat64stl_get_stats(const char *name, uint8_t set,
struct ipfw_nat64stl_stats *stats)
{
ipfw_obj_header *oh;
ipfw_obj_ctlv *oc;
size_t sz;
sz = sizeof(*oh) + sizeof(*oc) + sizeof(*stats);
oh = calloc(1, sz);
nat64stl_fill_ntlv(&oh->ntlv, name, set);
if (do_get3(IP_FW_NAT64STL_STATS, &oh->opheader, &sz) == 0) {
oc = (ipfw_obj_ctlv *)(oh + 1);
memcpy(stats, oc + 1, sizeof(*stats));
free(oh);
return (0);
}
free(oh);
return (-1);
}
static void
nat64stl_stats(const char *name, uint8_t set)
{
struct ipfw_nat64stl_stats stats;
if (nat64stl_get_stats(name, set, &stats) != 0)
err(EX_OSERR, "Error retrieving stats");
if (g_co.use_set != 0 || set != 0)
printf("set %u ", set);
printf("nat64stl %s\n", name);
printf("\t%ju packets translated from IPv6 to IPv4\n",
(uintmax_t)stats.opcnt64);
printf("\t%ju packets translated from IPv4 to IPv6\n",
(uintmax_t)stats.opcnt46);
printf("\t%ju IPv6 fragments created\n",
(uintmax_t)stats.ofrags);
printf("\t%ju IPv4 fragments received\n",
(uintmax_t)stats.ifrags);
printf("\t%ju output packets dropped due to no bufs, etc.\n",
(uintmax_t)stats.oerrors);
printf("\t%ju output packets discarded due to no IPv4 route\n",
(uintmax_t)stats.noroute4);
printf("\t%ju output packets discarded due to no IPv6 route\n",
(uintmax_t)stats.noroute6);
printf("\t%ju packets discarded due to unsupported protocol\n",
(uintmax_t)stats.noproto);
printf("\t%ju packets discarded due to memory allocation problems\n",
(uintmax_t)stats.nomem);
printf("\t%ju packets discarded due to some errors\n",
(uintmax_t)stats.dropped);
}
/*
* Reset nat64stl instance statistics specified by @oh->ntlv.
* Request: [ ipfw_obj_header ]
*/
static void
nat64stl_reset_stats(const char *name, uint8_t set)
{
ipfw_obj_header oh;
memset(&oh, 0, sizeof(oh));
nat64stl_fill_ntlv(&oh.ntlv, name, set);
if (do_set3(IP_FW_NAT64STL_RESET_STATS, &oh.opheader, sizeof(oh)) != 0)
err(EX_OSERR, "failed to reset stats for instance %s", name);
}
static int
nat64stl_show_cb(ipfw_nat64stl_cfg *cfg, const char *name, uint8_t set)
{
char abuf[INET6_ADDRSTRLEN];
if (name != NULL && strcmp(cfg->name, name) != 0)
return (ESRCH);
if (g_co.use_set != 0 && cfg->set != set)
return (ESRCH);
if (g_co.use_set != 0 || cfg->set != 0)
printf("set %u ", cfg->set);
printf("nat64stl %s table4 %s table6 %s",
cfg->name, cfg->ntlv4.name, cfg->ntlv6.name);
inet_ntop(AF_INET6, &cfg->prefix6, abuf, sizeof(abuf));
printf(" prefix6 %s/%u", abuf, cfg->plen6);
if (cfg->flags & NAT64_LOG)
printf(" log");
if (cfg->flags & NAT64_ALLOW_PRIVATE)
printf(" allow_private");
printf("\n");
return (0);
}
static int
nat64stl_destroy_cb(ipfw_nat64stl_cfg *cfg, const char *name __unused,
uint8_t set)
{
if (g_co.use_set != 0 && cfg->set != set)
return (ESRCH);
nat64stl_destroy(cfg->name, cfg->set);
return (0);
}
/*
* Compare nat64stl instances names.
* Honor number comparison.
*/
static int
nat64name_cmp(const void *a, const void *b)
{
const ipfw_nat64stl_cfg *ca, *cb;
ca = (const ipfw_nat64stl_cfg *)a;
cb = (const ipfw_nat64stl_cfg *)b;
if (ca->set > cb->set)
return (1);
else if (ca->set < cb->set)
return (-1);
return (stringnum_cmp(ca->name, cb->name));
}
/*
* Retrieves nat64stl instance list from kernel,
* optionally sorts it and calls requested function for each instance.
*
* Request: [ ipfw_obj_lheader ]
* Reply: [ ipfw_obj_lheader ipfw_nat64stl_cfg x N ]
*/
static int
nat64stl_foreach(nat64stl_cb_t *f, const char *name, uint8_t set, int sort)
{
ipfw_obj_lheader *olh;
ipfw_nat64stl_cfg *cfg;
size_t sz;
uint32_t i;
/* Start with reasonable default */
sz = sizeof(*olh) + 16 * sizeof(*cfg);
for (;;) {
if ((olh = calloc(1, sz)) == NULL)
return (ENOMEM);
olh->size = sz;
if (do_get3(IP_FW_NAT64STL_LIST, &olh->opheader, &sz) != 0) {
sz = olh->size;
free(olh);
if (errno != ENOMEM)
return (errno);
continue;
}
if (sort != 0)
qsort(olh + 1, olh->count, olh->objsize,
nat64name_cmp);
cfg = (ipfw_nat64stl_cfg *)(olh + 1);
for (i = 0; i < olh->count; i++) {
(void)f(cfg, name, set); /* Ignore errors for now */
cfg = (ipfw_nat64stl_cfg *)((caddr_t)cfg +
olh->objsize);
}
free(olh);
break;
}
return (0);
}
+452
View File
@@ -0,0 +1,452 @@
/*-
* Copyright (c) 2016 Yandex LLC
* Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
* 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 THE AUTHOR ``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 THE AUTHOR 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/socket.h>
#include "ipfw2.h"
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <inttypes.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 <netinet6/ip_fw_nptv6.h>
#include <arpa/inet.h>
typedef int (nptv6_cb_t)(ipfw_nptv6_cfg *i, const char *name, uint8_t set);
static int nptv6_foreach(nptv6_cb_t *f, const char *name, uint8_t set,
int sort);
static void nptv6_create(const char *name, uint8_t set, int ac, char **av);
static void nptv6_destroy(const char *name, uint8_t set);
static void nptv6_stats(const char *name, uint8_t set);
static void nptv6_reset_stats(const char *name, uint8_t set);
static int nptv6_show_cb(ipfw_nptv6_cfg *cfg, const char *name, uint8_t set);
static int nptv6_destroy_cb(ipfw_nptv6_cfg *cfg, const char *name, uint8_t set);
static struct _s_x nptv6cmds[] = {
{ "create", TOK_CREATE },
{ "destroy", TOK_DESTROY },
{ "list", TOK_LIST },
{ "show", TOK_LIST },
{ "stats", TOK_STATS },
{ NULL, 0 }
};
static struct _s_x nptv6statscmds[] = {
{ "reset", TOK_RESET },
{ NULL, 0 }
};
/*
* This one handles all NPTv6-related commands
* ipfw [set N] nptv6 NAME {create | config} ...
* ipfw [set N] nptv6 NAME stats [reset]
* ipfw [set N] nptv6 {NAME | all} destroy
* ipfw [set N] nptv6 {NAME | all} {list | show}
*/
#define nptv6_check_name table_check_name
void
ipfw_nptv6_handler(int ac, char *av[])
{
const char *name;
int tcmd;
uint8_t set;
if (g_co.use_set != 0)
set = g_co.use_set - 1;
else
set = 0;
ac--; av++;
NEED1("nptv6 needs instance name");
name = *av;
if (nptv6_check_name(name) != 0) {
if (strcmp(name, "all") == 0) {
name = NULL;
} else
errx(EX_USAGE, "nptv6 instance name %s is invalid",
name);
}
ac--; av++;
NEED1("nptv6 needs command");
tcmd = get_token(nptv6cmds, *av, "nptv6 command");
if (name == NULL && tcmd != TOK_DESTROY && tcmd != TOK_LIST)
errx(EX_USAGE, "nptv6 instance name required");
switch (tcmd) {
case TOK_CREATE:
ac--; av++;
nptv6_create(name, set, ac, av);
break;
case TOK_LIST:
nptv6_foreach(nptv6_show_cb, name, set, 1);
break;
case TOK_DESTROY:
if (name == NULL)
nptv6_foreach(nptv6_destroy_cb, NULL, set, 0);
else
nptv6_destroy(name, set);
break;
case TOK_STATS:
ac--; av++;
if (ac == 0) {
nptv6_stats(name, set);
break;
}
tcmd = get_token(nptv6statscmds, *av, "stats command");
if (tcmd == TOK_RESET)
nptv6_reset_stats(name, set);
}
}
static void
nptv6_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set)
{
ntlv->head.type = IPFW_TLV_EACTION_NAME(1); /* it doesn't matter */
ntlv->head.length = sizeof(ipfw_obj_ntlv);
ntlv->idx = 1;
ntlv->set = set;
strlcpy(ntlv->name, name, sizeof(ntlv->name));
}
static struct _s_x nptv6newcmds[] = {
{ "int_prefix", TOK_INTPREFIX },
{ "ext_prefix", TOK_EXTPREFIX },
{ "prefixlen", TOK_PREFIXLEN },
{ "ext_if", TOK_EXTIF },
{ NULL, 0 }
};
static void
nptv6_parse_prefix(const char *arg, struct in6_addr *prefix, int *len)
{
long plen;
char *p, *l;
p = strdup(arg);
if (p == NULL)
err(EX_OSERR, NULL);
if ((l = strchr(p, '/')) != NULL)
*l++ = '\0';
if (inet_pton(AF_INET6, p, prefix) != 1)
errx(EX_USAGE, "Bad prefix: %s", p);
if (l != NULL) {
plen = strtol(l, &l, 10);
if (*l != '\0' || plen < 8 || plen > 64)
errx(EX_USAGE, "Bad prefix length: %s", arg);
*len = plen;
} else
*len = 0;
free(p);
}
/*
* Creates new nptv6 instance
* ipfw nptv6 <NAME> create int_prefix <prefix> ext_prefix <prefix>
* Request: [ ipfw_obj_lheader ipfw_nptv6_cfg ]
*/
#define NPTV6_HAS_INTPREFIX 0x01
#define NPTV6_HAS_EXTPREFIX 0x02
#define NPTV6_HAS_PREFIXLEN 0x04
static void
nptv6_create(const char *name, uint8_t set, int ac, char *av[])
{
char buf[sizeof(ipfw_obj_lheader) + sizeof(ipfw_nptv6_cfg)];
struct in6_addr mask;
ipfw_nptv6_cfg *cfg;
ipfw_obj_lheader *olh;
int tcmd, flags, iplen, eplen, pplen;
char *p;
iplen = eplen = pplen = 0;
memset(buf, 0, sizeof(buf));
olh = (ipfw_obj_lheader *)buf;
cfg = (ipfw_nptv6_cfg *)(olh + 1);
cfg->set = set;
flags = 0;
while (ac > 0) {
tcmd = get_token(nptv6newcmds, *av, "option");
ac--; av++;
switch (tcmd) {
case TOK_INTPREFIX:
NEED1("IPv6 prefix required");
nptv6_parse_prefix(*av, &cfg->internal, &iplen);
flags |= NPTV6_HAS_INTPREFIX;
ac--; av++;
break;
case TOK_EXTPREFIX:
if (flags & NPTV6_HAS_EXTPREFIX)
errx(EX_USAGE,
"Only one ext_prefix or ext_if allowed");
NEED1("IPv6 prefix required");
nptv6_parse_prefix(*av, &cfg->external, &eplen);
flags |= NPTV6_HAS_EXTPREFIX;
ac--; av++;
break;
case TOK_EXTIF:
if (flags & NPTV6_HAS_EXTPREFIX)
errx(EX_USAGE,
"Only one ext_prefix or ext_if allowed");
NEED1("Interface name required");
if (strlen(*av) >= sizeof(cfg->if_name))
errx(EX_USAGE, "Invalid interface name");
flags |= NPTV6_HAS_EXTPREFIX;
cfg->flags |= NPTV6_DYNAMIC_PREFIX;
strncpy(cfg->if_name, *av, sizeof(cfg->if_name));
ac--; av++;
break;
case TOK_PREFIXLEN:
NEED1("IPv6 prefix length required");
pplen = strtol(*av, &p, 10);
if (*p != '\0' || pplen < 8 || pplen > 64)
errx(EX_USAGE, "wrong prefix length: %s", *av);
ac--; av++;
break;
}
}
/* RFC 6296 Sec. 3.1 */
if (pplen != 0) {
if ((eplen != 0 && eplen != pplen) ||
(iplen != 0 && iplen != pplen))
errx(EX_USAGE, "prefix length mismatch");
cfg->plen = pplen;
flags |= NPTV6_HAS_PREFIXLEN;
} else if (eplen != 0 || iplen != 0) {
if (eplen != 0 && iplen != 0 && eplen != iplen)
errx(EX_USAGE, "prefix length mismatch");
warnx("use prefixlen instead");
cfg->plen = eplen ? eplen : iplen;
flags |= NPTV6_HAS_PREFIXLEN;
}
/* Check validness */
if ((flags & NPTV6_HAS_INTPREFIX) != NPTV6_HAS_INTPREFIX)
errx(EX_USAGE, "int_prefix required");
if ((flags & NPTV6_HAS_EXTPREFIX) != NPTV6_HAS_EXTPREFIX)
errx(EX_USAGE, "ext_prefix or ext_if required");
if ((flags & NPTV6_HAS_PREFIXLEN) != NPTV6_HAS_PREFIXLEN)
errx(EX_USAGE, "prefixlen required");
n2mask(&mask, cfg->plen);
APPLY_MASK(&cfg->internal, &mask);
if ((cfg->flags & NPTV6_DYNAMIC_PREFIX) == 0)
APPLY_MASK(&cfg->external, &mask);
olh->count = 1;
olh->objsize = sizeof(*cfg);
olh->size = sizeof(buf);
strlcpy(cfg->name, name, sizeof(cfg->name));
if (do_set3(IP_FW_NPTV6_CREATE, &olh->opheader, sizeof(buf)) != 0)
err(EX_OSERR, "nptv6 instance creation failed");
}
/*
* Destroys NPTv6 instance.
* Request: [ ipfw_obj_header ]
*/
static void
nptv6_destroy(const char *name, uint8_t set)
{
ipfw_obj_header oh;
memset(&oh, 0, sizeof(oh));
nptv6_fill_ntlv(&oh.ntlv, name, set);
if (do_set3(IP_FW_NPTV6_DESTROY, &oh.opheader, sizeof(oh)) != 0)
err(EX_OSERR, "failed to destroy nat instance %s", name);
}
/*
* Get NPTv6 instance statistics.
* Request: [ ipfw_obj_header ]
* Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ] ]
*/
static int
nptv6_get_stats(const char *name, uint8_t set, struct ipfw_nptv6_stats *stats)
{
ipfw_obj_header *oh;
ipfw_obj_ctlv *oc;
size_t sz;
sz = sizeof(*oh) + sizeof(*oc) + sizeof(*stats);
oh = calloc(1, sz);
nptv6_fill_ntlv(&oh->ntlv, name, set);
if (do_get3(IP_FW_NPTV6_STATS, &oh->opheader, &sz) == 0) {
oc = (ipfw_obj_ctlv *)(oh + 1);
memcpy(stats, oc + 1, sizeof(*stats));
free(oh);
return (0);
}
free(oh);
return (-1);
}
static void
nptv6_stats(const char *name, uint8_t set)
{
struct ipfw_nptv6_stats stats;
if (nptv6_get_stats(name, set, &stats) != 0)
err(EX_OSERR, "Error retrieving stats");
if (g_co.use_set != 0 || set != 0)
printf("set %u ", set);
printf("nptv6 %s\n", name);
printf("\t%ju packets translated (internal to external)\n",
(uintmax_t)stats.in2ex);
printf("\t%ju packets translated (external to internal)\n",
(uintmax_t)stats.ex2in);
printf("\t%ju packets dropped due to some error\n",
(uintmax_t)stats.dropped);
}
/*
* Reset NPTv6 instance statistics specified by @oh->ntlv.
* Request: [ ipfw_obj_header ]
*/
static void
nptv6_reset_stats(const char *name, uint8_t set)
{
ipfw_obj_header oh;
memset(&oh, 0, sizeof(oh));
nptv6_fill_ntlv(&oh.ntlv, name, set);
if (do_set3(IP_FW_NPTV6_RESET_STATS, &oh.opheader, sizeof(oh)) != 0)
err(EX_OSERR, "failed to reset stats for instance %s", name);
}
static int
nptv6_show_cb(ipfw_nptv6_cfg *cfg, const char *name, uint8_t set)
{
char abuf[INET6_ADDRSTRLEN];
if (name != NULL && strcmp(cfg->name, name) != 0)
return (ESRCH);
if (g_co.use_set != 0 && cfg->set != set)
return (ESRCH);
if (g_co.use_set != 0 || cfg->set != 0)
printf("set %u ", cfg->set);
inet_ntop(AF_INET6, &cfg->internal, abuf, sizeof(abuf));
printf("nptv6 %s int_prefix %s ", cfg->name, abuf);
if (cfg->flags & NPTV6_DYNAMIC_PREFIX)
printf("ext_if %s ", cfg->if_name);
else {
inet_ntop(AF_INET6, &cfg->external, abuf, sizeof(abuf));
printf("ext_prefix %s ", abuf);
}
printf("prefixlen %u\n", cfg->plen);
return (0);
}
static int
nptv6_destroy_cb(ipfw_nptv6_cfg *cfg, const char *name __unused, uint8_t set)
{
if (g_co.use_set != 0 && cfg->set != set)
return (ESRCH);
nptv6_destroy(cfg->name, cfg->set);
return (0);
}
/*
* Compare NPTv6 instances names.
* Honor number comparison.
*/
static int
nptv6name_cmp(const void *a, const void *b)
{
const ipfw_nptv6_cfg *ca, *cb;
ca = (const ipfw_nptv6_cfg *)a;
cb = (const ipfw_nptv6_cfg *)b;
if (ca->set > cb->set)
return (1);
else if (ca->set < cb->set)
return (-1);
return (stringnum_cmp(ca->name, cb->name));
}
/*
* Retrieves NPTv6 instance list from kernel,
* Request: [ ipfw_obj_lheader ]
* Reply: [ ipfw_obj_lheader ipfw_nptv6_cfg x N ]
*/
static int
nptv6_foreach(nptv6_cb_t *f, const char *name, uint8_t set, int sort)
{
ipfw_obj_lheader *olh;
ipfw_nptv6_cfg *cfg;
size_t sz;
uint32_t i;
/* Start with reasonable default */
sz = sizeof(*olh) + 16 * sizeof(*cfg);
for (;;) {
if ((olh = calloc(1, sz)) == NULL)
return (ENOMEM);
olh->size = sz;
if (do_get3(IP_FW_NPTV6_LIST, &olh->opheader, &sz) != 0) {
sz = olh->size;
free(olh);
if (errno != ENOMEM)
return (errno);
continue;
}
if (sort != 0)
qsort(olh + 1, olh->count, olh->objsize, nptv6name_cmp);
cfg = (ipfw_nptv6_cfg *)(olh + 1);
for (i = 0; i < olh->count; i++) {
(void)f(cfg, name, set);
cfg = (ipfw_nptv6_cfg *)((caddr_t)cfg + olh->objsize);
}
free(olh);
break;
}
return (0);
}
+2096
View File
File diff suppressed because it is too large. Load diff
+358 -108
View File
File diff suppressed because it is too large. Load diff
+3 -2
View File
@@ -9,8 +9,8 @@
# The latest version can be obtained from
# http://www.linux-usb.org/usb.ids
#
# Version: 2025.09.15
# Date: 2025-09-15 20:34:02
# Version: 2025.12.13
# Date: 2025-12-13 20:34:01
#
# Vendors, devices and interfaces. Please keep sorted.
@@ -24056,6 +24056,7 @@ C 08 Mass Storage
00 Control/Bulk/Interrupt
01 Control/Bulk
50 Bulk-Only
62 USB Attached SCSI
C 09 Hub
00 Unused
00 Full speed (or root) hub
-5
View File
@@ -1,5 +0,0 @@
include GENERIC-KASAN
ident SYZKALLER
options COVERAGE
options KCOV
+1 -1
View File
@@ -1169,7 +1169,7 @@ linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
int
linux_umount(struct thread *td, struct linux_umount_args *args)
{
int flags;
uint64_t flags;
flags = 0;
if ((args->flags & LINUX_MNT_FORCE) != 0) {
+1 -1
View File
@@ -53,7 +53,7 @@
TYPE="FreeBSD"
REVISION="14.4"
BRANCH="PRERELEASE"
BRANCH="RELEASE"
if [ -n "${BRANCH_OVERRIDE}" ]; then
BRANCH=${BRANCH_OVERRIDE}
fi
@@ -52,7 +52,7 @@ extern int hz;
typedef longlong_t hrtime_t;
#if defined(__i386__) || defined(__powerpc__)
#ifdef __i386__
#define TIMESPEC_OVERFLOW(ts) \
((ts)->tv_sec < INT32_MIN || (ts)->tv_sec > INT32_MAX)
#else
+5
View File
@@ -248,6 +248,11 @@ pmc_intel_initialize(void)
cputype = PMC_CPU_INTEL_ATOM_TREMONT;
nclasses = 3;
break;
case 0xAD:
case 0xAE:
cputype = PMC_CPU_INTEL_GRANITE_RAPIDS;
nclasses = 3;
break;
case 0xBE:
cputype = PMC_CPU_INTEL_ALDERLAKEN;
nclasses = 3;
+21 -20
View File
@@ -1617,14 +1617,13 @@ ecore_sp_eth_filter_mcast(struct ecore_hwfn *p_hwfn,
struct ecore_spq_comp_cb *p_comp_data)
{
struct vport_update_ramrod_data *p_ramrod = OSAL_NULL;
u32 bins[ETH_MULTICAST_MAC_BINS_IN_REGS];
struct ecore_spq_entry *p_ent = OSAL_NULL;
struct ecore_sp_init_data init_data;
u8 abs_vport_id = 0;
enum _ecore_status_t rc;
int i;
if (p_filter_cmd->opcode == ECORE_FILTER_ADD)
if (p_filter_cmd->opcode == ECORE_FILTER_REPLACE)
rc = ecore_fw_vport(p_hwfn, p_filter_cmd->vport_to_add_to,
&abs_vport_id);
else
@@ -1654,30 +1653,33 @@ ecore_sp_eth_filter_mcast(struct ecore_hwfn *p_hwfn,
/* explicitly clear out the entire vector */
OSAL_MEMSET(&p_ramrod->approx_mcast.bins,
0, sizeof(p_ramrod->approx_mcast.bins));
OSAL_MEMSET(bins, 0, sizeof(u32) * ETH_MULTICAST_MAC_BINS_IN_REGS);
/* filter ADD op is explicit set op and it removes
* any existing filters for the vport.
*/
if (p_filter_cmd->opcode == ECORE_FILTER_ADD) {
for (i = 0; i < p_filter_cmd->num_mc_addrs; i++) {
u32 bit;
bit = ecore_mcast_bin_from_mac(p_filter_cmd->mac[i]);
bins[bit / 32] |= 1 << (bit % 32);
}
/*
* filter REPLACE op is explicit set op and it removes
* any existing filters for the vport.
*/
if (p_filter_cmd->opcode == ECORE_FILTER_REPLACE) {
_Static_assert(sizeof(p_filter_cmd->bins) == sizeof(p_ramrod->approx_mcast.bins), "Size mismatch");
_Static_assert(nitems(p_filter_cmd->bins) == ETH_MULTICAST_MAC_BINS_IN_REGS, "Size mismatch");
/* Convert to correct endianity */
for (i = 0; i < ETH_MULTICAST_MAC_BINS_IN_REGS; i++) {
struct vport_update_ramrod_mcast *p_ramrod_bins;
p_ramrod_bins = &p_ramrod->approx_mcast;
p_ramrod_bins->bins[i] = OSAL_CPU_TO_LE32(bins[i]);
p_ramrod_bins->bins[i] = OSAL_CPU_TO_LE32(p_filter_cmd->bins[i]);
}
}
} /* else FLUSH op clears existing filters */
p_ramrod->common.vport_id = abs_vport_id;
rc = ecore_spq_post(p_hwfn, p_ent, OSAL_NULL);
DP_INFO(p_hwfn, "Multicast filter cmd: [%s], bins: [%08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x], ret = %d\n",
p_filter_cmd->opcode == ECORE_FILTER_REPLACE ? "replace" : "flush",
p_ramrod->approx_mcast.bins[0], p_ramrod->approx_mcast.bins[1],
p_ramrod->approx_mcast.bins[2], p_ramrod->approx_mcast.bins[3],
p_ramrod->approx_mcast.bins[4], p_ramrod->approx_mcast.bins[5],
p_ramrod->approx_mcast.bins[6], p_ramrod->approx_mcast.bins[7], rc);
if (rc != ECORE_SUCCESS)
DP_ERR(p_hwfn, "Multicast filter command failed %d\n", rc);
@@ -1692,10 +1694,9 @@ enum _ecore_status_t ecore_filter_mcast_cmd(struct ecore_dev *p_dev,
enum _ecore_status_t rc = ECORE_SUCCESS;
int i;
/* only ADD and REMOVE operations are supported for multi-cast */
if ((p_filter_cmd->opcode != ECORE_FILTER_ADD &&
(p_filter_cmd->opcode != ECORE_FILTER_REMOVE)) ||
(p_filter_cmd->num_mc_addrs > ECORE_MAX_MC_ADDRS)) {
/* only REPLACE and FLUSH operations are supported for multi-cast */
if ((p_filter_cmd->opcode != ECORE_FILTER_REPLACE &&
(p_filter_cmd->opcode != ECORE_FILTER_FLUSH))) {
return ECORE_INVAL;
}
+4 -5
View File
@@ -162,14 +162,13 @@ struct ecore_filter_ucast {
};
struct ecore_filter_mcast {
/* MOVE is not supported for multicast */
/* Only REPLACE and FLUSH is supported for multicast */
enum ecore_filter_opcode opcode;
u8 vport_to_add_to;
u8 vport_to_remove_from;
u8 num_mc_addrs;
#define ECORE_MAX_MC_ADDRS 64
unsigned char mac[ECORE_MAX_MC_ADDRS][ETH_ALEN];
u32 bins[ETH_MULTICAST_MAC_BINS_IN_REGS];
};
#define ECORE_MAX_MC_ADDRS 64
struct ecore_filter_accept_flags {
u8 update_rx_mode_config;
@@ -384,7 +383,7 @@ struct ecore_sp_vport_update_params {
u8 anti_spoofing_en;
u8 update_accept_any_vlan_flg;
u8 accept_any_vlan;
u32 bins[8];
u32 bins[ETH_MULTICAST_MAC_BINS_IN_REGS];
struct ecore_rss_params *rss_params;
struct ecore_filter_accept_flags accept_flags;
struct ecore_sge_tpa_params *sge_tpa_params;
+3 -8
View File
@@ -1515,18 +1515,13 @@ void ecore_vf_pf_filter_mcast(struct ecore_hwfn *p_hwfn,
struct ecore_filter_mcast *p_filter_cmd)
{
struct ecore_sp_vport_update_params sp_params;
int i;
OSAL_MEMSET(&sp_params, 0, sizeof(sp_params));
sp_params.update_approx_mcast_flg = 1;
if (p_filter_cmd->opcode == ECORE_FILTER_ADD) {
for (i = 0; i < p_filter_cmd->num_mc_addrs; i++) {
u32 bit;
bit = ecore_mcast_bin_from_mac(p_filter_cmd->mac[i]);
sp_params.bins[bit / 32] |= 1 << (bit % 32);
}
if (p_filter_cmd->opcode == ECORE_FILTER_REPLACE) {
_Static_assert(sizeof(sp_params.bins) == sizeof(p_filter_cmd->bins), "Size mismatch");
memcpy(sp_params.bins, p_filter_cmd->bins, sizeof(sp_params.bins));
}
ecore_vf_pf_vport_update(p_hwfn, &sp_params);
+1 -6
View File
@@ -319,7 +319,6 @@ typedef struct qlnx_link_output qlnx_link_output_t;
#define QLNX_TPA_MAX_AGG_BUFFERS (20)
#define QLNX_MAX_NUM_MULTICAST_ADDRS ECORE_MAX_MC_ADDRS
typedef struct _qlnx_mcast {
uint16_t rsrvd;
uint8_t addr[6];
@@ -370,7 +369,6 @@ struct qlnx_host {
uint16_t device_id;
if_t ifp;
int if_flags;
volatile int link_up;
struct ifmedia media;
uint16_t max_frame_size;
@@ -443,9 +441,7 @@ struct qlnx_host {
qlnx_ivec_t irq_vec[QLNX_MAX_RSS];
uint8_t filter;
uint32_t nmcast;
qlnx_mcast_t mcast[QLNX_MAX_NUM_MULTICAST_ADDRS];
struct ecore_filter_mcast ecore_mcast;
uint32_t ecore_mcast_bins[ETH_MULTICAST_MAC_BINS_IN_REGS];
uint8_t primary_mac[ETH_ALEN];
uint8_t prio_to_tc[MAX_NUM_PRI];
struct ecore_eth_stats hw_stats;
@@ -683,7 +679,6 @@ extern int qlnx_grc_dump(qlnx_host_t *ha, uint32_t *num_dumped_dwords,
int hwfn_index);
extern int qlnx_idle_chk(qlnx_host_t *ha, uint32_t *num_dumped_dwords,
int hwfn_index);
extern uint8_t *qlnx_get_mac_addr(qlnx_host_t *ha);
extern void qlnx_fill_link(qlnx_host_t *ha, struct ecore_hwfn *hwfn,
struct qlnx_link_output *if_link);
extern int qlnx_set_lldp_tlvx(qlnx_host_t *ha, qlnx_lldp_sys_tlvs_t *lldp_tlvs);
+97 -254
View File
@@ -30,8 +30,6 @@
* Author : David C Somayajulu, Cavium, Inc., San Jose, CA 95131.
*/
#include "opt_inet.h"
#include <sys/cdefs.h>
#include "qlnx_os.h"
#include "bcm_osal.h"
@@ -50,6 +48,7 @@
#include "ecore_sp_commands.h"
#include "ecore_dev_api.h"
#include "ecore_l2_api.h"
#include "ecore_l2.h"
#include "ecore_mcp.h"
#include "ecore_hw_defs.h"
#include "mcp_public.h"
@@ -91,9 +90,9 @@ static void qlnx_fp_isr(void *arg);
static void qlnx_init_ifnet(device_t dev, qlnx_host_t *ha);
static void qlnx_init(void *arg);
static void qlnx_init_locked(qlnx_host_t *ha);
static int qlnx_set_multi(qlnx_host_t *ha, uint32_t add_multi);
static int qlnx_set_promisc(qlnx_host_t *ha, int enabled);
static int qlnx_set_allmulti(qlnx_host_t *ha, int enabled);
static int qlnx_set_multi(qlnx_host_t *ha);
static int qlnx_set_promisc_allmulti(qlnx_host_t *ha, int flags);
static int _qlnx_set_promisc_allmulti(qlnx_host_t *ha, bool promisc, bool allmulti);
static int qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data);
static int qlnx_media_change(if_t ifp);
static void qlnx_media_status(if_t ifp, struct ifmediareq *ifmr);
@@ -101,6 +100,7 @@ static void qlnx_stop(qlnx_host_t *ha);
static int qlnx_send(qlnx_host_t *ha, struct qlnx_fastpath *fp,
struct mbuf **m_headp);
static int qlnx_get_ifq_snd_maxlen(qlnx_host_t *ha);
static void qlnx_get_mac_addr(qlnx_host_t *ha);
static uint32_t qlnx_get_optics(qlnx_host_t *ha,
struct qlnx_link_output *if_link);
static int qlnx_transmit(if_t ifp, struct mbuf *mp);
@@ -128,14 +128,13 @@ static void qlnx_set_id(struct ecore_dev *cdev, char name[NAME_SIZE],
char ver_str[VER_SIZE]);
static void qlnx_unload(qlnx_host_t *ha);
static int qlnx_load(qlnx_host_t *ha);
static void qlnx_hw_set_multi(qlnx_host_t *ha, uint8_t *mta, uint32_t mcnt,
uint32_t add_mac);
static void qlnx_dump_buf8(qlnx_host_t *ha, const char *msg, void *dbuf,
uint32_t len);
static int qlnx_alloc_rx_buffer(qlnx_host_t *ha, struct qlnx_rx_queue *rxq);
static void qlnx_reuse_rx_data(struct qlnx_rx_queue *rxq);
static void qlnx_update_rx_prod(struct ecore_hwfn *p_hwfn,
struct qlnx_rx_queue *rxq);
static int qlnx_remove_all_mcast_mac(qlnx_host_t *ha);
static int qlnx_set_rx_accept_filter(qlnx_host_t *ha, uint8_t filter);
static int qlnx_grc_dumpsize(qlnx_host_t *ha, uint32_t *num_dwords,
int hwfn_index);
@@ -2322,7 +2321,7 @@ qlnx_init_ifnet(device_t dev, qlnx_host_t *ha)
ha->max_frame_size = if_getmtu(ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN;
memcpy(ha->primary_mac, qlnx_get_mac_addr(ha), ETH_ALEN);
qlnx_get_mac_addr(ha);
if (!ha->primary_mac[0] && !ha->primary_mac[1] &&
!ha->primary_mac[2] && !ha->primary_mac[3] &&
@@ -2392,8 +2391,6 @@ qlnx_init_ifnet(device_t dev, qlnx_host_t *ha)
ifmedia_set(&ha->media, (IFM_ETHER | IFM_AUTO));
ether_ifattach(ifp, ha->primary_mac);
bcopy(if_getlladdr(ha->ifp), ha->primary_mac, ETHER_ADDR_LEN);
QL_DPRINT2(ha, "exit\n");
return;
@@ -2432,7 +2429,8 @@ qlnx_init(void *arg)
QL_DPRINT2(ha, "enter\n");
QLNX_LOCK(ha);
qlnx_init_locked(ha);
if ((if_getdrvflags(ha->ifp) & IFF_DRV_RUNNING) == 0)
qlnx_init_locked(ha);
QLNX_UNLOCK(ha);
QL_DPRINT2(ha, "exit\n");
@@ -2440,181 +2438,91 @@ qlnx_init(void *arg)
return;
}
static int
qlnx_config_mcast_mac_addr(qlnx_host_t *ha, uint8_t *mac_addr, uint32_t add_mac)
{
struct ecore_filter_mcast *mcast;
struct ecore_dev *cdev;
int rc;
cdev = &ha->cdev;
mcast = &ha->ecore_mcast;
bzero(mcast, sizeof(struct ecore_filter_mcast));
if (add_mac)
mcast->opcode = ECORE_FILTER_ADD;
else
mcast->opcode = ECORE_FILTER_REMOVE;
mcast->num_mc_addrs = 1;
memcpy(mcast->mac, mac_addr, ETH_ALEN);
rc = ecore_filter_mcast_cmd(cdev, mcast, ECORE_SPQ_MODE_CB, NULL);
return (rc);
}
static int
qlnx_hw_add_mcast(qlnx_host_t *ha, uint8_t *mta)
{
int i;
for (i = 0; i < QLNX_MAX_NUM_MULTICAST_ADDRS; i++) {
if (QL_MAC_CMP(ha->mcast[i].addr, mta) == 0)
return 0; /* its been already added */
}
for (i = 0; i < QLNX_MAX_NUM_MULTICAST_ADDRS; i++) {
if ((ha->mcast[i].addr[0] == 0) &&
(ha->mcast[i].addr[1] == 0) &&
(ha->mcast[i].addr[2] == 0) &&
(ha->mcast[i].addr[3] == 0) &&
(ha->mcast[i].addr[4] == 0) &&
(ha->mcast[i].addr[5] == 0)) {
if (qlnx_config_mcast_mac_addr(ha, mta, 1))
return (-1);
bcopy(mta, ha->mcast[i].addr, ETH_ALEN);
ha->nmcast++;
return 0;
}
}
return 0;
}
static int
qlnx_hw_del_mcast(qlnx_host_t *ha, uint8_t *mta)
{
int i;
for (i = 0; i < QLNX_MAX_NUM_MULTICAST_ADDRS; i++) {
if (QL_MAC_CMP(ha->mcast[i].addr, mta) == 0) {
if (qlnx_config_mcast_mac_addr(ha, mta, 0))
return (-1);
ha->mcast[i].addr[0] = 0;
ha->mcast[i].addr[1] = 0;
ha->mcast[i].addr[2] = 0;
ha->mcast[i].addr[3] = 0;
ha->mcast[i].addr[4] = 0;
ha->mcast[i].addr[5] = 0;
ha->nmcast--;
return 0;
}
}
return 0;
}
/*
* Name: qls_hw_set_multi
* Function: Sets the Multicast Addresses provided the host O.S into the
* hardware (for the given interface)
*/
static void
qlnx_hw_set_multi(qlnx_host_t *ha, uint8_t *mta, uint32_t mcnt,
uint32_t add_mac)
{
int i;
for (i = 0; i < mcnt; i++) {
if (add_mac) {
if (qlnx_hw_add_mcast(ha, mta))
break;
} else {
if (qlnx_hw_del_mcast(ha, mta))
break;
}
mta += ETHER_ADDR_LEN;
}
return;
}
static u_int
qlnx_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt)
qlnx_mcast_bins_from_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt)
{
uint8_t *mta = arg;
uint8_t bit;
uint32_t *bins = arg;
if (mcnt == QLNX_MAX_NUM_MULTICAST_ADDRS)
return (0);
bcopy(LLADDR(sdl), &mta[mcnt * ETHER_ADDR_LEN], ETHER_ADDR_LEN);
bit = ecore_mcast_bin_from_mac(LLADDR(sdl));
bins[bit / 32] |= 1 << (bit % 32);
return (1);
}
static int
qlnx_set_multi(qlnx_host_t *ha, uint32_t add_multi)
qlnx_set_multi(qlnx_host_t *ha)
{
uint8_t mta[QLNX_MAX_NUM_MULTICAST_ADDRS * ETHER_ADDR_LEN];
if_t ifp = ha->ifp;
u_int mcnt;
struct ecore_filter_mcast mcast;
struct ecore_dev *cdev;
if_t ifp = ha->ifp;
u_int mcnt __unused;
int rc;
if (qlnx_vf_device(ha) == 0)
return (0);
mcnt = if_foreach_llmaddr(ifp, qlnx_copy_maddr, mta);
bzero(&mcast, sizeof(struct ecore_filter_mcast));
mcnt = if_foreach_llmaddr(ifp, qlnx_mcast_bins_from_maddr, mcast.bins);
QL_DPRINT1(ha, "total %d multicast MACs found\n", mcnt);
QLNX_LOCK(ha);
qlnx_hw_set_multi(ha, mta, mcnt, add_multi);
QLNX_UNLOCK(ha);
return (0);
}
static int
qlnx_set_promisc(qlnx_host_t *ha, int enabled)
{
int rc = 0;
uint8_t filter;
if (qlnx_vf_device(ha) == 0)
if (memcmp(ha->ecore_mcast_bins, mcast.bins, sizeof(mcast.bins)) == 0)
return (0);
filter = ha->filter;
if (enabled) {
filter |= ECORE_ACCEPT_MCAST_UNMATCHED;
filter |= ECORE_ACCEPT_UCAST_UNMATCHED;
} else {
filter &= ~ECORE_ACCEPT_MCAST_UNMATCHED;
filter &= ~ECORE_ACCEPT_UCAST_UNMATCHED;
}
cdev = &ha->cdev;
mcast.opcode = ECORE_FILTER_REPLACE;
rc = ecore_filter_mcast_cmd(cdev, &mcast, ECORE_SPQ_MODE_CB, NULL);
if (rc == 0)
memcpy(ha->ecore_mcast_bins, mcast.bins, sizeof(mcast.bins));
rc = qlnx_set_rx_accept_filter(ha, filter);
QL_DPRINT1(ha, "ecore_filter_mcast_cmd: end(%d)\n", rc);
return (rc);
}
static int
qlnx_set_allmulti(qlnx_host_t *ha, int enabled)
qlnx_set_promisc_allmulti(qlnx_host_t *ha, int flags)
{
int rc = 0;
uint8_t filter;
if (qlnx_vf_device(ha) == 0)
return (0);
filter = ha->filter;
if (enabled) {
filter |= ECORE_ACCEPT_MCAST_UNMATCHED;
} else {
filter &= ~ECORE_ACCEPT_MCAST_UNMATCHED;
}
rc = qlnx_set_rx_accept_filter(ha, filter);
rc = _qlnx_set_promisc_allmulti(ha, flags & IFF_PROMISC,
flags & IFF_ALLMULTI);
return (rc);
}
static int
_qlnx_set_promisc_allmulti(qlnx_host_t *ha, bool promisc, bool allmulti)
{
int rc = 0;
uint8_t filter;
bool mcast, ucast;
filter = ha->filter;
filter |= ECORE_ACCEPT_UCAST_MATCHED;
filter |= ECORE_ACCEPT_MCAST_MATCHED;
filter |= ECORE_ACCEPT_BCAST;
mcast = promisc || allmulti;
ucast = promisc;
if (mcast)
filter |= ECORE_ACCEPT_MCAST_UNMATCHED;
else
filter &= ~ECORE_ACCEPT_MCAST_UNMATCHED;
if (ucast)
filter |= ECORE_ACCEPT_UCAST_UNMATCHED;
else
filter &= ~ECORE_ACCEPT_UCAST_UNMATCHED;
if (filter == ha->filter)
return (0);
rc = qlnx_set_rx_accept_filter(ha, filter);
if (rc == 0)
ha->filter = filter;
return (rc);
}
@@ -2624,35 +2532,11 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data)
int ret = 0, mask;
int flags;
struct ifreq *ifr = (struct ifreq *)data;
#ifdef INET
struct ifaddr *ifa = (struct ifaddr *)data;
#endif
qlnx_host_t *ha;
ha = (qlnx_host_t *)if_getsoftc(ifp);
switch (cmd) {
case SIOCSIFADDR:
QL_DPRINT4(ha, "SIOCSIFADDR (0x%lx)\n", cmd);
#ifdef INET
if (ifa->ifa_addr->sa_family == AF_INET) {
if_setflagbits(ifp, IFF_UP, 0);
if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
QLNX_LOCK(ha);
qlnx_init_locked(ha);
QLNX_UNLOCK(ha);
}
QL_DPRINT4(ha, "SIOCSIFADDR (0x%lx) ipv4 [0x%08x]\n",
cmd, ntohl(IA_SIN(ifa)->sin_addr.s_addr));
arp_ifinit(ifp, ifa);
break;
}
#endif
ether_ioctl(ifp, cmd, data);
break;
case SIOCSIFMTU:
QL_DPRINT4(ha, "SIOCSIFMTU (0x%lx)\n", cmd);
@@ -2680,13 +2564,8 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data)
if (flags & IFF_UP) {
if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
if ((flags ^ ha->if_flags) &
IFF_PROMISC) {
ret = qlnx_set_promisc(ha, flags & IFF_PROMISC);
} else if ((if_getflags(ifp) ^ ha->if_flags) &
IFF_ALLMULTI) {
ret = qlnx_set_allmulti(ha, flags & IFF_ALLMULTI);
}
if (qlnx_set_promisc_allmulti(ha, flags) != 0)
ret = EINVAL;
} else {
ha->max_frame_size = if_getmtu(ifp) +
ETHER_HDR_LEN + ETHER_CRC_LEN;
@@ -2697,26 +2576,19 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data)
qlnx_stop(ha);
}
ha->if_flags = if_getflags(ifp);
QLNX_UNLOCK(ha);
break;
case SIOCADDMULTI:
QL_DPRINT4(ha, "%s (0x%lx)\n", "SIOCADDMULTI", cmd);
if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
if (qlnx_set_multi(ha, 1))
ret = EINVAL;
}
break;
case SIOCDELMULTI:
QL_DPRINT4(ha, "%s (0x%lx)\n", "SIOCDELMULTI", cmd);
QL_DPRINT4(ha, "%s (0x%lx)\n", "SIOCADDMULTI/SIOCDELMULTI", cmd);
if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
if (qlnx_set_multi(ha, 0))
QLNX_LOCK(ha);
if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) {
if (qlnx_set_multi(ha) != 0)
ret = EINVAL;
}
QLNX_UNLOCK(ha);
break;
case SIOCSIFMEDIA:
@@ -3018,6 +2890,7 @@ qlnx_transmit_locked(if_t ifp, struct qlnx_fastpath *fp, struct mbuf *mp)
drbr_advance(ifp, fp->tx_br);
fp->tx_pkts_transmitted++;
fp->tx_pkts_processed++;
ETHER_BPF_MTAP(ifp, mp);
}
mp = drbr_peek(ifp, fp->tx_br);
@@ -3774,7 +3647,7 @@ qlnx_get_ifq_snd_maxlen(qlnx_host_t *ha)
return(TX_RING_SIZE - 1);
}
uint8_t *
static void
qlnx_get_mac_addr(qlnx_host_t *ha)
{
struct ecore_hwfn *p_hwfn;
@@ -3783,8 +3656,10 @@ qlnx_get_mac_addr(qlnx_host_t *ha)
p_hwfn = &ha->cdev.hwfns[0];
if (qlnx_vf_device(ha) != 0)
return (p_hwfn->hw_info.hw_mac_addr);
if (qlnx_vf_device(ha) != 0) {
memcpy(ha->primary_mac, p_hwfn->hw_info.hw_mac_addr, ETH_ALEN);
return;
}
ecore_vf_read_bulletin(p_hwfn, &p_is_forced);
if (ecore_vf_bulletin_get_forced_mac(p_hwfn, mac, &p_is_forced) ==
@@ -3794,8 +3669,6 @@ qlnx_get_mac_addr(qlnx_host_t *ha)
p_is_forced, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
memcpy(ha->primary_mac, mac, ETH_ALEN);
}
return (ha->primary_mac);
}
static uint32_t
@@ -6979,31 +6852,18 @@ qlnx_remove_all_ucast_mac(qlnx_host_t *ha)
static int
qlnx_remove_all_mcast_mac(qlnx_host_t *ha)
{
struct ecore_filter_mcast *mcast;
struct ecore_filter_mcast mcast;
struct ecore_dev *cdev;
int rc, i;
int rc;
cdev = &ha->cdev;
mcast = &ha->ecore_mcast;
bzero(mcast, sizeof(struct ecore_filter_mcast));
bzero(&mcast, sizeof(struct ecore_filter_mcast));
mcast.opcode = ECORE_FILTER_FLUSH;
mcast->opcode = ECORE_FILTER_REMOVE;
for (i = 0; i < QLNX_MAX_NUM_MULTICAST_ADDRS; i++) {
if (ha->mcast[i].addr[0] || ha->mcast[i].addr[1] ||
ha->mcast[i].addr[2] || ha->mcast[i].addr[3] ||
ha->mcast[i].addr[4] || ha->mcast[i].addr[5]) {
memcpy(&mcast->mac[i][0], &ha->mcast[i].addr[0], ETH_ALEN);
mcast->num_mc_addrs++;
}
}
mcast = &ha->ecore_mcast;
rc = ecore_filter_mcast_cmd(cdev, mcast, ECORE_SPQ_MODE_CB, NULL);
bzero(ha->mcast, (sizeof(qlnx_mcast_t) * QLNX_MAX_NUM_MULTICAST_ADDRS));
ha->nmcast = 0;
rc = ecore_filter_mcast_cmd(cdev, &mcast, ECORE_SPQ_MODE_CB, NULL);
if (rc == 0)
bzero(ha->ecore_mcast_bins, sizeof(ha->ecore_mcast_bins));
return (rc);
}
@@ -7013,6 +6873,9 @@ qlnx_clean_filters(qlnx_host_t *ha)
{
int rc = 0;
/* Reset rx filter */
ha->filter = 0;
/* Remove all unicast macs */
rc = qlnx_remove_all_ucast_mac(ha);
if (rc)
@@ -7056,40 +6919,20 @@ static int
qlnx_set_rx_mode(qlnx_host_t *ha)
{
int rc = 0;
uint8_t filter;
const if_t ifp = ha->ifp;
const struct ifaddr *ifa;
struct sockaddr_dl *sdl;
ifa = if_getifaddr(ifp);
if (if_gettype(ifp) == IFT_ETHER && ifa != NULL &&
ifa->ifa_addr != NULL) {
sdl = (struct sockaddr_dl *) ifa->ifa_addr;
rc = qlnx_set_ucast_rx_mac(ha, ECORE_FILTER_REPLACE, if_getlladdr(ifp));
if (rc)
return rc;
rc = qlnx_set_ucast_rx_mac(ha, ECORE_FILTER_REPLACE, LLADDR(sdl));
} else {
rc = qlnx_set_ucast_rx_mac(ha, ECORE_FILTER_REPLACE, ha->primary_mac);
}
rc = qlnx_set_multi(ha);
if (rc)
return rc;
rc = qlnx_remove_all_mcast_mac(ha);
if (rc)
return rc;
filter = ECORE_ACCEPT_UCAST_MATCHED |
ECORE_ACCEPT_MCAST_MATCHED |
ECORE_ACCEPT_BCAST;
if (qlnx_vf_device(ha) == 0 || (if_getflags(ha->ifp) & IFF_PROMISC)) {
filter |= ECORE_ACCEPT_UCAST_UNMATCHED;
filter |= ECORE_ACCEPT_MCAST_UNMATCHED;
} else if (if_getflags(ha->ifp) & IFF_ALLMULTI) {
filter |= ECORE_ACCEPT_MCAST_UNMATCHED;
}
ha->filter = filter;
rc = qlnx_set_rx_accept_filter(ha, filter);
if (qlnx_vf_device(ha) == 0)
rc = _qlnx_set_promisc_allmulti(ha, true, true);
else
rc = qlnx_set_promisc_allmulti(ha, if_getflags(ifp));
return (rc);
}
+1
View File
@@ -449,6 +449,7 @@ static struct acpi_uart_compat_data acpi_compat_data[] = {
{"AMDI0020", &uart_ns8250_class, 0, 2, 0, 48000000, UART_F_BUSY_DETECT, "AMD / Synopsys Designware UART"},
{"APMC0D08", &uart_ns8250_class, ACPI_DBG2_16550_COMPATIBLE, 2, 4, 0, 0, "APM compatible UART"},
{"MRVL0001", &uart_ns8250_class, ACPI_DBG2_16550_SUBSET, 2, 0, 200000000, UART_F_BUSY_DETECT, "Marvell / Synopsys Designware UART"},
{"", &uart_ns8250_class, ACPI_DBG2_16550_WITH_GAS, 0, 0, 0, 0, "ACPI 16550 WITH GAS"},
{"SCX0006", &uart_ns8250_class, 0, 2, 0, 62500000, UART_F_BUSY_DETECT, "SynQuacer / Synopsys Designware UART"},
{"HISI0031", &uart_ns8250_class, 0, 2, 0, 200000000, UART_F_BUSY_DETECT, "HiSilicon / Synopsys Designware UART"},
{"NXP0018", &uart_ns8250_class, 0, 0, 0, 350000000, UART_F_BUSY_DETECT, "NXP / Synopsys Designware UART"},
Loaded 100 of 122 files, more files were not shown because too many files have changed in this diff. Show more