Page MenuHomeFreeBSD

D25447.id85187.diff
No OneTemporary

D25447.id85187.diff

diff --git a/Makefile.inc1 b/Makefile.inc1
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -2898,8 +2898,10 @@
lib/libelf lib/libexpat \
lib/libfigpar \
${_lib_libgssapi} \
+ lib/libifconfig \
lib/libjail \
lib/libkiconv lib/libkvm lib/liblzma lib/libmd lib/libnv \
+ lib/libsysdecode \
lib/libzstd \
${_lib_casper} \
lib/ncurses/ncurses \
@@ -2936,6 +2938,7 @@
lib/libgeom__L: lib/libexpat__L lib/libsbuf__L
lib/libkvm__L: lib/libelf__L
+lib/libifconfig__L: lib/msun__L
.if ${MK_RADIUS_SUPPORT} != "no"
_lib_libradius= lib/libradius
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -3067,11 +3067,6 @@
OLD_DIRS+=usr/lib/clang/7.0.1
# 20190227: rename seq.h to seqc.h
OLD_FILES+=usr/include/sys/seq.h
-# 20190222: libifconfig made INTERNALLIB
-OLD_FILES+=usr/lib/libprivateifconfig.a
-OLD_FILES+=usr/lib/libprivateifconfig_p.a
-OLD_FILES+=usr/lib32/libprivateifconfig.a
-OLD_FILES+=usr/lib32/libprivateifconfig_p.a
# 20190131: pfil(9) changed
OLD_FILES+=usr/share/man/man9/pfil_hook_get.9.gz
OLD_FILES+=usr/share/man/man9/pfil_rlock.9.gz
diff --git a/lib/Makefile b/lib/Makefile
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -145,7 +145,7 @@
.if !defined(COMPAT_32BIT)
SUBDIR+= flua
-SUBDIR_DEPEND_flua= libjail
+SUBDIR_DEPEND_flua= libifconfig libjail libsysdecode
.endif
# NB: keep these sorted by MK_* knobs
diff --git a/lib/flua/Makefile b/lib/flua/Makefile
--- a/lib/flua/Makefile
+++ b/lib/flua/Makefile
@@ -1,5 +1,5 @@
# $FreeBSD$
-SUBDIR= libjail
+SUBDIR= libifconfig libjail
.include <bsd.subdir.mk>
diff --git a/lib/flua/libifconfig/Makefile b/lib/flua/libifconfig/Makefile
new file mode 100644
--- /dev/null
+++ b/lib/flua/libifconfig/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+SHLIB_NAME= ifconfig.so
+SHLIBDIR= ${LIBDIR}/flua
+
+SRCS+= lua_ifconfig.c
+
+CFLAGS+= \
+ -I${SRCTOP}/contrib/lua/src \
+ -I${SRCTOP}/lib/liblua \
+ -I${SRCTOP}/lib/libifconfig \
+ -I${LIBIFCONFIGDIR} \
+
+LIBADD+= ifconfig sysdecode
+
+MAN= ifconfig.3lua
+
+.include <bsd.lib.mk>
diff --git a/lib/flua/libifconfig/ifconfig.3lua b/lib/flua/libifconfig/ifconfig.3lua
new file mode 100644
--- /dev/null
+++ b/lib/flua/libifconfig/ifconfig.3lua
@@ -0,0 +1,793 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+.\"
+.\" 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$
+.\"
+.Dd October 11, 2020
+.Dt IFCONFIG 3lua
+.Os
+.Sh NAME
+.Nm open ,
+.Nm close ,
+.Nm error ,
+.Nm foreach_iface ,
+.Nm foreach_ifaddr ,
+.Nm get_description ,
+.Nm set_description ,
+.Nm unset_description ,
+.Nm set_name ,
+.Nm get_orig_name ,
+.Nm get_fib ,
+.Nm set_mtu ,
+.Nm get_mtu ,
+.Nm get_nd6 ,
+.Nm set_metric ,
+.Nm get_metric ,
+.Nm set_capabilities ,
+.Nm get_capabilities ,
+.Nm get_groups ,
+.Nm get_status ,
+.Nm get_media ,
+.Nm get_carp ,
+.Nm addr_info ,
+.Nm get_bridge_status ,
+.Nm get_lagg_status ,
+.Nm get_laggport_laggdev ,
+.Nm destroy ,
+.Nm create ,
+.Nm create_vlan ,
+.Nm set_vlantag ,
+.Nm list_cloners ,
+.Nm get_sfp_info ,
+.Nm get_sfp_vendor_info ,
+.Nm get_sfp_status ,
+.Nm get_sfp_dump
+.Nd Lua binding to
+.Xr ifconfig 3
+.Sh SYNOPSIS
+.Bd -literal
+local ifconfig = require('ifconfig')
+.Ed
+.Pp
+.Bl -tag -width XXXX -compact
+.It Dv ifcfg = ifconfig.open()
+.It Dv ifcfg:close()
+.It Dv errtype, errno, ioctlname = ifcfg:error()
+.It Dv udata = ifcfg:foreach_iface(cb, udata )
+.It Dv udata = ifcfg:foreach_ifaddr(iface, cb, udata )
+.It Dv desc = ifcfg:get_description(name)
+.It Dv res = ifcfg:set_description(name, desc )
+.It Dv res = ifcfg:unset_description(name)
+.It Dv res = ifcfg:set_name(name, newname )
+.It Dv name = ifcfg:get_orig_name(name)
+.It Dv fib = ifcfg:get_fib(name)
+.It Dv res = ifcfg:set_mtu(name, mtu )
+.It Dv mtu = ifcfg:get_mtu(name)
+.It Dv nd6 = ifcfg:get_nd6(name)
+.It Dv res = ifcfg:set_metric(name, metric )
+.It Dv metric = ifcfg:get_metric(name)
+.It Dv res = ifcfg:set_capabilities(name, caps )
+.It Dv caps = ifcfg:get_capabilities(name)
+.It Dv groups = ifcfg:get_groups(name)
+.It Dv status = ifcfg:get_status(name)
+.It Dv media = ifcfg:get_media(name)
+.It Dv carp = ifcfg:get_carp(name)
+.It Dv ai = ifcfg:addr_info(addr)
+.It Dv status = ifcfg:get_bridge_status(name)
+.It Dv status = ifcfg:get_lagg_status(name)
+.It Dv lagg = ifcfg:get_laggport_laggdev(name)
+.It Dv res = ifcfg:destroy(name)
+.It Dv name = ifcfg:create(name)
+.It Dv name = ifcfg:create_vlan(name, vlandev, vlantag )
+.It Dv res = ifcfg:set_vlantag(name, vlandev, vlantag )
+.It Dv cloners = ifcfg:list_cloners()
+.It Dv info = ifcfg:get_sfp_info(name)
+.It Dv vendor_info = ifcfg:get_sfp_vendor_info(name)
+.It Dv status = ifcfg:get_sfp_status(name)
+.It Dv dump = ifcfg:get_sfp_dump(name)
+.It Vt struct ifaddrs *
+.El
+.Sh DESCRIPTION
+The
+.Nm ifconfig
+module is a binding to the
+.Xr ifconfig 3
+library.
+It provides a high-level interface for many socket ioctls that query and
+control network interface configuration and status information.
+.Bl -tag -width XXXX
+.It Dv ifcfg = ifconfig.open()
+Open a libifconfig handle.
+The handle is a userdata object used to perform the various socket operations
+underlying most libifconfig functionality.
+An open handle will be closed when garbage collected, or it can be explicitly
+closed with
+.Fn close .
+.It Dv ifcfg:close()
+Explicitly close a handle opened by
+.Fn open .
+.It Dv errtype, errno, ioctlname = ifcfg:error()
+Get information about the last error.
+If the last operation was succcessful,
+.Dv nil
+is returned.
+Otherwise, returns the error type, errno, and if applicable the name of the
+ioctl that failed.
+The error type is one of "OTHER", "IOCTL", or "SOCKET".
+.It Dv udata = ifcfg:foreach_iface(cb, udata )
+Iterate over interfaces.
+This is a higher-order fold operation, where
+.Fa cb
+is a callback function of the form
+.Dl (handle, iface, udata) -> udata
+which is called for each interface in succession.
+.Pp
+The
+.Fa handle
+passed to the callback is the handle that was used to invoke
+.Fn foreach_iface .
+.Pp
+The
+.Fa iface
+passed to the callback is a
+.Vt struct ifaddrs *
+userdata object that is only valid until the callback function returns.
+It must not be retained outside the scope of the callback.
+.Pp
+The
+.Fa udata
+parameter is an accumulator.
+The initial value passed to
+.Fn foreach_iface
+is forwarded to the callback function on the first iteration.
+The return value of the callback function is passed to the callback as
+.Fa udata
+on the next iteration.
+The value returned from the callback function on the final iteration is
+returned from
+.Fn foreach_iface
+on success.
+.Pp
+An error may be raised if iteration fails due to an internal error.
+.It Dv udata = ifcfg:foreach_ifaddr(iface, cb, udata )
+Iterate over interface addresses.
+This is a higher-order fold operation, where
+.Fa cb
+is a callback function of the form
+.Dl (handle, ifaddr, udata) -> udata
+which is called for each interface address in succession.
+.Pp
+The interface
+.Fa iface
+is the
+.Vt struct ifaddrs *
+userdata object passed to the callback function for
+.Fn foreach_iface .
+.Pp
+The
+.Fa handle
+passed to the callback is the handle that was used to invoke
+.Fn foreach_ifaddr .
+.Pp
+The
+.Fa udata
+parameter is an accumulator.
+The initial value passed to
+.Fn foreach_ifaddr
+is forwarded to the callback function on the first iteration.
+The return value of the callback function is passed to the callback as
+.Fa udata
+on the next iteration.
+The value returned from the callback function on the final iteration is
+returned from
+.Fn foreach_ifaddr .
+.It Dv desc = ifcfg:get_description(name)
+Given the
+.Fa name
+of an interface, returns the description string if set, otherwise
+.Dv nil .
+.It Dv res = ifcfg:set_description(name, desc )
+Given the
+.Fa name
+of an interface, sets the description string to
+.Fa desc .
+.It Dv res = ifcfg:unset_description(name)
+Given the
+.Fa name
+of an interface, unsets the description string if set.
+.It Dv res = ifcfg:set_name(name, newname )
+Given the
+.Fa name
+of an interface, changes the interface name to
+.Fa newname .
+.It Dv name = ifcfg:get_orig_name(name)
+Given the
+.Fa name
+of an interface, returns the original name string of the interface.
+.It Dv fib = ifcfg:get_fib(name)
+Given the
+.Fa name
+of an interface, returns the interface FIB number.
+.It Dv res = ifcfg:set_mtu(name, mtu )
+Given the
+.Fa name
+of an interface, sets the interface MTU to
+.Fa mtu .
+.It Dv mtu = ifcfg:get_mtu(name)
+Given the
+.Fa name
+of an interface, returns the interface MTU.
+.It Dv nd6 = ifcfg:get_nd6(name)
+Given the
+.Fa name
+of an interface, returns a list of the enabled ICMPv6 Neighbor Discovery
+Protocol options.
+.It Dv res = ifcfg:set_metric(name, metric )
+Given the
+.Fa name
+of an interface, sets the interface metric to
+.Fa metric .
+.It Dv metric = ifcfg:get_metric(name)
+Given the
+.Fa name
+of an interface, returns the interface metric.
+.It Dv res = ifcfg:set_capabilities(name, caps )
+Given the
+.Fa name
+of an interface, enables the list of capabilities given as strings in the list
+.Fa caps
+and disables the capabilities not in the list, returning true if successful or
+false if an error occurs.
+.It Dv caps = ifcfg:get_capabilities(name)
+Given the
+.Fa name
+of an interface, returns a table of the form
+.Bd -literal -compact
+{
+ enabled = { "", ... },
+ supported = { "", ... }
+}
+.Ed
+where
+.Nm enabled
+and
+.Nm supported
+are the lists of enabled and supported capabilities with each capability
+represented by a string.
+.It Dv groups = ifcfg:get_groups(name)
+Given the
+.Fa name
+of an interface, returns a list of the names of the groups containing the
+interface.
+.It Dv status = ifcfg:get_status(name)
+Given the
+.Fa name
+of an interface, returns the interface status as a string.
+.It Dv media = ifcfg:get_media(name)
+Given the
+.Fa name
+of an interface, returns a table of the form
+.Bd -literal -compact
+{
+ current = {},
+ active = {},
+ supported = { {}, ... },
+ status = "",
+ [ down_reason = ""|# ]
+}
+.Ed
+where
+.Nm current
+and
+.Nm active
+are tables of the form
+.Bd -literal -compact
+{
+ [ type = "",]
+ [ subtype = "",]
+ [ mode = "",]
+ options = { "", ... }
+}
+.Ed
+and
+.Nm supported
+is a list of the same form of tables.
+.It Dv carp = ifcfg:get_carp(name)
+Given the
+.Fa name
+of an interface, returns a list of tables of the form
+.Bd -literal -compact
+{
+ state = "",
+ vhid = #,
+ advbase = #,
+ advskew = #
+}
+.Ed
+describing the interface
+.Xr carp 4
+VHIDs.
+.It Dv ai = ifcfg:addr_info(addr)
+Given a
+.Vt struct ifaddrs *
+userdata object as
+.Fa addr ,
+returns a table describing the address.
+The format of the table depends on the type of address.
+.Bl -inset
+.It Nm AF_INET
+addresses are described by a table of the form
+.Bd -literal -compact
+{
+ inet = "",
+ netmask = "",
+ [ destination = "",]
+ [ broadcast = "",]
+ [ vhid = # ]
+}
+.Ed
+.It Nm AF_INET6
+addresses are described by a table of the form
+.Bd -literal -compact
+{
+ inet6 = "",
+ prefixlen = #,
+ flags = { "", ... },
+ [ destination = "",]
+ [ scopeid = #,]
+ [ preferred_lifetime = #, valid_lifetime = #,]
+ [ vhid = # ]
+}
+.Ed
+.It Nm AF_LINK
+addresses are described by a table of the form
+.Bd -literal -compact
+{
+ ether = ""
+}
+.Ed
+for link types
+.Nm IFT_ETHER ,
+.Nm IFT_L2VLAN ,
+and
+.Nm IFT_BRIDGE
+or
+.Bd -literal -compact
+{
+ lladdr = ""
+}
+.Ed
+for other link types.
+.It Nm AF_LOCAL
+addresses are described by a table of the form
+.Bd -literal -compact
+{
+ path = ""
+}
+.Ed
+.El
+.It Dv status = ifcfg:get_bridge_status(name)
+Given the
+.Fa name
+of a
+.Xr bridge 4
+interface, returns a table of the form
+.Bd -literal -compact
+{
+ address_cache_size = #,
+ address_cache_lifetime = #,
+ priority = #,
+ protocol = ""|#,
+ hello_time = #,
+ forward_delay = #,
+ hold_count = #,
+ max_age = #,
+ id = "",
+ root_id = "",
+ root_priority = #,
+ root_path_cost = #,
+ root_port = #,
+ members = { {}, ... }
+}
+.Ed
+where
+.Nm members
+is a list of tables of the form
+.Bd -literal -compact
+{
+ flags = { "", ... },
+ ifmaxaddr = #,
+ port = #,
+ priority = #,
+ [ protocol = ""|#, role = ""|#, state = ""|#]
+}
+.Ed
+.It Dv status = ifcfg:get_lagg_status(name)
+Given the
+.Fa name
+of a
+.Xr lagg 4
+interface, returns a table of the form
+.Bd -literal -compact
+{
+ options = {},
+ stats = {},
+ ports = {}
+}
+.Ed
+where
+.Nm options
+is a table of the form
+.Bd -literal -compact
+{
+ laggproto = "",
+ lagghash = { "", ... },
+ flags = { "", ... },
+ flowid_shift = #,
+ [ rr_limit = # ]
+}
+.Ed
+.Nm stats
+is a table of the form
+.Bd -literal -compact
+{
+ active = #,
+ flapping = #
+}
+.Ed
+and
+.Nm ports
+is a table where the keys are the names of the laggports and the values are
+tables of the form
+.Bd -literal -compact
+{
+ flags = { "", ... },
+ [ lacp_state = { "", ... } ]
+}
+.Ed
+.It Dv lagg = ifcfg:get_laggport_laggdev(name)
+Given the
+.Fa name
+of an interface, returns the parent lagg device name.
+error occurs.
+.It Dv res = ifcfg:destroy(name)
+Given the
+.Fa name
+of an interface, destroys the interface.
+.It Dv name = ifcfg:create(name)
+Given the
+.Fa name
+of in interface, creates the interface and returns the name of the created
+interface.
+.It Dv name = ifcfg:create_vlan(name, vlandev, vlantag )
+Creates a
+.Xr vlan 4 interface with the given
+.Fa name
+attached to
+.Fa vlandev
+and using the vlan number specified by
+.Fa vlantag ,
+returning the name of the create interface.
+occurs.
+.It Dv res = ifcfg:set_vlantag(name, vlandev, vlantag )
+Given the
+.Fa name
+of an existing
+.Xr vlan 4
+interface, sets the specified
+.Fa vlandev
+and
+.Fa vlantag .
+.It Dv cloners = ifcfg:list_cloners()
+Returns a list of the names of all the interface cloners available on the
+system.
+.It Dv info = ifcfg:get_sfp_info(name)
+Given the
+.Fa name
+of an interface, returns SFP module information as a table of the form
+.Bd -literal -compact
+{
+ [ sfp_id = {},]
+ [ sfp_conn = {},]
+ [ sfp_eth_10g = {},]
+ [ sfp_eth = {},]
+ [ sfp_fc_len = {},]
+ [ sfp_cab_tech = {},]
+ [ sfp_fc_media = {},]
+ [ sfp_eth_1040g = {},]
+ [ sfp_eth_ext = {},]
+ [ sfp_rev = {}]
+}
+.Ed
+where each field, if present, is a table of the form
+.Bd -literal -compact
+{
+ description = "",
+ string = "",
+ value = #
+}
+.Ed
+or
+.Dv nil
+if no SFP module is present.
+.It Dv vendor_info = ifcfg:get_sfp_vendor_info(name)
+Given the
+.Fa name
+of an interface, returns SFP module vendor information as a table of the form
+.Bd -literal -compact
+{
+ name = "",
+ part_number = "",
+ serial_number = "",
+ date = ""
+}
+.Ed
+or
+.Dv nil
+if no SFP module is present.
+.It Dv status = ifcfg:get_sfp_status(name)
+Given the
+.Fa name
+of an interface, returns SFP module status as a table of the form
+.Bd -literal -compact
+{
+ voltage = #,
+ channels = { {}, ... },
+ [ temperature = #,]
+ [ bitrate = #]
+}
+.Ed
+where
+.Nm channels
+is a list of tables of the form
+.Bd -literal -compact
+{
+ rx_power = {},
+ tx_bias = {}
+}
+.Ed
+.Nm rx_power
+is a table of the form
+.Bd -literal -compact
+{
+ value = #,
+ mW = #,
+ dBm = #
+}
+.Ed
+.Nm tx_bias
+is a table of the form
+.Bd -literal -compact
+{
+ raw = #,
+ mA = #
+}
+.Ed
+or
+.Dv nil
+if no SFP module is present.
+.It Dv dump = ifcfg:get_sfp_dump(name)
+Given the
+.Fa name
+of an interface, returns a userdata blob containing a dump of the SFP module's
+I2C memory or
+.Dv nil
+if no SFP module is present.
+The userdata blob coerces to a string formatted as a hex dump similar to
+.Xr ifconfig 8
+with
+.Fl vv .
+.It Vt struct ifaddrs *
+The
+.Vt struct ifaddrs *
+userdata type describes an interface and various address types associated with
+it.
+An object of this type provides two address-agnostic methods:
+.Bl -tag -width XXXX
+.It Dv name = ifaddr:name()
+Get the name of the interface to which this address is assigned.
+.It Dv flags = ifaddr:flags()
+Get the flags set on the interface to which this address is assigned.
+.El
+Address-specific information is obtained by passing a
+.Vt struct ifaddrs *
+userdata object to the
+.Fn addr_info
+function.
+.El
+.Sh RETURN VALUES
+The
+.Fn open
+function returns an open
+.Vt ifconfig_handle_t
+userdata object on success, or
+.Dv nil
+on error.
+.Pp
+The
+.Fn error
+function returns multiple values on success, or
+.Dv nil
+on error.
+The values returned are the error type, errno, and the ioctl name if the error
+type is "IOCTL".
+The
+.Fn foreach_iface
+and
+.Fn foreach_ifaddr
+functions return the value returned by the
+.Fa cb
+function on the final iteration, or the initial
+.Fa udata
+argument if
+.Fa cb
+was not invoked.
+.Pp
+The functions
+.Fn get_description ,
+.Fn get_orig_name ,
+.Fn get_status ,
+.Fn get_laggport_laggdev ,
+.Fn create ,
+and
+.Fn create_vlan
+return a string on success, or
+.Dv nil
+on error.
+The string returned by
+.Fn create
+and
+.Fn create_vlan
+is the name of the created interface.
+.Pp
+The functions
+.Fn get_fib ,
+.Fn get_mtu ,
+and
+.Fn get_metric
+return an integer on success, or
+.Dv nil
+on error.
+.Pp
+The functions
+.Fn get_nd6 ,
+.Fn get_groups ,
+and
+.Fn list_cloners
+return a list of strings on success, or
+.Dv nil
+on error.
+.Pp
+The functions
+.Fn get_capabilities ,
+.Fn get_media ,
+.Fn get_carp ,
+.Fn addr_info ,
+.Fn get_bridge_status ,
+.Fn get_lagg_status ,
+.Fn get_sfp_info ,
+.Fn get_sfp_vendor_info ,
+.Fn get_sfp_status ,
+and
+.Fn get_sfp_dump
+return a table described for each function in the
+.Sx DESCRIPTION
+section, or
+.Dv nil
+on error.
+.Pp
+The functions
+.Fn set_description ,
+.Fn unset_description ,
+.Fn set_name ,
+.Fn set_mtu ,
+.Fn set_metric ,
+.Fn set_capabilities ,
+.Fn set_vlantag ,
+and
+.Fn destroy
+return
+.Dv true
+on success, or
+.Dv false
+on error.
+.Pp
+The
+.Fn ifaddr:name
+method returns a string and the
+.Fn ifaddr:flags
+method returns a list of strings.
+.Sh EXAMPLES
+Get a list of the names of all interfaces:
+.Bd -literal -offset indent
+local ifcfg = require('ifconfig').open()
+local ucl = require('ucl')
+
+local ifnames = ifcfg:foreach_iface(function(ifcfg, iface, ifnames)
+ table.insert(ifnames, iface:name())
+ return ifnames
+end, {})
+
+print(ucl.to_json(ifnames))
+.Ed
+.Pp
+Retrieve information about all SFP modules:
+.Bd -literal -offset indent
+local ifcfg = require('ifconfig').open()
+local ucl = require('ucl')
+
+local modules = ifcfg:foreach_iface(function(ifcfg, iface, modules)
+ local name = iface:name()
+ local sfp = ifcfg:get_sfp_info(name)
+ if sfp then
+ modules[name] = {
+ info = sfp,
+ vendor_info = ifcfg:get_sfp_vendor_info(name),
+ status = ifcfg:get_sfp_status(name),
+ -- Not generally interesting,
+ -- but for completeness:
+ -- dump = tostring(ifcfg:get_sfp_dump(name)),
+ }
+ end
+ return modules
+end, {})
+
+print(ucl.to_json(modules))
+.Ed
+.Pp
+Get error information:
+.Bd -literal -offset indent
+local ifcfg = require('ifconfig').open()
+
+local status = ifcfg:get_status('usb')
+if not status then
+ print(ifcfg:error())
+ -- Prints:
+ -- IOCTL 6 SIOCGIFSTATUS
+end
+
+local dump = ifcfg:get_sfp_dump('usb')
+if not dump then
+ local errtype, errno, ioctlname = ifcfg:error()
+ assert(errno == 6) -- ENXIO
+ print(errtype .. ':' .. ioctlname .. ' failed')
+ -- Prints:
+ -- IOCTL:SIOCGI2C failed
+end
+.Ed
+.Sh SEE ALSO
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm ifconfig
+Lua module for flua first appeared in
+.Fx 13.0 .
+.Sh AUTHORS
+.An Ryan Moeller ,
+with inspiration from
+.Nx
+gpio(3lua), by
+.An Mark Balmer .
diff --git a/lib/flua/libifconfig/lua_ifconfig.c b/lib/flua/libifconfig/lua_ifconfig.c
new file mode 100644
--- /dev/null
+++ b/lib/flua/libifconfig/lua_ifconfig.c
@@ -0,0 +1,1956 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * 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 REGENTS 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 REGENTS 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.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <arpa/inet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_bridgevar.h>
+#include <net/if_dl.h>
+#include <net/ieee8023ad_lacp.h>
+#include <net/if_lagg.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/ip_carp.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdecode.h>
+#include <sysexits.h>
+
+#include <libifconfig.h>
+#include <libifconfig_sfp.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#define IFCONFIG_HANDLE_META "ifconfig_handle_t"
+#define STRUCT_IFADDRS_META "struct ifaddrs *"
+#define SFP_DUMP_META "struct ifconfig_sfp_dump"
+
+#define IFFBITS \
+ "\020" \
+ "\001UP" \
+ "\002BROADCAST" \
+ "\003DEBUG" \
+ "\004LOOPBACK" \
+ "\005POINTOPOINT" \
+ "\007RUNNING" \
+ "\010NOARP" \
+ "\011PROMISC" \
+ "\012ALLMULTI" \
+ "\013OACTIVE" \
+ "\014SIMPLEX" \
+ "\015LINK0" \
+ "\016LINK1" \
+ "\017LINK2" \
+ "\020MULTICAST" \
+ "\022PPROMISC" \
+ "\023MONITOR" \
+ "\024STATICARP"
+
+#define IFCAPBITS \
+ "\020" \
+ "\001RXCSUM" \
+ "\002TXCSUM" \
+ "\003NETCONS" \
+ "\004VLAN_MTU" \
+ "\005VLAN_HWTAGGING" \
+ "\006JUMBO_MTU" \
+ "\007POLLING" \
+ "\010VLAN_HWCSUM" \
+ "\011TSO4" \
+ "\012TSO6" \
+ "\013LRO" \
+ "\014WOL_UCAST" \
+ "\015WOL_MCAST" \
+ "\016WOL_MAGIC" \
+ "\017TOE4" \
+ "\020TOE6" \
+ "\021VLAN_HWFILTER" \
+ "\023VLAN_HWTSO" \
+ "\024LINKSTATE" \
+ "\025NETMAP" \
+ "\026RXCSUM_IPV6" \
+ "\027TXCSUM_IPV6" \
+ "\031TXRTLMT" \
+ "\032HWRXTSTMP" \
+ "\033NOMAP" \
+ "\034TXTLS4" \
+ "\035TXTLS6"
+
+#define IN6BITS \
+ "\020" \
+ "\001anycast" \
+ "\002tenative" \
+ "\003duplicated" \
+ "\004detached" \
+ "\005deprecated" \
+ "\007nodad" \
+ "\010autoconf" \
+ "\011temporary" \
+ "\012prefer_source"
+
+#define ND6BITS \
+ "\020" \
+ "\001nud" \
+ "\002accept_rtadv" \
+ "\003prefer_source" \
+ "\004ifdisabled" \
+ "\005dont_set_ifroute" \
+ "\006auto_linklocal" \
+ "\007no_radr" \
+ "\010no_prefer_iface" \
+ "\011no_dad" \
+ "\012ipv6_only" \
+ "\013ipv6_only"
+
+#define LAGGHASHBITS \
+ "\020" \
+ "\001l2" \
+ "\002l3" \
+ "\003l4"
+
+static const char *carp_states[] = { CARP_STATES };
+static const struct lagg_protos lagg_protos[] = LAGG_PROTOS;
+static const char *stp_states[] = { STP_STATES };
+static const char *stp_protos[] = { STP_PROTOS };
+static const char *stp_roles[] = { STP_ROLES };
+
+int luaopen_ifconfig(lua_State *);
+
+/*
+ * Create an array of the set flags in v, using the kernel %b format bits.
+ */
+static void
+push_flags_array(lua_State *L, unsigned v, const char *bits)
+{
+ int i, len;
+
+ lua_newtable(L);
+
+ /* Skip numeric format. */
+ ++bits;
+
+ while ((i = *bits++) != '\0') {
+ if ((v & (1 << (i - 1))) != 0) {
+ for (len = 0; bits[len] > 32; ++len);
+ lua_pushlstring(L, bits, len);
+ lua_rawseti(L, -2, i);
+ bits += len;
+ } else {
+ for (; *bits > 32; ++bits);
+ }
+ }
+}
+
+/*
+ * Decode an array of the flags to set and return as an int.
+ */
+static int
+pop_flags_array(lua_State *L, int index, const char *bits)
+{
+ int v = 0;
+
+ /* Skip numeric format. */
+ ++bits;
+
+ lua_pushnil(L); /* first key */
+ while (lua_next(L, index) != 0) {
+ const char *flag, *flags = bits;
+ int i, len;
+
+ luaL_checkstring(L, index + 2);
+
+ flag = lua_tostring(L, index + 2);
+ lua_pop(L, 1);
+ while ((i = *flags++) != '\0') {
+ for (len = 0; flags[len] > 32; ++len);
+ if (strncmp(flag, flags, len) == 0) {
+ v |= 1 << (i - 1);
+ break;
+ }
+ flags += len;
+ }
+ }
+
+ return (v);
+}
+
+/*
+ * Push a table describing media information.
+ */
+static void
+push_media_info(lua_State *L, ifmedia_t media)
+{
+ const char *name, **opts;
+
+ lua_newtable(L);
+
+ name = ifconfig_media_get_type(media);
+ if (name != NULL) {
+ lua_pushstring(L, name);
+ lua_setfield(L, -2, "type");
+ }
+
+ name = ifconfig_media_get_subtype(media);
+ if (name != NULL) {
+ lua_pushstring(L, name);
+ lua_setfield(L, -2, "subtype");
+ }
+
+ name = ifconfig_media_get_mode(media);
+ if (name != NULL) {
+ lua_pushstring(L, name);
+ lua_setfield(L, -2, "mode");
+ }
+
+ lua_newtable(L);
+ opts = ifconfig_media_get_options(media);
+ if (opts != NULL) {
+ for (size_t i = 0; opts[i] != NULL; ++i) {
+ lua_pushstring(L, opts[i]);
+ lua_rawseti(L, -2, i);
+ }
+ free(opts);
+ }
+ lua_setfield(L, -2, "options");
+}
+
+/*
+ * Push a table describing an AF_INET address or nil if error.
+ */
+static void
+push_inet4_addrinfo(lua_State *L, ifconfig_handle_t *h, struct ifaddrs *ifa)
+{
+ char addr_buf[NI_MAXHOST];
+ struct ifconfig_inet_addr addr;
+
+ if (ifconfig_inet_get_addrinfo(h, ifa->ifa_name, ifa, &addr) != 0) {
+ lua_pushnil(L);
+ return;
+ }
+
+ lua_newtable(L);
+
+ /* TODO: can this just be inet_ntoa? */
+ inet_ntop(AF_INET, &addr.sin->sin_addr, addr_buf, sizeof addr_buf);
+ lua_pushstring(L, addr_buf);
+ lua_setfield(L, -2, "inet");
+
+ if (addr.dst != NULL) {
+ lua_pushstring(L, inet_ntoa_r(addr.dst->sin_addr, addr_buf,
+ sizeof addr_buf));
+ lua_setfield(L, -2, "destination");
+ }
+
+ lua_pushstring(L, inet_ntoa_r(addr.netmask->sin_addr, addr_buf,
+ sizeof addr_buf));
+ lua_setfield(L, -2, "netmask");
+
+ if (addr.broadcast != NULL) {
+ lua_pushstring(L, inet_ntoa_r(addr.broadcast->sin_addr,
+ addr_buf, sizeof addr_buf));
+ lua_setfield(L, -2, "broadcast");
+ }
+
+ if (addr.vhid != 0) {
+ lua_pushinteger(L, addr.vhid);
+ lua_setfield(L, -2, "vhid");
+ }
+}
+
+/*
+ * Push a table describing an AF_INET6 address or nil if error.
+ */
+static void
+push_inet6_addrinfo(lua_State *L, ifconfig_handle_t *h, struct ifaddrs *ifa)
+{
+ char addr_buf[NI_MAXHOST];
+ struct ifconfig_inet6_addr addr;
+ struct timespec now;
+
+ if (ifconfig_inet6_get_addrinfo(h, ifa->ifa_name, ifa, &addr) != 0) {
+ lua_pushnil(L);
+ return;
+ }
+
+ lua_newtable(L);
+
+ if (getnameinfo((struct sockaddr *)addr.sin6, addr.sin6->sin6_len,
+ addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST) != 0)
+ /* TODO: can this just be inet_ntoa? */
+ inet_ntop(AF_INET6, &addr.sin6->sin6_addr, addr_buf,
+ sizeof addr_buf);
+ lua_pushstring(L, addr_buf);
+ lua_setfield(L, -2, "inet6");
+
+ if (addr.dstin6 != NULL) {
+ inet_ntop(AF_INET6, addr.dstin6, addr_buf, sizeof addr_buf);
+ lua_pushstring(L, addr_buf);
+ lua_setfield(L, -2, "destination");
+ }
+
+ lua_pushinteger(L, addr.prefixlen);
+ lua_setfield(L, -2, "prefixlen");
+
+ if (addr.sin6->sin6_scope_id != 0) {
+ lua_pushinteger(L, addr.sin6->sin6_scope_id);
+ lua_setfield(L, -2, "scopeid");
+ }
+
+ push_flags_array(L, addr.flags, IN6BITS);
+ lua_setfield(L, -2, "flags");
+
+ clock_gettime(CLOCK_MONOTONIC_FAST, &now);
+ if (addr.lifetime.ia6t_preferred || addr.lifetime.ia6t_expire) {
+ lua_pushinteger(L, MAX(0l,
+ addr.lifetime.ia6t_preferred - now.tv_sec));
+ lua_setfield(L, -2, "preferred_lifetime");
+
+ lua_pushinteger(L, MAX(0l,
+ addr.lifetime.ia6t_expire - now.tv_sec));
+ lua_setfield(L, -2, "valid_lifetime");
+ }
+
+ if (addr.vhid != 0) {
+ lua_pushinteger(L, addr.vhid);
+ lua_setfield(L, -2, "vhid");
+ }
+}
+
+/*
+ * Push a table describing an AF_LINK address or nil if error.
+ */
+static void
+push_link_addrinfo(lua_State *L, ifconfig_handle_t *h __unused,
+ struct ifaddrs *ifa)
+{
+ char addr_buf[NI_MAXHOST];
+ union {
+ struct sockaddr *a;
+ struct sockaddr_dl *dl;
+ } s;
+ int n;
+
+ s.a = ifa->ifa_addr;
+ if (s.dl == NULL || s.dl->sdl_alen <= 0) {
+ lua_pushnil(L);
+ return;
+ }
+
+ lua_newtable(L);
+
+ switch (s.dl->sdl_type) {
+ case IFT_ETHER:
+ case IFT_L2VLAN:
+ case IFT_BRIDGE:
+ if (s.dl->sdl_alen != ETHER_ADDR_LEN)
+ break;
+ ether_ntoa_r((struct ether_addr *)LLADDR(s.dl), addr_buf);
+ lua_pushstring(L, addr_buf);
+ lua_setfield(L, -2, "ether");
+ break;
+ default:
+ n = s.dl->sdl_nlen > 0 ? s.dl->sdl_nlen + 1 : 0;
+ lua_pushstring(L, link_ntoa(s.dl) + n); /* FIXME: link_ntoa_r */
+ lua_setfield(L, -2, "lladdr");
+ break;
+ }
+}
+
+/*
+ * Push a table describing an AF_LOCAL address.
+ */
+static void
+push_local_addrinfo(lua_State *L, ifconfig_handle_t *h __unused,
+ struct ifaddrs *ifa)
+{
+ union {
+ struct sockaddr *a;
+ struct sockaddr_un *un;
+ } s;
+
+ lua_newtable(L);
+
+ s.a = ifa->ifa_addr;
+ if (strlen(s.un->sun_path) == 0)
+ lua_pushstring(L, "-");
+ else
+ lua_pushstring(L, s.un->sun_path);
+ lua_setfield(L, -2, "path");
+}
+
+/*
+ * Push a table describing SFP channel power.
+ */
+static void
+push_channel_power(lua_State *L, uint16_t power)
+{
+
+ lua_newtable(L);
+
+ lua_pushinteger(L, power);
+ lua_setfield(L, -2, "value");
+
+ lua_pushnumber(L, power_mW(power));
+ lua_setfield(L, -2, "mW");
+
+ lua_pushnumber(L, power_dBm(power));
+ lua_setfield(L, -2, "dBm");
+}
+
+/*
+ * Push a table describing SFP channel bias current.
+ */
+static void
+push_channel_bias(lua_State *L, uint16_t bias)
+{
+
+ lua_newtable(L);
+
+ lua_pushinteger(L, bias);
+ lua_setfield(L, -2, "raw");
+
+ lua_pushnumber(L, bias_mA(bias));
+ lua_setfield(L, -2, "mA");
+}
+
+/*
+ * Check the stack for an ifconfig handle userdata at the given index.
+ */
+static ifconfig_handle_t *
+l_ifconfig_checkhandle(lua_State *L, int index)
+{
+ ifconfig_handle_t *h, **hp;
+
+ hp = luaL_checkudata(L, index, IFCONFIG_HANDLE_META);
+ assert(hp != NULL);
+ h = *hp;
+ luaL_argcheck(L, h != NULL, index, "invalid ifconfig handle");
+ return (h);
+}
+
+/*
+ * Check the stack for an ifaddrs userdata at the given index.
+ */
+static struct ifaddrs *
+l_ifconfig_checkifaddrs(lua_State *L, int index)
+{
+ struct ifaddrs *ifa, **ifap;
+
+ ifap = luaL_checkudata(L, index, STRUCT_IFADDRS_META);
+ assert(ifap != NULL);
+ ifa = *ifap;
+ luaL_argcheck(L, ifa != NULL, index, "invalid ifaddr");
+ return (ifa);
+}
+
+/*
+ * Invoke a callback function on the stack with the handle and accumulator
+ * from the stack and the given ifaddrs, leaving the handle, callback, and
+ * accumulator result on the stack after the call.
+ *
+ * This is used by the ifconfig_foreach_* functions to invoke a lua callback.
+ */
+static void
+foreach_cb(ifconfig_handle_t *h __unused, struct ifaddrs *ifa, void *udata)
+{
+ lua_State *L = udata;
+ struct ifaddrs **ifap;
+
+ /* Stack: h,cb,acc */
+
+ /* Make copies of the callback and handle positioned for the call. */
+ lua_pushvalue(L, 1); /* -> h,cb,acc,h */
+ lua_pushvalue(L, 2); /* -> h,cb,acc,h,cb */
+ lua_insert(L, 3); /* -> h,cb,cb,acc,h */
+ lua_insert(L, 4); /* -> h,cb,cb,h,acc */
+
+ /* Push the ifa userdata. */
+ ifap = lua_newuserdata(L, sizeof ifa); /* -> h,cb,cb,h,acc,ifa */
+ assert(ifap != NULL);
+ *ifap = ifa;
+ luaL_getmetatable(L, STRUCT_IFADDRS_META);
+ lua_setmetatable(L, -2);
+
+ /* Reposition the accumulator to be last so it can be optional. */
+ lua_insert(L, 5); /* -> h,cb,cb,h,ifa,acc */
+
+ /* Invoke the callback. */
+ lua_call(L, 3, 1); /* -> h,cb,acc */
+}
+
+/** Explicit close method
+ */
+static int
+l_ifconfig_handle_close(lua_State *L)
+{
+ ifconfig_handle_t *h, **hp;
+
+ hp = luaL_checkudata(L, 1, IFCONFIG_HANDLE_META);
+ assert(hp != NULL);
+ h = *hp;
+ if (h != NULL) {
+ ifconfig_close(h);
+ *hp = NULL;
+ }
+ return (0);
+}
+
+/** Get error info
+ * @return errtype, errno, ioctlname?
+ */
+static int
+l_ifconfig_handle_error(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ ifconfig_errtype errtype;
+
+ h = l_ifconfig_checkhandle(L, 1);
+
+ errtype = ifconfig_err_errtype(h);
+ switch (errtype) {
+ case OK:
+ lua_pushnil(L);
+ return (1);
+ case OTHER:
+ lua_pushstring(L, "OTHER");
+ break;
+ case IOCTL:
+ lua_pushstring(L, "IOCTL");
+ break;
+ case SOCKET:
+ lua_pushstring(L, "SOCKET");
+ break;
+ default:
+ lua_pushstring(L, "<unknown>");
+ break;
+ }
+
+ lua_pushinteger(L, ifconfig_err_errno(h));
+
+ if (errtype == IOCTL) {
+ unsigned long req = ifconfig_err_ioctlreq(h);
+ lua_pushstring(L, sysdecode_ioctlname(req));
+ return (3);
+ }
+
+ return (2);
+}
+
+/** Higher-order fold iterator over interfaces
+ * @param cb A callback function (handle, iface, udata) -> udata
+ * @param udata An initial accumulator value (may be nil)
+ * @return The final accumulator value returned by cb
+ */
+static int
+l_ifconfig_foreach_iface(lua_State *L)
+{
+ const int MAXARGS = 3;
+ ifconfig_handle_t *h;
+ int n;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+
+ /* Ensure the correct number of args. Extras are discarded. */
+ n = lua_gettop(L);
+ if (n == (MAXARGS - 1))
+ lua_pushnil(L);
+ else if (n > MAXARGS)
+ lua_pop(L, n - MAXARGS);
+
+ if (ifconfig_foreach_iface(h, foreach_cb, L) != 0)
+ return luaL_error(L, "iteration failed");
+
+ return (1);
+}
+
+/** Higher-order fold iterator over interface addresses
+ * @param iface A STRUCT_IFADDRS_META userdata value from foreach_iface
+ * @param cb A callback function (handle, ifaddr, udata) -> udata
+ * @param udata An initial accumulator value (may be nil)
+ * @return The final accumulator value returned by cb
+ */
+static int
+l_ifconfig_foreach_ifaddr(lua_State *L)
+{
+ const int MAXARGS = 4;
+ ifconfig_handle_t *h;
+ struct ifaddrs *ifa;
+ int n;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ ifa = l_ifconfig_checkifaddrs(L, 2);
+ luaL_checktype(L, 3, LUA_TFUNCTION);
+
+ /* Ensure the correct number of args. Extras are discarded. */
+ n = lua_gettop(L);
+ if (n == (MAXARGS - 1))
+ lua_pushnil(L);
+ else if (n > MAXARGS)
+ lua_pop(L, n - MAXARGS);
+ lua_remove(L, 2);
+
+ ifconfig_foreach_ifaddr(h, ifa, foreach_cb, L);
+
+ return (1);
+}
+
+/** Get interface description
+ * @param name The name of an interface
+ * @return Description string if set, otherwise nil
+ */
+static int
+l_ifconfig_get_description(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ char *desc;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_description(h, name, &desc) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, desc);
+
+ return (1);
+}
+
+/** Set interface description
+ * @param name The name of an interface
+ * @param desc Description string to set
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_description(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name, *desc;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkstring(L, 3);
+
+ name = lua_tostring(L, 2);
+ desc = lua_tostring(L, 3);
+ if (ifconfig_set_description(h, name, desc) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Unset interface description
+ * @param name The name of an interface
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_unset_description(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_unset_description(h, name) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Set interface name
+ * @param name The name of an interface
+ * @param newname A new name for the interface
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_name(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name, *newname;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkstring(L, 3);
+
+ name = lua_tostring(L, 2);
+ newname = lua_tostring(L, 3);
+ if (ifconfig_set_name(h, name, newname) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Get original interface name
+ * @param name The name of an interface
+ * @return Original interface name or nil if error
+ */
+static int
+l_ifconfig_get_orig_name(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ char *orig_name;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_orig_name(h, name, &orig_name) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, orig_name);
+
+ return (1);
+}
+
+#if 0 /* setfib not implemented in libifconfig? */
+/** Set interface fib
+ * @param name The name of an interface
+ * @param fib A fib number to use
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_fib(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ ptrdiff_t fib;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkinteger(L, 3);
+
+ name = lua_tostring(L, 2);
+ fib = lua_tointeger(L, 3);
+ luaL_argcheck(L, INT_MAX < fib || fib < INT_MIN, 3, "fib out of range");
+ if (ifconfig_set_fib(h, name, fib) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+#endif
+
+/** Get interface fib
+ * @param name The name of an interface
+ * @return fib of the interface or nil if error
+ */
+static int
+l_ifconfig_get_fib(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ int fib;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_fib(h, name, &fib) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, fib);
+
+ return (1);
+}
+
+/** Set interface mtu
+ * @param name The name of an interface
+ * @param mtu A mtu to use
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_mtu(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ ptrdiff_t mtu;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkinteger(L, 3);
+
+ name = lua_tostring(L, 2);
+ mtu = lua_tointeger(L, 3);
+ luaL_argcheck(L, INT_MIN <= mtu && mtu <= INT_MAX, 3, "mtu out of range");
+ if (ifconfig_set_mtu(h, name, mtu) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Get interface mtu
+ * @param name The name of an interface
+ * @return mtu of the interface or nil if error
+ */
+static int
+l_ifconfig_get_mtu(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ int mtu;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_mtu(h, name, &mtu) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, mtu);
+
+ return (1);
+}
+
+/** Get interface nd6 info
+ * @param name The name of an interface
+ * @return An list of the enabled nd6 options or nil if error
+ */
+static int
+l_ifconfig_get_nd6(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct in6_ndireq nd;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_nd6(h, name, &nd) != 0)
+ lua_pushnil(L);
+ else
+ push_flags_array(L, nd.ndi.flags, ND6BITS);
+
+ return (1);
+}
+
+/** Set interface metric
+ * @param name The name of an interface
+ * @param metric A metric to use
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_metric(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ ptrdiff_t metric;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkinteger(L, 3);
+
+ name = lua_tostring(L, 2);
+ metric = lua_tointeger(L, 3);
+ luaL_argcheck(L, INT_MAX < metric || metric < INT_MIN, 3,
+ "metric out of range");
+ if (ifconfig_set_metric(h, name, metric) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Get interface metric
+ * @param name The name of an interface
+ * @return metric of the interface or nil if error
+ */
+static int
+l_ifconfig_get_metric(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ int metric;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_metric(h, name, &metric) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, metric);
+
+ return (1);
+}
+
+/** Set interface capabilities
+ * @param name The name of an interface
+ * @param caps An array of the capabilities to be enabled on the interface
+ * (capabilities not listed will be disabled)
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_capabilities(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ int capability;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checktype(L, 3, LUA_TTABLE);
+
+ name = lua_tostring(L, 2);
+ capability = pop_flags_array(L, 3, IFCAPBITS);
+ if (ifconfig_set_capability(h, name, capability) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Get interface capabilities
+ * @param name The name of an interface
+ * @return A table of the enabled/supported capabilites or nil if error
+ */
+static int
+l_ifconfig_get_capabilities(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifconfig_capabilities capability;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_capability(h, name, &capability) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ lua_pushstring(L, "enabled");
+ push_flags_array(L, capability.curcap, IFCAPBITS);
+ lua_rawset(L, 3);
+
+ lua_pushstring(L, "supported");
+ push_flags_array(L, capability.reqcap, IFCAPBITS);
+ lua_rawset(L, 3);
+
+ return (1);
+}
+
+/** Get interface groups list
+ * @param name The name of an interface
+ * @return A table of the groups containing the interface or nil if error
+ */
+static int
+l_ifconfig_get_groups(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifgroupreq ifgr;
+ struct ifg_req *ifg;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_groups(h, name, &ifgr) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ for (ifg = ifgr.ifgr_groups;
+ ifg != NULL && ifgr.ifgr_len >= sizeof *ifg;
+ ++ifg, ifgr.ifgr_len -= sizeof *ifg) {
+ if (strcmp(ifg->ifgrq_group, "all") == 0)
+ continue;
+ lua_pushstring(L, ifg->ifgrq_group);
+ lua_rawseti(L, 3, lua_rawlen(L, 3) + 1);
+ }
+
+ return (1);
+}
+
+/** Get interface status
+ * @param name The name of an interface
+ * @return Interface status as a string or nil if error
+ */
+static int
+l_ifconfig_get_status(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifstat status;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_ifstatus(h, name, &status) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, status.ascii);
+
+ return (1);
+}
+
+/** Get interface media info
+ * @param name The name of an interface
+ * @return A table describing the interface media or nil if error
+ */
+static int
+l_ifconfig_get_media(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name, *status;
+ struct ifmediareq *ifmr;
+ struct ifdownreason ifdr;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_media_get_mediareq(h, name, &ifmr) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ push_media_info(L, ifmr->ifm_current);
+ lua_setfield(L, 3, "current");
+
+ push_media_info(L, ifmr->ifm_active);
+ lua_setfield(L, 3, "active");
+
+ lua_newtable(L);
+ for (int i = 0; i < ifmr->ifm_count; ++i) {
+ push_media_info(L, ifmr->ifm_ulist[i]);
+ lua_rawseti(L, 4, lua_rawlen(L, 4) + 1);
+ }
+ lua_setfield(L, 3, "supported");
+
+ status = ifconfig_media_get_status(ifmr);
+ lua_pushstring(L, status);
+ lua_setfield(L, 3, "status");
+
+ if (strcmp(status, "no carrier") == 0 &&
+ ifconfig_media_get_downreason(h, name, &ifdr) == 0) {
+ switch (ifdr.ifdr_reason) {
+ case IFDR_REASON_MSG:
+ lua_pushstring(L, ifdr.ifdr_msg);
+ lua_setfield(L, 3, "down_reason");
+ break;
+ case IFDR_REASON_VENDOR:
+ lua_pushinteger(L, ifdr.ifdr_vendor);
+ lua_setfield(L, 3, "down_reason");
+ break;
+ default:
+ break;
+ }
+ }
+
+ free(ifmr);
+
+ return (1);
+}
+
+/** Get interface carp info
+ * @param name
+ * @return A table describing the interface carp vhids or nil if error
+ */
+static int
+l_ifconfig_get_carp(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct carpreq carpr[CARP_MAXVHID];
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_carp_get_info(h, name, carpr, nitems(carpr)) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ for (int i = 0; i < carpr[0].carpr_count; ++i) {
+ lua_newtable(L);
+
+ lua_pushstring(L, carp_states[carpr[i].carpr_state]);
+ lua_setfield(L, 4, "state");
+
+ lua_pushinteger(L, carpr[i].carpr_vhid);
+ lua_setfield(L, 4, "vhid");
+
+ lua_pushinteger(L, carpr[i].carpr_advbase);
+ lua_setfield(L, 4, "advbase");
+
+ lua_pushinteger(L, carpr[i].carpr_advskew);
+ lua_setfield(L, 4, "advskew");
+
+ lua_rawseti(L, 3, lua_rawlen(L, 3) + 1);
+ }
+
+ return (1);
+}
+
+/** Get address info
+ * @param addr An ifaddrs userdata object
+ * @return Table describing the address or nil if error
+ */
+static int
+l_ifconfig_addr_info(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ struct ifaddrs *ifa;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ ifa = l_ifconfig_checkifaddrs(L, 2);
+
+ switch (ifa->ifa_addr->sa_family) {
+ case AF_INET:
+ push_inet4_addrinfo(L, h, ifa);
+ break;
+ case AF_INET6:
+ push_inet6_addrinfo(L, h, ifa);
+ break;
+ case AF_LINK:
+ push_link_addrinfo(L, h, ifa);
+ break;
+ case AF_LOCAL:
+ push_local_addrinfo(L, h, ifa);
+ break;
+ case AF_UNSPEC:
+ default:
+ lua_pushnil(L);
+ break;
+ }
+
+ return (1);
+}
+
+/** Get bridge interface status
+ * @param name The name of a bridge interface
+ * @return Table describing the status of the bridge or nil if error
+ */
+static int
+l_ifconfig_get_bridge_status(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifconfig_bridge_status *bridge;
+ struct ifbropreq *params;
+ struct ifbreq *member;
+ uint8_t lladdr[ETHER_ADDR_LEN];
+ char addr_buf[NI_MAXHOST];
+ uint16_t bprio;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_bridge_get_bridge_status(h, name, &bridge) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ lua_pushinteger(L, bridge->cache_size);
+ lua_setfield(L, -2, "address_cache_size");
+
+ lua_pushinteger(L, bridge->cache_lifetime);
+ lua_setfield(L, -2, "address_cache_lifetime");
+
+ params = bridge->params;
+
+ lua_pushinteger(L, params->ifbop_priority);
+ lua_setfield(L, -2, "priority");
+
+ if (params->ifbop_protocol < nitems(stp_protos))
+ lua_pushstring(L, stp_protos[params->ifbop_protocol]);
+ else
+ lua_pushinteger(L, params->ifbop_protocol);
+ lua_setfield(L, -2, "protocol");
+
+ lua_pushinteger(L, params->ifbop_hellotime);
+ lua_setfield(L, -2, "hello_time");
+
+ lua_pushinteger(L, params->ifbop_fwddelay);
+ lua_setfield(L, -2, "forward_delay");
+
+ lua_pushinteger(L, params->ifbop_holdcount);
+ lua_setfield(L, -2, "hold_count");
+
+ lua_pushinteger(L, params->ifbop_maxage);
+ lua_setfield(L, -2, "max_age");
+
+ PV2ID(params->ifbop_bridgeid, bprio, lladdr);
+ lua_pushstring(L, ether_ntoa_r((struct ether_addr *)lladdr, addr_buf));
+ lua_setfield(L, -2, "id");
+
+ PV2ID(params->ifbop_designated_root, bprio, lladdr);
+ lua_pushstring(L, ether_ntoa_r((struct ether_addr *)lladdr, addr_buf));
+ lua_setfield(L, -2, "root_id");
+
+ lua_pushinteger(L, bprio);
+ lua_setfield(L, -2, "root_priority");
+
+ lua_pushinteger(L, params->ifbop_root_path_cost);
+ lua_setfield(L, -2, "root_path_cost");
+
+ lua_pushinteger(L, params->ifbop_root_port & 0xfff);
+ lua_setfield(L, -2, "root_port");
+
+ lua_newtable(L);
+
+ for (size_t i = 0; i < bridge->members_count; ++i) {
+ member = bridge->members + i;
+
+ lua_newtable(L);
+
+ push_flags_array(L, member->ifbr_ifsflags, IFBIFBITS);
+ lua_setfield(L, -2, "flags");
+
+ lua_pushinteger(L, member->ifbr_addrmax);
+ lua_setfield(L, -2, "ifmaxaddr");
+
+ lua_pushinteger(L, member->ifbr_portno);
+ lua_setfield(L, -2, "port");
+
+ lua_pushinteger(L, member->ifbr_priority);
+ lua_setfield(L, -2, "priority");
+
+ lua_pushinteger(L, member->ifbr_path_cost);
+ lua_setfield(L, -2, "path_cost");
+
+ if (member->ifbr_ifsflags & IFBIF_STP) {
+ if (member->ifbr_proto < nitems(stp_protos))
+ lua_pushstring(L,
+ stp_protos[member->ifbr_proto]);
+ else
+ lua_pushinteger(L, member->ifbr_proto);
+ lua_setfield(L, -2, "protocol");
+
+ if (member->ifbr_role < nitems(stp_roles))
+ lua_pushstring(L,
+ stp_roles[member->ifbr_role]);
+ else
+ lua_pushinteger(L, member->ifbr_role);
+ lua_setfield(L, -2, "role");
+
+ if (member->ifbr_state < nitems(stp_states))
+ lua_pushstring(L,
+ stp_states[member->ifbr_state]);
+ else
+ lua_pushinteger(L, member->ifbr_state);
+ lua_setfield(L, -2, "state");
+ }
+
+ lua_setfield(L, -2, member->ifbr_ifsname);
+ }
+
+ lua_setfield(L, -2, "members");
+
+ ifconfig_bridge_free_bridge_status(bridge);
+
+ return (1);
+}
+
+/** Get lagg interface status
+ * @param name The name of a lagg interface
+ * @return Table describing the status of the lagg or nil if error
+ */
+static int
+l_ifconfig_get_lagg_status(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifconfig_lagg_status *lagg_status;
+ const char *protoname = "<unknown>";
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_lagg_get_lagg_status(h, name, &lagg_status) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ for (size_t i = 0; i < nitems(lagg_protos); ++i) {
+ if (lagg_status->ra->ra_proto == lagg_protos[i].lpr_proto) {
+ protoname = lagg_protos[i].lpr_name;
+ break;
+ }
+ }
+ lua_pushstring(L, protoname);
+ lua_setfield(L, -2, "laggproto");
+
+ push_flags_array(L, lagg_status->rf->rf_flags & LAGG_F_HASHMASK,
+ LAGGHASHBITS);
+ lua_setfield(L, -2, "lagghash");
+
+ lua_newtable(L);
+
+ push_flags_array(L, lagg_status->ro->ro_opts, LAGG_OPT_BITS);
+ lua_setfield(L, -2, "flags");
+
+ lua_pushinteger(L, lagg_status->ro->ro_flowid_shift);
+ lua_setfield(L, -2, "flowid_shift");
+
+ if (lagg_status->ra->ra_proto == LAGG_PROTO_ROUNDROBIN) {
+ lua_pushinteger(L, lagg_status->ro->ro_bkt);
+ lua_setfield(L, -2, "rr_limit");
+ }
+
+ lua_setfield(L, -2, "options");
+
+ lua_newtable(L);
+
+ lua_pushinteger(L, lagg_status->ro->ro_active);
+ lua_setfield(L, -2, "active");
+
+ lua_pushinteger(L, lagg_status->ro->ro_flapping);
+ lua_setfield(L, -2, "flapping");
+
+ lua_setfield(L, -2, "stats");
+
+ lua_newtable(L);
+
+ for (int i = 0; i < lagg_status->ra->ra_ports; ++i) {
+ struct lagg_reqport *lagg_port = &lagg_status->ra->ra_port[i];
+
+ lua_newtable(L);
+
+ push_flags_array(L, lagg_port->rp_flags, LAGG_PORT_BITS);
+ lua_setfield(L, -2, "flags");
+
+ if (lagg_status->ra->ra_proto == LAGG_PROTO_LACP) {
+ struct lacp_opreq *lacp_port = (struct lacp_opreq *)
+ &lagg_port->rp_lacpreq;
+
+ push_flags_array(L, lacp_port->actor_state,
+ LACP_STATE_BITS);
+ lua_setfield(L, -2, "lacp_state");
+ }
+
+ lua_setfield(L, -2, lagg_port->rp_portname);
+ }
+
+ lua_setfield(L, -2, "ports");
+
+ ifconfig_lagg_free_lagg_status(lagg_status);
+
+ return (1);
+}
+
+/** Get the parent laggdev of a laggport interface
+ * @param name The name of a laggport interface
+ * @return Parent laggdev name or nil if error
+ */
+static int
+l_ifconfig_get_laggport_laggdev(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct lagg_reqport lagg_port;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_lagg_get_laggport_status(h, name, &lagg_port) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, lagg_port.rp_ifname);
+
+ return (1);
+}
+
+/** Destroy an interface
+ * @param name The name of an interface
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_destroy(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_destroy_interface(h, name) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Create an interface
+ * @param name The name of an interface
+ * @return Created interface name or nil if error
+ */
+static int
+l_ifconfig_create(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ char *ifname;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_create_interface(h, name, &ifname) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, ifname);
+
+ return (1);
+}
+
+/** Create a vlan interface
+ * @param name The name of a vlan interface to create
+ * @param vlandev The name of an interface to attach to
+ * @param vlantag A vlan number to use
+ * @return The name of the created interface or nil if error
+ */
+static int
+l_ifconfig_create_vlan(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name, *vlandev;
+ char *ifname;
+ ptrdiff_t vlantag;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkstring(L, 3);
+ luaL_checkinteger(L, 4);
+
+ name = lua_tostring(L, 2);
+ vlandev = lua_tostring(L, 3);
+ vlantag = lua_tointeger(L, 4);
+ luaL_argcheck(L, 0 <= vlantag && vlantag <= UINT16_MAX, 4,
+ "vlantag out of range");
+ if (ifconfig_create_interface_vlan(h, name, &ifname, vlandev, vlantag) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, ifname);
+
+ return (1);
+}
+
+/** Set vlandev and vlantag for a vlan interface
+ * @param name The name of a vlan interface
+ * @param vlandev The name of the interface to attach to
+ * @param vlantag A vlan number to use
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_vlantag(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name, *vlandev;
+ ptrdiff_t vlantag;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkstring(L, 3);
+ luaL_checkinteger(L, 4);
+
+ name = lua_tostring(L, 2);
+ vlandev = lua_tostring(L, 3);
+ vlantag = lua_tointeger(L, 4);
+ luaL_argcheck(L, 0 <= vlantag && vlantag <= UINT16_MAX, 4,
+ "vlantag out of range");
+ if (ifconfig_set_vlantag(h, name, vlandev, vlantag) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Get a list of all the interface cloners available on the system
+ * @return a list of the names of known interface cloners or nil if error
+ */
+static int
+l_ifconfig_list_cloners(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ char *cloners;
+ size_t cloners_count;
+
+ h = l_ifconfig_checkhandle(L, 1);
+
+ if (ifconfig_list_cloners(h, &cloners, &cloners_count) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ for (size_t i = 0; i < cloners_count; ++i) {
+ const char *name = cloners + i * IFNAMSIZ;
+
+ lua_pushstring(L, name);
+ lua_rawseti(L, -2, i);
+ }
+
+ free(cloners);
+ return (1);
+}
+
+/** Get SFP module information
+ * @param name The name of an interface
+ * @return Table describing available info about an SFP module if present,
+ * or nil if no module present or an error occurred
+ */
+static int
+l_ifconfig_get_sfp_info(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifconfig_sfp_info sfp;
+ struct ifconfig_sfp_info_strings strings;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_sfp_get_sfp_info(h, name, &sfp) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+ ifconfig_sfp_get_sfp_info_strings(&sfp, &strings);
+
+ lua_newtable(L);
+
+#define $(enu) \
+ if (sfp.sfp_##enu != 0) { \
+ lua_newtable(L); \
+ lua_pushstring(L, ifconfig_enum_sfp_##enu##_description()); \
+ lua_setfield(L, -2, "description"); \
+ lua_pushstring(L, strings.sfp_##enu); \
+ lua_setfield(L, -2, "string"); \
+ lua_pushinteger(L, sfp.sfp_##enu); \
+ lua_setfield(L, -2, "value"); \
+ lua_setfield(L, -2, "sfp_"#enu); \
+ }
+ $(id)
+ $(conn)
+ $(eth_10g)
+ $(eth)
+ $(fc_len)
+ $(cab_tech)
+ $(fc_media)
+ $(eth_1040g)
+ $(eth_ext)
+ $(rev)
+#undef $
+
+ return (1);
+}
+
+/** Get SFP module vendor info
+ * @param name The name of an interface
+ * @return Table of vendor info or nil if error
+ */
+static int
+l_ifconfig_get_sfp_vendor_info(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifconfig_sfp_vendor_info vendor;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_sfp_get_sfp_vendor_info(h, name, &vendor) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ lua_pushstring(L, vendor.name);
+ lua_setfield(L, -2, "name");
+
+ lua_pushstring(L, vendor.pn);
+ lua_setfield(L, -2, "part_number");
+
+ lua_pushstring(L, vendor.sn);
+ lua_setfield(L, -2, "serial_number");
+
+ lua_pushstring(L, vendor.date);
+ lua_setfield(L, -2, "date");
+
+ return (1);
+}
+
+/** Get SFP module status
+ * @param name The name of an interface
+ * @return Table describing module status if present
+ * or nil if no module or an error occurs
+ */
+static int
+l_ifconfig_get_sfp_status(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifconfig_sfp_status status;
+ size_t channels = 1;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_sfp_get_sfp_status(h, name, &status) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ if (-40.0 <= status.temp && status.temp <= 125.0) {
+ lua_pushnumber(L, status.temp);
+ lua_setfield(L, -2, "temperature");
+ }
+
+ lua_pushnumber(L, status.voltage);
+ lua_setfield(L, -2, "voltage");
+
+ if (status.bitrate != 0) {
+ lua_pushnumber(L, status.bitrate);
+ lua_setfield(L, -2, "bitrate");
+
+ channels = 4;
+ }
+
+ lua_newtable(L);
+
+ for (size_t chan = 0; chan < channels; ++chan) {
+ lua_newtable(L);
+
+ push_channel_power(L, status.channel[chan].rx);
+ lua_setfield(L, -2, "rx_power");
+
+ push_channel_bias(L, status.channel[chan].tx);
+ lua_setfield(L, -2, "tx_bias");
+
+ lua_rawseti(L, -2, chan + 1);
+ }
+
+ lua_setfield(L, -2, "channels");
+
+ return (1);
+}
+
+/** Get SFP module I2C dump
+ * @param name The name of an interface
+ * @return A userdata blob with the dump or nil if error
+ */
+static int
+l_ifconfig_get_sfp_dump(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifconfig_sfp_dump *dump;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ dump = lua_newuserdata(L, sizeof(*dump));
+ assert(dump != NULL);
+ luaL_getmetatable(L, SFP_DUMP_META);
+ lua_setmetatable(L, -2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_sfp_get_sfp_dump(h, name, dump) != 0)
+ lua_pushnil(L);
+
+ return (1);
+}
+
+static const struct luaL_Reg l_ifconfig_handle[] = {
+ {"close", l_ifconfig_handle_close},
+ {"error", l_ifconfig_handle_error},
+ {"foreach_iface", l_ifconfig_foreach_iface},
+ {"foreach_ifaddr", l_ifconfig_foreach_ifaddr},
+ {"get_description", l_ifconfig_get_description},
+ {"set_description", l_ifconfig_set_description},
+ {"unset_description", l_ifconfig_unset_description},
+ {"set_name", l_ifconfig_set_name},
+ {"get_orig_name", l_ifconfig_get_orig_name},
+#if 0 /* setfib not implemented in libifconfig? */
+ {"set_fib", l_ifconfig_set_fib},
+#endif
+ {"get_fib", l_ifconfig_get_fib},
+ {"set_mtu", l_ifconfig_set_mtu},
+ {"get_mtu", l_ifconfig_get_mtu},
+ {"get_nd6", l_ifconfig_get_nd6},
+ {"set_metric", l_ifconfig_set_metric},
+ {"get_metric", l_ifconfig_get_metric},
+ {"set_capabilities", l_ifconfig_set_capabilities},
+ {"get_capabilities", l_ifconfig_get_capabilities},
+ {"get_groups", l_ifconfig_get_groups},
+ {"get_status", l_ifconfig_get_status},
+ {"get_media", l_ifconfig_get_media},
+ {"get_carp", l_ifconfig_get_carp},
+ {"addr_info", l_ifconfig_addr_info},
+ {"get_bridge_status", l_ifconfig_get_bridge_status},
+ {"get_lagg_status", l_ifconfig_get_lagg_status},
+ {"get_laggport_laggdev", l_ifconfig_get_laggport_laggdev},
+ {"destroy", l_ifconfig_destroy},
+ {"create", l_ifconfig_create},
+ {"create_vlan", l_ifconfig_create_vlan},
+ {"set_vlantag", l_ifconfig_set_vlantag},
+ {"list_cloners", l_ifconfig_list_cloners},
+ {"get_sfp_info", l_ifconfig_get_sfp_info},
+ {"get_sfp_vendor_info", l_ifconfig_get_sfp_vendor_info},
+ {"get_sfp_status", l_ifconfig_get_sfp_status},
+ {"get_sfp_dump", l_ifconfig_get_sfp_dump},
+ {NULL, NULL}
+};
+
+static void
+l_ifconfig_handle_meta(lua_State *L)
+{
+ luaL_newmetatable(L, IFCONFIG_HANDLE_META);
+
+ /* metatable.__index = metatable */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ /* Automatically close handle when garbage collected. */
+ lua_pushcfunction(L, l_ifconfig_handle_close);
+ lua_setfield(L, -2, "__gc");
+
+ luaL_setfuncs(L, l_ifconfig_handle, 0);
+
+ lua_pop(L, 1);
+}
+
+/** Get interface name
+ * @return Name of the interface as a string
+ */
+static int
+l_struct_ifaddrs_name(lua_State *L)
+{
+ struct ifaddrs *ifa;
+
+ ifa = l_ifconfig_checkifaddrs(L, 1);
+
+ lua_pushstring(L, ifa->ifa_name);
+ return (1);
+}
+
+/** Get interface flags
+ * @return List of flags set on this interface
+ */
+static int
+l_struct_ifaddrs_flags(lua_State *L)
+{
+ struct ifaddrs *ifa;
+
+ ifa = l_ifconfig_checkifaddrs(L, 1);
+
+ push_flags_array(L, ifa->ifa_flags, IFFBITS);
+ return (1);
+}
+
+static const struct luaL_Reg l_struct_ifaddrs[] = {
+ {"name", l_struct_ifaddrs_name},
+ {"flags", l_struct_ifaddrs_flags},
+ {NULL, NULL}
+};
+
+static void
+l_struct_ifaddrs_meta(lua_State *L)
+{
+ luaL_newmetatable(L, STRUCT_IFADDRS_META);
+
+ /* metatable.__index = metatable */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ luaL_setfuncs(L, l_struct_ifaddrs, 0);
+
+ lua_pop(L, 1);
+}
+
+static size_t
+hex_dump(char *dst, const uint8_t *src, size_t len)
+{
+ const size_t LINE_BYTES = 16;
+ char *p = dst;
+
+ for (size_t i = 0; i < len; ++i) {
+ char sep;
+ if (i == (len - 1))
+ sep = '\n';
+ else if (((i + 1) % LINE_BYTES) != 0)
+ sep = ' ';
+ else
+ sep = '\n';
+ p += sprintf(p, "%02X%c", src[i], sep);
+ }
+
+ return (p - dst);
+}
+
+static int
+l_sfp_dump_tostring(lua_State *L)
+{
+ struct ifconfig_sfp_dump *dump;
+ char *p, *buf;
+
+ dump = luaL_checkudata(L, 1, SFP_DUMP_META);
+ assert(dump != NULL);
+
+ p = buf = malloc(SFF_DUMP_SIZE * 4); /* should be sufficiently large */
+ assert(p != NULL);
+ memset(p, 0, sizeof(buf));
+
+ switch (ifconfig_sfp_dump_region_count(dump)) {
+ case 2:
+ p += sprintf(p, "SFF8436 DUMP (0xA0 0..81 range):\n");
+ p += hex_dump(p, dump->data + QSFP_DUMP0_START,
+ QSFP_DUMP0_SIZE);
+ p += sprintf(p, "SFF8436 DUMP (0xA0 128..255 range):\n");
+ p += hex_dump(p, dump->data + QSFP_DUMP1_START,
+ QSFP_DUMP1_SIZE);
+ break;
+ case 1:
+ p += sprintf(p, "SFF8472 DUMP (0xA0 0..127 range):\n");
+ p += hex_dump(p, dump->data + SFP_DUMP_START, SFP_DUMP_SIZE);
+ break;
+ default:
+ p += sprintf(p, "UNIDENTIFIED DUMP (0xA0 0..255 range):\n");
+ p += hex_dump(p, dump->data, sizeof(dump->data));
+ break;
+ }
+
+ lua_pushstring(L, buf);
+ free(buf);
+ return (1);
+}
+
+static const struct luaL_Reg l_sfp_dump[] = {
+ {"__tostring", l_sfp_dump_tostring},
+ {NULL, NULL}
+};
+
+static void
+l_sfp_dump_meta(lua_State *L)
+{
+ luaL_newmetatable(L, SFP_DUMP_META);
+
+ /* metatable.__index = metatable */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ luaL_setfuncs(L, l_sfp_dump, 0);
+
+ lua_pop(L, 1);
+}
+
+static int
+l_ifconfig_open(lua_State *L)
+{
+ ifconfig_handle_t *h, **hp;
+
+ if ((h = ifconfig_open()) == NULL) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ hp = lua_newuserdata(L, sizeof h);
+ assert(hp != NULL);
+ *hp = h;
+ luaL_getmetatable(L, IFCONFIG_HANDLE_META);
+ lua_setmetatable(L, -2);
+ return (1);
+}
+
+static const struct luaL_Reg l_ifconfig[] = {
+ {"open", l_ifconfig_open},
+ {NULL, NULL}
+};
+
+int
+luaopen_ifconfig(lua_State *L)
+{
+ l_ifconfig_handle_meta(L);
+ l_struct_ifaddrs_meta(L);
+ l_sfp_dump_meta(L);
+
+ lua_newtable(L);
+ luaL_setfuncs(L, l_ifconfig, 0);
+ return (1);
+}
diff --git a/lib/libifconfig/Makefile b/lib/libifconfig/Makefile
--- a/lib/libifconfig/Makefile
+++ b/lib/libifconfig/Makefile
@@ -2,7 +2,7 @@
PACKAGE= lib${LIB}
LIB= ifconfig
-INTERNALLIB= true
+PRIVATELIB= true
LIBADD= m
@@ -36,10 +36,10 @@
CLEANFILES+= ${GEN}
-# If libifconfig become public uncomment those two lines
-#INCSDIR= ${INCLUDEDIR}
-#INCS= libifconfig.h libifconfig_sfp.h libifconfig_sfp_tables.h
+INCSDIR= ${INCLUDEDIR}
+INCS= libifconfig.h libifconfig_sfp.h libifconfig_sfp_tables.h
+# Uncomment this line if libifconfig becomes public.
#MAN= libifconfig.3
CFLAGS+= -I${.CURDIR} -I${.OBJDIR}
diff --git a/rescue/rescue/Makefile b/rescue/rescue/Makefile
--- a/rescue/rescue/Makefile
+++ b/rescue/rescue/Makefile
@@ -223,7 +223,7 @@
CRUNCH_ALIAS_chown= chgrp
##################################################################
-CRUNCH_LIBS+= ${OBJTOP}/lib/libifconfig/libifconfig.a
+CRUNCH_LIBS+= ${LDADD_ifconfig}
CRUNCH_BUILDOPTS+= CRUNCH_CFLAGS+=-I${OBJTOP}/lib/libifconfig
CRUNCH_LIBS+= -lm
diff --git a/share/examples/Makefile b/share/examples/Makefile
--- a/share/examples/Makefile
+++ b/share/examples/Makefile
@@ -100,7 +100,7 @@
find_interface.c
SE_DIRS+= flua
-SE_FLUA= libjail.lua
+SE_FLUA= libjail.lua libifconfig.lua
SE_DIRS+= indent
SE_INDENT= indent.pro
diff --git a/share/examples/flua/libifconfig.lua b/share/examples/flua/libifconfig.lua
new file mode 100755
--- /dev/null
+++ b/share/examples/flua/libifconfig.lua
@@ -0,0 +1,69 @@
+#!/usr/libexec/flua
+--[[
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * 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 REGENTS 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 REGENTS 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$
+ */
+]]--
+-- ex: et sw=4:
+
+local ifcfg = require('ifconfig').open()
+
+local ifaces = ifcfg:foreach_iface(function(_, iface, ifs)
+ local name = iface:name()
+ ifs[name] = {
+ flags = iface:flags(),
+ media = ifcfg:get_media(name),
+ status = ifcfg:get_status(name),
+ capabilities = ifcfg:get_capabilities(name),
+ groups = ifcfg:get_groups(name),
+ metric = ifcfg:get_metric(name),
+ mtu = ifcfg:get_mtu(name),
+ nd6 = ifcfg:get_nd6(name),
+ bridge_status = ifcfg:get_bridge_status(name),
+ lagg_status = ifcfg:get_lagg_status(name),
+ laggdev = ifcfg:get_laggport_laggdev(name),
+ addresses = ifcfg:foreach_ifaddr(iface, function(_, addr, addrs)
+ table.insert(addrs, ifcfg:addr_info(addr))
+ return addrs
+ end, {}),
+ sfp = (function()
+ local info = ifcfg:get_sfp_info(name)
+ return info and {
+ info = info,
+ vendor_info = ifcfg:get_sfp_vendor_info(name),
+ status = ifcfg:get_sfp_status(name),
+ -- Not generally interesting,
+ -- but for completeness:
+ -- dump = tostring(ifcfg:get_sfp_dump(name)),
+ }
+ end)(),
+ }
+ return ifs
+end, {})
+
+print(ucl.to_json(ifaces))
diff --git a/share/man/man3lua/intro.3lua b/share/man/man3lua/intro.3lua
--- a/share/man/man3lua/intro.3lua
+++ b/share/man/man3lua/intro.3lua
@@ -51,11 +51,15 @@
.Fx
are:
.Bl -tag -width jail
+.It Xr ifconfig 3lua
+Wrapper for
+.Xr ifconfig 3 .
.It Xr jail 3lua
Wrapper for
.Xr jail 3 .
.El
.Sh SEE ALSO
+.Xr ifconfig 3lua
.Xr jail 3lua
.Sh AUTHORS
.An Ryan Moeller ,
diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk
--- a/share/mk/src.libnames.mk
+++ b/share/mk/src.libnames.mk
@@ -25,6 +25,7 @@
gtest_main \
heimipcc \
heimipcs \
+ ifconfig \
ldns \
sqlite3 \
ssh \
@@ -39,7 +40,6 @@
cron \
elftc \
fifolog \
- ifconfig \
ipf \
kyua_cli \
kyua_drivers \
@@ -540,9 +540,6 @@
LIBSLDIR= ${_LIB_OBJTOP}/kerberos5/lib/libsl
LIBSL?= ${LIBSLDIR}/libsl${PIE_SUFFIX}.a
-LIBIFCONFIGDIR= ${_LIB_OBJTOP}/lib/libifconfig
-LIBIFCONFIG?= ${LIBIFCONFIGDIR}/libifconfig${PIE_SUFFIX}.a
-
LIBIPFDIR= ${_LIB_OBJTOP}/sbin/ipf/libipf
LIBIPF?= ${LIBIPFDIR}/libipf${PIE_SUFFIX}.a

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 28, 1:42 AM (4 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26252271
Default Alt Text
D25447.id85187.diff (71 KB)

Event Timeline