Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137903899
D25447.id85187.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
71 KB
Referenced Files
None
Subscribers
None
D25447.id85187.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D25447: lib/flua: Add bindings for libifconfig
Attached
Detach File
Event Timeline
Log In to Comment