Merge ^/head r364051 through r364081.

This commit is contained in:
Dimitry Andric 2020-08-10 16:58:05 +00:00
commit 8460d7540b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/clang1100-import/; revision=364082
38 changed files with 2455 additions and 992 deletions

View file

@ -27,6 +27,13 @@ r363180:
r363084:
nc(1) now implements SCTP mode, enabled by specifying the --sctp option.
r362681:
A new implementation of bc and dc has been imported. It offers
better standards compliance, performance, localization and comes
with extensive test cases that are optionally installed.
Use WITHOUT_GH_BC=yes to build and install the world with the
previous version instead of the new one, if required.
r362158, r362163:
struct export_args has changed so that the "user" specified for
the -maproot and -mapall exports(5) options may be in more than

View file

@ -23,4 +23,8 @@ SRCS+= fuzzer/FuzzerUtil.cpp
SRCS+= fuzzer/FuzzerUtilLinux.cpp
SRCS+= fuzzer/FuzzerUtilPosix.cpp
.PATH: ${CRTSRC}/include/fuzzer
INCSDIR= ${CLANGDIR}/include/fuzzer
INCS+= FuzzedDataProvider.h
.include <bsd.lib.mk>

View file

@ -25,4 +25,8 @@ SRCS+= profile/InstrProfilingUtil.c
SRCS+= profile/InstrProfilingValue.c
SRCS+= profile/InstrProfilingWriter.c
.PATH: ${CRTSRC}/include/profile
INCSDIR= ${CLANGDIR}/include/profile
INCS+= InstrProfData.inc
.include <bsd.lib.mk>

View file

@ -41,4 +41,10 @@ SRCS+= xray/xray_trampoline_x86_64.S
SRCS+= xray/xray_utils.cpp
SRCS+= xray/xray_x86_64.cpp
.PATH: ${CRTSRC}/include/xray
INCSDIR= ${CLANGDIR}/include/xray
INCS+= xray_interface.h
INCS+= xray_log_interface.h
INCS+= xray_records.h
.include <bsd.lib.mk>

View file

@ -13,15 +13,30 @@ SRCS= libifconfig.c \
libifconfig_inet6.c \
libifconfig_internal.c \
libifconfig_lagg.c \
libifconfig_media.c
libifconfig_media.c \
libifconfig_sfp.c
GEN= libifconfig_sfp_tables.h \
libifconfig_sfp_tables.c \
libifconfig_sfp_tables_internal.h
SRCS+= ${GEN}
.include <src.lua.mk>
.SUFFIXES: .tpl.c .tpl.h
.tpl.c.c .tpl.h.h: sfp.lua
${LUA} ${.CURDIR}/sfp.lua ${.IMPSRC} >${.TARGET}
CLEANFILES+= ${GEN}
# If libifconfig become public uncomment those two lines
#INCSDIR= ${INCLUDEDIR}
#INCS= libifconfig.h
#INCS= libifconfig.h libifconfig_sfp.h libifconfig_sfp_tables.h
#MAN= libifconfig.3
CFLAGS+= -I${.CURDIR}
CFLAGS+= -I${.CURDIR} -I${.OBJDIR}
NO_WCAST_ALIGN= yes
.include <bsd.lib.mk>

View file

@ -28,6 +28,10 @@
#pragma once
#include <sys/types.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet6/in6_var.h>

View file

@ -0,0 +1,592 @@
/*-
* Copyright (c) 2014, Alexander V. Chernikov
* Copyright (c) 2020, Ryan Moeller <freqlabs@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 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.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/sff8436.h>
#include <net/sff8472.h>
#include <math.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libifconfig.h>
#include <libifconfig_internal.h>
#include <libifconfig_sfp.h>
#include <libifconfig_sfp_tables_internal.h>
#define SFF_8636_EXT_COMPLIANCE 0x80
struct i2c_info {
struct ifreq ifr;
ifconfig_handle_t *h;
int error; /* Store first error */
enum sfp_id id; /* Module type */
};
static uint8_t
find_zero_bit(const struct sfp_enum_metadata *table, int value, int sz)
{
int v, m;
for (v = 1, m = 1 << (8 * sz); v < m; v <<= 1) {
if ((value & v) == 0)
continue;
if (find_metadata(table, value & v) != NULL) {
return (value & v);
}
}
return (0);
}
/*
* Reads i2c data from opened kernel socket.
*/
static int
read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len,
uint8_t *buf)
{
struct ifi2creq req;
int i, l;
if (ii->error != 0)
return (ii->error);
ii->ifr.ifr_data = (caddr_t)&req;
i = 0;
l = 0;
memset(&req, 0, sizeof(req));
req.dev_addr = addr;
req.offset = off;
req.len = len;
while (len > 0) {
l = MIN(sizeof(req.data), len);
req.len = l;
if (ifconfig_ioctlwrap(ii->h, AF_LOCAL, SIOCGI2C,
&ii->ifr) != 0) {
ii->error = errno;
return (errno);
}
memcpy(&buf[i], req.data, l);
len -= l;
i += l;
req.offset += l;
}
return (0);
}
static int
i2c_info_init(struct i2c_info *ii, ifconfig_handle_t *h, const char *name)
{
uint8_t id_byte;
memset(ii, 0, sizeof(*ii));
strlcpy(ii->ifr.ifr_name, name, sizeof(ii->ifr.ifr_name));
ii->h = h;
/*
* Try to read byte 0 from i2c:
* Both SFF-8472 and SFF-8436 use it as
* 'identification byte'.
* Stop reading status on zero as value -
* this might happen in case of empty transceiver slot.
*/
id_byte = 0;
read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &id_byte);
if (ii->error != 0)
return (-1);
if (id_byte == 0) {
h->error.errtype = OTHER;
h->error.errcode = ENOENT;
return (-1);
}
ii->id = id_byte;
return (0);
}
static int
get_sfp_info(struct i2c_info *ii, struct ifconfig_sfp_info *sfp)
{
uint8_t code;
read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &sfp->sfp_id);
read_i2c(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, &sfp->sfp_conn);
/* Use extended compliance code if it's valid */
read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS, 1, &sfp->sfp_eth_ext);
if (sfp->sfp_eth_ext == 0) {
/* Next, check 10G Ethernet/IB CCs */
read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, &code);
sfp->sfp_eth_10g = find_zero_bit(sfp_eth_10g_table, code, 1);
if (sfp->sfp_eth_10g == 0) {
/* No match. Try Ethernet 1G */
read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3,
1, &code);
sfp->sfp_eth = find_zero_bit(sfp_eth_table, code, 1);
}
}
return (ii->error);
}
static int
get_qsfp_info(struct i2c_info *ii, struct ifconfig_sfp_info *sfp)
{
uint8_t code;
read_i2c(ii, SFF_8436_BASE, SFF_8436_ID, 1, &sfp->sfp_id);
read_i2c(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, &sfp->sfp_conn);
read_i2c(ii, SFF_8436_BASE, SFF_8436_STATUS, 1, &sfp->sfp_rev);
/* Check for extended specification compliance */
read_i2c(ii, SFF_8436_BASE, SFF_8436_CODE_E1040100G, 1, &code);
if (code & SFF_8636_EXT_COMPLIANCE) {
read_i2c(ii, SFF_8436_BASE, SFF_8436_OPTIONS_START, 1,
&sfp->sfp_eth_ext);
} else {
/* Check 10/40G Ethernet class only */
sfp->sfp_eth_1040g =
find_zero_bit(sfp_eth_1040g_table, code, 1);
}
return (ii->error);
}
int
ifconfig_sfp_get_sfp_info(ifconfig_handle_t *h,
const char *name, struct ifconfig_sfp_info *sfp)
{
struct i2c_info ii;
char buf[8];
memset(sfp, 0, sizeof(*sfp));
if (i2c_info_init(&ii, h, name) != 0)
return (-1);
/* Read bytes 3-10 at once */
read_i2c(&ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, buf);
if (ii.error != 0)
return (ii.error);
/* Check 10G ethernet first */
sfp->sfp_eth_10g = find_zero_bit(sfp_eth_10g_table, buf[0], 1);
if (sfp->sfp_eth_10g == 0) {
/* No match. Try 1G */
sfp->sfp_eth = find_zero_bit(sfp_eth_table, buf[3], 1);
}
sfp->sfp_fc_len = find_zero_bit(sfp_fc_len_table, buf[4], 1);
sfp->sfp_fc_media = find_zero_bit(sfp_fc_media_table, buf[6], 1);
sfp->sfp_fc_speed = find_zero_bit(sfp_fc_speed_table, buf[7], 1);
sfp->sfp_cab_tech =
find_zero_bit(sfp_cab_tech_table, (buf[4] << 8) | buf[5], 2);
if (ifconfig_sfp_id_is_qsfp(ii.id))
return (get_qsfp_info(&ii, sfp));
return (get_sfp_info(&ii, sfp));
}
static size_t
channel_count(enum sfp_id id)
{
/* TODO: other ids */
switch (id) {
case SFP_ID_UNKNOWN:
return (0);
case SFP_ID_QSFP:
case SFP_ID_QSFPPLUS:
case SFP_ID_QSFP28:
return (4);
default:
return (1);
}
}
size_t
ifconfig_sfp_channel_count(const struct ifconfig_sfp_info *sfp)
{
return (channel_count(sfp->sfp_id));
}
/*
* Print SFF-8472/SFF-8436 string to supplied buffer.
* All (vendor-specific) strings are padded right with '0x20'.
*/
static void
get_sff_string(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
{
read_i2c(ii, addr, off, SFF_VENDOR_STRING_SIZE, dst);
dst += SFF_VENDOR_STRING_SIZE;
do { *dst-- = '\0'; } while (*dst == 0x20);
}
static void
get_sff_date(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
{
char buf[SFF_VENDOR_DATE_SIZE];
read_i2c(ii, addr, off, SFF_VENDOR_DATE_SIZE, buf);
sprintf(dst, "20%c%c-%c%c-%c%c", buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5]);
}
static int
get_sfp_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
{
get_sff_string(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, vi->name);
get_sff_string(ii, SFF_8472_BASE, SFF_8472_PN_START, vi->pn);
get_sff_string(ii, SFF_8472_BASE, SFF_8472_SN_START, vi->sn);
get_sff_date(ii, SFF_8472_BASE, SFF_8472_DATE_START, vi->date);
return (ii->error);
}
static int
get_qsfp_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
{
get_sff_string(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, vi->name);
get_sff_string(ii, SFF_8436_BASE, SFF_8436_PN_START, vi->pn);
get_sff_string(ii, SFF_8436_BASE, SFF_8436_SN_START, vi->sn);
get_sff_date(ii, SFF_8436_BASE, SFF_8436_DATE_START, vi->date);
return (ii->error);
}
int
ifconfig_sfp_get_sfp_vendor_info(ifconfig_handle_t *h,
const char *name, struct ifconfig_sfp_vendor_info *vi)
{
struct i2c_info ii;
memset(vi, 0, sizeof(*vi));
if (i2c_info_init(&ii, h, name) != 0)
return (-1);
if (ifconfig_sfp_id_is_qsfp(ii.id))
return (get_qsfp_vendor_info(&ii, vi));
return (get_sfp_vendor_info(&ii, vi));
}
/*
* Converts internal temperature (SFF-8472, SFF-8436)
* 16-bit unsigned value to human-readable representation:
*
* Internally measured Module temperature are represented
* as a 16-bit signed twos complement value in increments of
* 1/256 degrees Celsius, yielding a total range of 128C to +128C
* that is considered valid between 40 and +125C.
*/
static double
get_sff_temp(struct i2c_info *ii, uint8_t addr, uint8_t off)
{
double d;
uint8_t buf[2];
read_i2c(ii, addr, off, 2, buf);
d = (double)buf[0];
d += (double)buf[1] / 256;
return (d);
}
/*
* Retrieves supplied voltage (SFF-8472, SFF-8436).
* 16-bit usigned value, treated as range 0..+6.55 Volts
*/
static double
get_sff_voltage(struct i2c_info *ii, uint8_t addr, uint8_t off)
{
double d;
uint8_t buf[2];
read_i2c(ii, addr, off, 2, buf);
d = (double)((buf[0] << 8) | buf[1]);
return (d / 10000);
}
/*
* The following conversions assume internally-calibrated data.
* This is always true for SFF-8346, and explicitly checked for SFF-8472.
*/
double
power_mW(uint16_t power)
{
/* Power is specified in units of 0.1 uW. */
return (1.0 * power / 10000);
}
double
power_dBm(uint16_t power)
{
return (10.0 * log10(power_mW(power)));
}
double
bias_mA(uint16_t bias)
{
/* Bias current is specified in units of 2 uA. */
return (1.0 * bias / 500);
}
static uint16_t
get_sff_channel(struct i2c_info *ii, uint8_t addr, uint8_t off)
{
uint8_t buf[2];
read_i2c(ii, addr, off, 2, buf);
if (ii->error != 0)
return (0);
return ((buf[0] << 8) + buf[1]);
}
static int
get_sfp_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss)
{
uint8_t diag_type, flags;
/* Read diagnostic monitoring type */
read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type);
if (ii->error != 0)
return (-1);
/*
* Read monitoring data IFF it is supplied AND is
* internally calibrated
*/
flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL;
if ((diag_type & flags) != flags) {
ii->h->error.errtype = OTHER;
ii->h->error.errcode = ENXIO;
return (-1);
}
ss->temp = get_sff_temp(ii, SFF_8472_DIAG, SFF_8472_TEMP);
ss->voltage = get_sff_voltage(ii, SFF_8472_DIAG, SFF_8472_VCC);
ss->channel = calloc(channel_count(ii->id), sizeof(*ss->channel));
if (ss->channel == NULL) {
ii->h->error.errtype = OTHER;
ii->h->error.errcode = ENOMEM;
return (-1);
}
ss->channel[0].rx = get_sff_channel(ii, SFF_8472_DIAG, SFF_8472_RX_POWER);
ss->channel[0].tx = get_sff_channel(ii, SFF_8472_DIAG, SFF_8472_TX_BIAS);
return (ii->error);
}
static uint32_t
get_qsfp_bitrate(struct i2c_info *ii)
{
uint8_t code;
uint32_t rate;
code = 0;
read_i2c(ii, SFF_8436_BASE, SFF_8436_BITRATE, 1, &code);
rate = code * 100;
if (code == 0xFF) {
read_i2c(ii, SFF_8436_BASE, SFF_8636_BITRATE, 1, &code);
rate = code * 250;
}
return (rate);
}
static int
get_qsfp_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss)
{
size_t channels;
ss->temp = get_sff_temp(ii, SFF_8436_BASE, SFF_8436_TEMP);
ss->voltage = get_sff_voltage(ii, SFF_8436_BASE, SFF_8436_VCC);
channels = channel_count(ii->id);
ss->channel = calloc(channels, sizeof(*ss->channel));
if (ss->channel == NULL) {
ii->h->error.errtype = OTHER;
ii->h->error.errcode = ENOMEM;
return (-1);
}
for (size_t chan = 0; chan < channels; ++chan) {
uint8_t rxoffs = SFF_8436_RX_CH1_MSB + chan * sizeof(uint16_t);
uint8_t txoffs = SFF_8436_TX_CH1_MSB + chan * sizeof(uint16_t);
ss->channel[chan].rx =
get_sff_channel(ii, SFF_8436_BASE, rxoffs);
ss->channel[chan].tx =
get_sff_channel(ii, SFF_8436_BASE, txoffs);
}
ss->bitrate = get_qsfp_bitrate(ii);
return (ii->error);
}
int
ifconfig_sfp_get_sfp_status(ifconfig_handle_t *h, const char *name,
struct ifconfig_sfp_status *ss)
{
struct i2c_info ii;
memset(ss, 0, sizeof(*ss));
if (i2c_info_init(&ii, h, name) != 0)
return (-1);
if (ifconfig_sfp_id_is_qsfp(ii.id))
return (get_qsfp_status(&ii, ss));
return (get_sfp_status(&ii, ss));
}
void
ifconfig_sfp_free_sfp_status(struct ifconfig_sfp_status *ss)
{
if (ss != NULL)
free(ss->channel);
}
static const char *
sfp_id_string_alt(uint8_t value)
{
const char *id;
if (value <= SFF_8024_ID_LAST)
id = sff_8024_id[value];
else if (value > 0x80)
id = "Vendor specific";
else
id = "Reserved";
return (id);
}
static const char *
sfp_conn_string_alt(uint8_t value)
{
const char *conn;
if (value >= 0x0D && value <= 0x1F)
conn = "Unallocated";
else if (value >= 0x24 && value <= 0x7F)
conn = "Unallocated";
else
conn = "Vendor specific";
return (conn);
}
void
ifconfig_sfp_get_sfp_info_strings(const struct ifconfig_sfp_info *sfp,
struct ifconfig_sfp_info_strings *strings)
{
get_sfp_info_strings(sfp, strings);
if (strings->sfp_id == NULL)
strings->sfp_id = sfp_id_string_alt(sfp->sfp_id);
if (strings->sfp_conn == NULL)
strings->sfp_conn = sfp_conn_string_alt(sfp->sfp_conn);
if (strings->sfp_rev == NULL)
strings->sfp_rev = "Unallocated";
}
const char *
ifconfig_sfp_physical_spec(const struct ifconfig_sfp_info *sfp,
const struct ifconfig_sfp_info_strings *strings)
{
switch (sfp->sfp_id) {
case SFP_ID_UNKNOWN:
break;
case SFP_ID_QSFP:
case SFP_ID_QSFPPLUS:
case SFP_ID_QSFP28:
if (sfp->sfp_eth_1040g & SFP_ETH_1040G_EXTENDED)
return (strings->sfp_eth_ext);
else if (sfp->sfp_eth_1040g)
return (strings->sfp_eth_1040g);
break;
default:
if (sfp->sfp_eth_ext)
return (strings->sfp_eth_ext);
else if (sfp->sfp_eth_10g)
return (strings->sfp_eth_10g);
else if (sfp->sfp_eth)
return (strings->sfp_eth);
break;
}
return ("Unknown");
}
int
ifconfig_sfp_get_sfp_dump(ifconfig_handle_t *h, const char *name,
struct ifconfig_sfp_dump *dump)
{
struct i2c_info ii;
uint8_t *buf = dump->data;
memset(dump->data, 0, sizeof(dump->data));
if (i2c_info_init(&ii, h, name) != 0)
return (-1);
if (ifconfig_sfp_id_is_qsfp(ii.id)) {
read_i2c(&ii, SFF_8436_BASE, QSFP_DUMP0_START, QSFP_DUMP0_SIZE,
buf + QSFP_DUMP0_START);
read_i2c(&ii, SFF_8436_BASE, QSFP_DUMP1_START, QSFP_DUMP1_SIZE,
buf + QSFP_DUMP1_START);
} else {
read_i2c(&ii, SFF_8472_BASE, SFP_DUMP_START, SFP_DUMP_SIZE,
buf + SFP_DUMP_START);
}
return (ii.error != 0 ? -1 : 0);
}
size_t
ifconfig_sfp_dump_region_count(const struct ifconfig_sfp_dump *dp)
{
uint8_t id_byte = dp->data[0];
switch ((enum sfp_id)id_byte) {
case SFP_ID_UNKNOWN:
return (0);
case SFP_ID_QSFP:
case SFP_ID_QSFPPLUS:
case SFP_ID_QSFP28:
return (2);
default:
return (1);
}
}

View file

@ -0,0 +1,219 @@
/*-
* Copyright (c) 2014, Alexander V. Chernikov
* Copyright (c) 2020, Ryan Moeller <freqlabs@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 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.
*
* $FreeBSD$
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <libifconfig.h>
#include <libifconfig_sfp_tables.h>
/** SFP module information in raw numeric form
* These are static properties of the hardware.
*/
struct ifconfig_sfp_info;
/** SFP module information formatted as strings
* These are static strings that do not need to be freed.
*/
struct ifconfig_sfp_info_strings;
#define SFF_VENDOR_STRING_SIZE 16 /**< max chars in a vendor string */
#define SFF_VENDOR_DATE_SIZE 6 /**< chars in a vendor date code */
/** SFP module vendor info strings */
struct ifconfig_sfp_vendor_info {
char name[SFF_VENDOR_STRING_SIZE + 1]; /**< vendor name */
char pn[SFF_VENDOR_STRING_SIZE + 1]; /**< vendor part number */
char sn[SFF_VENDOR_STRING_SIZE + 1]; /**< vendor serial number */
char date[SFF_VENDOR_DATE_SIZE + 5]; /**< formatted vendor date */
};
/** SFP module status
* These are dynamic properties of the hardware.
*/
struct ifconfig_sfp_status {
double temp; /**< module temperature in degrees C,
valid range -40.0 to 125.0 */
double voltage; /**< module voltage in volts */
struct sfp_channel {
uint16_t rx; /**< channel receive power, LSB 0.1uW */
uint16_t tx; /**< channel transmit bias current, LSB 2uA */
} *channel; /**< array of channel rx/tx status */
uint32_t bitrate; /**< link bitrate,
only present for QSFP modules,
zero for SFP modules */
};
#define SFF_DUMP_SIZE 256 /**< size of the memory dump buffer */
#define SFP_DUMP_START 0 /**< start address of an SFP module dump */
#define SFP_DUMP_SIZE 128 /**< bytes in an SFP module dump */
#define QSFP_DUMP0_START 0 /**< start address of the first region
in a QSFP module dump */
#define QSFP_DUMP0_SIZE 82 /**< bytes in the first region
in a QSFP module dump */
#define QSFP_DUMP1_START 128 /**< start address of the second region
in a QSFP module dump */
#define QSFP_DUMP1_SIZE 128 /**< bytes in the second region
in a QSFP module dump */
/** SFP module I2C memory dump
* SFP modules have one region, QSFP modules have two regions.
*/
struct ifconfig_sfp_dump {
uint8_t data[SFF_DUMP_SIZE]; /**< memory dump data */
};
/** Get information about the static properties of an SFP/QSFP module
* The information is returned in numeric form.
* @see ifconfig_sfp_get_sfp_info_strings to get corresponding strings.
* @param h An open ifconfig state handle
* @param name The name of an interface
* @param sfp Pointer to an object to fill, will be zeroed by this function
* @return 0 if successful, -1 with error info set in the handle otherwise
*/
int ifconfig_sfp_get_sfp_info(ifconfig_handle_t *h, const char *name,
struct ifconfig_sfp_info *sfp);
/** Get the number of channels present on the given module
* @param sfp Pointer to a filled SFP module info object
* @return The number of channels or 0 if unknown
*/
size_t ifconfig_sfp_channel_count(const struct ifconfig_sfp_info *sfp);
/** Is the given module ID a QSFP
* NB: This convenience function is implemented in the header to keep the
* classification criteria visible to the user.
* @param id The sfp_id field of a SFP module info object
* @return A bool true if QSFP-type sfp_id otherwise false
*/
static inline bool
ifconfig_sfp_id_is_qsfp(enum sfp_id id)
{
switch (id) {
case SFP_ID_QSFP:
case SFP_ID_QSFPPLUS:
case SFP_ID_QSFP28:
return (true);
default:
return (false);
}
}
/** Get string descriptions of the given SFP/QSFP module info
* The strings are static and do not need to be freed.
* @see ifconfig_sfp_get_sfp_info to obtain the input info.
* @param sfp Pointer to a filled SFP module info object
* @param strings Pointer to an object to be filled with pointers to
* static strings describing the given info
*/
void ifconfig_sfp_get_sfp_info_strings(const struct ifconfig_sfp_info *sfp,
struct ifconfig_sfp_info_strings *strings);
/** Get a string describing the given SFP/QSFP module's physical layer spec
* The correct field in ifconfig_sfp_info varies depending on the module. This
* function chooses the appropriate string based on the provided module info.
* The string returned is static and does not need to be freed.
* @param sfp Pointer to a filled SFP module info object
* @param strings Pointer to a filled SFP module strings object
* @return Pointer to a static string describing the module's spec
*/
const char *ifconfig_sfp_physical_spec(const struct ifconfig_sfp_info *sfp,
const struct ifconfig_sfp_info_strings *strings);
/** Get the vendor info strings from an SFP/QSFP module
* @param h An open ifconfig state handle
* @param name The name of an interface
* @param vi Pointer to an object to be filled with the vendor info strings,
* will be zeroed by this function
* @return 0 if successful, -1 with error info set in the handle otherwise
*/
int ifconfig_sfp_get_sfp_vendor_info(ifconfig_handle_t *h, const char *name,
struct ifconfig_sfp_vendor_info *vi);
/** Get the status of an SFP/QSFP module's dynamic properties
* @see ifconfig_sfp_free_sfp_status to free the allocations
* @param h An open ifconfig state handle
* @param name The name of an interface
* @param ss Pointer to an object to be filled with the module's status
* @return 0 if successful, -1 with error info set in the handle otherwise
* where the errcode `ENXIO` indicates an SFP module that is not
* calibrated or does not provide diagnostic status measurements
*/
int ifconfig_sfp_get_sfp_status(ifconfig_handle_t *h, const char *name,
struct ifconfig_sfp_status *ss);
/** Free the memory allocations in an ifconfig_sfp_status struct
* @param ss Pointer to an object whose internal allocations are to be freed
* if not NULL
*/
void ifconfig_sfp_free_sfp_status(struct ifconfig_sfp_status *ss);
/** Dump the I2C memory of an SFP/QSFP module
* SFP modules have one memory region dumped, QSFP modules have two.
* @param h An open ifconfig state handle
* @param name The name of an interface
* @param buf Pointer to a dump data buffer object
* @return 0 if successful, -1 with error info set in the handle otherwise
*/
int ifconfig_sfp_get_sfp_dump(ifconfig_handle_t *h, const char *name,
struct ifconfig_sfp_dump *buf);
/** Get the number of I2C memory dump regions present in the given dump
* @param dp Pointer to a filled dump data buffer object
* @return The number of regions or 0 if unknown
*/
size_t ifconfig_sfp_dump_region_count(const struct ifconfig_sfp_dump *dp);
/** Convert channel power to milliwatts power
* This is provided as a convenience for displaying channel power levels.
* @see (struct ifconfig_sfp_status).channel
* @param power Power in 0.1 mW units
* @return Power in milliwatts (mW)
*/
double power_mW(uint16_t power);
/** Convert channel power to decibel-milliwats power level
* This is provided as a convenience for displaying channel power levels.
* @see (struct ifconfig_sfp_status).channel
* @param power Power in 0.1 mW units
* @return Power level in decibel-milliwatts (dBm)
*/
double power_dBm(uint16_t power);
/** Convert channel bias current to milliamps
* This is provided as a convenience for displaying channel bias currents.
* @see (struct ifconfig_sfp_status).channel
* @param bias Bias current in 2 mA units
* @return Bias current in milliamps (mA)
*/
double bias_mA(uint16_t bias);

View file

@ -0,0 +1,124 @@
/*-
* Copyright (c) 2020, Ryan Moeller <freqlabs@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 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.
*
* $FreeBSD$
*/
{# THIS IS A TEMPLATE PROCESSED BY lib/libifconfig/sfp.lua #}
#include <libifconfig_sfp_tables.h>
#include <libifconfig_sfp_tables_internal.h>
struct sfp_enum_metadata {
int value; /* numeric discriminant value */
const char *symbol; /* symbolic name */
const char *description; /* brief description */
const char *display; /* shortened display name */
};
const struct sfp_enum_metadata *
find_metadata(const struct sfp_enum_metadata *table, int value)
{
while (table->value != value && table->symbol != NULL)
++table;
return (table->symbol != NULL ? table : NULL);
}
{%
for _, ent in ipairs(enums) do
if type(ent) == "string" then
%}
/*
* {*ent*}
*/
{%
else
local enum = ent
local name = "sfp_"..enum.name
local sym, desc, disp
%}
static const struct sfp_enum_metadata {*name*}_table_[] = {
{%
for _, item in ipairs(enum.values) do
_, sym, desc, disp = table.unpack(item)
local symbol = string.upper(name).."_"..sym
%}
{
.value = {*symbol*},
.symbol = "{*symbol*}",
.description = "{*desc*}",
{%
if disp then
%}
.display = "{*disp*}",
{%
end
%}
},
{%
end
%}
{0}
};
const struct sfp_enum_metadata *{*name*}_table = {*name*}_table_;
const char *
ifconfig_{*name*}_symbol(enum {*name*} v)
{
const struct sfp_enum_metadata *metadata;
if ((metadata = find_metadata({*name*}_table, v)) == NULL)
return (NULL);
return (metadata->symbol);
}
const char *
ifconfig_{*name*}_description(enum {*name*} v)
{
const struct sfp_enum_metadata *metadata;
if ((metadata = find_metadata({*name*}_table, v)) == NULL)
return (NULL);
return (metadata->description);
}
{%
if disp then
%}
const char *
ifconfig_{*name*}_display(enum {*name*} v)
{
const struct sfp_enum_metadata *metadata;
if ((metadata = find_metadata({*name*}_table, v)) == NULL)
return (NULL);
return (metadata->display);
}
{%
end
end
end
%}

View file

@ -0,0 +1,130 @@
/*-
* Copyright (c) 2020, Ryan Moeller <freqlabs@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 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.
*
* $FreeBSD$
*/
{# THIS IS A TEMPLATE PROCESSED BY lib/libifconfig/sfp.lua #}
#pragma once
#include <stdint.h>
{%
for _, ent in ipairs(enums) do
if type(ent) == "string" then
%}
/*
* {*ent*}
*/
{%
else
local enum = ent
local name = "sfp_"..enum.name
local num, sym, desc, disp
%}
/** {*enum.description*} */
enum {*name*} {
{%
for _, item in ipairs(enum.values) do
val, sym, desc, disp = table.unpack(item)
local symbol = string.upper(name).."_"..sym
%}
{*symbol*} = {*val*}, /**< {*desc*} */
{%
end
%}
};
/** Get the symbolic name of a given {*name*} value */
const char *ifconfig_{*name*}_symbol(enum {*name*});
/** Get a brief description of a given {*name*} value */
const char *ifconfig_{*name*}_description(enum {*name*});
{%
if disp then
%}
/** Get a shortened user-friendly display name for a given {*name*} value */
const char *ifconfig_{*name*}_display(enum {*name*});
{%
end
end
end
%}
/*
* Descriptions of each enum
*/
{%
for _, ent in ipairs(enums) do
if type(ent) == "table" then
local enum = ent
local name = "sfp_"..enum.name
%}
/** Get a brief description of the {*name*} enum */
static inline const char *
ifconfig_enum_{*name*}_description(void)
{
return ("{*enum.description*}");
}
{%
end
end
%}
/*
* Info struct definitions
*/
struct ifconfig_sfp_info {
{%
for _, ent in ipairs(enums) do
if type(ent) == "table" then
local enum = ent
local name = "sfp_"..enum.name
local t = string.format("uint%d_t", enum.bits)
%}
{*t*} {*name*}; /**< {*enum.description*} */
{%
end
end
%}
};
struct ifconfig_sfp_info_strings {
{%
for _, ent in ipairs(enums) do
if type(ent) == "table" then
local enum = ent
local name = "sfp_"..enum.name
%}
const char *{*name*}; /**< {*enum.description*} */
{%
end
end
%}
};

View file

@ -0,0 +1,66 @@
/*-
* Copyright (c) 2020, Ryan Moeller <freqlabs@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 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.
*
* $FreeBSD$
*/
{# THIS IS A TEMPLATE PROCESSED BY lib/libifconfig/sfp.lua #}
#pragma once
#include <libifconfig_sfp.h>
#include <libifconfig_sfp_tables.h>
struct sfp_enum_metadata;
const struct sfp_enum_metadata *find_metadata(const struct sfp_enum_metadata *,
int);
{%
for _, ent in ipairs(enums) do
if type(ent) == "table" then
local enum = ent
local name = "sfp_"..enum.name
%}
extern const struct sfp_enum_metadata *{*name*}_table;
{%
end
end
%}
static inline void
get_sfp_info_strings(const struct ifconfig_sfp_info *sfp,
struct ifconfig_sfp_info_strings *strings)
{
{%
for _, ent in ipairs(enums) do
if type(ent) == "table" then
local enum = ent
local name = "sfp_"..enum.name
%}
strings->{*name*} = ifconfig_{*name*}_description(sfp->{*name*});
{%
end
end
%}
}

367
lib/libifconfig/sfp.lua Normal file
View file

@ -0,0 +1,367 @@
#!/usr/libexec/flua
-- ex: sw=4 et:
--[[
/*-
* Copyright (c) 2014, Alexander V. Chernikov
* Copyright (c) 2020, Ryan Moeller <freqlabs@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 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.
*
* $FreeBSD$
*/
]]
-- Try to put the template.lua library in the package search path.
package.path = (os.getenv("SRCTOP") or "/usr/src").."/tools/lua/?.lua"
-- Render the template named by the first argument to this script.
require("template").render(arg[1], { -- This table is the template's context.
-- The table `enums' is accessible in the template. It is a list of strings
-- and tables that describe the various enum types we are generating and the
-- ancillary metadata for generating other related code.
enums = {
-- Strings at this level are rendered as block comments for convenience.
"SFF-8024 Rev. 4.6 Table 4-1: Indentifier Values",
-- This table describes an enum type, in this case enum sfp_id:
{
name = "id", -- The template prepends the sfp_ prefix to our name.
description = "Transceiver identifier",
-- What width int is needed to store this type:
bits = 8, -- This could be inferred by the values below...
-- The values, symbols, display names, and descriptions of this enum:
values = {
-- The prefix SFP_ID_ is prepended to the symbolic names.
-- Only this enum has shortened names for the values, though they
-- could be added to the other enums.
-- value, symbolic name, description, shortened name
{0x00, "UNKNOWN", "Unknown or unspecified", "Unknown"},
{0x01, "GBIC", "GBIC", "GBIC"},
{0x02, "SFF", "Module soldered to motherboard (ex: SFF)",
"SFF"},
{0x03, "SFP", "SFP or SFP+", "SFP/SFP+/SFP28"},
{0x04, "XBI", "300 pin XBI", "XBI"},
{0x05, "XENPAK", "Xenpak", "Xenpak"},
{0x06, "XFP", "XFP", "XFP"},
{0x07, "XFF", "XFF", "XFF"},
{0x08, "XFPE", "XFP-E", "XFP-E"},
{0x09, "XPAK", "XPAK", "XPAK"},
{0x0A, "X2", "X2", "X2"},
{0x0B, "DWDM_SFP", "DWDM-SFP/SFP+", "DWDM-SFP/SFP+"},
{0x0C, "QSFP", "QSFP", "QSFP"},
{0x0D, "QSFPPLUS", "QSFP+ or later", "QSFP+"},
{0x0E, "CXP", "CXP", "CXP"},
{0x0F, "HD4X", "Shielded Mini Multilane HD 4X", "HD4X"},
{0x10, "HD8X", "Shielded Mini Multilane HD 8X", "HD8X"},
{0x11, "QSFP28", "QSFP28 or later", "QSFP28"},
{0x12, "CXP2", "CXP2 (aka CXP28)", "CXP2"},
{0x13, "CDFP", "CDFP (Style 1/Style 2)", "CDFP"},
{0x14, "SMM4", "Shielded Mini Multilane HD 4X fanout",
"SMM4"},
{0x15, "SMM8", "Shielded Mini Multilane HD 8X fanout",
"SMM8"},
{0x16, "CDFP3", "CDFP (Style 3)", "CDFP3"},
{0x17, "MICROQSFP", "microQSFP", "microQSFP"},
{0x18, "QSFP_DD", "QSFP-DD 8X pluggable transceiver", "QSFP-DD"},
{0x19, "QSFP8X", "QSFP 8X pluggable transceiver", "QSFP8X"},
{0x1A, "SFP_DD", "SFP-DD 2X pluggable transceiver", "SFP-DD"},
{0x1B, "DSFP", "DSFP Dual SFP pluggable transceiver", "DSFP"},
{0x1C, "X4ML", "x4 MiniLink/OcuLink", "x4MiniLink/OcuLink"},
{0x1D, "X8ML", "x8 MiniLink", "x8MiniLink"},
{0x1E, "QSFP_CMIS",
"QSFP+ or later w/Common Management Interface Specification",
"QSFP+(CMIS)"},
},
},
"SFF-8024 Rev. 4.6 Table 4-3: Connector Types",
{
name = "conn",
description = "Connector type",
bits = 8,
values = {
{0x00, "UNKNOWN", "Unknown"},
{0x01, "SC", "SC"},
{0x02, "FC_1_COPPER", "Fibre Channel Style 1 copper"},
{0x03, "FC_2_COPPER", "Fibre Channel Style 2 copper"},
{0x04, "BNC_TNC", "BNC/TNC"},
{0x05, "FC_COAX", "Fibre Channel coaxial"},
{0x06, "FIBER_JACK", "Fiber Jack"},
{0x07, "LC", "LC"},
{0x08, "MT_RJ", "MT-RJ"},
{0x09, "MU", "MU"},
{0x0A, "SG", "SG"},
{0x0B, "OPTICAL_PIGTAIL", "Optical pigtail"},
{0x0C, "MPO_1X12_POPTIC", "MPO 1x12 Parallel Optic"},
{0x0D, "MPO_2X16_POPTIC", "MPO 2x16 Parallel Optic"},
{0x20, "HSSDC_II", "HSSDC II"},
{0x21, "COPPER_PIGTAIL", "Copper pigtail"},
{0x22, "RJ45", "RJ45"},
{0x23, "NONE", "No separable connector"},
{0x24, "MXC_2X16", "MXC 2x16"},
{0x25, "CS_OPTICAL", "CS optical connector"},
{0x26, "MINI_CS_OPTICAL", "Mini CS optical connector"},
{0x27, "MPO_2X12_POPTIC", "MPO 2x12 Parallel Optic"},
{0x28, "MPO_1X16_POPTIC", "MPO 1x16 Parallel Optic"},
},
},
"SFF-8472 Rev. 11.4 table 3.5: Transceiver codes",
"10G Ethernet/IB compliance codes, byte 3",
{
name = "eth_10g",
description = "10G Ethernet/IB compliance",
bits = 8,
values = {
{0x80, "10G_BASE_ER", "10G Base-ER"},
{0x40, "10G_BASE_LRM", "10G Base-LRM"},
{0x20, "10G_BASE_LR", "10G Base-LR"},
{0x10, "10G_BASE_SR", "10G Base-SR"},
{0x08, "1X_SX", "1X SX"},
{0x04, "1X_LX", "1X LX"},
{0x02, "1X_COPPER_ACTIVE", "1X Copper Active"},
{0x01, "1X_COPPER_PASSIVE", "1X Copper Passive"},
},
},
"Ethernet compliance codes, byte 6",
{
name = "eth",
description = "Ethernet compliance",
bits = 8,
values = {
{0x80, "BASE_PX", "BASE-PX"},
{0x40, "BASE_BX10", "BASE-BX10"},
{0x20, "100BASE_FX", "100BASE-FX"},
{0x10, "100BASE_LX_LX10", "100BASE-LX/LX10"},
{0x08, "1000BASE_T", "1000BASE-T"},
{0x04, "1000BASE_CX", "1000BASE-CX"},
{0x02, "1000BASE_LX", "1000BASE-LX"},
{0x01, "1000BASE_SX", "1000BASE-SX"},
},
},
"FC link length, byte 7",
{
name = "fc_len",
description = "Fibre Channel link length",
bits = 8,
values = {
{0x80, "VERY_LONG", "very long distance"},
{0x40, "SHORT", "short distance"},
{0x20, "INTERMEDIATE", "intermediate distance"},
{0x10, "LONG", "long distance"},
{0x08, "MEDIUM", "medium distance"},
},
},
"Channel/Cable technology, byte 7-8",
{
name = "cab_tech",
description = "Channel/cable technology",
bits = 16,
values = {
{0x0400, "SA", "Shortwave laser (SA)"},
{0x0200, "LC", "Longwave laser (LC)"},
{0x0100, "EL_INTER", "Electrical inter-enclosure (EL)"},
{0x0080, "EL_INTRA", "Electrical intra-enclosure (EL)"},
{0x0040, "SN", "Shortwave laser (SN)"},
{0x0020, "SL", "Shortwave laser (SL)"},
{0x0010, "LL", "Longwave laser (LL)"},
{0x0008, "ACTIVE", "Active Cable"},
{0x0004, "PASSIVE", "Passive Cable"},
},
},
"FC Transmission media, byte 9",
{
name = "fc_media",
description = "Fibre Channel transmission media",
bits = 8,
values = {
{0x80, "TW", "Twin Axial Pair (TW)"},
{0x40, "TP", "Twisted Pair (TP)"},
{0x20, "MI", "Miniature Coax (MI)"},
{0x10, "TV", "Video Coax (TV)"},
{0x08, "M6", "Miltimode 62.5um (M6)"},
{0x04, "M5", "Multimode 50um (M5)"},
{0x02, "RESERVED", "Reserved"},
{0x01, "SM", "Single Mode (SM)"},
},
},
"FC Speed, byte 10",
{
name = "fc_speed",
description = "Fibre Channel speed",
bits = 8,
values = {
{0x80, "1200", "1200 MBytes/sec"},
{0x40, "800", "800 MBytes/sec"},
{0x20, "1600", "1600 MBytes/sec"},
{0x10, "400", "400 MBytes/sec"},
{0x08, "3200", "3200 MBytes/sec"},
{0x04, "200", "200 MBytes/sec"},
{0x01, "100", "100 MBytes/sec"},
},
},
"SFF-8436 Rev. 4.8 table 33: Specification compliance",
"10/40G Ethernet compliance codes, byte 128 + 3",
{
name = "eth_1040g",
description = "10/40G Ethernet compliance",
bits = 8,
values = {
{0x80, "EXTENDED", "Extended"},
{0x40, "10GBASE_LRM", "10GBASE-LRM"},
{0x20, "10GBASE_LR", "10GBASE-LR"},
{0x10, "10GBASE_SR", "10GBASE-SR"},
{0x08, "40GBASE_CR4", "40GBASE-CR4"},
{0x04, "40GBASE_SR4", "40GBASE-SR4"},
{0x02, "40GBASE_LR4", "40GBASE-LR4"},
{0x01, "40G_ACTIVE", "40G Active Cable"},
},
},
"SFF-8024 Rev. 4.6 table 4-4: Extended Specification Compliance",
{
name = "eth_ext",
description = "Extended specification compliance",
bits = 8,
values = {
{0xFF, "RESERVED_FF", "Reserved"},
{0x55, "128GFC_LW", "128GFC LW"},
{0x54, "128GFC_SW", "128GFC SW"},
{0x53, "128GFC_EA", "128GFC EA"},
{0x52, "64GFC_LW", "64GFC LW"},
{0x51, "64GFC_SW", "64GFC SW"},
{0x50, "64GFC_EA", "64GFC EA"},
{0x4F, "RESERVED_4F", "Reserved"},
{0x4E, "RESERVED_4E", "Reserved"},
{0x4D, "RESERVED_4D", "Reserved"},
{0x4C, "RESERVED_4C", "Reserved"},
{0x4B, "RESERVED_4B", "Reserved"},
{0x4A, "RESERVED_4A", "Reserved"},
{0x49, "RESERVED_49", "Reserved"},
{0x48, "RESERVED_48", "Reserved"},
{0x47, "RESERVED_47", "Reserved"},
{0x46, "200GBASE_LR4", "200GBASE-LR4"},
{0x45, "50GBASE_LR", "50GBASE-LR"},
{0x44, "200G_1550NM_PSM4", "200G 1550nm PSM4"},
{0x43, "200GBASE_FR4", "200GBASE-FR4"},
{0x42, "50GBASE_FR_200GBASE_DR4", "50GBASE-FR or 200GBASE-DR4"},
{0x41, "50GBASE_SR_100GBASE_SR2_200GBASE_SR4",
"50GBASE-SR/100GBASE-SR2/200GBASE-SR4"},
{0x40, "50GBASE_CR_100GBASE_CR2_200GBASE_CR4",
"50GBASE-CR/100GBASE-CR2/200GBASE-CR4"},
{0x3F, "RESERVED_3F", "Reserved"},
{0x3E, "RESERVED_3E", "Reserved"},
{0x3D, "RESERVED_3D", "Reserved"},
{0x3C, "RESERVED_3C", "Reserved"},
{0x3B, "RESERVED_3B", "Reserved"},
{0x3A, "RESERVED_3A", "Reserved"},
{0x39, "RESERVED_39", "Reserved"},
{0x38, "RESERVED_38", "Reserved"},
{0x37, "RESERVED_37", "Reserved"},
{0x36, "RESERVED_36", "Reserved"},
{0x35, "RESERVED_35", "Reserved"},
{0x34, "RESERVED_34", "Reserved"},
{0x33, "50_100_200GAUI_AOC_HI_BER",
"50GAUI/100GAUI-2/200GAUI-4 AOC (BER <2.6e-4)"},
{0x32, "50_100_200GAUI_ACC_HI_BER",
"50GAUI/100GAUI-2/200GAUI-4 ACC (BER <2.6e-4)"},
{0x31, "50_100_200GAUI_AOC_LO_BER",
"50GAUI/100GAUI-2/200GAUI-4 AOC (BER <1e-6)"},
{0x30, "50_100_200GAUI_ACC_LO_BER",
"50GAUI/100GAUI-2/200GAUI-4 ACC (BER <1e-6)"},
{0x2F, "RESERVED_2F", "Reserved"},
{0x2E, "RESERVED_2E", "Reserved"},
{0x2D, "RESERVED_2D", "Reserved"},
{0x2C, "RESERVED_2C", "Reserved"},
{0x2B, "RESERVED_2B", "Reserved"},
{0x2A, "RESERVED_2A", "Reserved"},
{0x29, "RESERVED_29", "Reserved"},
{0x28, "RESERVED_28", "Reserved"},
{0x27, "100G_LR", "100G-LR"},
{0x26, "100G_FR", "100G-FR"},
{0x25, "100GBASE_DR", "100GBASE-DR"},
{0x24, "4WDM_40_MSA", "4WDM-40 MSA"},
{0x23, "4WDM_20_MSA", "4WDM-20 MSA"},
{0x22, "4WDM_10_MSA", "4WDM-10 MSA"},
{0x21, "100G_PAM4_BIDI", "100G PAM4 BiDi"},
{0x20, "100G_SWDM4", "100G SWDM4"},
{0x1F, "40G_SWDM4", "40G SWDM4"},
{0x1E, "2_5GBASE_T", "2.5GBASE-T"},
{0x1D, "5GBASE_T", "5GBASE-T"},
{0x1C, "10GBASE_T_SR", "10GBASE-T Short Reach"},
{0x1B, "100G_1550NM_WDM", "100G 1550nm WDM"},
{0x1A, "100GE_DWDM2", "100GE-DWDM2"},
{0x19, "100G_25GAUI_C2M_ACC", "100G ACC or 25GAUI C2M ACC"},
{0x18, "100G_25GAUI_C2M_AOC", "100G AOC or 25GAUI C2M AOC"},
{0x17, "100G_CLR4", "100G CLR4"},
{0x16, "10GBASE_T_SFI",
"10GBASE-T with SFI electrical interface"},
{0x15, "G959_1_P1L1_2D2", "G959.1 profile P1L1-2D2"},
{0x14, "G959_1_P1S1_2D2", "G959.1 profile P1S1-2D2"},
{0x13, "G959_1_P1I1_2D1", "G959.1 profile P1I1-2D1"},
{0x12, "40G_PSM4", "40G PSM4 Parallel SMF"},
{0x11, "4X_10GBASE_SR", "4 x 10GBASE-SR"},
{0x10, "40GBASE_ER4", "40GBASE-ER4"},
{0x0F, "RESERVED_0F", "Reserved"},
{0x0E, "RESERVED_0E", "Reserved"},
{0x0D, "CA_25G_N", "25GBASE-CR CA-25G-N"},
{0x0C, "CA_25G_S", "25GBASE-CR CA-25G-S"},
{0x0B, "CA_L", "100GBASE-CR4 or 25GBASE-CR CA-L"},
{0x0A, "RESERVED_0A", "Reserved"},
{0x09, "OBSOLETE", "Obsolete"},
{0x08, "100G_25GAUI_C2M_ACC_1",
"100G ACC (Active Copper Cable"},
{0x07, "100G_PSM4_P_SMF", "100G PSM4 Parallel SMF"},
{0x06, "100G_CWDM4", "100G CWDM4"},
{0x05, "100GBASE_SR10", "100GBASE-SR10"},
{0x04, "100GBASE_ER4_25GBASE_ER", "100GBASE-ER4 or 25GBASE-ER"},
{0x03, "100GBASE_LR4_25GBASE_LR", "100GBASE-LR4 or 25GBASE-LR"},
{0x02, "100GBASE_SR4_25GBASE_SR", "100GBASE-SR4 or 25GBASE-SR"},
{0x01, "100G_25GAUI_C2M_AOC_1",
"100G AOC (Active Optical Cable"},
{0x00, "UNSPECIFIED", "Unspecified"},
},
},
"SFF-8636 Rev. 2.9 table 6.3: Revision compliance",
{
name = "rev",
description = "Revision compliance",
bits = 8,
values = {
{0x1, "SFF_8436_REV_LE_4_8", "SFF-8436 rev <=4.8"},
{0x2, "SFF_8436_REV_LE_4_8_ALT", "SFF-8436 rev <=4.8"},
{0x3, "SFF_8636_REV_LE_1_3", "SFF-8636 rev <=1.3"},
{0x4, "SFF_8636_REV_LE_1_4", "SFF-8636 rev <=1.4"},
{0x5, "SFF_8636_REV_LE_1_5", "SFF-8636 rev <=1.5"},
{0x6, "SFF_8636_REV_LE_2_0", "SFF-8636 rev <=2.0"},
{0x7, "SFF_8636_REV_LE_2_7", "SFF-8636 rev <=2.7"},
{0x8, "SFF_8363_REV_GE_2_8", "SFF-8636 rev >=2.8"},
{0x0, "UNSPECIFIED", "Unspecified"},
},
},
}
-- Nothing else in this context.
})

View file

@ -4,7 +4,7 @@
#
DTB_DIR="/usr/local/share/rpi-firmware"
DTB="bcm2710-rpi-3-b.dtb bcm2710-rpi-3-b-plus.dtb bcm2711-rpi-4-b.dtb"
DTB="bcm2709-rpi-2-b.dtb bcm2710-rpi-3-b.dtb bcm2710-rpi-3-b-plus.dtb bcm2711-rpi-4-b.dtb"
EMBEDDED_TARGET_ARCH="aarch64"
EMBEDDED_TARGET="arm64"
EMBEDDEDBUILD=1

View file

@ -224,6 +224,9 @@ CRUNCH_ALIAS_chown= chgrp
##################################################################
CRUNCH_LIBS+= -lm
CRUNCH_LIBS+= ${OBJTOP}/lib/libifconfig/libifconfig.a
CRUNCH_BUILDOPTS+= CRUNCH_CFLAGS+=-I${OBJTOP}/lib/libifconfig
.if ${MK_ISCSI} != "no"
CRUNCH_PROGS_usr.bin+= iscsictl
CRUNCH_PROGS_usr.sbin+= iscsid

View file

@ -37,7 +37,8 @@ SRCS+= ifgif.c # GIF reversed header workaround
SRCS+= ifipsec.c # IPsec VTI
SRCS+= sfp.c # SFP/SFP+ information
LIBADD+= m
LIBADD+= ifconfig m util
CFLAGS+= -I${SRCTOP}/lib/libifconfig -I${OBJTOP}/lib/libifconfig
.if ${MK_WIRELESS_SUPPORT} != "no"
SRCS+= ifieee80211.c # SIOC[GS]IEEE80211 support

File diff suppressed because it is too large Load diff

View file

@ -192,6 +192,7 @@ char *devfs_fqpn(char *, struct devfs_mount *, struct devfs_dirent *,
struct componentname *);
void devfs_delete(struct devfs_mount *, struct devfs_dirent *, int);
void devfs_dirent_free(struct devfs_dirent *);
int devfs_populate_needed(struct devfs_mount *dm);
void devfs_populate(struct devfs_mount *);
void devfs_cleanup(struct devfs_mount *);
void devfs_unmount_final(struct devfs_mount *);

View file

@ -659,6 +659,13 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup)
return (0);
}
int
devfs_populate_needed(struct devfs_mount *dm)
{
return (dm->dm_generation != devfs_generation);
}
/*
* The caller needs to hold the dm for the duration of the call.
*/
@ -668,9 +675,9 @@ devfs_populate(struct devfs_mount *dm)
unsigned gen;
sx_assert(&dm->dm_lock, SX_XLOCKED);
gen = devfs_generation;
if (dm->dm_generation == gen)
if (!devfs_populate_needed(dm))
return;
gen = devfs_generation;
while (devfs_populate_loop(dm, 0))
continue;
dm->dm_generation = gen;

View file

@ -235,6 +235,11 @@ devfs_populate_vp(struct vnode *vp)
ASSERT_VOP_LOCKED(vp, "devfs_populate_vp");
dmp = VFSTODEVFS(vp->v_mount);
if (!devfs_populate_needed(dmp)) {
sx_xlock(&dmp->dm_lock);
goto out_nopopulate;
}
locked = VOP_ISLOCKED(vp);
sx_xlock(&dmp->dm_lock);
@ -252,6 +257,7 @@ devfs_populate_vp(struct vnode *vp)
devfs_unmount_final(dmp);
return (ERESTART);
}
out_nopopulate:
if (VN_IS_DOOMED(vp)) {
sx_xunlock(&dmp->dm_lock);
return (ERESTART);
@ -420,6 +426,7 @@ devfs_allocv(struct devfs_dirent *de, struct mount *mp, int lockmode,
struct cdev *dev;
struct devfs_mount *dmp;
struct cdevsw *dsw;
enum vgetstate vs;
dmp = VFSTODEVFS(mp);
if (de->de_flags & DE_DOOMED) {
@ -432,10 +439,10 @@ devfs_allocv(struct devfs_dirent *de, struct mount *mp, int lockmode,
mtx_lock(&devfs_de_interlock);
vp = de->de_vnode;
if (vp != NULL) {
VI_LOCK(vp);
vs = vget_prep(vp);
mtx_unlock(&devfs_de_interlock);
sx_xunlock(&dmp->dm_lock);
vget(vp, lockmode | LK_INTERLOCK | LK_RETRY, curthread);
vget_finish(vp, lockmode | LK_RETRY, vs);
sx_xlock(&dmp->dm_lock);
if (devfs_allocv_drop_refs(0, dmp, de)) {
vput(vp);
@ -1492,13 +1499,14 @@ devfs_revoke(struct vop_revoke_args *ap)
struct cdev *dev;
struct cdev_priv *cdp;
struct devfs_dirent *de;
enum vgetstate vs;
u_int i;
KASSERT((ap->a_flags & REVOKEALL) != 0, ("devfs_revoke !REVOKEALL"));
dev = vp->v_rdev;
cdp = cdev2priv(dev);
dev_lock();
cdp->cdp_inuse++;
dev_unlock();
@ -1521,17 +1529,16 @@ devfs_revoke(struct vop_revoke_args *ap)
vp2 = de->de_vnode;
if (vp2 != NULL) {
dev_unlock();
VI_LOCK(vp2);
vs = vget_prep(vp2);
mtx_unlock(&devfs_de_interlock);
if (vget(vp2, LK_EXCLUSIVE | LK_INTERLOCK,
curthread))
if (vget_finish(vp2, LK_EXCLUSIVE, vs) != 0)
goto loop;
vhold(vp2);
vgone(vp2);
vdrop(vp2);
vput(vp2);
break;
}
}
}
if (vp2 != NULL) {
continue;
@ -1927,6 +1934,9 @@ static struct vop_vector devfs_vnodeops = {
#endif
.vop_symlink = devfs_symlink,
.vop_vptocnp = devfs_vptocnp,
.vop_lock1 = vop_lock,
.vop_unlock = vop_unlock,
.vop_islocked = vop_islocked,
};
VFS_VOP_VECTOR_REGISTER(devfs_vnodeops);
@ -1965,6 +1975,9 @@ static struct vop_vector devfs_specops = {
.vop_symlink = VOP_PANIC,
.vop_vptocnp = devfs_vptocnp,
.vop_write = dead_write,
.vop_lock1 = vop_lock,
.vop_unlock = vop_unlock,
.vop_islocked = vop_islocked,
};
VFS_VOP_VECTOR_REGISTER(devfs_specops);

View file

@ -182,6 +182,7 @@
#include <sys/namei.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
#include <sys/stat.h>
#include <fs/nullfs/null.h>
@ -484,8 +485,20 @@ null_setattr(struct vop_setattr_args *ap)
}
/*
* We handle getattr only to change the fsid.
* We handle stat and getattr only to change the fsid.
*/
static int
null_stat(struct vop_stat_args *ap)
{
int error;
if ((error = null_bypass((struct vop_generic_args *)ap)) != 0)
return (error);
ap->a_sb->st_dev = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
return (0);
}
static int
null_getattr(struct vop_getattr_args *ap)
{
@ -918,6 +931,7 @@ struct vop_vector null_vnodeops = {
.vop_accessx = null_accessx,
.vop_advlockpurge = vop_stdadvlockpurge,
.vop_bmap = VOP_EOPNOTSUPP,
.vop_stat = null_stat,
.vop_getattr = null_getattr,
.vop_getwritemount = null_getwritemount,
.vop_inactive = null_inactive,

View file

@ -372,6 +372,13 @@ tmpfs_mount(struct mount *mp)
}
tmp->tm_nomtime = vfs_getopt(mp->mnt_optnew, "nomtime", NULL,
0) == 0;
MNT_ILOCK(mp);
if ((mp->mnt_flag & MNT_UNION) == 0) {
mp->mnt_kern_flag |= MNTK_FPLOOKUP;
} else {
mp->mnt_kern_flag &= ~MNTK_FPLOOKUP;
}
MNT_IUNLOCK(mp);
return (0);
}
@ -462,7 +469,7 @@ tmpfs_mount(struct mount *mp)
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED |
MNTK_TEXT_REFS | MNTK_NOMSYNC;
if (!nonc)
if (!nonc && (mp->mnt_flag & MNT_UNION) == 0)
mp->mnt_kern_flag |= MNTK_FPLOOKUP;
MNT_IUNLOCK(mp);

View file

@ -159,6 +159,17 @@ struct namecache_ts {
* alignment for everyone. Note this is a nop for 64-bit platforms.
*/
#define CACHE_ZONE_ALIGNMENT UMA_ALIGNOF(time_t)
#define CACHE_PATH_CUTOFF 39
#define CACHE_ZONE_SMALL_SIZE (sizeof(struct namecache) + CACHE_PATH_CUTOFF + 1)
#define CACHE_ZONE_SMALL_TS_SIZE (sizeof(struct namecache_ts) + CACHE_PATH_CUTOFF + 1)
#define CACHE_ZONE_LARGE_SIZE (sizeof(struct namecache) + NAME_MAX + 1)
#define CACHE_ZONE_LARGE_TS_SIZE (sizeof(struct namecache_ts) + NAME_MAX + 1)
_Static_assert((CACHE_ZONE_SMALL_SIZE % (CACHE_ZONE_ALIGNMENT + 1)) == 0, "bad zone size");
_Static_assert((CACHE_ZONE_SMALL_TS_SIZE % (CACHE_ZONE_ALIGNMENT + 1)) == 0, "bad zone size");
_Static_assert((CACHE_ZONE_LARGE_SIZE % (CACHE_ZONE_ALIGNMENT + 1)) == 0, "bad zone size");
_Static_assert((CACHE_ZONE_LARGE_TS_SIZE % (CACHE_ZONE_ALIGNMENT + 1)) == 0, "bad zone size");
#define nc_vp n_un.nu_vp
#define nc_neg n_un.nu_neg
@ -339,8 +350,6 @@ static uma_zone_t __read_mostly cache_zone_small_ts;
static uma_zone_t __read_mostly cache_zone_large;
static uma_zone_t __read_mostly cache_zone_large_ts;
#define CACHE_PATH_CUTOFF 35
static struct namecache *
cache_alloc(int len, int ts)
{
@ -1934,7 +1943,8 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp,
}
len = ncp->nc_nlen = cnp->cn_namelen;
hash = cache_get_hash(cnp->cn_nameptr, len, dvp);
strlcpy(ncp->nc_name, cnp->cn_nameptr, len + 1);
memcpy(ncp->nc_name, cnp->cn_nameptr, len);
ncp->nc_name[len] = '\0';
cache_enter_lock(&cel, dvp, vp, hash);
/*
@ -2094,22 +2104,14 @@ nchinit(void *dummy __unused)
{
u_int i;
cache_zone_small = uma_zcreate("S VFS Cache",
sizeof(struct namecache) + CACHE_PATH_CUTOFF + 1,
NULL, NULL, NULL, NULL, CACHE_ZONE_ALIGNMENT,
UMA_ZONE_ZINIT);
cache_zone_small_ts = uma_zcreate("STS VFS Cache",
sizeof(struct namecache_ts) + CACHE_PATH_CUTOFF + 1,
NULL, NULL, NULL, NULL, CACHE_ZONE_ALIGNMENT,
UMA_ZONE_ZINIT);
cache_zone_large = uma_zcreate("L VFS Cache",
sizeof(struct namecache) + NAME_MAX + 1,
NULL, NULL, NULL, NULL, CACHE_ZONE_ALIGNMENT,
UMA_ZONE_ZINIT);
cache_zone_large_ts = uma_zcreate("LTS VFS Cache",
sizeof(struct namecache_ts) + NAME_MAX + 1,
NULL, NULL, NULL, NULL, CACHE_ZONE_ALIGNMENT,
UMA_ZONE_ZINIT);
cache_zone_small = uma_zcreate("S VFS Cache", CACHE_ZONE_SMALL_SIZE,
NULL, NULL, NULL, NULL, CACHE_ZONE_ALIGNMENT, UMA_ZONE_ZINIT);
cache_zone_small_ts = uma_zcreate("STS VFS Cache", CACHE_ZONE_SMALL_TS_SIZE,
NULL, NULL, NULL, NULL, CACHE_ZONE_ALIGNMENT, UMA_ZONE_ZINIT);
cache_zone_large = uma_zcreate("L VFS Cache", CACHE_ZONE_LARGE_SIZE,
NULL, NULL, NULL, NULL, CACHE_ZONE_ALIGNMENT, UMA_ZONE_ZINIT);
cache_zone_large_ts = uma_zcreate("LTS VFS Cache", CACHE_ZONE_LARGE_TS_SIZE,
NULL, NULL, NULL, NULL, CACHE_ZONE_ALIGNMENT, UMA_ZONE_ZINIT);
VFS_SMR_ZONE_SET(cache_zone_small);
VFS_SMR_ZONE_SET(cache_zone_small_ts);
@ -3143,8 +3145,8 @@ cache_fpl_handled_impl(struct cache_fpl *fpl, int error, int line)
#define cache_fpl_handled(x, e) cache_fpl_handled_impl((x), (e), __LINE__)
#define CACHE_FPL_SUPPORTED_CN_FLAGS \
(LOCKLEAF | LOCKPARENT | WANTPARENT | FOLLOW | LOCKSHARED | SAVENAME | \
ISOPEN | NOMACCHECK | AUDITVNODE1 | AUDITVNODE2)
(LOCKLEAF | LOCKPARENT | WANTPARENT | NOCACHE | FOLLOW | LOCKSHARED | SAVENAME | \
SAVESTART | WILLBEDIR | ISOPEN | NOMACCHECK | AUDITVNODE1 | AUDITVNODE2)
#define CACHE_FPL_INTERNAL_CN_FLAGS \
(ISDOTDOT | MAKEENTRY | ISLASTCN)
@ -3194,10 +3196,6 @@ cache_can_fplookup(struct cache_fpl *fpl)
cache_fpl_aborted(fpl);
return (false);
}
if (cnp->cn_nameiop != LOOKUP) {
cache_fpl_aborted(fpl);
return (false);
}
if (ndp->ni_dirfd != AT_FDCWD) {
cache_fpl_aborted(fpl);
return (false);
@ -3407,6 +3405,22 @@ cache_fplookup_final_child(struct cache_fpl *fpl, enum vgetstate tvs)
return (cache_fpl_handled(fpl, 0));
}
/*
* They want to possibly modify the state of the namecache.
*
* Don't try to match the API contract, just leave.
* TODO: this leaves scalability on the table
*/
static int
cache_fplookup_final_modifying(struct cache_fpl *fpl)
{
struct componentname *cnp;
cnp = fpl->cnp;
MPASS(cnp->cn_nameiop != LOOKUP);
return (cache_fpl_partial(fpl));
}
static int __noinline
cache_fplookup_final_withparent(struct cache_fpl *fpl)
{
@ -3489,6 +3503,10 @@ cache_fplookup_final(struct cache_fpl *fpl)
VNPASS(cache_fplookup_vnode_supported(dvp), dvp);
if (cnp->cn_nameiop != LOOKUP) {
return (cache_fplookup_final_modifying(fpl));
}
if ((cnp->cn_flags & (LOCKPARENT|WANTPARENT)) != 0)
return (cache_fplookup_final_withparent(fpl));
@ -3633,6 +3651,12 @@ cache_fplookup_next(struct cache_fpl *fpl)
tvp = atomic_load_ptr(&ncp->nc_vp);
nc_flag = atomic_load_char(&ncp->nc_flag);
if ((nc_flag & NCF_NEGATIVE) != 0) {
/*
* If they want to create an entry we need to replace this one.
*/
if (__predict_false(fpl->cnp->cn_nameiop != LOOKUP)) {
return (cache_fpl_partial(fpl));
}
negstate = NCP2NEGSTATE(ncp);
neg_hot = ((negstate->neg_flag & NEG_HOT) != 0);
if (__predict_false(!cache_ncp_canuse(ncp))) {
@ -3678,8 +3702,6 @@ cache_fplookup_mp_supported(struct mount *mp)
return (false);
if ((mp->mnt_kern_flag & MNTK_FPLOOKUP) == 0)
return (false);
if ((mp->mnt_flag & MNT_UNION) != 0)
return (false);
return (true);
}
@ -3789,8 +3811,6 @@ cache_fplookup_parse(struct cache_fpl *fpl)
struct nameidata *ndp;
struct componentname *cnp;
char *cp;
char *prev_ni_next; /* saved ndp->ni_next */
size_t prev_ni_pathlen; /* saved ndp->ni_pathlen */
ndp = fpl->ndp;
cnp = fpl->cnp;
@ -3810,11 +3830,9 @@ cache_fplookup_parse(struct cache_fpl *fpl)
cache_fpl_smr_exit(fpl);
return (cache_fpl_handled(fpl, ENAMETOOLONG));
}
prev_ni_pathlen = ndp->ni_pathlen;
ndp->ni_pathlen -= cnp->cn_namelen;
KASSERT(ndp->ni_pathlen <= PATH_MAX,
("%s: ni_pathlen underflow to %zd\n", __func__, ndp->ni_pathlen));
prev_ni_next = ndp->ni_next;
ndp->ni_next = cp;
/*
@ -3938,7 +3956,7 @@ cache_fplookup_impl(struct vnode *dvp, struct cache_fpl *fpl)
VNPASS(cache_fplookup_vnode_supported(fpl->dvp), fpl->dvp);
error = VOP_FPLOOKUP_VEXEC(fpl->dvp, cnp->cn_cred, cnp->cn_thread);
error = VOP_FPLOOKUP_VEXEC(fpl->dvp, cnp->cn_cred);
if (__predict_false(error != 0)) {
error = cache_fplookup_failed_vexec(fpl, error);
break;
@ -4108,6 +4126,9 @@ cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status,
fpl.cnp = &ndp->ni_cnd;
MPASS(curthread == fpl.cnp->cn_thread);
if ((fpl.cnp->cn_flags & SAVESTART) != 0)
MPASS(fpl.cnp->cn_nameiop != LOOKUP);
if (!cache_can_fplookup(&fpl)) {
SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status);
*status = fpl.status;

View file

@ -484,6 +484,9 @@ namei(struct nameidata *ndp)
("namei: nameiop contaminated with flags"));
KASSERT((cnp->cn_flags & OPMASK) == 0,
("namei: flags contaminated with nameiops"));
if (cnp->cn_flags & NOCACHE)
KASSERT(cnp->cn_nameiop != LOOKUP,
("%s: NOCACHE passed with LOOKUP", __func__));
MPASS(ndp->ni_startdir == NULL || ndp->ni_startdir->v_type == VDIR ||
ndp->ni_startdir->v_type == VBAD);

View file

@ -408,7 +408,7 @@ sysctl_try_reclaim_vnode(SYSCTL_HANDLER_ARGS)
buf[req->newlen] = '\0';
ndflags = LOCKLEAF | NOFOLLOW | AUDITVNODE1 | NOCACHE | SAVENAME;
ndflags = LOCKLEAF | NOFOLLOW | AUDITVNODE1 | SAVENAME;
NDINIT(&nd, LOOKUP, ndflags, UIO_SYSSPACE, buf, curthread);
if ((error = namei(&nd)) != 0)
goto out;

View file

@ -153,7 +153,6 @@ vop_close {
vop_fplookup_vexec {
IN struct vnode *vp;
IN struct ucred *cred;
IN struct thread *td;
};

View file

@ -998,6 +998,13 @@ in_ifdetach(struct ifnet *ifp)
in_pcbpurgeif0(&V_ulitecbinfo, ifp);
in_purgemaddrs(ifp);
IN_MULTI_UNLOCK();
/*
* Make sure all multicast deletions invoking if_ioctl() are
* completed before returning. Else we risk accessing a freed
* ifnet structure pointer.
*/
inm_release_wait(NULL);
}
/*

View file

@ -224,17 +224,37 @@ inm_is_ifp_detached(const struct in_multi *inm)
}
#endif
static struct task free_task;
/*
* Interface detach can happen in a taskqueue thread context, so we must use a
* dedicated thread to avoid deadlocks when draining inm_release tasks.
*/
TASKQUEUE_DEFINE_THREAD(inm_free);
static struct task inm_free_task;
static struct in_multi_head inm_free_list = SLIST_HEAD_INITIALIZER();
static void inm_release_task(void *arg __unused, int pending __unused);
static void
inm_init(void)
inm_init(void *arg __unused)
{
TASK_INIT(&free_task, 0, inm_release_task, NULL);
TASK_INIT(&inm_free_task, 0, inm_release_task, NULL);
}
SYSINIT(inm_init, SI_SUB_TASKQ, SI_ORDER_ANY, inm_init, NULL);
void
inm_release_wait(void *arg __unused)
{
/*
* Make sure all pending multicast addresses are freed before
* the VNET or network device is destroyed:
*/
taskqueue_drain(taskqueue_inm_free, &inm_free_task);
}
#ifdef VIMAGE
/* XXX-BZ FIXME, see D24914. */
VNET_SYSUNINIT(inm_release_wait, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, inm_release_wait, NULL);
#endif
void
inm_release_list_deferred(struct in_multi_head *inmh)
{
@ -244,7 +264,7 @@ inm_release_list_deferred(struct in_multi_head *inmh)
mtx_lock(&in_multi_free_mtx);
SLIST_CONCAT(&inm_free_list, inmh, in_multi, inm_nrele);
mtx_unlock(&in_multi_free_mtx);
taskqueue_enqueue(taskqueue_thread, &free_task);
taskqueue_enqueue(taskqueue_inm_free, &inm_free_task);
}
void

View file

@ -450,6 +450,7 @@ void inm_print(const struct in_multi *);
int inm_record_source(struct in_multi *inm, const in_addr_t);
void inm_release_deferred(struct in_multi *);
void inm_release_list_deferred(struct in_multi_head *);
void inm_release_wait(void *);
struct in_multi *
in_addmulti(struct in_addr *, struct ifnet *);
int in_joingroup(struct ifnet *, const struct in_addr *,

View file

@ -510,6 +510,9 @@ syncache_timer(void *xsch)
sch->sch_nextc = sc->sc_rxttime;
continue;
}
if (sc->sc_rxmits > V_tcp_ecn_maxretries) {
sc->sc_flags &= ~SCF_ECN;
}
if (sc->sc_rxmits > V_tcp_syncache.rexmt_limit) {
if ((s = tcp_log_addrs(&sc->sc_inc, NULL, NULL, NULL))) {
log(LOG_DEBUG, "%s; %s: Retransmits exhausted, "
@ -1505,6 +1508,13 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
sc->sc_tsreflect = to->to_tsval;
else
sc->sc_flags &= ~SCF_TIMESTAMP;
/*
* Disable ECN if needed.
*/
if ((sc->sc_flags & SCF_ECN) &&
((th->th_flags & (TH_ECE|TH_CWR)) != (TH_ECE|TH_CWR))) {
sc->sc_flags &= ~SCF_ECN;
}
#ifdef MAC
/*
* Since we have already unconditionally allocated label

View file

@ -871,7 +871,7 @@ in6_purgemaddrs(struct ifnet *ifp)
* completed before returning. Else we risk accessing a freed
* ifnet structure pointer.
*/
in6m_release_wait();
in6m_release_wait(NULL);
}
void

View file

@ -521,7 +521,7 @@ static struct in6_multi_head in6m_free_list = SLIST_HEAD_INITIALIZER();
static void in6m_release_task(void *arg __unused, int pending __unused);
static void
in6m_init(void)
in6m_init(void *arg __unused)
{
TASK_INIT(&in6m_free_task, 0, in6m_release_task, NULL);
}
@ -539,10 +539,19 @@ in6m_release_list_deferred(struct in6_multi_head *inmh)
}
void
in6m_release_wait(void)
in6m_release_wait(void *arg __unused)
{
/*
* Make sure all pending multicast addresses are freed before
* the VNET or network device is destroyed:
*/
taskqueue_drain_all(taskqueue_in6m_free);
}
#ifdef VIMAGE
/* XXX-BZ FIXME, see D24914. */
VNET_SYSUNINIT(in6m_release_wait, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, in6m_release_wait, NULL);
#endif
void
in6m_disconnect_locked(struct in6_multi_head *inmh, struct in6_multi *inm)

View file

@ -870,7 +870,7 @@ void in6m_commit(struct in6_multi *);
void in6m_print(const struct in6_multi *);
int in6m_record_source(struct in6_multi *, const struct in6_addr *);
void in6m_release_list_deferred(struct in6_multi_head *);
void in6m_release_wait(void);
void in6m_release_wait(void *);
void ip6_freemoptions(struct ip6_moptions *);
int ip6_getmoptions(struct inpcb *, struct sockopt *);
int ip6_setmoptions(struct inpcb *, struct sockopt *);

View file

@ -159,7 +159,6 @@ int cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status,
#define ISWHITEOUT 0x00020000 /* found whiteout */
#define DOWHITEOUT 0x00040000 /* do whiteouts */
#define WILLBEDIR 0x00080000 /* new files will be dirs; allow trailing / */
#define ISUNICODE 0x00100000 /* current component name is unicode*/
#define ISOPEN 0x00200000 /* caller is opening; return a real vnode. */
#define NOCROSSMOUNT 0x00400000 /* do not cross mount points */
#define NOMACCHECK 0x00800000 /* do not perform MAC checks */

View file

@ -805,7 +805,7 @@ ffs_mount(struct mount *mp)
*/
if ((mp->mnt_kern_flag & MNTK_FPLOOKUP) != 0)
panic("MNTK_FPLOOKUP set on mount %p when it should not be", mp);
if ((mp->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0)
if ((mp->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS | MNT_UNION)) == 0)
mp->mnt_kern_flag |= MNTK_FPLOOKUP;
MNT_IUNLOCK(mp);

652
tools/lua/template.lua Normal file
View file

@ -0,0 +1,652 @@
-- From lua-resty-template (modified to remove external dependencies)
--[[
Copyright (c) 2014 - 2020 Aapo Talvensaari
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* 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.
* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
]]--
-- $FreeBSD$
local setmetatable = setmetatable
local loadstring = loadstring
local tostring = tostring
local setfenv = setfenv
local require = require
local concat = table.concat
local assert = assert
local write = io.write
local pcall = pcall
local phase
local open = io.open
local load = load
local type = type
local dump = string.dump
local find = string.find
local gsub = string.gsub
local byte = string.byte
local null
local sub = string.sub
local var
local _VERSION = _VERSION
local _ENV = _ENV -- luacheck: globals _ENV
local _G = _G
local HTML_ENTITIES = {
["&"] = "&amp;",
["<"] = "&lt;",
[">"] = "&gt;",
['"'] = "&quot;",
["'"] = "&#39;",
["/"] = "&#47;"
}
local CODE_ENTITIES = {
["{"] = "&#123;",
["}"] = "&#125;",
["&"] = "&amp;",
["<"] = "&lt;",
[">"] = "&gt;",
['"'] = "&quot;",
["'"] = "&#39;",
["/"] = "&#47;"
}
local VAR_PHASES
local ESC = byte("\27")
local NUL = byte("\0")
local HT = byte("\t")
local VT = byte("\v")
local LF = byte("\n")
local SOL = byte("/")
local BSOL = byte("\\")
local SP = byte(" ")
local AST = byte("*")
local NUM = byte("#")
local LPAR = byte("(")
local LSQB = byte("[")
local LCUB = byte("{")
local MINUS = byte("-")
local PERCNT = byte("%")
local EMPTY = ""
local VIEW_ENV
if _VERSION == "Lua 5.1" then
VIEW_ENV = { __index = function(t, k)
return t.context[k] or t.template[k] or _G[k]
end }
else
VIEW_ENV = { __index = function(t, k)
return t.context[k] or t.template[k] or _ENV[k]
end }
end
local newtab
do
local ok
ok, newtab = pcall(require, "table.new")
if not ok then newtab = function() return {} end end
end
local function enabled(val)
if val == nil then return true end
return val == true or (val == "1" or val == "true" or val == "on")
end
local function trim(s)
return gsub(gsub(s, "^%s+", EMPTY), "%s+$", EMPTY)
end
local function rpos(view, s)
while s > 0 do
local c = byte(view, s, s)
if c == SP or c == HT or c == VT or c == NUL then
s = s - 1
else
break
end
end
return s
end
local function escaped(view, s)
if s > 1 and byte(view, s - 1, s - 1) == BSOL then
if s > 2 and byte(view, s - 2, s - 2) == BSOL then
return false, 1
else
return true, 1
end
end
return false, 0
end
local function read_file(path)
local file, err = open(path, "rb")
if not file then return nil, err end
local content
content, err = file:read "*a"
file:close()
return content, err
end
local function load_view(template)
return function(view, plain)
if plain == true then return view end
local path, root = view, template.root
if root and root ~= EMPTY then
if byte(root, -1) == SOL then root = sub(root, 1, -2) end
if byte(view, 1) == SOL then path = sub(view, 2) end
path = root .. "/" .. path
end
return plain == false and assert(read_file(path)) or read_file(path) or view
end
end
local function load_file(func)
return function(view) return func(view, false) end
end
local function load_string(func)
return function(view) return func(view, true) end
end
local function loader(template)
return function(view)
return assert(load(view, nil, nil, setmetatable({ template = template }, VIEW_ENV)))
end
end
local function visit(visitors, content, tag, name)
if not visitors then
return content
end
for i = 1, visitors.n do
content = visitors[i](content, tag, name)
end
return content
end
local function new(template, safe)
template = template or newtab(0, 26)
template._VERSION = "2.0"
template.cache = {}
template.load = load_view(template)
template.load_file = load_file(template.load)
template.load_string = load_string(template.load)
template.print = write
local load_chunk = loader(template)
local caching
if VAR_PHASES and VAR_PHASES[phase()] then
caching = enabled(var.template_cache)
else
caching = true
end
local visitors
function template.visit(func)
if not visitors then
visitors = { func, n = 1 }
return
end
visitors.n = visitors.n + 1
visitors[visitors.n] = func
end
function template.caching(enable)
if enable ~= nil then caching = enable == true end
return caching
end
function template.output(s)
if s == nil or s == null then return EMPTY end
if type(s) == "function" then return template.output(s()) end
return tostring(s)
end
function template.escape(s, c)
if type(s) == "string" then
if c then return gsub(s, "[}{\">/<'&]", CODE_ENTITIES) end
return gsub(s, "[\">/<'&]", HTML_ENTITIES)
end
return template.output(s)
end
function template.new(view, layout)
local vt = type(view)
if vt == "boolean" then return new(nil, view) end
if vt == "table" then return new(view, safe) end
if vt == "nil" then return new(nil, safe) end
local render
local process
if layout then
if type(layout) == "table" then
render = function(self, context)
context = context or self
context.blocks = context.blocks or {}
context.view = template.process(view, context)
layout.blocks = context.blocks or {}
layout.view = context.view or EMPTY
layout:render()
end
process = function(self, context)
context = context or self
context.blocks = context.blocks or {}
context.view = template.process(view, context)
layout.blocks = context.blocks or {}
layout.view = context.view
return tostring(layout)
end
else
render = function(self, context)
context = context or self
context.blocks = context.blocks or {}
context.view = template.process(view, context)
template.render(layout, context)
end
process = function(self, context)
context = context or self
context.blocks = context.blocks or {}
context.view = template.process(view, context)
return template.process(layout, context)
end
end
else
render = function(self, context)
return template.render(view, context or self)
end
process = function(self, context)
return template.process(view, context or self)
end
end
if safe then
return setmetatable({
render = function(...)
local ok, err = pcall(render, ...)
if not ok then
return nil, err
end
end,
process = function(...)
local ok, output = pcall(process, ...)
if not ok then
return nil, output
end
return output
end,
}, {
__tostring = function(...)
local ok, output = pcall(process, ...)
if not ok then
return ""
end
return output
end })
end
return setmetatable({
render = render,
process = process
}, {
__tostring = process
})
end
function template.precompile(view, path, strip, plain)
local chunk = dump(template.compile(view, nil, plain), strip ~= false)
if path then
local file = open(path, "wb")
file:write(chunk)
file:close()
end
return chunk
end
function template.precompile_string(view, path, strip)
return template.precompile(view, path, strip, true)
end
function template.precompile_file(view, path, strip)
return template.precompile(view, path, strip, false)
end
function template.compile(view, cache_key, plain)
assert(view, "view was not provided for template.compile(view, cache_key, plain)")
if cache_key == "no-cache" then
return load_chunk(template.parse(view, plain)), false
end
cache_key = cache_key or view
local cache = template.cache
if cache[cache_key] then return cache[cache_key], true end
local func = load_chunk(template.parse(view, plain))
if caching then cache[cache_key] = func end
return func, false
end
function template.compile_file(view, cache_key)
return template.compile(view, cache_key, false)
end
function template.compile_string(view, cache_key)
return template.compile(view, cache_key, true)
end
function template.parse(view, plain)
assert(view, "view was not provided for template.parse(view, plain)")
if plain ~= true then
view = template.load(view, plain)
if byte(view, 1, 1) == ESC then return view end
end
local j = 2
local c = {[[
context=... or {}
local ___,blocks,layout={},blocks or {}
local function include(v, c) return template.process(v, c or context) end
local function echo(...) for i=1,select("#", ...) do ___[#___+1] = tostring(select(i, ...)) end end
]] }
local i, s = 1, find(view, "{", 1, true)
while s do
local t, p = byte(view, s + 1, s + 1), s + 2
if t == LCUB then
local e = find(view, "}}", p, true)
if e then
local z, w = escaped(view, s)
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
c[j+2] = "]=]\n"
j=j+3
end
if z then
i = s
else
c[j] = "___[#___+1]=template.escape("
c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "{")
c[j+2] = ")\n"
j=j+3
s, i = e + 1, e + 2
end
end
elseif t == AST then
local e = find(view, "*}", p, true)
if e then
local z, w = escaped(view, s)
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
c[j+2] = "]=]\n"
j=j+3
end
if z then
i = s
else
c[j] = "___[#___+1]=template.output("
c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "*")
c[j+2] = ")\n"
j=j+3
s, i = e + 1, e + 2
end
end
elseif t == PERCNT then
local e = find(view, "%}", p, true)
if e then
local z, w = escaped(view, s)
if z then
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
c[j+2] = "]=]\n"
j=j+3
end
i = s
else
local n = e + 2
if byte(view, n, n) == LF then
n = n + 1
end
local r = rpos(view, s - 1)
if i <= r then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, sub(view, i, r))
c[j+2] = "]=]\n"
j=j+3
end
c[j] = visit(visitors, trim(sub(view, p, e - 1)), "%")
c[j+1] = "\n"
j=j+2
s, i = n - 1, n
end
end
elseif t == LPAR then
local e = find(view, ")}", p, true)
if e then
local z, w = escaped(view, s)
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
c[j+2] = "]=]\n"
j=j+3
end
if z then
i = s
else
local f = visit(visitors, sub(view, p, e - 1), "(")
local x = find(f, ",", 2, true)
if x then
c[j] = "___[#___+1]=include([=["
c[j+1] = trim(sub(f, 1, x - 1))
c[j+2] = "]=],"
c[j+3] = trim(sub(f, x + 1))
c[j+4] = ")\n"
j=j+5
else
c[j] = "___[#___+1]=include([=["
c[j+1] = trim(f)
c[j+2] = "]=])\n"
j=j+3
end
s, i = e + 1, e + 2
end
end
elseif t == LSQB then
local e = find(view, "]}", p, true)
if e then
local z, w = escaped(view, s)
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
c[j+2] = "]=]\n"
j=j+3
end
if z then
i = s
else
c[j] = "___[#___+1]=include("
c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "[")
c[j+2] = ")\n"
j=j+3
s, i = e + 1, e + 2
end
end
elseif t == MINUS then
local e = find(view, "-}", p, true)
if e then
local x, y = find(view, sub(view, s, e + 1), e + 2, true)
if x then
local z, w = escaped(view, s)
if z then
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
c[j+2] = "]=]\n"
j=j+3
end
i = s
else
y = y + 1
x = x - 1
if byte(view, y, y) == LF then
y = y + 1
end
local b = trim(sub(view, p, e - 1))
if b == "verbatim" or b == "raw" then
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
c[j+2] = "]=]\n"
j=j+3
end
c[j] = "___[#___+1]=[=["
c[j+1] = visit(visitors, sub(view, e + 2, x))
c[j+2] = "]=]\n"
j=j+3
else
if byte(view, x, x) == LF then
x = x - 1
end
local r = rpos(view, s - 1)
if i <= r then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, sub(view, i, r))
c[j+2] = "]=]\n"
j=j+3
end
c[j] = 'blocks["'
c[j+1] = b
c[j+2] = '"]=include[=['
c[j+3] = visit(visitors, sub(view, e + 2, x), "-", b)
c[j+4] = "]=]\n"
j=j+5
end
s, i = y - 1, y
end
end
end
elseif t == NUM then
local e = find(view, "#}", p, true)
if e then
local z, w = escaped(view, s)
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
c[j+2] = "]=]\n"
j=j+3
end
if z then
i = s
else
e = e + 2
if byte(view, e, e) == LF then
e = e + 1
end
s, i = e - 1, e
end
end
end
s = find(view, "{", s + 1, true)
end
s = sub(view, i)
if s and s ~= EMPTY then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = visit(visitors, s)
c[j+2] = "]=]\n"
j=j+3
end
c[j] = "return layout and include(layout,setmetatable({view=table.concat(___),blocks=blocks},{__index=context})) or table.concat(___)" -- luacheck: ignore
return concat(c)
end
function template.parse_file(view)
return template.parse(view, false)
end
function template.parse_string(view)
return template.parse(view, true)
end
function template.process(view, context, cache_key, plain)
assert(view, "view was not provided for template.process(view, context, cache_key, plain)")
return template.compile(view, cache_key, plain)(context)
end
function template.process_file(view, context, cache_key)
assert(view, "view was not provided for template.process_file(view, context, cache_key)")
return template.compile(view, cache_key, false)(context)
end
function template.process_string(view, context, cache_key)
assert(view, "view was not provided for template.process_string(view, context, cache_key)")
return template.compile(view, cache_key, true)(context)
end
function template.render(view, context, cache_key, plain)
assert(view, "view was not provided for template.render(view, context, cache_key, plain)")
template.print(template.process(view, context, cache_key, plain))
end
function template.render_file(view, context, cache_key)
assert(view, "view was not provided for template.render_file(view, context, cache_key)")
template.render(view, context, cache_key, false)
end
function template.render_string(view, context, cache_key)
assert(view, "view was not provided for template.render_string(view, context, cache_key)")
template.render(view, context, cache_key, true)
end
if safe then
return setmetatable({}, {
__index = function(_, k)
if type(template[k]) == "function" then
return function(...)
local ok, a, b = pcall(template[k], ...)
if not ok then
return nil, a
end
return a, b
end
end
return template[k]
end,
__new_index = function(_, k, v)
template[k] = v
end,
})
end
return template
end
return new()

View file

@ -408,7 +408,6 @@
08/06 Caricom in Barbados
08/06 Cy Young pitches first game, 1890
08/07 Jack the Ripper makes his first kill, 1888
08/08 Atomic bomb dropped on Nagasaki, 1945
08/08 Montenegro declares war on Germany, 1914
08/08 Richard Nixon resigns the US presidency, 1974
08/08 The Great Train Robbery -- $7,368,000, 1963

View file

@ -104,7 +104,7 @@ LANG=de_DE.ISO8859-1
10/01 Verkündigung der Urteile im Nürnberger Hauptkriegsverbrecherprozeß, 1946
02/25 Auflösung der Landes Preußen durch den Kontrollrat, 1947
08/06 Erster Atombombenabwurf auf Hiroshima, 1945
08/08 Atombombenabwurf auf Nagasaki, 1945
08/09 Atombombenabwurf auf Nagasaki, 1945
04/19 Aufstand im Warschauer Ghetto, 1943
12/07 Japan bombardiert Pearl Harbor, 1941

View file

@ -28,7 +28,7 @@
.\" @(#)uname.1 8.3 (Berkeley) 4/8/94
.\" $FreeBSD$
.\"
.Dd June 27, 2019
.Dd August 10, 2020
.Dt UNAME 1
.Os
.Sh NAME
@ -107,6 +107,9 @@ and
flags are intended to be used for fine grain differentiation of incremental
.Fx
development and user visible changes.
Note that when both of these two options are specified, regardless of their
order, the kernel version would be printed first, followed by the user
environment version.
.Sh ENVIRONMENT
An environment variable composed of the string
.Ev UNAME_