mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-29 20:23:01 +02:00
Merge branch 'sysrepo'
This commit is contained in:
+1
-2
@@ -1,4 +1,3 @@
|
||||
[submodule "buildroot"]
|
||||
path = buildroot
|
||||
url = https://github.com/buildroot/buildroot.git
|
||||
branch = 2023.02.x
|
||||
url = ../buildroot.git
|
||||
|
||||
@@ -141,7 +141,6 @@ CONFIG_MTD_SPI_NOR=y
|
||||
CONFIG_OF_OVERLAY=y
|
||||
CONFIG_BLK_DEV_NULL_BLK=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_NBD=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_BLK_DEV_NVME=y
|
||||
|
||||
@@ -95,7 +95,6 @@ CONFIG_FW_CFG_SYSFS=y
|
||||
CONFIG_FW_CFG_SYSFS_CMDLINE=y
|
||||
CONFIG_BLK_DEV_NULL_BLK=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_NBD=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
|
||||
@@ -16,4 +16,4 @@ alias ipaddr='ip addr'
|
||||
alias iplink='ip link'
|
||||
alias bridge='bridge --color=auto'
|
||||
alias setup='pdmenu; clear'
|
||||
alias cli='clixon_cli'
|
||||
alias cli='klish'
|
||||
|
||||
+1
-1
Submodule buildroot updated: 8cca1e6de1...588141749e
@@ -48,6 +48,7 @@ BR2_PACKAGE_UBOOT_TOOLS_FIT_SUPPORT=y
|
||||
BR2_PACKAGE_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
|
||||
BR2_PACKAGE_UBOOT_TOOLS_FIT_CHECK_SIGN=y
|
||||
BR2_PACKAGE_LIBCURL_CURL=y
|
||||
BR2_PACKAGE_NETOPEER2_CLI=y
|
||||
BR2_PACKAGE_NSS_MDNS=y
|
||||
BR2_PACKAGE_ONIGURUMA=y
|
||||
BR2_PACKAGE_AVAHI=y
|
||||
@@ -74,10 +75,6 @@ BR2_PACKAGE_NETCALC=y
|
||||
BR2_PACKAGE_NETCAT_OPENBSD=y
|
||||
BR2_PACKAGE_NETSNMP=y
|
||||
BR2_PACKAGE_NFTABLES=y
|
||||
BR2_PACKAGE_NGINX_HTTP_SSL_MODULE=y
|
||||
BR2_PACKAGE_NGINX_HTTP_V2_MODULE=y
|
||||
BR2_PACKAGE_NGINX_HTTP_GUNZIP_MODULE=y
|
||||
BR2_PACKAGE_NGINX_HTTP_AUTH_REQUEST_MODULE=y
|
||||
BR2_PACKAGE_NMAP=y
|
||||
BR2_PACKAGE_NMAP_NCAT=y
|
||||
BR2_PACKAGE_NMAP_NMAP=y
|
||||
@@ -102,7 +99,6 @@ BR2_PACKAGE_PWGEN=y
|
||||
BR2_PACKAGE_RAUC=y
|
||||
BR2_PACKAGE_RAUC_GPT=y
|
||||
BR2_PACKAGE_RAUC_NETWORK=y
|
||||
BR2_PACKAGE_RAUC_STREAMING=y
|
||||
BR2_PACKAGE_SYSKLOGD=y
|
||||
BR2_PACKAGE_SYSKLOGD_LOGGER=y
|
||||
BR2_PACKAGE_WATCHDOGD=y
|
||||
@@ -119,7 +115,7 @@ BR2_PACKAGE_HOST_RAUC=y
|
||||
BR2_PACKAGE_HOST_UBOOT_TOOLS=y
|
||||
BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT=y
|
||||
BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
|
||||
BR2_PACKAGE_CLIXON_RESTCONF_FCGI=y
|
||||
BR2_PACKAGE_CONFD=y
|
||||
BR2_PACKAGE_FACTORY=y
|
||||
BR2_PACKAGE_FINIT_SULOGIN=y
|
||||
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
|
||||
@@ -130,7 +126,7 @@ BR2_PACKAGE_FINIT_PLUGIN_RTC=y
|
||||
BR2_PACKAGE_FINIT_PLUGIN_TTY=y
|
||||
BR2_PACKAGE_FINIT_PLUGIN_URANDOM=y
|
||||
BR2_PACKAGE_IFUPDOWN_NG=y
|
||||
BR2_PACKAGE_MECH=y
|
||||
BR2_PACKAGE_KLINFIX=y
|
||||
BR2_PACKAGE_P_NET=y
|
||||
BR2_PACKAGE_P_NET_MAX_SUBSLOTS=12
|
||||
BR2_PACKAGE_P_NET_MAX_PHYSICAL_PORTS=10
|
||||
|
||||
@@ -45,6 +45,7 @@ BR2_PACKAGE_UBOOT_TOOLS_FIT_SUPPORT=y
|
||||
BR2_PACKAGE_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
|
||||
BR2_PACKAGE_UBOOT_TOOLS_FIT_CHECK_SIGN=y
|
||||
BR2_PACKAGE_LIBCURL_CURL=y
|
||||
BR2_PACKAGE_NETOPEER2_CLI=y
|
||||
BR2_PACKAGE_NSS_MDNS=y
|
||||
BR2_PACKAGE_ONIGURUMA=y
|
||||
BR2_PACKAGE_AVAHI=y
|
||||
@@ -71,10 +72,6 @@ BR2_PACKAGE_NETCALC=y
|
||||
BR2_PACKAGE_NETCAT_OPENBSD=y
|
||||
BR2_PACKAGE_NETSNMP=y
|
||||
BR2_PACKAGE_NFTABLES=y
|
||||
BR2_PACKAGE_NGINX_HTTP_SSL_MODULE=y
|
||||
BR2_PACKAGE_NGINX_HTTP_V2_MODULE=y
|
||||
BR2_PACKAGE_NGINX_HTTP_GUNZIP_MODULE=y
|
||||
BR2_PACKAGE_NGINX_HTTP_AUTH_REQUEST_MODULE=y
|
||||
BR2_PACKAGE_NMAP=y
|
||||
BR2_PACKAGE_NMAP_NCAT=y
|
||||
BR2_PACKAGE_NMAP_NMAP=y
|
||||
@@ -99,7 +96,6 @@ BR2_PACKAGE_PWGEN=y
|
||||
BR2_PACKAGE_RAUC=y
|
||||
BR2_PACKAGE_RAUC_GPT=y
|
||||
BR2_PACKAGE_RAUC_NETWORK=y
|
||||
BR2_PACKAGE_RAUC_STREAMING=y
|
||||
BR2_PACKAGE_SYSKLOGD=y
|
||||
BR2_PACKAGE_SYSKLOGD_LOGGER=y
|
||||
BR2_PACKAGE_WATCHDOGD=y
|
||||
@@ -114,15 +110,17 @@ BR2_TARGET_GRUB2_X86_64_EFI=y
|
||||
BR2_TARGET_GRUB2_BUILTIN_MODULES_EFI="boot linux ext2 fat squash4 part_gpt normal efi_gop configfile loadenv test terminfo terminal echo"
|
||||
BR2_TARGET_GRUB2_BUILTIN_CONFIG_EFI="${BR2_EXTERNAL_INFIX_PATH}/board/amd64/grub-embed.cfg"
|
||||
BR2_TARGET_GRUB2_INSTALL_TOOLS=y
|
||||
BR2_PACKAGE_HOST_DOSFSTOOLS=y
|
||||
BR2_PACKAGE_HOST_E2FSPROGS=y
|
||||
BR2_PACKAGE_HOST_ENVIRONMENT_SETUP=y
|
||||
BR2_PACKAGE_HOST_GENEXT2FS=y
|
||||
BR2_PACKAGE_HOST_GENIMAGE=y
|
||||
BR2_PACKAGE_HOST_MTOOLS=y
|
||||
BR2_PACKAGE_HOST_RAUC=y
|
||||
BR2_PACKAGE_HOST_UBOOT_TOOLS=y
|
||||
BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT=y
|
||||
BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
|
||||
BR2_PACKAGE_CLIXON_RESTCONF_FCGI=y
|
||||
BR2_PACKAGE_CONFD=y
|
||||
BR2_PACKAGE_FACTORY=y
|
||||
BR2_PACKAGE_FINIT_SULOGIN=y
|
||||
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
|
||||
@@ -133,7 +131,7 @@ BR2_PACKAGE_FINIT_PLUGIN_RTC=y
|
||||
BR2_PACKAGE_FINIT_PLUGIN_TTY=y
|
||||
BR2_PACKAGE_FINIT_PLUGIN_URANDOM=y
|
||||
BR2_PACKAGE_IFUPDOWN_NG=y
|
||||
BR2_PACKAGE_MECH=y
|
||||
BR2_PACKAGE_KLINFIX=y
|
||||
BR2_PACKAGE_P_NET=y
|
||||
BR2_PACKAGE_P_NET_MAX_SUBSLOTS=12
|
||||
BR2_PACKAGE_P_NET_MAX_PHYSICAL_PORTS=10
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/cligen/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/clixon/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/confd/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/factory/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/faux/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/finit/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/ifupdown2/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/ifupdown-ng/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/klinfix/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/klish/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/klish-plugin-sysrepo/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/mdnsd/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/mech/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/osal/Config.in"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
config BR2_PACKAGE_CONFD
|
||||
bool "confd"
|
||||
select BR2_PACKAGE_SYSREPO
|
||||
select BR2_PACKAGE_NETOPEER2
|
||||
select BR2_PACKAGE_AUGEAS
|
||||
select BR2_PACKAGE_JANSSON
|
||||
help
|
||||
A plugin to sysrepo that provides the core YANG models used to
|
||||
manage an Infix based system. Configuration can be done using
|
||||
either the on-system CLI or using NETCONF.
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This is an unmanaged node, leave /etc as-is
|
||||
/lib/infix/use-etc && exit 0
|
||||
|
||||
# This is a managed node, ignore all default configuration ...
|
||||
# ... except for some core services
|
||||
reserved()
|
||||
{
|
||||
for svc in dnsmasq getty klish lldpd nginx sysklogd sysrepo; do
|
||||
[ "$1" = "${svc}.conf" ] && return 0
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
for file in /etc/finit.d/enabled/*.conf; do
|
||||
reserved "$(basename "$file")" && continue
|
||||
rm "$file"
|
||||
done
|
||||
@@ -0,0 +1,26 @@
|
||||
################################################################################
|
||||
#
|
||||
# confd
|
||||
#
|
||||
################################################################################
|
||||
|
||||
CONFD_VERSION = 1.0
|
||||
CONFD_LICENSE = BSD-3-Clause
|
||||
CONFD_SITE_METHOD = local
|
||||
CONFD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/confd
|
||||
CONFD_DEPENDENCIES = augeas sysrepo
|
||||
CONFD_AUTORECONF = YES
|
||||
|
||||
define CONFD_INSTALL_EXTRA
|
||||
cp $(CONFD_PKGDIR)/sysrepo.conf $(FINIT_D)/available/
|
||||
ln -sf ../available/sysrepo.conf $(FINIT_D)/enabled/sysrepo.conf
|
||||
cp $(CONFD_PKGDIR)/tmpfiles.conf $(TARGET_DIR)/etc/tmpfiles.d/confd.conf
|
||||
mkdir -p $(TARGET_DIR)/usr/share/factory/cfg
|
||||
cp $(CONFD_PKGDIR)/factory.cfg $(TARGET_DIR)/usr/share/factory/cfg/startup-config.cfg
|
||||
mkdir -p $(TARGET_DIR)/lib/infix
|
||||
cp $(CONFD_PKGDIR)/prep-db $(TARGET_DIR)/lib/infix/
|
||||
cp $(CONFD_PKGDIR)/clean-etc $(TARGET_DIR)/lib/infix/
|
||||
endef
|
||||
CONFD_TARGET_FINALIZE_HOOKS += CONFD_INSTALL_EXTRA
|
||||
|
||||
$(eval $(autotools-package))
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ietf-system:system": {
|
||||
"hostname": "default"
|
||||
}
|
||||
}
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,8 @@
|
||||
run if:<boot/netconf> [S] /lib/infix/clean-etc --
|
||||
run if:<boot/netconf> [S] /lib/infix/prep-db --
|
||||
|
||||
service if:<boot/netconf> name:sysrepo [S12345789] sysrepo-plugind -p /run/sysrepo.pid -n -- Configuration daemon
|
||||
run if:<boot/netconf> [S] log <pid/sysrepo> sysrepocfg -v4 -E/cfg/startup-config.cfg -f json --
|
||||
service if:<boot/netconf> name:netopeer [12345789] netopeer2-server -n -- NETCONF daemon
|
||||
|
||||
task if:<boot/netconf> [12345789] resolvconf -u -- Update DNS configuration
|
||||
@@ -0,0 +1,2 @@
|
||||
d /run/resolvconf/interfaces - - -
|
||||
C /cfg/startup-config.cfg - - -
|
||||
@@ -0,0 +1,7 @@
|
||||
config BR2_PACKAGE_FAUX
|
||||
bool "faux"
|
||||
depends on BR2_USE_MMU
|
||||
help
|
||||
The library contains a set of auxiliary functions.
|
||||
|
||||
https://src.libcode.org/pkun/faux/
|
||||
@@ -0,0 +1,3 @@
|
||||
# Locally calculated
|
||||
sha256 9d9d33b873917ca5d0bdcc47a36d2fd385971ab0c045d1472fcadf95ee5bcf5b LICENCE
|
||||
sha256 8e369f54c2da317030ff4cad905e501303d0489b98e4b208d0ff611b4484c94e faux-tags_2.1.0-br1.tar.gz
|
||||
@@ -0,0 +1,15 @@
|
||||
################################################################################
|
||||
#
|
||||
# faux
|
||||
#
|
||||
################################################################################
|
||||
|
||||
FAUX_VERSION = tags/2.1.0
|
||||
FAUX_SITE = https://src.libcode.org/pkun/faux.git
|
||||
FAUX_SITE_METHOD = git
|
||||
FAUX_LICENSE = BSD-3
|
||||
FAUX_LICENSE_FILES = LICENSE
|
||||
FAUX_INSTALL_STAGING = YES
|
||||
FAUX_AUTORECONF = YES
|
||||
|
||||
$(eval $(autotools-package))
|
||||
@@ -150,6 +150,28 @@ config BR2_PACKAGE_FINIT_PLUGIN_RTC
|
||||
|
||||
For lxc/docker application builds you do not need this.
|
||||
|
||||
if BR2_PACKAGE_FINIT_PLUGIN_RTC
|
||||
|
||||
config BR2_PACKAGE_FINIT_RTC_DATE
|
||||
string "Fallback RTC date"
|
||||
help
|
||||
On many embedded systems there is no RTC battery, maybe there
|
||||
is a "supercap" but on first boot it is usually out of juice.
|
||||
When this happens the RTC will return its default value, or
|
||||
the driver will fail and report error. In these cases Linux
|
||||
will detect a too old/invalid date set from userspace. Any
|
||||
date prior to 2000-01-01 00:00 is denied. (Previously this
|
||||
was the start of the UNIX epoch, Jan 1 1970.)
|
||||
|
||||
This setting changes the default fallback date/time the RTC
|
||||
plugin uses in case of such failures. Useful, e.g., for an
|
||||
HTTPS certificate generated at first boot before any network
|
||||
connection (DHCP/NTP) has been made to get the current time.
|
||||
Ensuring the default system time to be closer to actual time
|
||||
for a period after releasing a firmware image.
|
||||
|
||||
endif
|
||||
|
||||
config BR2_PACKAGE_FINIT_PLUGIN_TTY
|
||||
bool "TTY plugin"
|
||||
help
|
||||
|
||||
@@ -89,6 +89,12 @@ else
|
||||
FINIT_CONF_OPTS += --disable-rtc-plugin
|
||||
endif
|
||||
|
||||
ifeq ($(BR2_PACKAGE_FINIT_RTC_DATE),y)
|
||||
FINIT_CONF_OPTS += --with-rtc-date="$(BR2_PACKAGE_FINIT_RTC_DATE)"
|
||||
else
|
||||
FINIT_CONF_OPTS += --without-rtc-date
|
||||
endif
|
||||
|
||||
ifeq ($(BR2_PACKAGE_FINIT_PLUGIN_TTY),y)
|
||||
FINIT_CONF_OPTS += --enable-tty-plugin
|
||||
else
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
config BR2_PACKAGE_KLINFIX
|
||||
bool "klinfix"
|
||||
select BR2_PACKAGE_KLISH
|
||||
select BR2_PACKAGE_KLISH_PLUGIN_SYSREPO
|
||||
select BR2_PACKAGE_SYSREPO
|
||||
help
|
||||
A plugin to klish with an opinionated config and some
|
||||
command extensions, suitable for systems running Infix.
|
||||
@@ -0,0 +1,14 @@
|
||||
################################################################################
|
||||
#
|
||||
# klinfix
|
||||
#
|
||||
################################################################################
|
||||
|
||||
KLINFIX_VERSION = 1.0
|
||||
KLINFIX_LICENSE = BSD-3-Clause
|
||||
KLINFIX_SITE_METHOD = local
|
||||
KLINFIX_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/klinfix
|
||||
KLINFIX_DEPENDENCIES = klish-plugin-sysrepo
|
||||
KLINFIX_AUTORECONF = YES
|
||||
|
||||
$(eval $(autotools-package))
|
||||
@@ -0,0 +1,22 @@
|
||||
config BR2_PACKAGE_KLISH_PLUGIN_SYSREPO
|
||||
bool "klish-plugin-sysrepo"
|
||||
depends on BR2_PACKAGE_KLISH
|
||||
depends on BR2_PACKAGE_SYSREPO
|
||||
help
|
||||
This plugin allows klish framework to implement Juniper-like
|
||||
interface for configuration. It uses sysrepo project as
|
||||
background for datastores and libyang for yang files parsing
|
||||
and configuration schemes.
|
||||
|
||||
https://src.libcode.org/pkun/klish-plugin-sysrepo/
|
||||
|
||||
config BR2_PACKAGE_KLISH_PLUGIN_SYSREPO_XML
|
||||
bool "install xml"
|
||||
depends on BR2_PACKAGE_KLISH_PLUGIN_SYSREPO
|
||||
depends on !BR2_PACKAGE_KLINFIX
|
||||
default y
|
||||
help
|
||||
Install the default XML spec bundled with the project, which
|
||||
exports the 'show' command, and the 'configure' view, etc.
|
||||
|
||||
If unsure, say Y.
|
||||
@@ -0,0 +1,4 @@
|
||||
# Locally calculated
|
||||
sha256 9d9d33b873917ca5d0bdcc47a36d2fd385971ab0c045d1472fcadf95ee5bcf5b LICENCE
|
||||
sha256 515fa2a3c66b41d6ab5ec93d61cdd32097115b2f46e39c522659b84d555eebf5 klish-plugin-sysrepo-cdd3eb51a7f7ee0ed5bd925fa636061d3b1b85fb-br1.tar.gz
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
################################################################################
|
||||
#
|
||||
# klish-plugin-sysrepo
|
||||
#
|
||||
################################################################################
|
||||
|
||||
KLISH_PLUGIN_SYSREPO_VERSION = cdd3eb51a7f7ee0ed5bd925fa636061d3b1b85fb
|
||||
KLISH_PLUGIN_SYSREPO_SITE = https://src.libcode.org/pkun/klish-plugin-sysrepo.git
|
||||
KLISH_PLUGIN_SYSREPO_SITE_METHOD = git
|
||||
KLISH_PLUGIN_SYSREPO_LICENSE = BSD-3
|
||||
KLISH_PLUGIN_SYSREPO_LICENSE_FILES = LICENSE
|
||||
KLISH_PLUGIN_SYSREPO_DEPENDENCIES = klish sysrepo
|
||||
KLISH_PLUGIN_SYSREPO_INSTALL_STAGING = YES
|
||||
KLISH_PLUGIN_SYSREPO_AUTORECONF = YES
|
||||
|
||||
ifeq ($(BR2_PACKAGE_KLISH_PLUGIN_SYSREPO_XML),y)
|
||||
define KLISH_PLUGIN_SYSREPO_INSTALL_XML
|
||||
$(INSTALL) -t $(TARGET_DIR)/etc/klish -D -m 0644 \
|
||||
$(@D)/xml/sysrepo.xml
|
||||
endef
|
||||
KLISH_PLUGIN_SYSREPO_POST_INSTALL_TARGET_HOOKS += \
|
||||
KLISH_PLUGIN_SYSREPO_INSTALL_XML
|
||||
endif
|
||||
|
||||
$(eval $(autotools-package))
|
||||
@@ -0,0 +1,22 @@
|
||||
config BR2_PACKAGE_KLISH
|
||||
bool "klish"
|
||||
depends on BR2_USE_MMU
|
||||
select BR2_PACKAGE_FAUX
|
||||
select BR2_PACKAGE_LIBXML2
|
||||
help
|
||||
Klish is a framework for implementing a CISCO-like or
|
||||
Juniper-like CLI on a UNIX systems.
|
||||
|
||||
https://src.libcode.org/pkun/klish/
|
||||
|
||||
config BR2_PACKAGE_KLISH_DEFAULT_XML
|
||||
bool "install xml"
|
||||
depends on BR2_PACKAGE_KLISH
|
||||
depends on !BR2_PACKAGE_KLINFIX
|
||||
default y
|
||||
help
|
||||
Install a small XML spec containing a definition of an
|
||||
'exit' command. This lets klish work out-of-the-box, even if
|
||||
no other specs are available.
|
||||
|
||||
If unsure, say Y.
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<KLISH
|
||||
xmlns="https://klish.libcode.org/klish3"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://src.libcode.org/pkun/klish/src/master/klish.xsd">
|
||||
|
||||
<PLUGIN name="klish"/>
|
||||
|
||||
<ENTRY name="COMMAND" purpose="ptype">
|
||||
<ENTRY name="completion" purpose="completion">
|
||||
<ACTION sym="completion_COMMAND"/>
|
||||
</ENTRY>
|
||||
<ENTRY name="help" purpose="help">
|
||||
<ACTION sym="completion_COMMAND"/>
|
||||
</ENTRY>
|
||||
<ACTION sym="COMMAND"/>
|
||||
</ENTRY>
|
||||
|
||||
<ENTRY name="main" mode="switch" container="true">
|
||||
|
||||
<ENTRY name="prompt" purpose="prompt">
|
||||
<ACTION sym="prompt">%u@%h> </ACTION>
|
||||
</ENTRY>
|
||||
|
||||
<ENTRY name="exit" help="Exit view">
|
||||
<ENTRY name="COMMAND" purpose="ptype" ref="/COMMAND"/>
|
||||
<ACTION sym="nav">pop</ACTION>
|
||||
<ACTION sym="printl">Exiting klish session</ACTION>
|
||||
</ENTRY>
|
||||
|
||||
<HOTKEY key="^Z" cmd="exit"/>
|
||||
|
||||
</ENTRY>
|
||||
|
||||
</KLISH>
|
||||
@@ -0,0 +1,3 @@
|
||||
# Locally calculated
|
||||
sha256 9d9d33b873917ca5d0bdcc47a36d2fd385971ab0c045d1472fcadf95ee5bcf5b LICENCE
|
||||
sha256 e7c09457ed0b030eddd8eaf7d9f7c9344c2fcd7ac2083f1d8ebeaafc4ed6dba6 klish-tags_3.0.0-br1.tar.gz
|
||||
@@ -0,0 +1,46 @@
|
||||
################################################################################
|
||||
#
|
||||
# klish
|
||||
#
|
||||
################################################################################
|
||||
|
||||
KLISH_VERSION = tags/3.0.0
|
||||
KLISH_SITE = https://src.libcode.org/pkun/klish.git
|
||||
KLISH_SITE_METHOD = git
|
||||
KLISH_LICENSE = BSD-3
|
||||
KLISH_LICENSE_FILES = LICENSE
|
||||
KLISH_DEPENDENCIES = libxml2
|
||||
KLISH_INSTALL_STAGING = YES
|
||||
KLISH_AUTORECONF = YES
|
||||
|
||||
KLISH_CONF_OPTS += --with-libxml2
|
||||
|
||||
define KLISH_INSTALL_CONFIG
|
||||
$(INSTALL) -t $(TARGET_DIR)/etc/klish -D -m 0644 \
|
||||
$(@D)/klish.conf $(@D)/klishd.conf
|
||||
|
||||
# klish's default pager settings assumes that less understands
|
||||
# all GNU options, so we disable it.
|
||||
sed -i -e 's/#UsePager=y/UsePager=n/' \
|
||||
$(TARGET_DIR)/etc/klish/klish.conf
|
||||
endef
|
||||
KLISH_POST_INSTALL_TARGET_HOOKS += KLISH_INSTALL_CONFIG
|
||||
|
||||
ifeq ($(BR2_PACKAGE_KLISH_DEFAULT_XML),y)
|
||||
define KLISH_INSTALL_XML
|
||||
$(INSTALL) -t $(TARGET_DIR)/etc/klish -D -m 0644 \
|
||||
$(BR2_EXTERNAL_INFIX_PATH)/package/klish/default.xml
|
||||
endef
|
||||
KLISH_POST_INSTALL_TARGET_HOOKS += KLISH_INSTALL_XML
|
||||
endif
|
||||
|
||||
define KLISH_INSTALL_FINIT_SVC
|
||||
$(INSTALL) -D -m 0644 $(BR2_EXTERNAL_INFIX_PATH)/package/klish/klish.svc \
|
||||
$(FINIT_D)/available/klish.conf
|
||||
$(INSTALL) -d -m 0755 $(FINIT_D)/enabled
|
||||
ln -sf ../available/klish.conf $(FINIT_D)/enabled/klish.conf
|
||||
endef
|
||||
|
||||
KLISH_POST_INSTALL_TARGET_HOOKS += KLISH_INSTALL_FINIT_SVC
|
||||
|
||||
$(eval $(autotools-package))
|
||||
@@ -0,0 +1 @@
|
||||
service <!> [2345789] /usr/bin/klishd -d -- CLI backend
|
||||
@@ -15,6 +15,9 @@ define MECH_INSTALL_EXTRA
|
||||
cp $(MECH_PKGDIR)/clixon.conf $(FINIT_D)/available/
|
||||
ln -sf ../available/clixon.conf $(FINIT_D)/enabled/clixon.conf
|
||||
cp $(MECH_PKGDIR)/tmpfiles.conf $(TARGET_DIR)/etc/tmpfiles.d/mech.conf
|
||||
mkdir -p $(TARGET_DIR)/lib/infix
|
||||
cp $(MECH_PKGDIR)/prep-db $(TARGET_DIR)/lib/infix/
|
||||
cp $(MECH_PKGDIR)/clean-etc $(TARGET_DIR)/lib/infix/
|
||||
endef
|
||||
MECH_TARGET_FINALIZE_HOOKS += MECH_INSTALL_EXTRA
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ define SYSREPO_PLUGIN_SYSTEM_INSTALL_YANG_MODELS
|
||||
$(TARGET_DIR)/usr/share/yang/modules/sysrepo-plugin-system/iana-crypt-hash@2014-08-06.yang
|
||||
$(INSTALL) -D -m 0644 $(@D)/yang/ietf-system@2014-08-06.yang \
|
||||
$(TARGET_DIR)/usr/share/yang/modules/sysrepo-plugin-system/ietf-system@2014-08-06.yang
|
||||
$(INSTALL) -D -m 0644 $(@D)/yang/infix-system@2014-08-06.yang \
|
||||
$(TARGET_DIR)/usr/share/yang/modules/sysrepo-plugin-system/infix-system@2014-08-06.yang
|
||||
endef
|
||||
SYSREPO_PLUGIN_SYSTEM_POST_INSTALL_TARGET_HOOKS += SYSREPO_PLUGIN_SYSTEM_INSTALL_YANG_MODELS
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
commit 9e18bd10df1ac2aabd46a790ac6148c638a513b8
|
||||
Author: Joachim Wiberg <troglobit@gmail.com>
|
||||
Date: Fri Mar 31 10:44:32 2023 +0200
|
||||
|
||||
netopeer2-server: add support for running in foreground with syslog
|
||||
|
||||
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
|
||||
|
||||
diff --git a/src/main.c b/src/main.c
|
||||
index 6d054f5..c403000 100644
|
||||
--- a/src/main.c
|
||||
+++ b/src/main.c
|
||||
@@ -1082,6 +1082,7 @@ print_usage(char *progname)
|
||||
fprintf(stdout, " -f PATH Path to netopeer2 server files directory (default path is \"%s\")\n", SERVER_DIR);
|
||||
fprintf(stdout, " -U[PATH] Listen on a local UNIX socket (default path is \"%s\").\n", NP2SRV_UNIX_SOCK_PATH);
|
||||
fprintf(stdout, " -m MODE Set mode for the listening UNIX socket.\n");
|
||||
+ fprintf(stdout, " -n Run in foreground and log to syslog.\n");
|
||||
fprintf(stdout, " -u UID Set UID/user for the listening UNIX socket.\n");
|
||||
fprintf(stdout, " -g GID Set GID/group for the listening UNIX socket.\n");
|
||||
fprintf(stdout, " -t TIMEOUT Timeout in seconds of all sysrepo functions (applying edit-config, reading data, ...),\n");
|
||||
@@ -1112,7 +1113,7 @@ main(int argc, char *argv[])
|
||||
{
|
||||
int ret = EXIT_SUCCESS;
|
||||
int c, *idx, i;
|
||||
- int daemonize = 1, verb = 0;
|
||||
+ int daemonize = 1, verb = 0, use_syslog = 0;
|
||||
int pidfd;
|
||||
const char *pidfile = NP2SRV_PID_FILE_PATH;
|
||||
char pid[8];
|
||||
@@ -1145,7 +1146,7 @@ main(int argc, char *argv[])
|
||||
np2srv.server_dir = SERVER_DIR;
|
||||
|
||||
/* process command line options */
|
||||
- while ((c = getopt(argc, argv, "dhVp:f:U::m:u:g:t:x:v:c:")) != -1) {
|
||||
+ while ((c = getopt(argc, argv, "dhVp:f:U::m:nu:g:t:x:v:c:")) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
daemonize = 0;
|
||||
@@ -1202,6 +1203,10 @@ main(int argc, char *argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
+ case 'n':
|
||||
+ daemonize = 0;
|
||||
+ use_syslog = 1;
|
||||
+ break;
|
||||
case 'u':
|
||||
np2srv.unix_uid = strtoul(optarg, &ptr, 10);
|
||||
if (*ptr) {
|
||||
@@ -1306,6 +1311,10 @@ main(int argc, char *argv[])
|
||||
np2_stderr_log = 0;
|
||||
}
|
||||
|
||||
+ /* use syslog even if running in foreground */
|
||||
+ if (use_syslog == 1)
|
||||
+ np2_stderr_log = 0;
|
||||
+
|
||||
/* make sure we are the only instance - lock the PID file and write the PID */
|
||||
pidfd = open(pidfile, O_RDWR | O_CREAT, 0640);
|
||||
if (pidfd < 0) {
|
||||
@@ -0,0 +1,64 @@
|
||||
commit 6fc440089353d76a9b8cb7c480402ee911a1387d
|
||||
Author: Joachim Wiberg <troglobit@gmail.com>
|
||||
Date: Tue Mar 28 10:37:53 2023 +0200
|
||||
|
||||
sysrepo-plugind: add support for running in foreground with syslog
|
||||
|
||||
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
|
||||
|
||||
diff --git a/src/executables/sysrepo-plugind.c b/src/executables/sysrepo-plugind.c
|
||||
index bd584ed5..3079a855 100644
|
||||
--- a/src/executables/sysrepo-plugind.c
|
||||
+++ b/src/executables/sysrepo-plugind.c
|
||||
@@ -97,6 +97,7 @@ help_print(void)
|
||||
" Change verbosity to a level (none, error, warning, info, debug) or\n"
|
||||
" number (0, 1, 2, 3, 4).\n"
|
||||
" -d, --debug Debug mode - is not daemonized and logs to stderr instead of syslog.\n"
|
||||
+ " -n, --foreground Run in foreground and log to syslog.\n"
|
||||
" -P, --plugin-install <path>\n"
|
||||
" Install a sysrepo-plugind plugin. The plugin is simply copied\n"
|
||||
" to the designated plugin directory.\n"
|
||||
@@ -200,6 +201,8 @@ daemon_init(int debug, sr_log_level_t log_level)
|
||||
|
||||
if (debug) {
|
||||
handle_signals();
|
||||
+ if (debug < 0)
|
||||
+ goto done;
|
||||
sr_log_stderr(log_level);
|
||||
return;
|
||||
}
|
||||
@@ -240,6 +243,7 @@ daemon_init(int debug, sr_log_level_t log_level)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
+done:
|
||||
/* set verbosity */
|
||||
sr_log_syslog("sysrepo-plugind", log_level);
|
||||
}
|
||||
@@ -459,6 +463,7 @@ main(int argc, char **argv)
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
{"verbosity", required_argument, NULL, 'v'},
|
||||
{"debug", no_argument, NULL, 'd'},
|
||||
+ {"foreground", no_argument, NULL, 'n'},
|
||||
{"plugin-install", required_argument, NULL, 'P'},
|
||||
{"pid-file", required_argument, NULL, 'p'},
|
||||
{"fatal-plugin-fail", no_argument, NULL, 'f'},
|
||||
@@ -467,7 +472,7 @@ main(int argc, char **argv)
|
||||
|
||||
/* process options */
|
||||
opterr = 0;
|
||||
- while ((opt = getopt_long(argc, argv, "hVv:dP:p:f", options, NULL)) != -1) {
|
||||
+ while ((opt = getopt_long(argc, argv, "hVv:dnP:p:f", options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
version_print();
|
||||
@@ -499,6 +504,9 @@ main(int argc, char **argv)
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
+ case 'n':
|
||||
+ debug = -1;
|
||||
+ break;
|
||||
case 'P':
|
||||
/* plugin-install */
|
||||
if (get_plugins_dir(&plugins_dir)) {
|
||||
@@ -0,0 +1,33 @@
|
||||
*~
|
||||
*.o
|
||||
*.la
|
||||
*.lo
|
||||
*.so
|
||||
.deps
|
||||
.libs
|
||||
|
||||
/aclocal.m4
|
||||
/autom4te.cache/
|
||||
/aux
|
||||
/clixon.xml
|
||||
/compile
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.guess
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/depcomp
|
||||
/install-sh
|
||||
/libtool
|
||||
/ltmain.sh
|
||||
/m4
|
||||
/missing
|
||||
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
Copyright (c) 2020 Denis Kalashnikov
|
||||
Copyright (c) 2023 The KernelKit Authors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
SUBDIRS = src yang
|
||||
DISTCLEANFILES = *~ *.d
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
@@ -0,0 +1,15 @@
|
||||
Configuration Daemon
|
||||
====================
|
||||
|
||||
`confd` is the Infix configuration daemon that serves as the glue
|
||||
between sysrepo and netopeer2 (NETCONF) and the UNIX system under
|
||||
it all.
|
||||
|
||||
|
||||
Origin & References
|
||||
-------------------
|
||||
|
||||
Based on the Open Source [dklibc/sysrepo_plugin_ietf_system][0]
|
||||
project by Denis Kalashnikov.
|
||||
|
||||
[0]: https://github.com/dklibc/sysrepo_plugin_ietf_system
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
autoreconf -W portability -vifm
|
||||
@@ -0,0 +1,55 @@
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([confd], [1.0.0],
|
||||
[https://github.com/kernelkit/infix/issues])
|
||||
AM_INIT_AUTOMAKE(1.11 foreign subdir-objects)
|
||||
AM_SILENT_RULES(yes)
|
||||
|
||||
LT_INIT
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
yang/Makefile
|
||||
])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
|
||||
# Check for pkg-config first, warn if it's not installed
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
PKG_CHECK_MODULES([sysrepo], [sysrepo >= 2.2.36])
|
||||
PKG_CHECK_MODULES([augeas], [augeas >= 1.12.0])
|
||||
PKG_CHECK_MODULES([jansson], [jansson >= 2.0.0])
|
||||
|
||||
# Plugin installation path for sysrepo-plugind
|
||||
PKG_CHECK_VAR([srpdplugindir], [sysrepo], [SRPD_PLUGINS_PATH])
|
||||
AC_SUBST(srpdplugindir)
|
||||
|
||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
||||
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
|
||||
|
||||
DATAROOTDIR=`eval echo $datarootdir`
|
||||
DATAROOTDIR=`eval echo $DATAROOTDIR`
|
||||
AC_SUBST(DATAROOTDIR)
|
||||
|
||||
YANGDIR=`eval echo $datarootdir/yang/modules/confd`
|
||||
AC_SUBST(YANGDIR)
|
||||
|
||||
LIBDIR=`eval echo $libdir`
|
||||
LIBDIR=`eval echo $LIBDIR`
|
||||
AC_SUBST(LIBDIR)
|
||||
|
||||
LOCALSTATEDIR=`eval echo $localstatedir`
|
||||
LOCALSTATEDIR=`eval echo $LOCALSTATEDIR`
|
||||
AC_SUBST(LOCALSTATEDIR)
|
||||
|
||||
RUNSTATEDIR=`eval echo $runstatedir`
|
||||
RUNSTATEDIR=`eval echo $RUNSTATEDIR`
|
||||
AC_SUBST(RUNSTATEDIR)
|
||||
|
||||
SYSCONFDIR=`eval echo $sysconfdir`
|
||||
SYSCONFDIR=`eval echo $SYSCONFDIR`
|
||||
AC_SUBST(SYSCONFDIR)
|
||||
|
||||
AC_OUTPUT
|
||||
@@ -0,0 +1,10 @@
|
||||
CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter
|
||||
AM_CPPFLAGS = -D_DEFAULT_SOURCE -D_XOPEN_SOURCE -DYANG_PATH_=\"$(YANGDIR)/\"
|
||||
|
||||
plugindir = $(srpdplugindir)
|
||||
plugin_LTLIBRARIES = confd-plugin.la
|
||||
|
||||
confd_plugin_la_CFLAGS = $(augeas_CFLAGS) $(sysrepo_CFLAGS) $(CFLAGS)
|
||||
confd_plugin_la_LIBADD = $(augeas_LIBS) $(sysrepo_LIBS)
|
||||
confd_plugin_la_LDFLAGS = -module -avoid-version -shared
|
||||
confd_plugin_la_SOURCES = core.c core.h run.c ietf-system.c ietf-interfaces.c
|
||||
@@ -0,0 +1,89 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "core.h"
|
||||
|
||||
static struct confd confd;
|
||||
|
||||
static int startup_save_hook(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
|
||||
{
|
||||
if (run("sysrepocfg -X/cfg/startup-config.cfg -d startup -f json"))
|
||||
return SR_ERR_SYS;
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
static int commit_done_hook(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
|
||||
{
|
||||
if (system("initctl -nbq reload"))
|
||||
return SR_ERR_SYS;
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv)
|
||||
{
|
||||
sr_session_ctx_t *startup;
|
||||
int rc = SR_ERR_SYS;
|
||||
|
||||
openlog("confd", LOG_USER, 0);
|
||||
|
||||
/* Save context with default running config datastore for all our models */
|
||||
*priv = (void *)&confd;
|
||||
confd.session = session;
|
||||
confd.conn = sr_session_get_connection(session);
|
||||
confd.sub = NULL;
|
||||
|
||||
if (!confd.conn)
|
||||
goto err;
|
||||
|
||||
confd.aug = aug_init(NULL, "", 0);
|
||||
if (!confd.aug)
|
||||
goto err;
|
||||
|
||||
rc = ietf_interfaces_init(&confd);
|
||||
if (rc)
|
||||
goto err;
|
||||
rc = ietf_system_init(&confd);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
/* YOUR_INIT GOES HERE */
|
||||
|
||||
/* Set up hook to save startup-config to persisten backend store */
|
||||
rc = sr_session_start(confd.conn, SR_DS_STARTUP, &startup);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = sr_module_change_subscribe(startup, "ietf-system", "/ietf-system:system//.",
|
||||
startup_save_hook, NULL, 0, SR_SUBSCR_PASSIVE | SR_SUBSCR_DONE_ONLY, &confd.sub);
|
||||
if (rc) {
|
||||
ERROR("failed setting up startup-config hook: %s", sr_strerror(rc));
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = sr_module_change_subscribe(session, "ietf-system", "/ietf-system:system//.",
|
||||
commit_done_hook, NULL, 0, SR_SUBSCR_PASSIVE | SR_SUBSCR_DONE_ONLY, &confd.sub);
|
||||
if (rc) {
|
||||
ERROR("failed setting up startup-config hook: %s", sr_strerror(rc));
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = sr_install_module(confd.conn, YANG_PATH_"kernelkit-infix-deviations.yang", NULL, NULL);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
return SR_ERR_OK;
|
||||
err:
|
||||
ERROR("init failed: %s", sr_strerror(rc));
|
||||
sr_unsubscribe(confd.sub);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void sr_plugin_cleanup_cb(sr_session_ctx_t *session, void *priv)
|
||||
{
|
||||
sr_unsubscribe((sr_subscription_ctx_t *)priv);
|
||||
closelog();
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
#ifndef CONFD_CORE_H_
|
||||
#define CONFD_CORE_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <augeas.h>
|
||||
#include <libyang/libyang.h>
|
||||
#include <sysrepo.h>
|
||||
#include <sysrepo/values.h>
|
||||
#include <sysrepo/xpath.h>
|
||||
|
||||
|
||||
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
#define DEBUG(frmt, ...)
|
||||
//#define DEBUG(frmt, ...) syslog(LOG_DEBUG, "%s: "frmt, __func__, ##__VA_ARGS__)
|
||||
#define ERROR(frmt, ...) syslog(LOG_ERR, "%s: " frmt, __func__, ##__VA_ARGS__)
|
||||
#define ERRNO(frmt, ...) syslog(LOG_ERR, "%s: " frmt ": %s", __func__, ##__VA_ARGS__, strerror(errno))
|
||||
|
||||
static inline void print_val(sr_val_t *val)
|
||||
{
|
||||
char *str;
|
||||
|
||||
if (sr_print_val_mem(&str, val))
|
||||
return;
|
||||
ERROR("%s", str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
#define REGISTER_CHANGE(s,m,x,f,c,a,u) \
|
||||
if ((rc = register_change(s, m, x, f, c, a, u))) \
|
||||
goto err
|
||||
|
||||
#define REGISTER_RPC(s,x,c,a,u) \
|
||||
if ((rc = register_rpc(s, x, c, a, u))) \
|
||||
goto err
|
||||
|
||||
struct confd {
|
||||
sr_session_ctx_t *session;
|
||||
sr_conn_ctx_t *conn;
|
||||
sr_subscription_ctx_t *sub;
|
||||
|
||||
augeas *aug;
|
||||
};
|
||||
|
||||
static inline int register_change(sr_session_ctx_t *session, const char *module, const char *xpath,
|
||||
int flags, sr_module_change_cb cb, void *arg, sr_subscription_ctx_t **sub)
|
||||
{
|
||||
int rc = sr_module_change_subscribe(session, module, xpath, cb, arg, 0, flags | SR_SUBSCR_DEFAULT, sub);
|
||||
if (rc)
|
||||
ERROR("failed subscribing to changes of %s: %s", xpath, sr_strerror(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int register_rpc(sr_session_ctx_t *session, const char *xpath,
|
||||
sr_rpc_cb cb, void *arg, sr_subscription_ctx_t **sub)
|
||||
{
|
||||
int rc = sr_rpc_subscribe(session, xpath, cb, arg, 0, SR_SUBSCR_DEFAULT, sub);
|
||||
if (rc)
|
||||
ERROR("failed subscribing to %s rpc: %s", xpath, sr_strerror(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* core.c */
|
||||
int run(const char *fmt, ...);
|
||||
|
||||
/* ietf-interfaces.c */
|
||||
int ietf_interfaces_init(struct confd *confd);
|
||||
|
||||
/* ietf-system.c */
|
||||
int ietf_system_init(struct confd *confd);
|
||||
|
||||
#endif /* CONFD_CORE_H_ */
|
||||
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "core.h"
|
||||
|
||||
int ietf_interfaces_init(struct confd *confd)
|
||||
{
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
@@ -0,0 +1,795 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "core.h"
|
||||
#include <ctype.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#define CLOCK_PATH_ "/ietf-system:system-state/clock"
|
||||
#define PLATFORM_PATH_ "/ietf-system:system-state/platform"
|
||||
|
||||
static char *ver = NULL;
|
||||
static char *rel = NULL;
|
||||
static char *sys = NULL;
|
||||
static char *os = NULL;
|
||||
|
||||
static char *strip_quotes(char *str)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
while (*str && (isspace(*str) || *str == '"'))
|
||||
str++;
|
||||
|
||||
for (ptr = str + strlen(str); ptr > str; ptr--) {
|
||||
if (*ptr != '"')
|
||||
continue;
|
||||
|
||||
*ptr = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static void setvar(char *line, const char *nm, char **var)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (!strncmp(line, nm, strlen(nm)) && (ptr = strchr(line, '='))) {
|
||||
if (*var)
|
||||
free(*var);
|
||||
*var = strdup(strip_quotes(++ptr));
|
||||
}
|
||||
}
|
||||
|
||||
static void os_init(void)
|
||||
{
|
||||
struct utsname uts;
|
||||
char line[80];
|
||||
FILE *fp;
|
||||
|
||||
if (!uname(&uts)) {
|
||||
os = strdup(uts.sysname);
|
||||
ver = strdup(uts.release);
|
||||
rel = strdup(uts.release);
|
||||
sys = strdup(uts.machine);
|
||||
}
|
||||
|
||||
fp = fopen("/etc/os-release", "r");
|
||||
if (!fp) {
|
||||
fp = fopen("/usr/lib/os-release", "r");
|
||||
if (!fp)
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
line[strlen(line) - 1] = 0; /* drop \n */
|
||||
setvar(line, "NAME", &os);
|
||||
setvar(line, "VERSION_ID", &ver);
|
||||
setvar(line, "BUILD_ID", &rel);
|
||||
setvar(line, "ARCHITECTURE", &sys);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static char *fmtime(time_t t, char *buf, size_t len)
|
||||
{
|
||||
const char *isofmt = "%FT%T%z";
|
||||
struct tm tm;
|
||||
size_t i, n;
|
||||
|
||||
localtime_r(&t, &tm);
|
||||
n = strftime(buf, len, isofmt, &tm);
|
||||
i = n - 5;
|
||||
if (buf[i] == '+' || buf[i] == '-') {
|
||||
buf[i + 6] = buf[i + 5];
|
||||
buf[i + 5] = buf[i + 4];
|
||||
buf[i + 4] = buf[i + 3];
|
||||
buf[i + 3] = ':';
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int clock_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *path, const char *request_path, uint32_t request_id,
|
||||
struct lyd_node **parent, void *priv)
|
||||
{
|
||||
static char boottime[64] = { 0 };
|
||||
const struct ly_ctx *ctx;
|
||||
char curtime[64];
|
||||
time_t now, boot;
|
||||
char *buf;
|
||||
int rc;
|
||||
|
||||
DEBUG("path=%s, request_path=%s", path, request_path);
|
||||
ctx = sr_acquire_context(sr_session_get_connection(session));
|
||||
|
||||
rc = lyd_new_path(NULL, ctx, CLOCK_PATH_, NULL, 0, parent);
|
||||
if (rc) {
|
||||
fail:
|
||||
ERROR("Failed building data tree, libyang error %d", rc);
|
||||
return SR_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
lyd_print_mem(&buf, *parent, LYD_XML, 0);
|
||||
DEBUG("%s", buf);
|
||||
|
||||
now = time(NULL);
|
||||
if (!boottime[0]) {
|
||||
struct sysinfo si;
|
||||
|
||||
sysinfo(&si);
|
||||
boot = now - si.uptime;
|
||||
fmtime(boot, boottime, sizeof(boottime));
|
||||
}
|
||||
|
||||
rc = lyd_new_path(*parent, NULL, CLOCK_PATH_ "/boot-datetime", boottime, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
fmtime(now, curtime, sizeof(curtime));
|
||||
rc = lyd_new_path(*parent, NULL, CLOCK_PATH_ "/current-datetime", curtime, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
lyd_print_mem(&buf, *parent, LYD_XML, 0);
|
||||
DEBUG("%s", buf);
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
static int platform_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *path, const char *request_path, uint32_t request_id,
|
||||
struct lyd_node **parent, void *priv)
|
||||
{
|
||||
const struct ly_ctx *ctx;
|
||||
char *buf;
|
||||
int rc;
|
||||
|
||||
DEBUG("path=%s request_path=%s", path, request_path);
|
||||
ctx = sr_acquire_context(sr_session_get_connection(session));
|
||||
|
||||
rc = lyd_new_path(NULL, ctx, PLATFORM_PATH_, NULL, 0, parent);
|
||||
if (rc) {
|
||||
fail:
|
||||
ERROR("Failed building data tree, libyang error %d", rc);
|
||||
return SR_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
lyd_print_mem(&buf, *parent, LYD_XML, 0);
|
||||
DEBUG("%s", buf);
|
||||
|
||||
rc = lyd_new_path(*parent, NULL, PLATFORM_PATH_"/os-name", os, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
rc = lyd_new_path(*parent, NULL, PLATFORM_PATH_"/os-release", rel, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
rc = lyd_new_path(*parent, NULL, PLATFORM_PATH_"/os-version", ver, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
rc = lyd_new_path(*parent, NULL, PLATFORM_PATH_"/machine", sys, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
lyd_print_mem(&buf, *parent, LYD_XML, 0);
|
||||
DEBUG("%s", buf);
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
static int rpc_exec(sr_session_ctx_t *session, uint32_t sub_id, const char *path,
|
||||
const sr_val_t *input, const size_t input_cnt,
|
||||
sr_event_t event, unsigned request_id,
|
||||
sr_val_t **output, size_t *output_cnt,
|
||||
void *priv)
|
||||
{
|
||||
DEBUG("path: %s", path);
|
||||
|
||||
if (run(priv))
|
||||
return SR_ERR_INTERNAL;
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
/* '/ietf-system:set-current-date-time' */
|
||||
static int rpc_set_datetime(sr_session_ctx_t *session, uint32_t sub_id,
|
||||
const char *path, const sr_val_t *input,
|
||||
const size_t input_cnt, sr_event_t event,
|
||||
unsigned request_id, sr_val_t **output,
|
||||
size_t *output_cnt, void *priv)
|
||||
{
|
||||
const char *isofmt = "%FT%T%z";
|
||||
static int rc = SR_ERR_SYS;
|
||||
struct timeval tv;
|
||||
struct tm tm;
|
||||
char tz[24];
|
||||
char *buf;
|
||||
size_t n;
|
||||
|
||||
buf = strdup(input->data.string_val);
|
||||
if (!buf)
|
||||
return SR_ERR_NO_MEMORY;
|
||||
|
||||
n = strlen(buf);
|
||||
if (buf[n - 3] == ':' && (buf[n - 6] == '+' || buf[n - 6] == '-')) {
|
||||
buf[n - 3] = buf[n - 2];
|
||||
buf[n - 2] = buf[n - 1];
|
||||
buf[n - 1] = 0;
|
||||
} else
|
||||
isofmt = "%FT%TZ";
|
||||
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
if (!strptime(buf, isofmt, &tm)) {
|
||||
ERRNO("ietf-system:failed strptime: %s", strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
snprintf(tz, sizeof(tz), "UTC%s%ld", tm.tm_gmtoff > 0 ? "+" : "", tm.tm_gmtoff / 3600);
|
||||
setenv("TZ", tz, 1);
|
||||
|
||||
tv.tv_sec = mktime(&tm);
|
||||
tv.tv_usec = 0;
|
||||
if (settimeofday(&tv, NULL)) {
|
||||
ERRNO("ietf-system:settimeofday() failed");
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = SR_ERR_OK;
|
||||
done:
|
||||
unsetenv("TZ");
|
||||
free(buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sys_reload_services(void)
|
||||
{
|
||||
return run("initctl -nbq touch sysklogd lldpd");
|
||||
}
|
||||
|
||||
int sr_get_int(sr_session_ctx_t *session, const char *fmt, ...)
|
||||
{
|
||||
sr_val_t *val = NULL;
|
||||
char *xpath;
|
||||
va_list ap;
|
||||
int rc = 0;
|
||||
int len;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(NULL, 0, fmt, ap) + 1;
|
||||
va_end(ap);
|
||||
|
||||
xpath = alloca(len);
|
||||
if (!xpath)
|
||||
goto fail;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(xpath, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (sr_get_item(session, xpath, 0, &val) || !val)
|
||||
goto fail;
|
||||
|
||||
switch (val->type) {
|
||||
case SR_INT8_T:
|
||||
rc = val->data.int8_val;
|
||||
break;
|
||||
case SR_UINT8_T:
|
||||
rc = val->data.uint8_val;
|
||||
break;
|
||||
case SR_INT16_T:
|
||||
rc = val->data.int16_val;
|
||||
break;
|
||||
case SR_UINT16_T:
|
||||
rc = val->data.uint16_val;
|
||||
break;
|
||||
case SR_INT32_T:
|
||||
rc = val->data.int32_val;
|
||||
break;
|
||||
case SR_UINT32_T:
|
||||
rc = val->data.uint32_val;
|
||||
break;
|
||||
case SR_INT64_T:
|
||||
rc = val->data.int64_val;
|
||||
break;
|
||||
case SR_UINT64_T:
|
||||
rc = val->data.uint64_val;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
if (val)
|
||||
sr_free_val(val);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sr_get_bool(sr_session_ctx_t *session, const char *fmt, ...)
|
||||
{
|
||||
sr_val_t *val = NULL;
|
||||
char *xpath;
|
||||
va_list ap;
|
||||
int rc = 0;
|
||||
int len;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(NULL, 0, fmt, ap) + 1;
|
||||
va_end(ap);
|
||||
|
||||
xpath = alloca(len);
|
||||
if (!xpath)
|
||||
goto fail;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(xpath, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (sr_get_item(session, xpath, 0, &val))
|
||||
goto fail;
|
||||
if (!val || val->type != SR_BOOL_T)
|
||||
goto fail;
|
||||
|
||||
rc = val->data.bool_val;
|
||||
fail:
|
||||
if (val)
|
||||
sr_free_val(val);
|
||||
return rc;
|
||||
}
|
||||
|
||||
char *sr_get_str(sr_session_ctx_t *session, const char *fmt, ...)
|
||||
{
|
||||
char *str = NULL;
|
||||
sr_val_t *val;
|
||||
char *xpath;
|
||||
va_list ap;
|
||||
int len;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(NULL, 0, fmt, ap) + 1;
|
||||
va_end(ap);
|
||||
|
||||
xpath = alloca(len);
|
||||
if (!xpath)
|
||||
return NULL;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(xpath, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (sr_get_item(session, xpath, 0, &val)) {
|
||||
ERROR("Failed reading string value from xpath %s", xpath);
|
||||
goto fail;
|
||||
}
|
||||
if (!val || val->type != SR_STRING_T)
|
||||
goto fail;
|
||||
|
||||
str = strdup(val->data.string_val);
|
||||
fail:
|
||||
if (val)
|
||||
sr_free_val(val);
|
||||
return str;
|
||||
}
|
||||
|
||||
#define TIMEZONE_CONF "/etc/timezone"
|
||||
#define TIMEZONE_PREV TIMEZONE_CONF "-"
|
||||
#define TIMEZONE_NEXT TIMEZONE_CONF "+"
|
||||
|
||||
static int change_clock(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
|
||||
{
|
||||
char *timezone;
|
||||
FILE *fp;
|
||||
|
||||
switch (event) {
|
||||
case SR_EV_ENABLED: /* first time, on register. */
|
||||
case SR_EV_CHANGE: /* regular change (copy cand running) */
|
||||
/* Set up next timezone */
|
||||
break;
|
||||
|
||||
case SR_EV_ABORT: /* User abort, or other plugin failed */
|
||||
remove(TIMEZONE_NEXT);
|
||||
return SR_ERR_OK;
|
||||
|
||||
case SR_EV_DONE:
|
||||
/* Check if passed validation in previous event */
|
||||
if (access(TIMEZONE_NEXT, F_OK))
|
||||
return SR_ERR_OK;
|
||||
|
||||
remove(TIMEZONE_PREV);
|
||||
rename(TIMEZONE_CONF, TIMEZONE_PREV);
|
||||
rename(TIMEZONE_NEXT, TIMEZONE_CONF);
|
||||
|
||||
remove("/etc/localtime-");
|
||||
rename("/etc/localtime", "/etc/localtime-");
|
||||
rename("/etc/localtime+", "/etc/localtime");
|
||||
|
||||
return SR_ERR_OK;
|
||||
|
||||
default:
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
/* XXX: add support also for /ietf-system:system/clock/timezone-utc-offset (deviation) */
|
||||
timezone = sr_get_str(session, "/ietf-system:system/clock/timezone-name");
|
||||
if (!timezone) {
|
||||
ERROR("Failed reading timezone-name");
|
||||
return SR_ERR_VALIDATION_FAILED;
|
||||
}
|
||||
|
||||
remove("/etc/localtime+");
|
||||
if (run("ln -s /usr/share/zoneinfo/%s /etc/localtime+", timezone)) {
|
||||
ERROR("No such timezone %s", timezone);
|
||||
return SR_ERR_VALIDATION_FAILED;
|
||||
}
|
||||
|
||||
fp = fopen(TIMEZONE_NEXT, "w");
|
||||
if (!fp) {
|
||||
ERRNO("Failed preparing %s", TIMEZONE_NEXT);
|
||||
return SR_ERR_SYS;
|
||||
}
|
||||
fprintf(fp, "%s\n", timezone);
|
||||
fclose(fp);
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
#define CHRONY_CONF "/etc/chrony.conf"
|
||||
#define CHRONY_PREV CHRONY_CONF "-"
|
||||
#define CHRONY_NEXT CHRONY_CONF "+"
|
||||
|
||||
static int change_ntp(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
|
||||
{
|
||||
const char *fn = CHRONY_NEXT;
|
||||
int valid = -1;
|
||||
sr_val_t *val;
|
||||
size_t cnt;
|
||||
FILE *fp;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case SR_EV_ENABLED: /* first time, on register. */
|
||||
case SR_EV_CHANGE: /* regular change (copy cand running) */
|
||||
/* Generate next config */
|
||||
break;
|
||||
|
||||
case SR_EV_ABORT: /* User abort, or other plugin failed */
|
||||
remove(CHRONY_NEXT);
|
||||
return SR_ERR_OK;
|
||||
|
||||
case SR_EV_DONE:
|
||||
/* Check if passed validation in previous event */
|
||||
if (access(CHRONY_NEXT, F_OK))
|
||||
return SR_ERR_OK;
|
||||
|
||||
remove(CHRONY_PREV);
|
||||
rename(CHRONY_CONF, CHRONY_PREV);
|
||||
rename(CHRONY_NEXT, CHRONY_CONF);
|
||||
if (!sr_get_bool(session, "/ietf-system:system/ntp/enabled")) {
|
||||
run("initctl -nbq disable chronyd");
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
/*
|
||||
* If chrony is alrady enabled we tell Finit it's been
|
||||
* modified , so Finit restarts it, otherwise enable it.
|
||||
*/
|
||||
run("initctl -nbq touch chronyd");
|
||||
run("initctl -nbq enable chronyd");
|
||||
return SR_ERR_OK;
|
||||
|
||||
default:
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
rc = sr_get_items(session, "/ietf-system:system/ntp/server", 0, 0, &val, &cnt);
|
||||
if (rc) {
|
||||
remove(CHRONY_NEXT);
|
||||
return rc;
|
||||
}
|
||||
|
||||
fp = fopen(fn, "w");
|
||||
if (!fp) {
|
||||
ERROR("failed updating %s: %s", fn, strerror(errno));
|
||||
sr_free_values(val, cnt);
|
||||
return SR_ERR_SYS;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cnt; i++) {
|
||||
const char *xpath = val[i].xpath;
|
||||
char *type, *ptr;
|
||||
int server = 0;
|
||||
|
||||
/*
|
||||
* Handle empty startup-config on SR_EV_ENABLED,
|
||||
* prevents subscribe failure due to false invalid.
|
||||
*/
|
||||
if (i == 0)
|
||||
valid = 0;
|
||||
|
||||
/* Get /ietf-system:system/ntp/server[name='foo'] */
|
||||
ptr = sr_get_str(session, "%s/udp/address", xpath);
|
||||
if (ptr) {
|
||||
type = sr_get_str(session, "%s/association-type", xpath);
|
||||
fprintf(fp, "%s %s", type ?: "server", ptr);
|
||||
server++;
|
||||
if (type)
|
||||
free(type);
|
||||
free(ptr);
|
||||
|
||||
ptr = sr_get_str(session, "%s/udp/port", xpath);
|
||||
if (ptr) {
|
||||
fprintf(fp, " port %s", ptr);
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (server) {
|
||||
if (sr_get_bool(session, "%s/iburst", xpath))
|
||||
fprintf(fp, " iburst");
|
||||
if (sr_get_bool(session, "%s/prefer", xpath))
|
||||
fprintf(fp, " prefer");
|
||||
|
||||
fprintf(fp, "\n");
|
||||
valid++;
|
||||
}
|
||||
}
|
||||
sr_free_values(val, cnt);
|
||||
|
||||
fprintf(fp, "driftfile /var/lib/chrony/drift\n");
|
||||
fprintf(fp, "makestep 1.0 3\n");
|
||||
fprintf(fp, "maxupdateskew 100.0\n");
|
||||
fprintf(fp, "dumpdir /var/lib/chrony\n");
|
||||
fprintf(fp, "rtcfile /var/lib/chrony/rtc\n");
|
||||
fclose(fp);
|
||||
|
||||
if (!valid) {
|
||||
remove(fn);
|
||||
return SR_ERR_VALIDATION_FAILED;
|
||||
}
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
#define RESOLV_CONF "/etc/resolv.conf.head"
|
||||
#define RESOLV_PREV RESOLV_CONF "-"
|
||||
#define RESOLV_NEXT RESOLV_CONF "+"
|
||||
|
||||
static int change_dns(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
|
||||
{
|
||||
const char *fn = RESOLV_NEXT;
|
||||
int timeout, attempts;
|
||||
int rc = SR_ERR_SYS;
|
||||
sr_val_t *val;
|
||||
size_t cnt;
|
||||
FILE *fp;
|
||||
|
||||
switch (event) {
|
||||
case SR_EV_ENABLED: /* first time, on register. */
|
||||
case SR_EV_CHANGE: /* regular change (copy cand running) */
|
||||
/* Generate next config */
|
||||
break;
|
||||
|
||||
case SR_EV_ABORT: /* User abort, or other plugin failed */
|
||||
remove(RESOLV_NEXT);
|
||||
return SR_ERR_OK;
|
||||
|
||||
case SR_EV_DONE:
|
||||
/* Check if passed validation in previous event */
|
||||
if (access(RESOLV_NEXT, F_OK))
|
||||
return SR_ERR_OK;
|
||||
|
||||
remove(RESOLV_PREV);
|
||||
rename(RESOLV_CONF, RESOLV_PREV);
|
||||
rename(RESOLV_NEXT, RESOLV_CONF);
|
||||
|
||||
/* in bootstrap, another resolvconf will soon take your call */
|
||||
if (run("initctl cond get hook/sys/up"))
|
||||
return 0;
|
||||
|
||||
run("resolvconf -u");
|
||||
return SR_ERR_OK;
|
||||
|
||||
default:
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
fp = fopen(fn, "w");
|
||||
if (!fp) {
|
||||
ERROR("failed updating %s: %s", fn, strerror(errno));
|
||||
sr_free_values(val, cnt);
|
||||
return SR_ERR_SYS;
|
||||
}
|
||||
|
||||
timeout = sr_get_int(session, "/ietf-system:system/dns-resolver/options/timeout");
|
||||
attempts = sr_get_int(session, "/ietf-system:system/dns-resolver/options/attempts");
|
||||
if (timeout || attempts) {
|
||||
fprintf(fp, "options");
|
||||
if (timeout)
|
||||
fprintf(fp, " timeout:%d", timeout);
|
||||
if (attempts)
|
||||
fprintf(fp, " attempts:%d ", attempts);
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
rc = sr_get_items(session, "/ietf-system:system/dns-resolver/search", 0, 0, &val, &cnt);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
if (cnt) {
|
||||
fprintf(fp, "search ");
|
||||
for (size_t i = 0; i < cnt; i++)
|
||||
fprintf(fp, "%s ", val[i].data.string_val);
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
sr_free_values(val, cnt);
|
||||
|
||||
rc = sr_get_items(session, "/ietf-system:system/dns-resolver/server", 0, 0, &val, &cnt);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
for (size_t i = 0; i < cnt; i++) {
|
||||
const char *xpath = val[i].xpath;
|
||||
char *ptr;
|
||||
|
||||
/* Get /ietf-system:system/dns-resolver/server[name='foo'] */
|
||||
ptr = sr_get_str(session, "%s/udp-and-tcp/address", xpath);
|
||||
if (ptr)
|
||||
/* XXX: add support also for udp-and-tcp/port */
|
||||
fprintf(fp, "nameserver %s\n", ptr);
|
||||
}
|
||||
sr_free_values(val, cnt);
|
||||
|
||||
rc = SR_ERR_OK;
|
||||
fail:
|
||||
fclose(fp);
|
||||
if (rc)
|
||||
remove(fn);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int change_motd(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
|
||||
{
|
||||
char *nm;
|
||||
FILE *fp;
|
||||
|
||||
/* Ignore all events except SR_EV_DONE */
|
||||
if (event != SR_EV_DONE)
|
||||
return SR_ERR_OK;
|
||||
|
||||
fp = fopen("/etc/motd", "w");
|
||||
if (!fp)
|
||||
return SR_ERR_SYS;
|
||||
|
||||
nm = sr_get_str(session, xpath);
|
||||
if (nm) {
|
||||
fprintf(fp, "%s\n", nm);
|
||||
} else {
|
||||
/* XXX: derive from global "options.h" or /usr/share/factory/ */
|
||||
fprintf(fp, "\033[1;90mNote:\033[0m ");
|
||||
fprintf(fp, "\033[0;90m use help, show, and setup commands to set up and diagnose the system\033[0m\n");
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
static int change_hostname(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
|
||||
{
|
||||
struct confd *confd = (struct confd *)priv;
|
||||
const char *host, *tmp = NULL;
|
||||
char **hosts, *current;
|
||||
int err, i, nhosts;
|
||||
char *nm;
|
||||
|
||||
if (event != SR_EV_DONE)
|
||||
return SR_ERR_OK;
|
||||
|
||||
nm = sr_get_str(session, xpath);
|
||||
if (!nm) {
|
||||
/* XXX: derive from global "options.h" or /usr/share/factory/ */
|
||||
nm = strdup("infix");
|
||||
if (!nm)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (aug_get(confd->aug, "etc/hostname/hostname", &tmp) <= 0)
|
||||
goto err;
|
||||
|
||||
current = strdup(tmp);
|
||||
if (!current)
|
||||
goto err;
|
||||
|
||||
err = sethostname(nm, strlen(nm));
|
||||
err = err ? : aug_set(confd->aug, "etc/hostname/hostname", nm);
|
||||
|
||||
nhosts = aug_match(confd->aug, "etc/hosts/*/canonical", &hosts);
|
||||
for (i = 0; i < nhosts; i++) {
|
||||
if (aug_get(confd->aug, hosts[i], &host) <= 0)
|
||||
continue;
|
||||
|
||||
if (!strcmp(host, current))
|
||||
err = err ? : aug_set(confd->aug, hosts[i], nm);
|
||||
|
||||
free(hosts[i]);
|
||||
}
|
||||
|
||||
if (nhosts)
|
||||
free(hosts);
|
||||
free(current);
|
||||
err:
|
||||
if (nm)
|
||||
free(nm);
|
||||
|
||||
if (err) {
|
||||
ERROR("Failed activating changes.");
|
||||
return err;
|
||||
}
|
||||
|
||||
ERROR("Reload hostname-dependent services ...");
|
||||
err = err ? : aug_save(confd->aug);
|
||||
if (sys_reload_services())
|
||||
return SR_ERR_SYS;
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
int ietf_system_init(struct confd *confd)
|
||||
{
|
||||
const char *features[] = {
|
||||
"ntp",
|
||||
"ntp-udp-port",
|
||||
"timezone-name",
|
||||
NULL
|
||||
};
|
||||
int rc;
|
||||
|
||||
os_init();
|
||||
|
||||
if (aug_load_file(confd->aug, "/etc/hostname") ||
|
||||
aug_load_file(confd->aug, "/etc/hosts")) {
|
||||
ERROR("ietf-system: Augeas initialization failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = sr_install_module(confd->conn, YANG_PATH_"ietf-system@2014-08-06.yang", NULL, features);
|
||||
if (rc)
|
||||
goto err;
|
||||
/* Augment to ietf-systems */
|
||||
rc = sr_install_module(confd->conn, YANG_PATH_"infix-system@2014-08-06.yang", NULL, NULL);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = sr_oper_get_subscribe(confd->session, "ietf-system", CLOCK_PATH_,
|
||||
clock_cb, NULL, SR_SUBSCR_DEFAULT, &confd->sub);
|
||||
if (rc != SR_ERR_OK)
|
||||
goto err;
|
||||
|
||||
rc = sr_oper_get_subscribe(confd->session, "ietf-system", PLATFORM_PATH_,
|
||||
platform_cb, NULL, SR_SUBSCR_DEFAULT, &confd->sub);
|
||||
if (rc != SR_ERR_OK)
|
||||
goto err;
|
||||
|
||||
REGISTER_CHANGE(confd->session, "ietf-system", "/ietf-system:system/hostname", 0, change_hostname, confd, &confd->sub);
|
||||
REGISTER_CHANGE(confd->session, "ietf-system", "/ietf-system:system/infix-system:motd", 0, change_motd, confd, &confd->sub);
|
||||
REGISTER_CHANGE(confd->session, "ietf-system", "/ietf-system:system/clock", 0, change_clock, confd, &confd->sub);
|
||||
REGISTER_CHANGE(confd->session, "ietf-system", "/ietf-system:system/ntp", 0, change_ntp, confd, &confd->sub);
|
||||
REGISTER_CHANGE(confd->session, "ietf-system", "/ietf-system:system/dns-resolver", 0, change_dns, confd, &confd->sub);
|
||||
|
||||
REGISTER_RPC(confd->session, "/ietf-system:system-restart", rpc_exec, "reboot", &confd->sub);
|
||||
REGISTER_RPC(confd->session, "/ietf-system:system-shutdown", rpc_exec, "poweroff", &confd->sub);
|
||||
REGISTER_RPC(confd->session, "/ietf-system:set-current-datetime", rpc_set_datetime, NULL, &confd->sub);
|
||||
|
||||
return SR_ERR_OK;
|
||||
err:
|
||||
ERROR("init failed: %s", sr_strerror(rc));
|
||||
sr_unsubscribe(confd->sub);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/**
|
||||
* Like system(), but takes a formatted string as argument.
|
||||
* @param fmt printf style format list to command to run
|
||||
*
|
||||
* This system() wrapper greatly simplifies operations that usually
|
||||
* consist of composing a command from parts into a dynamic buffer
|
||||
* before calling it. The return value from system() is also parsed,
|
||||
* checking for proper exit and signals.
|
||||
*
|
||||
* @returns If the command exits normally, the return code of the command
|
||||
* is returned. Otherwise, if the command is signalled, the return code
|
||||
* is -1 and @a errno is set to @c EINTR.
|
||||
*/
|
||||
int run(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *cmd;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
cmd = alloca(++len);
|
||||
if (!cmd) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(cmd, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
rc = system(cmd);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
|
||||
if (WIFEXITED(rc)) {
|
||||
errno = 0;
|
||||
rc = WEXITSTATUS(rc);
|
||||
} else if (WIFSIGNALED(rc)) {
|
||||
errno = EINTR;
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
yangdir = $(YANGDIR)
|
||||
yang_DATA = $(wildcard *.yang)
|
||||
@@ -0,0 +1,120 @@
|
||||
module iana-crypt-hash {
|
||||
namespace "urn:ietf:params:xml:ns:yang:iana-crypt-hash";
|
||||
prefix ianach;
|
||||
|
||||
organization "IANA";
|
||||
contact
|
||||
" Internet Assigned Numbers Authority
|
||||
|
||||
Postal: ICANN
|
||||
12025 Waterfront Drive, Suite 300
|
||||
Los Angeles, CA 90094-2536
|
||||
United States
|
||||
|
||||
Tel: +1 310 301 5800
|
||||
E-Mail: iana@iana.org>";
|
||||
description
|
||||
"This YANG module defines a type for storing passwords
|
||||
using a hash function and features to indicate which hash
|
||||
functions are supported by an implementation.
|
||||
|
||||
The latest revision of this YANG module can be obtained from
|
||||
the IANA web site.
|
||||
|
||||
Requests for new values should be made to IANA via
|
||||
email (iana@iana.org).
|
||||
|
||||
Copyright (c) 2014 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
The initial version of this YANG module is part of RFC 7317;
|
||||
see the RFC itself for full legal notices.";
|
||||
|
||||
revision 2014-08-06 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 7317: A YANG Data Model for System Management";
|
||||
}
|
||||
|
||||
typedef crypt-hash {
|
||||
type string {
|
||||
pattern
|
||||
'$0$.*'
|
||||
+ '|$1$[a-zA-Z0-9./]{1,8}$[a-zA-Z0-9./]{22}'
|
||||
+ '|$5$(rounds=\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{43}'
|
||||
+ '|$6$(rounds=\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{86}';
|
||||
}
|
||||
description
|
||||
"The crypt-hash type is used to store passwords using
|
||||
a hash function. The algorithms for applying the hash
|
||||
function and encoding the result are implemented in
|
||||
various UNIX systems as the function crypt(3).
|
||||
|
||||
A value of this type matches one of the forms:
|
||||
|
||||
$0$<clear text password>
|
||||
$<id>$<salt>$<password hash>
|
||||
$<id>$<parameter>$<salt>$<password hash>
|
||||
|
||||
The '$0$' prefix signals that the value is clear text. When
|
||||
such a value is received by the server, a hash value is
|
||||
calculated, and the string '$<id>$<salt>$' or
|
||||
$<id>$<parameter>$<salt>$ is prepended to the result. This
|
||||
value is stored in the configuration data store.
|
||||
If a value starting with '$<id>$', where <id> is not '0', is
|
||||
received, the server knows that the value already represents a
|
||||
hashed value and stores it 'as is' in the data store.
|
||||
|
||||
When a server needs to verify a password given by a user, it
|
||||
finds the stored password hash string for that user, extracts
|
||||
the salt, and calculates the hash with the salt and given
|
||||
password as input. If the calculated hash value is the same
|
||||
as the stored value, the password given by the client is
|
||||
accepted.
|
||||
|
||||
This type defines the following hash functions:
|
||||
|
||||
id | hash function | feature
|
||||
---+---------------+-------------------
|
||||
1 | MD5 | crypt-hash-md5
|
||||
5 | SHA-256 | crypt-hash-sha-256
|
||||
6 | SHA-512 | crypt-hash-sha-512
|
||||
|
||||
The server indicates support for the different hash functions
|
||||
by advertising the corresponding feature.";
|
||||
reference
|
||||
"IEEE Std 1003.1-2008 - crypt() function
|
||||
RFC 1321: The MD5 Message-Digest Algorithm
|
||||
FIPS.180-4.2012: Secure Hash Standard (SHS)";
|
||||
}
|
||||
|
||||
feature crypt-hash-md5 {
|
||||
description
|
||||
"Indicates that the device supports the MD5
|
||||
hash function in 'crypt-hash' values.";
|
||||
reference "RFC 1321: The MD5 Message-Digest Algorithm";
|
||||
}
|
||||
|
||||
feature crypt-hash-sha-256 {
|
||||
description
|
||||
"Indicates that the device supports the SHA-256
|
||||
hash function in 'crypt-hash' values.";
|
||||
reference "FIPS.180-4.2012: Secure Hash Standard (SHS)";
|
||||
}
|
||||
|
||||
feature crypt-hash-sha-512 {
|
||||
description
|
||||
"Indicates that the device supports the SHA-512
|
||||
hash function in 'crypt-hash' values.";
|
||||
reference "FIPS.180-4.2012: Secure Hash Standard (SHS)";
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,117 @@
|
||||
module ietf-datastores {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-datastores";
|
||||
prefix ds;
|
||||
|
||||
organization
|
||||
"IETF Network Modeling (NETMOD) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <https://datatracker.ietf.org/wg/netmod/>
|
||||
|
||||
WG List: <mailto:netmod@ietf.org>
|
||||
|
||||
Author: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>
|
||||
|
||||
Author: Juergen Schoenwaelder
|
||||
<mailto:j.schoenwaelder@jacobs-university.de>
|
||||
|
||||
Author: Phil Shafer
|
||||
<mailto:phil@juniper.net>
|
||||
|
||||
Author: Kent Watsen
|
||||
<mailto:kwatsen@juniper.net>
|
||||
|
||||
Author: Rob Wilton
|
||||
<rwilton@cisco.com>";
|
||||
|
||||
description
|
||||
"This YANG module defines a set of identities for identifying
|
||||
datastores.
|
||||
|
||||
Copyright (c) 2018 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject to
|
||||
the license terms contained in, the Simplified BSD License set
|
||||
forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(https://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 8342
|
||||
(https://www.rfc-editor.org/info/rfc8342); see the RFC itself
|
||||
for full legal notices.";
|
||||
|
||||
revision 2018-02-14 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 8342: Network Management Datastore Architecture (NMDA)";
|
||||
}
|
||||
|
||||
/*
|
||||
* Identities
|
||||
*/
|
||||
|
||||
identity datastore {
|
||||
description
|
||||
"Abstract base identity for datastore identities.";
|
||||
}
|
||||
|
||||
identity conventional {
|
||||
base datastore;
|
||||
description
|
||||
"Abstract base identity for conventional configuration
|
||||
datastores.";
|
||||
}
|
||||
|
||||
identity running {
|
||||
base conventional;
|
||||
description
|
||||
"The running configuration datastore.";
|
||||
}
|
||||
|
||||
identity candidate {
|
||||
base conventional;
|
||||
description
|
||||
"The candidate configuration datastore.";
|
||||
}
|
||||
|
||||
identity startup {
|
||||
base conventional;
|
||||
description
|
||||
"The startup configuration datastore.";
|
||||
}
|
||||
|
||||
identity intended {
|
||||
base conventional;
|
||||
description
|
||||
"The intended configuration datastore.";
|
||||
}
|
||||
|
||||
identity dynamic {
|
||||
base datastore;
|
||||
description
|
||||
"Abstract base identity for dynamic configuration datastores.";
|
||||
}
|
||||
|
||||
identity operational {
|
||||
base datastore;
|
||||
description
|
||||
"The operational state datastore.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Type definitions
|
||||
*/
|
||||
|
||||
typedef datastore-ref {
|
||||
type identityref {
|
||||
base datastore;
|
||||
}
|
||||
description
|
||||
"A datastore identity reference.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,458 @@
|
||||
module ietf-inet-types {
|
||||
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
|
||||
prefix "inet";
|
||||
|
||||
organization
|
||||
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <http://tools.ietf.org/wg/netmod/>
|
||||
WG List: <mailto:netmod@ietf.org>
|
||||
|
||||
WG Chair: David Kessens
|
||||
<mailto:david.kessens@nsn.com>
|
||||
|
||||
WG Chair: Juergen Schoenwaelder
|
||||
<mailto:j.schoenwaelder@jacobs-university.de>
|
||||
|
||||
Editor: Juergen Schoenwaelder
|
||||
<mailto:j.schoenwaelder@jacobs-university.de>";
|
||||
|
||||
description
|
||||
"This module contains a collection of generally useful derived
|
||||
YANG data types for Internet addresses and related things.
|
||||
|
||||
Copyright (c) 2013 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 6991; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision 2013-07-15 {
|
||||
description
|
||||
"This revision adds the following new data types:
|
||||
- ip-address-no-zone
|
||||
- ipv4-address-no-zone
|
||||
- ipv6-address-no-zone";
|
||||
reference
|
||||
"RFC 6991: Common YANG Data Types";
|
||||
}
|
||||
|
||||
revision 2010-09-24 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 6021: Common YANG Data Types";
|
||||
}
|
||||
|
||||
/*** collection of types related to protocol fields ***/
|
||||
|
||||
typedef ip-version {
|
||||
type enumeration {
|
||||
enum unknown {
|
||||
value "0";
|
||||
description
|
||||
"An unknown or unspecified version of the Internet
|
||||
protocol.";
|
||||
}
|
||||
enum ipv4 {
|
||||
value "1";
|
||||
description
|
||||
"The IPv4 protocol as defined in RFC 791.";
|
||||
}
|
||||
enum ipv6 {
|
||||
value "2";
|
||||
description
|
||||
"The IPv6 protocol as defined in RFC 2460.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"This value represents the version of the IP protocol.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the InetVersion textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 791: Internet Protocol
|
||||
RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
|
||||
RFC 4001: Textual Conventions for Internet Network Addresses";
|
||||
}
|
||||
|
||||
typedef dscp {
|
||||
type uint8 {
|
||||
range "0..63";
|
||||
}
|
||||
description
|
||||
"The dscp type represents a Differentiated Services Code Point
|
||||
that may be used for marking packets in a traffic stream.
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the Dscp textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 3289: Management Information Base for the Differentiated
|
||||
Services Architecture
|
||||
RFC 2474: Definition of the Differentiated Services Field
|
||||
(DS Field) in the IPv4 and IPv6 Headers
|
||||
RFC 2780: IANA Allocation Guidelines For Values In
|
||||
the Internet Protocol and Related Headers";
|
||||
}
|
||||
|
||||
typedef ipv6-flow-label {
|
||||
type uint32 {
|
||||
range "0..1048575";
|
||||
}
|
||||
description
|
||||
"The ipv6-flow-label type represents the flow identifier or Flow
|
||||
Label in an IPv6 packet header that may be used to
|
||||
discriminate traffic flows.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the IPv6FlowLabel textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 3595: Textual Conventions for IPv6 Flow Label
|
||||
RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
|
||||
}
|
||||
|
||||
typedef port-number {
|
||||
type uint16 {
|
||||
range "0..65535";
|
||||
}
|
||||
description
|
||||
"The port-number type represents a 16-bit port number of an
|
||||
Internet transport-layer protocol such as UDP, TCP, DCCP, or
|
||||
SCTP. Port numbers are assigned by IANA. A current list of
|
||||
all assignments is available from <http://www.iana.org/>.
|
||||
|
||||
Note that the port number value zero is reserved by IANA. In
|
||||
situations where the value zero does not make sense, it can
|
||||
be excluded by subtyping the port-number type.
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the InetPortNumber textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 768: User Datagram Protocol
|
||||
RFC 793: Transmission Control Protocol
|
||||
RFC 4960: Stream Control Transmission Protocol
|
||||
RFC 4340: Datagram Congestion Control Protocol (DCCP)
|
||||
RFC 4001: Textual Conventions for Internet Network Addresses";
|
||||
}
|
||||
|
||||
/*** collection of types related to autonomous systems ***/
|
||||
|
||||
typedef as-number {
|
||||
type uint32;
|
||||
description
|
||||
"The as-number type represents autonomous system numbers
|
||||
which identify an Autonomous System (AS). An AS is a set
|
||||
of routers under a single technical administration, using
|
||||
an interior gateway protocol and common metrics to route
|
||||
packets within the AS, and using an exterior gateway
|
||||
protocol to route packets to other ASes. IANA maintains
|
||||
the AS number space and has delegated large parts to the
|
||||
regional registries.
|
||||
|
||||
Autonomous system numbers were originally limited to 16
|
||||
bits. BGP extensions have enlarged the autonomous system
|
||||
number space to 32 bits. This type therefore uses an uint32
|
||||
base type without a range restriction in order to support
|
||||
a larger autonomous system number space.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the InetAutonomousSystemNumber textual convention of
|
||||
the SMIv2.";
|
||||
reference
|
||||
"RFC 1930: Guidelines for creation, selection, and registration
|
||||
of an Autonomous System (AS)
|
||||
RFC 4271: A Border Gateway Protocol 4 (BGP-4)
|
||||
RFC 4001: Textual Conventions for Internet Network Addresses
|
||||
RFC 6793: BGP Support for Four-Octet Autonomous System (AS)
|
||||
Number Space";
|
||||
}
|
||||
|
||||
/*** collection of types related to IP addresses and hostnames ***/
|
||||
|
||||
typedef ip-address {
|
||||
type union {
|
||||
type inet:ipv4-address;
|
||||
type inet:ipv6-address;
|
||||
}
|
||||
description
|
||||
"The ip-address type represents an IP address and is IP
|
||||
version neutral. The format of the textual representation
|
||||
implies the IP version. This type supports scoped addresses
|
||||
by allowing zone identifiers in the address format.";
|
||||
reference
|
||||
"RFC 4007: IPv6 Scoped Address Architecture";
|
||||
}
|
||||
|
||||
typedef ipv4-address {
|
||||
type string {
|
||||
pattern
|
||||
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
|
||||
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
|
||||
+ '(%[\p{N}\p{L}]+)?';
|
||||
}
|
||||
description
|
||||
"The ipv4-address type represents an IPv4 address in
|
||||
dotted-quad notation. The IPv4 address may include a zone
|
||||
index, separated by a % sign.
|
||||
|
||||
The zone index is used to disambiguate identical address
|
||||
values. For link-local addresses, the zone index will
|
||||
typically be the interface index number or the name of an
|
||||
interface. If the zone index is not present, the default
|
||||
zone of the device will be used.
|
||||
|
||||
The canonical format for the zone index is the numerical
|
||||
format";
|
||||
}
|
||||
|
||||
typedef ipv6-address {
|
||||
type string {
|
||||
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
|
||||
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
|
||||
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
|
||||
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
|
||||
+ '(%[\p{N}\p{L}]+)?';
|
||||
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
|
||||
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
|
||||
+ '(%.+)?';
|
||||
}
|
||||
description
|
||||
"The ipv6-address type represents an IPv6 address in full,
|
||||
mixed, shortened, and shortened-mixed notation. The IPv6
|
||||
address may include a zone index, separated by a % sign.
|
||||
|
||||
The zone index is used to disambiguate identical address
|
||||
values. For link-local addresses, the zone index will
|
||||
typically be the interface index number or the name of an
|
||||
interface. If the zone index is not present, the default
|
||||
zone of the device will be used.
|
||||
|
||||
The canonical format of IPv6 addresses uses the textual
|
||||
representation defined in Section 4 of RFC 5952. The
|
||||
canonical format for the zone index is the numerical
|
||||
format as described in Section 11.2 of RFC 4007.";
|
||||
reference
|
||||
"RFC 4291: IP Version 6 Addressing Architecture
|
||||
RFC 4007: IPv6 Scoped Address Architecture
|
||||
RFC 5952: A Recommendation for IPv6 Address Text
|
||||
Representation";
|
||||
}
|
||||
|
||||
typedef ip-address-no-zone {
|
||||
type union {
|
||||
type inet:ipv4-address-no-zone;
|
||||
type inet:ipv6-address-no-zone;
|
||||
}
|
||||
description
|
||||
"The ip-address-no-zone type represents an IP address and is
|
||||
IP version neutral. The format of the textual representation
|
||||
implies the IP version. This type does not support scoped
|
||||
addresses since it does not allow zone identifiers in the
|
||||
address format.";
|
||||
reference
|
||||
"RFC 4007: IPv6 Scoped Address Architecture";
|
||||
}
|
||||
|
||||
typedef ipv4-address-no-zone {
|
||||
type inet:ipv4-address {
|
||||
pattern '[0-9\.]*';
|
||||
}
|
||||
description
|
||||
"An IPv4 address without a zone index. This type, derived from
|
||||
ipv4-address, may be used in situations where the zone is
|
||||
known from the context and hence no zone index is needed.";
|
||||
}
|
||||
|
||||
typedef ipv6-address-no-zone {
|
||||
type inet:ipv6-address {
|
||||
pattern '[0-9a-fA-F:\.]*';
|
||||
}
|
||||
description
|
||||
"An IPv6 address without a zone index. This type, derived from
|
||||
ipv6-address, may be used in situations where the zone is
|
||||
known from the context and hence no zone index is needed.";
|
||||
reference
|
||||
"RFC 4291: IP Version 6 Addressing Architecture
|
||||
RFC 4007: IPv6 Scoped Address Architecture
|
||||
RFC 5952: A Recommendation for IPv6 Address Text
|
||||
Representation";
|
||||
}
|
||||
|
||||
typedef ip-prefix {
|
||||
type union {
|
||||
type inet:ipv4-prefix;
|
||||
type inet:ipv6-prefix;
|
||||
}
|
||||
description
|
||||
"The ip-prefix type represents an IP prefix and is IP
|
||||
version neutral. The format of the textual representations
|
||||
implies the IP version.";
|
||||
}
|
||||
|
||||
typedef ipv4-prefix {
|
||||
type string {
|
||||
pattern
|
||||
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
|
||||
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
|
||||
+ '/(([0-9])|([1-2][0-9])|(3[0-2]))';
|
||||
}
|
||||
description
|
||||
"The ipv4-prefix type represents an IPv4 address prefix.
|
||||
The prefix length is given by the number following the
|
||||
slash character and must be less than or equal to 32.
|
||||
|
||||
A prefix length value of n corresponds to an IP address
|
||||
mask that has n contiguous 1-bits from the most
|
||||
significant bit (MSB) and all other bits set to 0.
|
||||
|
||||
The canonical format of an IPv4 prefix has all bits of
|
||||
the IPv4 address set to zero that are not part of the
|
||||
IPv4 prefix.";
|
||||
}
|
||||
|
||||
typedef ipv6-prefix {
|
||||
type string {
|
||||
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
|
||||
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
|
||||
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
|
||||
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
|
||||
+ '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
|
||||
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
|
||||
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
|
||||
+ '(/.+)';
|
||||
}
|
||||
|
||||
description
|
||||
"The ipv6-prefix type represents an IPv6 address prefix.
|
||||
The prefix length is given by the number following the
|
||||
slash character and must be less than or equal to 128.
|
||||
|
||||
A prefix length value of n corresponds to an IP address
|
||||
mask that has n contiguous 1-bits from the most
|
||||
significant bit (MSB) and all other bits set to 0.
|
||||
|
||||
The IPv6 address should have all bits that do not belong
|
||||
to the prefix set to zero.
|
||||
|
||||
The canonical format of an IPv6 prefix has all bits of
|
||||
the IPv6 address set to zero that are not part of the
|
||||
IPv6 prefix. Furthermore, the IPv6 address is represented
|
||||
as defined in Section 4 of RFC 5952.";
|
||||
reference
|
||||
"RFC 5952: A Recommendation for IPv6 Address Text
|
||||
Representation";
|
||||
}
|
||||
|
||||
/*** collection of domain name and URI types ***/
|
||||
|
||||
typedef domain-name {
|
||||
type string {
|
||||
pattern
|
||||
'((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
|
||||
+ '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
|
||||
+ '|\.';
|
||||
length "1..253";
|
||||
}
|
||||
description
|
||||
"The domain-name type represents a DNS domain name. The
|
||||
name SHOULD be fully qualified whenever possible.
|
||||
|
||||
Internet domain names are only loosely specified. Section
|
||||
3.5 of RFC 1034 recommends a syntax (modified in Section
|
||||
2.1 of RFC 1123). The pattern above is intended to allow
|
||||
for current practice in domain name use, and some possible
|
||||
future expansion. It is designed to hold various types of
|
||||
domain names, including names used for A or AAAA records
|
||||
(host names) and other records, such as SRV records. Note
|
||||
that Internet host names have a stricter syntax (described
|
||||
in RFC 952) than the DNS recommendations in RFCs 1034 and
|
||||
1123, and that systems that want to store host names in
|
||||
schema nodes using the domain-name type are recommended to
|
||||
adhere to this stricter standard to ensure interoperability.
|
||||
|
||||
The encoding of DNS names in the DNS protocol is limited
|
||||
to 255 characters. Since the encoding consists of labels
|
||||
prefixed by a length bytes and there is a trailing NULL
|
||||
byte, only 253 characters can appear in the textual dotted
|
||||
notation.
|
||||
|
||||
The description clause of schema nodes using the domain-name
|
||||
type MUST describe when and how these names are resolved to
|
||||
IP addresses. Note that the resolution of a domain-name value
|
||||
may require to query multiple DNS records (e.g., A for IPv4
|
||||
and AAAA for IPv6). The order of the resolution process and
|
||||
which DNS record takes precedence can either be defined
|
||||
explicitly or may depend on the configuration of the
|
||||
resolver.
|
||||
|
||||
Domain-name values use the US-ASCII encoding. Their canonical
|
||||
format uses lowercase US-ASCII characters. Internationalized
|
||||
domain names MUST be A-labels as per RFC 5890.";
|
||||
reference
|
||||
"RFC 952: DoD Internet Host Table Specification
|
||||
RFC 1034: Domain Names - Concepts and Facilities
|
||||
RFC 1123: Requirements for Internet Hosts -- Application
|
||||
and Support
|
||||
RFC 2782: A DNS RR for specifying the location of services
|
||||
(DNS SRV)
|
||||
RFC 5890: Internationalized Domain Names in Applications
|
||||
(IDNA): Definitions and Document Framework";
|
||||
}
|
||||
|
||||
typedef host {
|
||||
type union {
|
||||
type inet:ip-address;
|
||||
type inet:domain-name;
|
||||
}
|
||||
description
|
||||
"The host type represents either an IP address or a DNS
|
||||
domain name.";
|
||||
}
|
||||
|
||||
typedef uri {
|
||||
type string;
|
||||
description
|
||||
"The uri type represents a Uniform Resource Identifier
|
||||
(URI) as defined by STD 66.
|
||||
|
||||
Objects using the uri type MUST be in US-ASCII encoding,
|
||||
and MUST be normalized as described by RFC 3986 Sections
|
||||
6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
|
||||
percent-encoding is removed, and all case-insensitive
|
||||
characters are set to lowercase except for hexadecimal
|
||||
digits, which are normalized to uppercase as described in
|
||||
Section 6.2.2.1.
|
||||
|
||||
The purpose of this normalization is to help provide
|
||||
unique URIs. Note that this normalization is not
|
||||
sufficient to provide uniqueness. Two URIs that are
|
||||
textually distinct after this normalization may still be
|
||||
equivalent.
|
||||
|
||||
Objects using the uri type may restrict the schemes that
|
||||
they permit. For example, 'data:' and 'urn:' schemes
|
||||
might not be appropriate.
|
||||
|
||||
A zero-length URI is not a valid URI. This can be used to
|
||||
express 'URI absent' where required.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the Uri SMIv2 textual convention defined in RFC 5017.";
|
||||
reference
|
||||
"RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
|
||||
RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
|
||||
Group: Uniform Resource Identifiers (URIs), URLs,
|
||||
and Uniform Resource Names (URNs): Clarifications
|
||||
and Recommendations
|
||||
RFC 5017: MIB Textual Conventions for Uniform Resource
|
||||
Identifiers (URIs)";
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,876 @@
|
||||
module ietf-ip {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-ip";
|
||||
prefix ip;
|
||||
|
||||
import ietf-interfaces {
|
||||
prefix if;
|
||||
}
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETMOD (Network Modeling) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <https://datatracker.ietf.org/wg/netmod/>
|
||||
WG List: <mailto:netmod@ietf.org>
|
||||
|
||||
Editor: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>";
|
||||
description
|
||||
"This module contains a collection of YANG definitions for
|
||||
managing IP implementations.
|
||||
|
||||
Copyright (c) 2018 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(https://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 8344; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision 2018-02-22 {
|
||||
description
|
||||
"Updated to support NMDA.";
|
||||
reference
|
||||
"RFC 8344: A YANG Data Model for IP Management";
|
||||
}
|
||||
|
||||
revision 2014-06-16 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 7277: A YANG Data Model for IP Management";
|
||||
}
|
||||
|
||||
/*
|
||||
* Features
|
||||
*/
|
||||
|
||||
feature ipv4-non-contiguous-netmasks {
|
||||
description
|
||||
"Indicates support for configuring non-contiguous
|
||||
subnet masks.";
|
||||
}
|
||||
|
||||
feature ipv6-privacy-autoconf {
|
||||
description
|
||||
"Indicates support for privacy extensions for stateless address
|
||||
autoconfiguration in IPv6.";
|
||||
reference
|
||||
"RFC 4941: Privacy Extensions for Stateless Address
|
||||
Autoconfiguration in IPv6";
|
||||
}
|
||||
|
||||
/*
|
||||
* Typedefs
|
||||
*/
|
||||
|
||||
typedef ip-address-origin {
|
||||
type enumeration {
|
||||
enum other {
|
||||
description
|
||||
"None of the following.";
|
||||
}
|
||||
|
||||
enum static {
|
||||
description
|
||||
"Indicates that the address has been statically
|
||||
configured -- for example, using the Network Configuration
|
||||
Protocol (NETCONF) or a command line interface.";
|
||||
}
|
||||
enum dhcp {
|
||||
description
|
||||
"Indicates an address that has been assigned to this
|
||||
system by a DHCP server.";
|
||||
}
|
||||
enum link-layer {
|
||||
description
|
||||
"Indicates an address created by IPv6 stateless
|
||||
autoconfiguration that embeds a link-layer address in its
|
||||
interface identifier.";
|
||||
}
|
||||
enum random {
|
||||
description
|
||||
"Indicates an address chosen by the system at
|
||||
random, e.g., an IPv4 address within 169.254/16, a
|
||||
temporary address as described in RFC 4941, or a
|
||||
semantically opaque address as described in RFC 7217.";
|
||||
reference
|
||||
"RFC 4941: Privacy Extensions for Stateless Address
|
||||
Autoconfiguration in IPv6
|
||||
RFC 7217: A Method for Generating Semantically Opaque
|
||||
Interface Identifiers with IPv6 Stateless
|
||||
Address Autoconfiguration (SLAAC)";
|
||||
}
|
||||
}
|
||||
description
|
||||
"The origin of an address.";
|
||||
}
|
||||
|
||||
typedef neighbor-origin {
|
||||
type enumeration {
|
||||
enum other {
|
||||
description
|
||||
"None of the following.";
|
||||
}
|
||||
enum static {
|
||||
description
|
||||
"Indicates that the mapping has been statically
|
||||
configured -- for example, using NETCONF or a command line
|
||||
interface.";
|
||||
}
|
||||
|
||||
enum dynamic {
|
||||
description
|
||||
"Indicates that the mapping has been dynamically resolved
|
||||
using, for example, IPv4 ARP or the IPv6 Neighbor
|
||||
Discovery protocol.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"The origin of a neighbor entry.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Data nodes
|
||||
*/
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
description
|
||||
"IP parameters on interfaces.
|
||||
|
||||
If an interface is not capable of running IP, the server
|
||||
must not allow the client to configure these parameters.";
|
||||
|
||||
container ipv4 {
|
||||
presence
|
||||
"Enables IPv4 unless the 'enabled' leaf
|
||||
(which defaults to 'true') is set to 'false'";
|
||||
description
|
||||
"Parameters for the IPv4 address family.";
|
||||
|
||||
leaf enabled {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Controls whether IPv4 is enabled or disabled on this
|
||||
interface. When IPv4 is enabled, this interface is
|
||||
connected to an IPv4 stack, and the interface can send
|
||||
and receive IPv4 packets.";
|
||||
}
|
||||
leaf forwarding {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Controls IPv4 packet forwarding of datagrams received by,
|
||||
but not addressed to, this interface. IPv4 routers
|
||||
forward datagrams. IPv4 hosts do not (except those
|
||||
source-routed via the host).";
|
||||
}
|
||||
|
||||
leaf mtu {
|
||||
type uint16 {
|
||||
range "68..max";
|
||||
}
|
||||
units "octets";
|
||||
description
|
||||
"The size, in octets, of the largest IPv4 packet that the
|
||||
interface will send and receive.
|
||||
|
||||
The server may restrict the allowed values for this leaf,
|
||||
depending on the interface's type.
|
||||
|
||||
If this leaf is not configured, the operationally used MTU
|
||||
depends on the interface's type.";
|
||||
reference
|
||||
"RFC 791: Internet Protocol";
|
||||
}
|
||||
list address {
|
||||
key "ip";
|
||||
description
|
||||
"The list of IPv4 addresses on the interface.";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv4-address-no-zone;
|
||||
description
|
||||
"The IPv4 address on the interface.";
|
||||
}
|
||||
choice subnet {
|
||||
mandatory true;
|
||||
description
|
||||
"The subnet can be specified as a prefix length or,
|
||||
if the server supports non-contiguous netmasks, as
|
||||
a netmask.";
|
||||
leaf prefix-length {
|
||||
type uint8 {
|
||||
range "0..32";
|
||||
}
|
||||
description
|
||||
"The length of the subnet prefix.";
|
||||
}
|
||||
leaf netmask {
|
||||
if-feature ipv4-non-contiguous-netmasks;
|
||||
type yang:dotted-quad;
|
||||
description
|
||||
"The subnet specified as a netmask.";
|
||||
}
|
||||
}
|
||||
|
||||
leaf origin {
|
||||
type ip-address-origin;
|
||||
config false;
|
||||
description
|
||||
"The origin of this address.";
|
||||
}
|
||||
}
|
||||
list neighbor {
|
||||
key "ip";
|
||||
description
|
||||
"A list of mappings from IPv4 addresses to
|
||||
link-layer addresses.
|
||||
|
||||
Entries in this list in the intended configuration are
|
||||
used as static entries in the ARP Cache.
|
||||
|
||||
In the operational state, this list represents the ARP
|
||||
Cache.";
|
||||
reference
|
||||
"RFC 826: An Ethernet Address Resolution Protocol";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv4-address-no-zone;
|
||||
description
|
||||
"The IPv4 address of the neighbor node.";
|
||||
}
|
||||
leaf link-layer-address {
|
||||
type yang:phys-address;
|
||||
mandatory true;
|
||||
description
|
||||
"The link-layer address of the neighbor node.";
|
||||
}
|
||||
leaf origin {
|
||||
type neighbor-origin;
|
||||
config false;
|
||||
description
|
||||
"The origin of this neighbor entry.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container ipv6 {
|
||||
presence
|
||||
"Enables IPv6 unless the 'enabled' leaf
|
||||
(which defaults to 'true') is set to 'false'";
|
||||
description
|
||||
"Parameters for the IPv6 address family.";
|
||||
|
||||
leaf enabled {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Controls whether IPv6 is enabled or disabled on this
|
||||
interface. When IPv6 is enabled, this interface is
|
||||
connected to an IPv6 stack, and the interface can send
|
||||
and receive IPv6 packets.";
|
||||
}
|
||||
leaf forwarding {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Controls IPv6 packet forwarding of datagrams received by,
|
||||
but not addressed to, this interface. IPv6 routers
|
||||
forward datagrams. IPv6 hosts do not (except those
|
||||
source-routed via the host).";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
|
||||
Section 6.2.1, IsRouter";
|
||||
}
|
||||
leaf mtu {
|
||||
type uint32 {
|
||||
range "1280..max";
|
||||
}
|
||||
units "octets";
|
||||
description
|
||||
"The size, in octets, of the largest IPv6 packet that the
|
||||
interface will send and receive.
|
||||
|
||||
The server may restrict the allowed values for this leaf,
|
||||
depending on the interface's type.
|
||||
|
||||
If this leaf is not configured, the operationally used MTU
|
||||
depends on the interface's type.";
|
||||
reference
|
||||
"RFC 8200: Internet Protocol, Version 6 (IPv6)
|
||||
Specification
|
||||
Section 5";
|
||||
}
|
||||
|
||||
list address {
|
||||
key "ip";
|
||||
description
|
||||
"The list of IPv6 addresses on the interface.";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv6-address-no-zone;
|
||||
description
|
||||
"The IPv6 address on the interface.";
|
||||
}
|
||||
leaf prefix-length {
|
||||
type uint8 {
|
||||
range "0..128";
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"The length of the subnet prefix.";
|
||||
}
|
||||
leaf origin {
|
||||
type ip-address-origin;
|
||||
config false;
|
||||
description
|
||||
"The origin of this address.";
|
||||
}
|
||||
leaf status {
|
||||
type enumeration {
|
||||
enum preferred {
|
||||
description
|
||||
"This is a valid address that can appear as the
|
||||
destination or source address of a packet.";
|
||||
}
|
||||
enum deprecated {
|
||||
description
|
||||
"This is a valid but deprecated address that should
|
||||
no longer be used as a source address in new
|
||||
communications, but packets addressed to such an
|
||||
address are processed as expected.";
|
||||
}
|
||||
enum invalid {
|
||||
description
|
||||
"This isn't a valid address, and it shouldn't appear
|
||||
as the destination or source address of a packet.";
|
||||
}
|
||||
|
||||
enum inaccessible {
|
||||
description
|
||||
"The address is not accessible because the interface
|
||||
to which this address is assigned is not
|
||||
operational.";
|
||||
}
|
||||
enum unknown {
|
||||
description
|
||||
"The status cannot be determined for some reason.";
|
||||
}
|
||||
enum tentative {
|
||||
description
|
||||
"The uniqueness of the address on the link is being
|
||||
verified. Addresses in this state should not be
|
||||
used for general communication and should only be
|
||||
used to determine the uniqueness of the address.";
|
||||
}
|
||||
enum duplicate {
|
||||
description
|
||||
"The address has been determined to be non-unique on
|
||||
the link and so must not be used.";
|
||||
}
|
||||
enum optimistic {
|
||||
description
|
||||
"The address is available for use, subject to
|
||||
restrictions, while its uniqueness on a link is
|
||||
being verified.";
|
||||
}
|
||||
}
|
||||
config false;
|
||||
description
|
||||
"The status of an address. Most of the states correspond
|
||||
to states from the IPv6 Stateless Address
|
||||
Autoconfiguration protocol.";
|
||||
reference
|
||||
"RFC 4293: Management Information Base for the
|
||||
Internet Protocol (IP)
|
||||
- IpAddressStatusTC
|
||||
RFC 4862: IPv6 Stateless Address Autoconfiguration";
|
||||
}
|
||||
}
|
||||
|
||||
list neighbor {
|
||||
key "ip";
|
||||
description
|
||||
"A list of mappings from IPv6 addresses to
|
||||
link-layer addresses.
|
||||
|
||||
Entries in this list in the intended configuration are
|
||||
used as static entries in the Neighbor Cache.
|
||||
|
||||
In the operational state, this list represents the
|
||||
Neighbor Cache.";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv6-address-no-zone;
|
||||
description
|
||||
"The IPv6 address of the neighbor node.";
|
||||
}
|
||||
leaf link-layer-address {
|
||||
type yang:phys-address;
|
||||
mandatory true;
|
||||
description
|
||||
"The link-layer address of the neighbor node.
|
||||
|
||||
In the operational state, if the neighbor's 'state' leaf
|
||||
is 'incomplete', this leaf is not instantiated.";
|
||||
}
|
||||
leaf origin {
|
||||
type neighbor-origin;
|
||||
config false;
|
||||
description
|
||||
"The origin of this neighbor entry.";
|
||||
}
|
||||
leaf is-router {
|
||||
type empty;
|
||||
config false;
|
||||
description
|
||||
"Indicates that the neighbor node acts as a router.";
|
||||
}
|
||||
|
||||
leaf state {
|
||||
type enumeration {
|
||||
enum incomplete {
|
||||
description
|
||||
"Address resolution is in progress, and the
|
||||
link-layer address of the neighbor has not yet been
|
||||
determined.";
|
||||
}
|
||||
enum reachable {
|
||||
description
|
||||
"Roughly speaking, the neighbor is known to have been
|
||||
reachable recently (within tens of seconds ago).";
|
||||
}
|
||||
enum stale {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, but
|
||||
until traffic is sent to the neighbor no attempt
|
||||
should be made to verify its reachability.";
|
||||
}
|
||||
enum delay {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, and
|
||||
traffic has recently been sent to the neighbor.
|
||||
Rather than probe the neighbor immediately, however,
|
||||
delay sending probes for a short while in order to
|
||||
give upper-layer protocols a chance to provide
|
||||
reachability confirmation.";
|
||||
}
|
||||
enum probe {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, and
|
||||
unicast Neighbor Solicitation probes are being sent
|
||||
to verify reachability.";
|
||||
}
|
||||
}
|
||||
config false;
|
||||
description
|
||||
"The Neighbor Unreachability Detection state of this
|
||||
entry.";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
|
||||
Section 7.3.2";
|
||||
}
|
||||
}
|
||||
|
||||
leaf dup-addr-detect-transmits {
|
||||
type uint32;
|
||||
default 1;
|
||||
description
|
||||
"The number of consecutive Neighbor Solicitation messages
|
||||
sent while performing Duplicate Address Detection on a
|
||||
tentative address. A value of zero indicates that
|
||||
Duplicate Address Detection is not performed on
|
||||
tentative addresses. A value of one indicates a single
|
||||
transmission with no follow-up retransmissions.";
|
||||
reference
|
||||
"RFC 4862: IPv6 Stateless Address Autoconfiguration";
|
||||
}
|
||||
container autoconf {
|
||||
description
|
||||
"Parameters to control the autoconfiguration of IPv6
|
||||
addresses, as described in RFC 4862.";
|
||||
reference
|
||||
"RFC 4862: IPv6 Stateless Address Autoconfiguration";
|
||||
|
||||
leaf create-global-addresses {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"If enabled, the host creates global addresses as
|
||||
described in RFC 4862.";
|
||||
reference
|
||||
"RFC 4862: IPv6 Stateless Address Autoconfiguration
|
||||
Section 5.5";
|
||||
}
|
||||
leaf create-temporary-addresses {
|
||||
if-feature ipv6-privacy-autoconf;
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"If enabled, the host creates temporary addresses as
|
||||
described in RFC 4941.";
|
||||
reference
|
||||
"RFC 4941: Privacy Extensions for Stateless Address
|
||||
Autoconfiguration in IPv6";
|
||||
}
|
||||
|
||||
leaf temporary-valid-lifetime {
|
||||
if-feature ipv6-privacy-autoconf;
|
||||
type uint32;
|
||||
units "seconds";
|
||||
default 604800;
|
||||
description
|
||||
"The time period during which the temporary address
|
||||
is valid.";
|
||||
reference
|
||||
"RFC 4941: Privacy Extensions for Stateless Address
|
||||
Autoconfiguration in IPv6
|
||||
- TEMP_VALID_LIFETIME";
|
||||
}
|
||||
leaf temporary-preferred-lifetime {
|
||||
if-feature ipv6-privacy-autoconf;
|
||||
type uint32;
|
||||
units "seconds";
|
||||
default 86400;
|
||||
description
|
||||
"The time period during which the temporary address is
|
||||
preferred.";
|
||||
reference
|
||||
"RFC 4941: Privacy Extensions for Stateless Address
|
||||
Autoconfiguration in IPv6
|
||||
- TEMP_PREFERRED_LIFETIME";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy operational state data nodes
|
||||
*/
|
||||
|
||||
augment "/if:interfaces-state/if:interface" {
|
||||
status deprecated;
|
||||
description
|
||||
"Data nodes for the operational state of IP on interfaces.";
|
||||
|
||||
container ipv4 {
|
||||
presence
|
||||
"Present if IPv4 is enabled on this interface";
|
||||
config false;
|
||||
status deprecated;
|
||||
description
|
||||
"Interface-specific parameters for the IPv4 address family.";
|
||||
|
||||
leaf forwarding {
|
||||
type boolean;
|
||||
status deprecated;
|
||||
description
|
||||
"Indicates whether IPv4 packet forwarding is enabled or
|
||||
disabled on this interface.";
|
||||
}
|
||||
leaf mtu {
|
||||
type uint16 {
|
||||
range "68..max";
|
||||
}
|
||||
units "octets";
|
||||
status deprecated;
|
||||
description
|
||||
"The size, in octets, of the largest IPv4 packet that the
|
||||
interface will send and receive.";
|
||||
reference
|
||||
"RFC 791: Internet Protocol";
|
||||
}
|
||||
list address {
|
||||
key "ip";
|
||||
status deprecated;
|
||||
description
|
||||
"The list of IPv4 addresses on the interface.";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv4-address-no-zone;
|
||||
status deprecated;
|
||||
description
|
||||
"The IPv4 address on the interface.";
|
||||
}
|
||||
choice subnet {
|
||||
status deprecated;
|
||||
description
|
||||
"The subnet can be specified as a prefix length or,
|
||||
if the server supports non-contiguous netmasks, as
|
||||
a netmask.";
|
||||
leaf prefix-length {
|
||||
type uint8 {
|
||||
range "0..32";
|
||||
}
|
||||
status deprecated;
|
||||
description
|
||||
"The length of the subnet prefix.";
|
||||
}
|
||||
leaf netmask {
|
||||
if-feature ipv4-non-contiguous-netmasks;
|
||||
type yang:dotted-quad;
|
||||
status deprecated;
|
||||
description
|
||||
"The subnet specified as a netmask.";
|
||||
}
|
||||
}
|
||||
leaf origin {
|
||||
type ip-address-origin;
|
||||
status deprecated;
|
||||
description
|
||||
"The origin of this address.";
|
||||
}
|
||||
}
|
||||
list neighbor {
|
||||
key "ip";
|
||||
status deprecated;
|
||||
description
|
||||
"A list of mappings from IPv4 addresses to
|
||||
link-layer addresses.
|
||||
|
||||
This list represents the ARP Cache.";
|
||||
reference
|
||||
"RFC 826: An Ethernet Address Resolution Protocol";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv4-address-no-zone;
|
||||
status deprecated;
|
||||
description
|
||||
"The IPv4 address of the neighbor node.";
|
||||
}
|
||||
|
||||
leaf link-layer-address {
|
||||
type yang:phys-address;
|
||||
status deprecated;
|
||||
description
|
||||
"The link-layer address of the neighbor node.";
|
||||
}
|
||||
leaf origin {
|
||||
type neighbor-origin;
|
||||
status deprecated;
|
||||
description
|
||||
"The origin of this neighbor entry.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container ipv6 {
|
||||
presence
|
||||
"Present if IPv6 is enabled on this interface";
|
||||
config false;
|
||||
status deprecated;
|
||||
description
|
||||
"Parameters for the IPv6 address family.";
|
||||
|
||||
leaf forwarding {
|
||||
type boolean;
|
||||
default false;
|
||||
status deprecated;
|
||||
description
|
||||
"Indicates whether IPv6 packet forwarding is enabled or
|
||||
disabled on this interface.";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
|
||||
Section 6.2.1, IsRouter";
|
||||
}
|
||||
leaf mtu {
|
||||
type uint32 {
|
||||
range "1280..max";
|
||||
}
|
||||
units "octets";
|
||||
status deprecated;
|
||||
description
|
||||
"The size, in octets, of the largest IPv6 packet that the
|
||||
interface will send and receive.";
|
||||
reference
|
||||
"RFC 8200: Internet Protocol, Version 6 (IPv6)
|
||||
Specification
|
||||
Section 5";
|
||||
}
|
||||
list address {
|
||||
key "ip";
|
||||
status deprecated;
|
||||
description
|
||||
"The list of IPv6 addresses on the interface.";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv6-address-no-zone;
|
||||
status deprecated;
|
||||
description
|
||||
"The IPv6 address on the interface.";
|
||||
}
|
||||
leaf prefix-length {
|
||||
type uint8 {
|
||||
range "0..128";
|
||||
}
|
||||
mandatory true;
|
||||
status deprecated;
|
||||
description
|
||||
"The length of the subnet prefix.";
|
||||
}
|
||||
leaf origin {
|
||||
type ip-address-origin;
|
||||
status deprecated;
|
||||
description
|
||||
"The origin of this address.";
|
||||
}
|
||||
leaf status {
|
||||
type enumeration {
|
||||
enum preferred {
|
||||
description
|
||||
"This is a valid address that can appear as the
|
||||
destination or source address of a packet.";
|
||||
}
|
||||
enum deprecated {
|
||||
description
|
||||
"This is a valid but deprecated address that should
|
||||
no longer be used as a source address in new
|
||||
communications, but packets addressed to such an
|
||||
address are processed as expected.";
|
||||
}
|
||||
enum invalid {
|
||||
description
|
||||
"This isn't a valid address, and it shouldn't appear
|
||||
as the destination or source address of a packet.";
|
||||
}
|
||||
|
||||
enum inaccessible {
|
||||
description
|
||||
"The address is not accessible because the interface
|
||||
to which this address is assigned is not
|
||||
operational.";
|
||||
}
|
||||
enum unknown {
|
||||
description
|
||||
"The status cannot be determined for some reason.";
|
||||
}
|
||||
enum tentative {
|
||||
description
|
||||
"The uniqueness of the address on the link is being
|
||||
verified. Addresses in this state should not be
|
||||
used for general communication and should only be
|
||||
used to determine the uniqueness of the address.";
|
||||
}
|
||||
enum duplicate {
|
||||
description
|
||||
"The address has been determined to be non-unique on
|
||||
the link and so must not be used.";
|
||||
}
|
||||
enum optimistic {
|
||||
description
|
||||
"The address is available for use, subject to
|
||||
restrictions, while its uniqueness on a link is
|
||||
being verified.";
|
||||
}
|
||||
}
|
||||
status deprecated;
|
||||
description
|
||||
"The status of an address. Most of the states correspond
|
||||
to states from the IPv6 Stateless Address
|
||||
Autoconfiguration protocol.";
|
||||
reference
|
||||
"RFC 4293: Management Information Base for the
|
||||
Internet Protocol (IP)
|
||||
- IpAddressStatusTC
|
||||
RFC 4862: IPv6 Stateless Address Autoconfiguration";
|
||||
}
|
||||
}
|
||||
|
||||
list neighbor {
|
||||
key "ip";
|
||||
status deprecated;
|
||||
description
|
||||
"A list of mappings from IPv6 addresses to
|
||||
link-layer addresses.
|
||||
|
||||
This list represents the Neighbor Cache.";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv6-address-no-zone;
|
||||
status deprecated;
|
||||
description
|
||||
"The IPv6 address of the neighbor node.";
|
||||
}
|
||||
leaf link-layer-address {
|
||||
type yang:phys-address;
|
||||
status deprecated;
|
||||
description
|
||||
"The link-layer address of the neighbor node.";
|
||||
}
|
||||
leaf origin {
|
||||
type neighbor-origin;
|
||||
status deprecated;
|
||||
description
|
||||
"The origin of this neighbor entry.";
|
||||
}
|
||||
leaf is-router {
|
||||
type empty;
|
||||
status deprecated;
|
||||
description
|
||||
"Indicates that the neighbor node acts as a router.";
|
||||
}
|
||||
leaf state {
|
||||
type enumeration {
|
||||
enum incomplete {
|
||||
description
|
||||
"Address resolution is in progress, and the
|
||||
link-layer address of the neighbor has not yet been
|
||||
determined.";
|
||||
}
|
||||
enum reachable {
|
||||
description
|
||||
"Roughly speaking, the neighbor is known to have been
|
||||
reachable recently (within tens of seconds ago).";
|
||||
}
|
||||
enum stale {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, but
|
||||
until traffic is sent to the neighbor no attempt
|
||||
should be made to verify its reachability.";
|
||||
}
|
||||
enum delay {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, and
|
||||
traffic has recently been sent to the neighbor.
|
||||
Rather than probe the neighbor immediately, however,
|
||||
delay sending probes for a short while in order to
|
||||
give upper-layer protocols a chance to provide
|
||||
reachability confirmation.";
|
||||
}
|
||||
enum probe {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, and
|
||||
unicast Neighbor Solicitation probes are being sent
|
||||
to verify reachability.";
|
||||
}
|
||||
}
|
||||
status deprecated;
|
||||
description
|
||||
"The Neighbor Unreachability Detection state of this
|
||||
entry.";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
|
||||
Section 7.3.2";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
module ietf-netconf-acm {
|
||||
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";
|
||||
|
||||
prefix nacm;
|
||||
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <https://datatracker.ietf.org/wg/netconf/>
|
||||
WG List: <mailto:netconf@ietf.org>
|
||||
|
||||
Author: Andy Bierman
|
||||
<mailto:andy@yumaworks.com>
|
||||
|
||||
Author: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>";
|
||||
|
||||
description
|
||||
"Network Configuration Access Control Model.
|
||||
|
||||
Copyright (c) 2012 - 2018 IETF Trust and the persons
|
||||
identified as authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD
|
||||
License set forth in Section 4.c of the IETF Trust's
|
||||
Legal Provisions Relating to IETF Documents
|
||||
(https://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 8341; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision "2018-02-14" {
|
||||
description
|
||||
"Added support for YANG 1.1 actions and notifications tied to
|
||||
data nodes. Clarified how NACM extensions can be used by
|
||||
other data models.";
|
||||
reference
|
||||
"RFC 8341: Network Configuration Access Control Model";
|
||||
}
|
||||
|
||||
revision "2012-02-22" {
|
||||
description
|
||||
"Initial version.";
|
||||
reference
|
||||
"RFC 6536: Network Configuration Protocol (NETCONF)
|
||||
Access Control Model";
|
||||
}
|
||||
|
||||
/*
|
||||
* Extension statements
|
||||
*/
|
||||
|
||||
extension default-deny-write {
|
||||
description
|
||||
"Used to indicate that the data model node
|
||||
represents a sensitive security system parameter.
|
||||
|
||||
If present, the NETCONF server will only allow the designated
|
||||
'recovery session' to have write access to the node. An
|
||||
explicit access control rule is required for all other users.
|
||||
|
||||
If the NACM module is used, then it must be enabled (i.e.,
|
||||
/nacm/enable-nacm object equals 'true'), or this extension
|
||||
is ignored.
|
||||
|
||||
The 'default-deny-write' extension MAY appear within a data
|
||||
definition statement. It is ignored otherwise.";
|
||||
}
|
||||
|
||||
extension default-deny-all {
|
||||
description
|
||||
"Used to indicate that the data model node
|
||||
controls a very sensitive security system parameter.
|
||||
|
||||
If present, the NETCONF server will only allow the designated
|
||||
'recovery session' to have read, write, or execute access to
|
||||
the node. An explicit access control rule is required for all
|
||||
other users.
|
||||
|
||||
If the NACM module is used, then it must be enabled (i.e.,
|
||||
/nacm/enable-nacm object equals 'true'), or this extension
|
||||
is ignored.
|
||||
|
||||
The 'default-deny-all' extension MAY appear within a data
|
||||
definition statement, 'rpc' statement, or 'notification'
|
||||
statement. It is ignored otherwise.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Derived types
|
||||
*/
|
||||
|
||||
typedef user-name-type {
|
||||
type string {
|
||||
length "1..max";
|
||||
}
|
||||
description
|
||||
"General-purpose username string.";
|
||||
}
|
||||
|
||||
typedef matchall-string-type {
|
||||
type string {
|
||||
pattern '\*';
|
||||
}
|
||||
description
|
||||
"The string containing a single asterisk '*' is used
|
||||
to conceptually represent all possible values
|
||||
for the particular leaf using this data type.";
|
||||
}
|
||||
|
||||
typedef access-operations-type {
|
||||
type bits {
|
||||
bit create {
|
||||
description
|
||||
"Any protocol operation that creates a
|
||||
new data node.";
|
||||
}
|
||||
bit read {
|
||||
description
|
||||
"Any protocol operation or notification that
|
||||
returns the value of a data node.";
|
||||
}
|
||||
bit update {
|
||||
description
|
||||
"Any protocol operation that alters an existing
|
||||
data node.";
|
||||
}
|
||||
bit delete {
|
||||
description
|
||||
"Any protocol operation that removes a data node.";
|
||||
}
|
||||
bit exec {
|
||||
description
|
||||
"Execution access to the specified protocol operation.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Access operation.";
|
||||
}
|
||||
|
||||
typedef group-name-type {
|
||||
type string {
|
||||
length "1..max";
|
||||
pattern '[^\*].*';
|
||||
}
|
||||
description
|
||||
"Name of administrative group to which
|
||||
users can be assigned.";
|
||||
}
|
||||
|
||||
typedef action-type {
|
||||
type enumeration {
|
||||
enum permit {
|
||||
description
|
||||
"Requested action is permitted.";
|
||||
}
|
||||
enum deny {
|
||||
description
|
||||
"Requested action is denied.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Action taken by the server when a particular
|
||||
rule matches.";
|
||||
}
|
||||
|
||||
typedef node-instance-identifier {
|
||||
type yang:xpath1.0;
|
||||
description
|
||||
"Path expression used to represent a special
|
||||
data node, action, or notification instance-identifier
|
||||
string.
|
||||
|
||||
A node-instance-identifier value is an
|
||||
unrestricted YANG instance-identifier expression.
|
||||
All the same rules as an instance-identifier apply,
|
||||
except that predicates for keys are optional. If a key
|
||||
predicate is missing, then the node-instance-identifier
|
||||
represents all possible server instances for that key.
|
||||
|
||||
This XML Path Language (XPath) expression is evaluated in the
|
||||
following context:
|
||||
|
||||
o The set of namespace declarations are those in scope on
|
||||
the leaf element where this type is used.
|
||||
|
||||
o The set of variable bindings contains one variable,
|
||||
'USER', which contains the name of the user of the
|
||||
current session.
|
||||
|
||||
o The function library is the core function library, but
|
||||
note that due to the syntax restrictions of an
|
||||
instance-identifier, no functions are allowed.
|
||||
|
||||
o The context node is the root node in the data tree.
|
||||
|
||||
The accessible tree includes actions and notifications tied
|
||||
to data nodes.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Data definition statements
|
||||
*/
|
||||
|
||||
container nacm {
|
||||
nacm:default-deny-all;
|
||||
|
||||
description
|
||||
"Parameters for NETCONF access control model.";
|
||||
|
||||
leaf enable-nacm {
|
||||
type boolean;
|
||||
default "true";
|
||||
description
|
||||
"Enables or disables all NETCONF access control
|
||||
enforcement. If 'true', then enforcement
|
||||
is enabled. If 'false', then enforcement
|
||||
is disabled.";
|
||||
}
|
||||
|
||||
leaf read-default {
|
||||
type action-type;
|
||||
default "permit";
|
||||
description
|
||||
"Controls whether read access is granted if
|
||||
no appropriate rule is found for a
|
||||
particular read request.";
|
||||
}
|
||||
|
||||
leaf write-default {
|
||||
type action-type;
|
||||
default "deny";
|
||||
description
|
||||
"Controls whether create, update, or delete access
|
||||
is granted if no appropriate rule is found for a
|
||||
particular write request.";
|
||||
}
|
||||
|
||||
leaf exec-default {
|
||||
type action-type;
|
||||
default "permit";
|
||||
description
|
||||
"Controls whether exec access is granted if no appropriate
|
||||
rule is found for a particular protocol operation request.";
|
||||
}
|
||||
|
||||
leaf enable-external-groups {
|
||||
type boolean;
|
||||
default "true";
|
||||
description
|
||||
"Controls whether the server uses the groups reported by the
|
||||
NETCONF transport layer when it assigns the user to a set of
|
||||
NACM groups. If this leaf has the value 'false', any group
|
||||
names reported by the transport layer are ignored by the
|
||||
server.";
|
||||
}
|
||||
|
||||
leaf denied-operations {
|
||||
type yang:zero-based-counter32;
|
||||
config false;
|
||||
mandatory true;
|
||||
description
|
||||
"Number of times since the server last restarted that a
|
||||
protocol operation request was denied.";
|
||||
}
|
||||
|
||||
leaf denied-data-writes {
|
||||
type yang:zero-based-counter32;
|
||||
config false;
|
||||
mandatory true;
|
||||
description
|
||||
"Number of times since the server last restarted that a
|
||||
protocol operation request to alter
|
||||
a configuration datastore was denied.";
|
||||
}
|
||||
|
||||
leaf denied-notifications {
|
||||
type yang:zero-based-counter32;
|
||||
config false;
|
||||
mandatory true;
|
||||
description
|
||||
"Number of times since the server last restarted that
|
||||
a notification was dropped for a subscription because
|
||||
access to the event type was denied.";
|
||||
}
|
||||
|
||||
container groups {
|
||||
description
|
||||
"NETCONF access control groups.";
|
||||
|
||||
list group {
|
||||
key name;
|
||||
|
||||
description
|
||||
"One NACM group entry. This list will only contain
|
||||
configured entries, not any entries learned from
|
||||
any transport protocols.";
|
||||
|
||||
leaf name {
|
||||
type group-name-type;
|
||||
description
|
||||
"Group name associated with this entry.";
|
||||
}
|
||||
|
||||
leaf-list user-name {
|
||||
type user-name-type;
|
||||
description
|
||||
"Each entry identifies the username of
|
||||
a member of the group associated with
|
||||
this entry.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list rule-list {
|
||||
key name;
|
||||
ordered-by user;
|
||||
description
|
||||
"An ordered collection of access control rules.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1..max";
|
||||
}
|
||||
description
|
||||
"Arbitrary name assigned to the rule-list.";
|
||||
}
|
||||
leaf-list group {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type group-name-type;
|
||||
}
|
||||
description
|
||||
"List of administrative groups that will be
|
||||
assigned the associated access rights
|
||||
defined by the 'rule' list.
|
||||
|
||||
The string '*' indicates that all groups apply to the
|
||||
entry.";
|
||||
}
|
||||
|
||||
list rule {
|
||||
key name;
|
||||
ordered-by user;
|
||||
description
|
||||
"One access control rule.
|
||||
|
||||
Rules are processed in user-defined order until a match is
|
||||
found. A rule matches if 'module-name', 'rule-type', and
|
||||
'access-operations' match the request. If a rule
|
||||
matches, the 'action' leaf determines whether or not
|
||||
access is granted.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1..max";
|
||||
}
|
||||
description
|
||||
"Arbitrary name assigned to the rule.";
|
||||
}
|
||||
|
||||
leaf module-name {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type string;
|
||||
}
|
||||
default "*";
|
||||
description
|
||||
"Name of the module associated with this rule.
|
||||
|
||||
This leaf matches if it has the value '*' or if the
|
||||
object being accessed is defined in the module with the
|
||||
specified module name.";
|
||||
}
|
||||
choice rule-type {
|
||||
description
|
||||
"This choice matches if all leafs present in the rule
|
||||
match the request. If no leafs are present, the
|
||||
choice matches all requests.";
|
||||
case protocol-operation {
|
||||
leaf rpc-name {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type string;
|
||||
}
|
||||
description
|
||||
"This leaf matches if it has the value '*' or if
|
||||
its value equals the requested protocol operation
|
||||
name.";
|
||||
}
|
||||
}
|
||||
case notification {
|
||||
leaf notification-name {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type string;
|
||||
}
|
||||
description
|
||||
"This leaf matches if it has the value '*' or if its
|
||||
value equals the requested notification name.";
|
||||
}
|
||||
}
|
||||
|
||||
case data-node {
|
||||
leaf path {
|
||||
type node-instance-identifier;
|
||||
mandatory true;
|
||||
description
|
||||
"Data node instance-identifier associated with the
|
||||
data node, action, or notification controlled by
|
||||
this rule.
|
||||
|
||||
Configuration data or state data
|
||||
instance-identifiers start with a top-level
|
||||
data node. A complete instance-identifier is
|
||||
required for this type of path value.
|
||||
|
||||
The special value '/' refers to all possible
|
||||
datastore contents.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leaf access-operations {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type access-operations-type;
|
||||
}
|
||||
default "*";
|
||||
description
|
||||
"Access operations associated with this rule.
|
||||
|
||||
This leaf matches if it has the value '*' or if the
|
||||
bit corresponding to the requested operation is set.";
|
||||
}
|
||||
|
||||
leaf action {
|
||||
type action-type;
|
||||
mandatory true;
|
||||
description
|
||||
"The access control action associated with the
|
||||
rule. If a rule has been determined to match a
|
||||
particular request, then this object is used
|
||||
to determine whether to permit or deny the
|
||||
request.";
|
||||
}
|
||||
|
||||
leaf comment {
|
||||
type string;
|
||||
description
|
||||
"A textual description of the access rule.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,800 @@
|
||||
module ietf-system {
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-system";
|
||||
prefix "sys";
|
||||
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
|
||||
import ietf-netconf-acm {
|
||||
prefix nacm;
|
||||
}
|
||||
|
||||
import iana-crypt-hash {
|
||||
prefix ianach;
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <http://tools.ietf.org/wg/netmod/>
|
||||
WG List: <mailto:netmod@ietf.org>
|
||||
|
||||
WG Chair: Thomas Nadeau
|
||||
<mailto:tnadeau@lucidvision.com>
|
||||
|
||||
WG Chair: Juergen Schoenwaelder
|
||||
<mailto:j.schoenwaelder@jacobs-university.de>
|
||||
|
||||
Editor: Andy Bierman
|
||||
<mailto:andy@yumaworks.com>
|
||||
|
||||
Editor: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>";
|
||||
|
||||
description
|
||||
"This module contains a collection of YANG definitions for the
|
||||
configuration and identification of some common system
|
||||
properties within a device containing a NETCONF server. This
|
||||
includes data node definitions for system identification,
|
||||
time-of-day management, user management, DNS resolver
|
||||
configuration, and some protocol operations for system
|
||||
management.
|
||||
|
||||
Copyright (c) 2014 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 7317; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision 2014-08-06 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 7317: A YANG Data Model for System Management";
|
||||
}
|
||||
|
||||
/*
|
||||
* Typedefs
|
||||
*/
|
||||
|
||||
typedef timezone-name {
|
||||
type string;
|
||||
description
|
||||
"A time zone name as used by the Time Zone Database,
|
||||
sometimes referred to as the 'Olson Database'.
|
||||
|
||||
The exact set of valid values is an implementation-specific
|
||||
matter. Client discovery of the exact set of time zone names
|
||||
for a particular server is out of scope.";
|
||||
reference
|
||||
"RFC 6557: Procedures for Maintaining the Time Zone Database";
|
||||
}
|
||||
|
||||
/*
|
||||
* Features
|
||||
*/
|
||||
|
||||
feature radius {
|
||||
description
|
||||
"Indicates that the device can be configured as a RADIUS
|
||||
client.";
|
||||
reference
|
||||
"RFC 2865: Remote Authentication Dial In User Service (RADIUS)";
|
||||
}
|
||||
|
||||
feature authentication {
|
||||
description
|
||||
"Indicates that the device supports configuration of
|
||||
user authentication.";
|
||||
}
|
||||
|
||||
feature local-users {
|
||||
if-feature authentication;
|
||||
description
|
||||
"Indicates that the device supports configuration of
|
||||
local user authentication.";
|
||||
}
|
||||
|
||||
feature radius-authentication {
|
||||
if-feature radius;
|
||||
if-feature authentication;
|
||||
description
|
||||
"Indicates that the device supports configuration of user
|
||||
authentication over RADIUS.";
|
||||
reference
|
||||
"RFC 2865: Remote Authentication Dial In User Service (RADIUS)
|
||||
RFC 5607: Remote Authentication Dial-In User Service (RADIUS)
|
||||
Authorization for Network Access Server (NAS)
|
||||
Management";
|
||||
}
|
||||
|
||||
feature ntp {
|
||||
description
|
||||
"Indicates that the device can be configured to use one or
|
||||
more NTP servers to set the system date and time.";
|
||||
}
|
||||
|
||||
feature ntp-udp-port {
|
||||
if-feature ntp;
|
||||
description
|
||||
"Indicates that the device supports the configuration of
|
||||
the UDP port for NTP servers.
|
||||
|
||||
This is a 'feature', since many implementations do not support
|
||||
any port other than the default port.";
|
||||
}
|
||||
|
||||
feature timezone-name {
|
||||
description
|
||||
"Indicates that the local time zone on the device
|
||||
can be configured to use the TZ database
|
||||
to set the time zone and manage daylight saving time.";
|
||||
reference
|
||||
"RFC 6557: Procedures for Maintaining the Time Zone Database";
|
||||
}
|
||||
|
||||
feature dns-udp-tcp-port {
|
||||
description
|
||||
"Indicates that the device supports the configuration of
|
||||
the UDP and TCP port for DNS servers.
|
||||
|
||||
This is a 'feature', since many implementations do not support
|
||||
any port other than the default port.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Identities
|
||||
*/
|
||||
|
||||
identity authentication-method {
|
||||
description
|
||||
"Base identity for user authentication methods.";
|
||||
}
|
||||
|
||||
identity radius {
|
||||
base authentication-method;
|
||||
description
|
||||
"Indicates user authentication using RADIUS.";
|
||||
reference
|
||||
"RFC 2865: Remote Authentication Dial In User Service (RADIUS)
|
||||
RFC 5607: Remote Authentication Dial-In User Service (RADIUS)
|
||||
Authorization for Network Access Server (NAS)
|
||||
Management";
|
||||
}
|
||||
|
||||
identity local-users {
|
||||
base authentication-method;
|
||||
description
|
||||
"Indicates password-based authentication of locally
|
||||
configured users.";
|
||||
}
|
||||
|
||||
identity radius-authentication-type {
|
||||
description
|
||||
"Base identity for RADIUS authentication types.";
|
||||
}
|
||||
|
||||
identity radius-pap {
|
||||
base radius-authentication-type;
|
||||
description
|
||||
"The device requests Password Authentication Protocol (PAP)
|
||||
authentication from the RADIUS server.";
|
||||
reference
|
||||
"RFC 2865: Remote Authentication Dial In User Service (RADIUS)";
|
||||
}
|
||||
|
||||
identity radius-chap {
|
||||
base radius-authentication-type;
|
||||
description
|
||||
"The device requests Challenge Handshake Authentication
|
||||
Protocol (CHAP) authentication from the RADIUS server.";
|
||||
reference
|
||||
"RFC 2865: Remote Authentication Dial In User Service (RADIUS)";
|
||||
}
|
||||
|
||||
/*
|
||||
* Configuration data nodes
|
||||
*/
|
||||
|
||||
container system {
|
||||
description
|
||||
"System group configuration.";
|
||||
|
||||
leaf contact {
|
||||
type string;
|
||||
description
|
||||
"The administrator contact information for the system.
|
||||
|
||||
A server implementation MAY map this leaf to the sysContact
|
||||
MIB object. Such an implementation needs to use some
|
||||
mechanism to handle the differences in size and characters
|
||||
allowed between this leaf and sysContact. The definition of
|
||||
such a mechanism is outside the scope of this document.";
|
||||
reference
|
||||
"RFC 3418: Management Information Base (MIB) for the
|
||||
Simple Network Management Protocol (SNMP)
|
||||
SNMPv2-MIB.sysContact";
|
||||
}
|
||||
leaf hostname {
|
||||
type inet:domain-name;
|
||||
description
|
||||
"The name of the host. This name can be a single domain
|
||||
label or the fully qualified domain name of the host.";
|
||||
}
|
||||
leaf location {
|
||||
type string;
|
||||
description
|
||||
"The system location.
|
||||
|
||||
A server implementation MAY map this leaf to the sysLocation
|
||||
MIB object. Such an implementation needs to use some
|
||||
mechanism to handle the differences in size and characters
|
||||
allowed between this leaf and sysLocation. The definition
|
||||
of such a mechanism is outside the scope of this document.";
|
||||
reference
|
||||
"RFC 3418: Management Information Base (MIB) for the
|
||||
Simple Network Management Protocol (SNMP)
|
||||
SNMPv2-MIB.sysLocation";
|
||||
}
|
||||
|
||||
container clock {
|
||||
description
|
||||
"Configuration of the system date and time properties.";
|
||||
|
||||
choice timezone {
|
||||
description
|
||||
"The system time zone information.";
|
||||
|
||||
case timezone-name {
|
||||
if-feature timezone-name;
|
||||
leaf timezone-name {
|
||||
type timezone-name;
|
||||
description
|
||||
"The TZ database name to use for the system, such
|
||||
as 'Europe/Stockholm'.";
|
||||
}
|
||||
}
|
||||
case timezone-utc-offset {
|
||||
leaf timezone-utc-offset {
|
||||
type int16 {
|
||||
range "-1500 .. 1500";
|
||||
}
|
||||
units "minutes";
|
||||
description
|
||||
"The number of minutes to add to UTC time to
|
||||
identify the time zone for this system. For example,
|
||||
'UTC - 8:00 hours' would be represented as '-480'.
|
||||
Note that automatic daylight saving time adjustment
|
||||
is not provided if this object is used.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container ntp {
|
||||
if-feature ntp;
|
||||
presence
|
||||
"Enables the NTP client unless the 'enabled' leaf
|
||||
(which defaults to 'true') is set to 'false'";
|
||||
description
|
||||
"Configuration of the NTP client.";
|
||||
|
||||
leaf enabled {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Indicates that the system should attempt to
|
||||
synchronize the system clock with an NTP server
|
||||
from the 'ntp/server' list.";
|
||||
}
|
||||
list server {
|
||||
key name;
|
||||
description
|
||||
"List of NTP servers to use for system clock
|
||||
synchronization. If '/system/ntp/enabled'
|
||||
is 'true', then the system will attempt to
|
||||
contact and utilize the specified NTP servers.";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for the NTP server.";
|
||||
}
|
||||
choice transport {
|
||||
mandatory true;
|
||||
description
|
||||
"The transport-protocol-specific parameters for this
|
||||
server.";
|
||||
|
||||
case udp {
|
||||
container udp {
|
||||
description
|
||||
"Contains UDP-specific configuration parameters
|
||||
for NTP.";
|
||||
leaf address {
|
||||
type inet:host;
|
||||
mandatory true;
|
||||
description
|
||||
"The address of the NTP server.";
|
||||
}
|
||||
leaf port {
|
||||
if-feature ntp-udp-port;
|
||||
type inet:port-number;
|
||||
default 123;
|
||||
description
|
||||
"The port number of the NTP server.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf association-type {
|
||||
type enumeration {
|
||||
enum server {
|
||||
description
|
||||
"Use client association mode. This device
|
||||
will not provide synchronization to the
|
||||
configured NTP server.";
|
||||
}
|
||||
enum peer {
|
||||
description
|
||||
"Use symmetric active association mode.
|
||||
This device may provide synchronization
|
||||
to the configured NTP server.";
|
||||
}
|
||||
enum pool {
|
||||
description
|
||||
"Use client association mode with one or
|
||||
more of the NTP servers found by DNS
|
||||
resolution of the domain name given by
|
||||
the 'address' leaf. This device will not
|
||||
provide synchronization to the servers.";
|
||||
}
|
||||
}
|
||||
default server;
|
||||
description
|
||||
"The desired association type for this NTP server.";
|
||||
}
|
||||
leaf iburst {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Indicates whether this server should enable burst
|
||||
synchronization or not.";
|
||||
}
|
||||
leaf prefer {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Indicates whether this server should be preferred
|
||||
or not.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container dns-resolver {
|
||||
description
|
||||
"Configuration of the DNS resolver.";
|
||||
|
||||
leaf-list search {
|
||||
type inet:domain-name;
|
||||
ordered-by user;
|
||||
description
|
||||
"An ordered list of domains to search when resolving
|
||||
a host name.";
|
||||
}
|
||||
list server {
|
||||
key name;
|
||||
ordered-by user;
|
||||
description
|
||||
"List of the DNS servers that the resolver should query.
|
||||
|
||||
When the resolver is invoked by a calling application, it
|
||||
sends the query to the first name server in this list. If
|
||||
no response has been received within 'timeout' seconds,
|
||||
the resolver continues with the next server in the list.
|
||||
If no response is received from any server, the resolver
|
||||
continues with the first server again. When the resolver
|
||||
has traversed the list 'attempts' times without receiving
|
||||
any response, it gives up and returns an error to the
|
||||
calling application.
|
||||
|
||||
Implementations MAY limit the number of entries in this
|
||||
list.";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for the DNS server.";
|
||||
}
|
||||
choice transport {
|
||||
mandatory true;
|
||||
description
|
||||
"The transport-protocol-specific parameters for this
|
||||
server.";
|
||||
|
||||
case udp-and-tcp {
|
||||
container udp-and-tcp {
|
||||
description
|
||||
"Contains UDP- and TCP-specific configuration
|
||||
parameters for DNS.";
|
||||
reference
|
||||
"RFC 1035: Domain Names - Implementation and
|
||||
Specification
|
||||
RFC 5966: DNS Transport over TCP - Implementation
|
||||
Requirements";
|
||||
|
||||
leaf address {
|
||||
type inet:ip-address;
|
||||
mandatory true;
|
||||
description
|
||||
"The address of the DNS server.";
|
||||
}
|
||||
leaf port {
|
||||
if-feature dns-udp-tcp-port;
|
||||
type inet:port-number;
|
||||
default 53;
|
||||
description
|
||||
"The UDP and TCP port number of the DNS server.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
container options {
|
||||
description
|
||||
"Resolver options. The set of available options has been
|
||||
limited to those that are generally available across
|
||||
different resolver implementations and generally useful.";
|
||||
leaf timeout {
|
||||
type uint8 {
|
||||
range "1..max";
|
||||
}
|
||||
units "seconds";
|
||||
default "5";
|
||||
description
|
||||
"The amount of time the resolver will wait for a
|
||||
response from each remote name server before
|
||||
retrying the query via a different name server.";
|
||||
}
|
||||
leaf attempts {
|
||||
type uint8 {
|
||||
range "1..max";
|
||||
}
|
||||
default "2";
|
||||
description
|
||||
"The number of times the resolver will send a query to
|
||||
all of its name servers before giving up and returning
|
||||
an error to the calling application.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container radius {
|
||||
if-feature radius;
|
||||
|
||||
description
|
||||
"Configuration of the RADIUS client.";
|
||||
|
||||
list server {
|
||||
key name;
|
||||
ordered-by user;
|
||||
description
|
||||
"List of RADIUS servers used by the device.
|
||||
|
||||
When the RADIUS client is invoked by a calling
|
||||
application, it sends the query to the first server in
|
||||
this list. If no response has been received within
|
||||
'timeout' seconds, the client continues with the next
|
||||
server in the list. If no response is received from any
|
||||
server, the client continues with the first server again.
|
||||
When the client has traversed the list 'attempts' times
|
||||
without receiving any response, it gives up and returns an
|
||||
error to the calling application.";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for the RADIUS server.";
|
||||
}
|
||||
choice transport {
|
||||
mandatory true;
|
||||
description
|
||||
"The transport-protocol-specific parameters for this
|
||||
server.";
|
||||
|
||||
case udp {
|
||||
container udp {
|
||||
description
|
||||
"Contains UDP-specific configuration parameters
|
||||
for RADIUS.";
|
||||
leaf address {
|
||||
type inet:host;
|
||||
mandatory true;
|
||||
description
|
||||
"The address of the RADIUS server.";
|
||||
}
|
||||
|
||||
leaf authentication-port {
|
||||
type inet:port-number;
|
||||
default "1812";
|
||||
description
|
||||
"The port number of the RADIUS server.";
|
||||
}
|
||||
leaf shared-secret {
|
||||
type string;
|
||||
mandatory true;
|
||||
nacm:default-deny-all;
|
||||
description
|
||||
"The shared secret, which is known to both the
|
||||
RADIUS client and server.";
|
||||
reference
|
||||
"RFC 2865: Remote Authentication Dial In User
|
||||
Service (RADIUS)";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf authentication-type {
|
||||
type identityref {
|
||||
base radius-authentication-type;
|
||||
}
|
||||
default radius-pap;
|
||||
description
|
||||
"The authentication type requested from the RADIUS
|
||||
server.";
|
||||
}
|
||||
}
|
||||
container options {
|
||||
description
|
||||
"RADIUS client options.";
|
||||
|
||||
leaf timeout {
|
||||
type uint8 {
|
||||
range "1..max";
|
||||
}
|
||||
units "seconds";
|
||||
default "5";
|
||||
description
|
||||
"The number of seconds the device will wait for a
|
||||
response from each RADIUS server before trying with a
|
||||
different server.";
|
||||
}
|
||||
|
||||
leaf attempts {
|
||||
type uint8 {
|
||||
range "1..max";
|
||||
}
|
||||
default "2";
|
||||
description
|
||||
"The number of times the device will send a query to
|
||||
all of its RADIUS servers before giving up.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container authentication {
|
||||
nacm:default-deny-write;
|
||||
if-feature authentication;
|
||||
|
||||
description
|
||||
"The authentication configuration subtree.";
|
||||
|
||||
leaf-list user-authentication-order {
|
||||
type identityref {
|
||||
base authentication-method;
|
||||
}
|
||||
must '(. != "sys:radius" or ../../radius/server)' {
|
||||
error-message
|
||||
"When 'radius' is used, a RADIUS server"
|
||||
+ " must be configured.";
|
||||
description
|
||||
"When 'radius' is used as an authentication method,
|
||||
a RADIUS server must be configured.";
|
||||
}
|
||||
ordered-by user;
|
||||
|
||||
description
|
||||
"When the device authenticates a user with a password,
|
||||
it tries the authentication methods in this leaf-list in
|
||||
order. If authentication with one method fails, the next
|
||||
method is used. If no method succeeds, the user is
|
||||
denied access.
|
||||
|
||||
An empty user-authentication-order leaf-list still allows
|
||||
authentication of users using mechanisms that do not
|
||||
involve a password.
|
||||
|
||||
If the 'radius-authentication' feature is advertised by
|
||||
the NETCONF server, the 'radius' identity can be added to
|
||||
this list.
|
||||
|
||||
If the 'local-users' feature is advertised by the
|
||||
NETCONF server, the 'local-users' identity can be
|
||||
added to this list.";
|
||||
}
|
||||
|
||||
list user {
|
||||
if-feature local-users;
|
||||
key name;
|
||||
description
|
||||
"The list of local users configured on this device.";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"The user name string identifying this entry.";
|
||||
}
|
||||
leaf password {
|
||||
type ianach:crypt-hash;
|
||||
description
|
||||
"The password for this entry.";
|
||||
}
|
||||
list authorized-key {
|
||||
key name;
|
||||
description
|
||||
"A list of public SSH keys for this user. These keys
|
||||
are allowed for SSH authentication, as described in
|
||||
RFC 4253.";
|
||||
reference
|
||||
"RFC 4253: The Secure Shell (SSH) Transport Layer
|
||||
Protocol";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for the SSH key.";
|
||||
}
|
||||
|
||||
leaf algorithm {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"The public key algorithm name for this SSH key.
|
||||
|
||||
Valid values are the values in the IANA 'Secure Shell
|
||||
(SSH) Protocol Parameters' registry, Public Key
|
||||
Algorithm Names.";
|
||||
reference
|
||||
"IANA 'Secure Shell (SSH) Protocol Parameters'
|
||||
registry, Public Key Algorithm Names";
|
||||
}
|
||||
leaf key-data {
|
||||
type binary;
|
||||
mandatory true;
|
||||
description
|
||||
"The binary public key data for this SSH key, as
|
||||
specified by RFC 4253, Section 6.6, i.e.:
|
||||
|
||||
string certificate or public key format
|
||||
identifier
|
||||
byte[n] key/certificate data.";
|
||||
reference
|
||||
"RFC 4253: The Secure Shell (SSH) Transport Layer
|
||||
Protocol";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Operational state data nodes
|
||||
*/
|
||||
|
||||
container system-state {
|
||||
config false;
|
||||
description
|
||||
"System group operational state.";
|
||||
|
||||
container platform {
|
||||
description
|
||||
"Contains vendor-specific information for
|
||||
identifying the system platform and operating system.";
|
||||
reference
|
||||
"IEEE Std 1003.1-2008 - sys/utsname.h";
|
||||
|
||||
leaf os-name {
|
||||
type string;
|
||||
description
|
||||
"The name of the operating system in use -
|
||||
for example, 'Linux'.";
|
||||
reference
|
||||
"IEEE Std 1003.1-2008 - utsname.sysname";
|
||||
}
|
||||
leaf os-release {
|
||||
type string;
|
||||
description
|
||||
"The current release level of the operating
|
||||
system in use. This string MAY indicate
|
||||
the OS source code revision.";
|
||||
reference
|
||||
"IEEE Std 1003.1-2008 - utsname.release";
|
||||
}
|
||||
leaf os-version {
|
||||
type string;
|
||||
description
|
||||
"The current version level of the operating
|
||||
system in use. This string MAY indicate
|
||||
the specific OS build date and target variant
|
||||
information.";
|
||||
reference
|
||||
"IEEE Std 1003.1-2008 - utsname.version";
|
||||
}
|
||||
leaf machine {
|
||||
type string;
|
||||
description
|
||||
"A vendor-specific identifier string representing
|
||||
the hardware in use.";
|
||||
reference
|
||||
"IEEE Std 1003.1-2008 - utsname.machine";
|
||||
}
|
||||
}
|
||||
|
||||
container clock {
|
||||
description
|
||||
"Monitoring of the system date and time properties.";
|
||||
|
||||
leaf current-datetime {
|
||||
type yang:date-and-time;
|
||||
description
|
||||
"The current system date and time.";
|
||||
}
|
||||
|
||||
leaf boot-datetime {
|
||||
type yang:date-and-time;
|
||||
description
|
||||
"The system date and time when the system last restarted.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc set-current-datetime {
|
||||
nacm:default-deny-all;
|
||||
description
|
||||
"Set the /system-state/clock/current-datetime leaf
|
||||
to the specified value.
|
||||
|
||||
If the system is using NTP (i.e., /system/ntp/enabled
|
||||
is set to 'true'), then this operation will fail with
|
||||
error-tag 'operation-failed' and error-app-tag value of
|
||||
'ntp-active'.";
|
||||
input {
|
||||
leaf current-datetime {
|
||||
type yang:date-and-time;
|
||||
mandatory true;
|
||||
description
|
||||
"The current system date and time.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc system-restart {
|
||||
nacm:default-deny-all;
|
||||
description
|
||||
"Request that the entire system be restarted immediately.
|
||||
A server SHOULD send an rpc reply to the client before
|
||||
restarting the system.";
|
||||
}
|
||||
|
||||
rpc system-shutdown {
|
||||
nacm:default-deny-all;
|
||||
description
|
||||
"Request that the entire system be shut down immediately.
|
||||
A server SHOULD send an rpc reply to the client before
|
||||
shutting down the system.";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
module ietf-yang-types {
|
||||
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
|
||||
prefix "yang";
|
||||
|
||||
organization
|
||||
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <http://tools.ietf.org/wg/netmod/>
|
||||
WG List: <mailto:netmod@ietf.org>
|
||||
|
||||
WG Chair: David Kessens
|
||||
<mailto:david.kessens@nsn.com>
|
||||
|
||||
WG Chair: Juergen Schoenwaelder
|
||||
<mailto:j.schoenwaelder@jacobs-university.de>
|
||||
|
||||
Editor: Juergen Schoenwaelder
|
||||
<mailto:j.schoenwaelder@jacobs-university.de>";
|
||||
|
||||
description
|
||||
"This module contains a collection of generally useful derived
|
||||
YANG data types.
|
||||
|
||||
Copyright (c) 2013 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 6991; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision 2013-07-15 {
|
||||
description
|
||||
"This revision adds the following new data types:
|
||||
- yang-identifier
|
||||
- hex-string
|
||||
- uuid
|
||||
- dotted-quad";
|
||||
reference
|
||||
"RFC 6991: Common YANG Data Types";
|
||||
}
|
||||
|
||||
revision 2010-09-24 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 6021: Common YANG Data Types";
|
||||
}
|
||||
|
||||
/*** collection of counter and gauge types ***/
|
||||
|
||||
typedef counter32 {
|
||||
type uint32;
|
||||
description
|
||||
"The counter32 type represents a non-negative integer
|
||||
that monotonically increases until it reaches a
|
||||
maximum value of 2^32-1 (4294967295 decimal), when it
|
||||
wraps around and starts increasing again from zero.
|
||||
|
||||
Counters have no defined 'initial' value, and thus, a
|
||||
single value of a counter has (in general) no information
|
||||
content. Discontinuities in the monotonically increasing
|
||||
value normally occur at re-initialization of the
|
||||
management system, and at other times as specified in the
|
||||
description of a schema node using this type. If such
|
||||
other times can occur, for example, the creation of
|
||||
a schema node of type counter32 at times other than
|
||||
re-initialization, then a corresponding schema node
|
||||
should be defined, with an appropriate type, to indicate
|
||||
the last discontinuity.
|
||||
|
||||
The counter32 type should not be used for configuration
|
||||
schema nodes. A default statement SHOULD NOT be used in
|
||||
combination with the type counter32.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the Counter32 type of the SMIv2.";
|
||||
reference
|
||||
"RFC 2578: Structure of Management Information Version 2
|
||||
(SMIv2)";
|
||||
}
|
||||
|
||||
typedef zero-based-counter32 {
|
||||
type yang:counter32;
|
||||
default "0";
|
||||
description
|
||||
"The zero-based-counter32 type represents a counter32
|
||||
that has the defined 'initial' value zero.
|
||||
|
||||
A schema node of this type will be set to zero (0) on creation
|
||||
and will thereafter increase monotonically until it reaches
|
||||
a maximum value of 2^32-1 (4294967295 decimal), when it
|
||||
wraps around and starts increasing again from zero.
|
||||
|
||||
Provided that an application discovers a new schema node
|
||||
of this type within the minimum time to wrap, it can use the
|
||||
'initial' value as a delta. It is important for a management
|
||||
station to be aware of this minimum time and the actual time
|
||||
between polls, and to discard data if the actual time is too
|
||||
long or there is no defined minimum time.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the ZeroBasedCounter32 textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 4502: Remote Network Monitoring Management Information
|
||||
Base Version 2";
|
||||
}
|
||||
|
||||
typedef counter64 {
|
||||
type uint64;
|
||||
description
|
||||
"The counter64 type represents a non-negative integer
|
||||
that monotonically increases until it reaches a
|
||||
maximum value of 2^64-1 (18446744073709551615 decimal),
|
||||
when it wraps around and starts increasing again from zero.
|
||||
|
||||
Counters have no defined 'initial' value, and thus, a
|
||||
single value of a counter has (in general) no information
|
||||
content. Discontinuities in the monotonically increasing
|
||||
value normally occur at re-initialization of the
|
||||
management system, and at other times as specified in the
|
||||
description of a schema node using this type. If such
|
||||
other times can occur, for example, the creation of
|
||||
a schema node of type counter64 at times other than
|
||||
re-initialization, then a corresponding schema node
|
||||
should be defined, with an appropriate type, to indicate
|
||||
the last discontinuity.
|
||||
|
||||
The counter64 type should not be used for configuration
|
||||
schema nodes. A default statement SHOULD NOT be used in
|
||||
combination with the type counter64.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the Counter64 type of the SMIv2.";
|
||||
reference
|
||||
"RFC 2578: Structure of Management Information Version 2
|
||||
(SMIv2)";
|
||||
}
|
||||
|
||||
typedef zero-based-counter64 {
|
||||
type yang:counter64;
|
||||
default "0";
|
||||
description
|
||||
"The zero-based-counter64 type represents a counter64 that
|
||||
has the defined 'initial' value zero.
|
||||
|
||||
A schema node of this type will be set to zero (0) on creation
|
||||
and will thereafter increase monotonically until it reaches
|
||||
a maximum value of 2^64-1 (18446744073709551615 decimal),
|
||||
when it wraps around and starts increasing again from zero.
|
||||
|
||||
Provided that an application discovers a new schema node
|
||||
of this type within the minimum time to wrap, it can use the
|
||||
'initial' value as a delta. It is important for a management
|
||||
station to be aware of this minimum time and the actual time
|
||||
between polls, and to discard data if the actual time is too
|
||||
long or there is no defined minimum time.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the ZeroBasedCounter64 textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 2856: Textual Conventions for Additional High Capacity
|
||||
Data Types";
|
||||
}
|
||||
|
||||
typedef gauge32 {
|
||||
type uint32;
|
||||
description
|
||||
"The gauge32 type represents a non-negative integer, which
|
||||
may increase or decrease, but shall never exceed a maximum
|
||||
value, nor fall below a minimum value. The maximum value
|
||||
cannot be greater than 2^32-1 (4294967295 decimal), and
|
||||
the minimum value cannot be smaller than 0. The value of
|
||||
a gauge32 has its maximum value whenever the information
|
||||
being modeled is greater than or equal to its maximum
|
||||
value, and has its minimum value whenever the information
|
||||
being modeled is smaller than or equal to its minimum value.
|
||||
If the information being modeled subsequently decreases
|
||||
below (increases above) the maximum (minimum) value, the
|
||||
gauge32 also decreases (increases).
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the Gauge32 type of the SMIv2.";
|
||||
reference
|
||||
"RFC 2578: Structure of Management Information Version 2
|
||||
(SMIv2)";
|
||||
}
|
||||
|
||||
typedef gauge64 {
|
||||
type uint64;
|
||||
description
|
||||
"The gauge64 type represents a non-negative integer, which
|
||||
may increase or decrease, but shall never exceed a maximum
|
||||
value, nor fall below a minimum value. The maximum value
|
||||
cannot be greater than 2^64-1 (18446744073709551615), and
|
||||
the minimum value cannot be smaller than 0. The value of
|
||||
a gauge64 has its maximum value whenever the information
|
||||
being modeled is greater than or equal to its maximum
|
||||
value, and has its minimum value whenever the information
|
||||
being modeled is smaller than or equal to its minimum value.
|
||||
If the information being modeled subsequently decreases
|
||||
below (increases above) the maximum (minimum) value, the
|
||||
gauge64 also decreases (increases).
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the CounterBasedGauge64 SMIv2 textual convention defined
|
||||
in RFC 2856";
|
||||
reference
|
||||
"RFC 2856: Textual Conventions for Additional High Capacity
|
||||
Data Types";
|
||||
}
|
||||
|
||||
/*** collection of identifier-related types ***/
|
||||
|
||||
typedef object-identifier {
|
||||
type string {
|
||||
pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
|
||||
+ '(\.(0|([1-9]\d*)))*';
|
||||
}
|
||||
description
|
||||
"The object-identifier type represents administratively
|
||||
assigned names in a registration-hierarchical-name tree.
|
||||
|
||||
Values of this type are denoted as a sequence of numerical
|
||||
non-negative sub-identifier values. Each sub-identifier
|
||||
value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
|
||||
are separated by single dots and without any intermediate
|
||||
whitespace.
|
||||
|
||||
The ASN.1 standard restricts the value space of the first
|
||||
sub-identifier to 0, 1, or 2. Furthermore, the value space
|
||||
of the second sub-identifier is restricted to the range
|
||||
0 to 39 if the first sub-identifier is 0 or 1. Finally,
|
||||
the ASN.1 standard requires that an object identifier
|
||||
has always at least two sub-identifiers. The pattern
|
||||
captures these restrictions.
|
||||
|
||||
Although the number of sub-identifiers is not limited,
|
||||
module designers should realize that there may be
|
||||
implementations that stick with the SMIv2 limit of 128
|
||||
sub-identifiers.
|
||||
|
||||
This type is a superset of the SMIv2 OBJECT IDENTIFIER type
|
||||
since it is not restricted to 128 sub-identifiers. Hence,
|
||||
this type SHOULD NOT be used to represent the SMIv2 OBJECT
|
||||
IDENTIFIER type; the object-identifier-128 type SHOULD be
|
||||
used instead.";
|
||||
reference
|
||||
"ISO9834-1: Information technology -- Open Systems
|
||||
Interconnection -- Procedures for the operation of OSI
|
||||
Registration Authorities: General procedures and top
|
||||
arcs of the ASN.1 Object Identifier tree";
|
||||
}
|
||||
|
||||
typedef object-identifier-128 {
|
||||
type object-identifier {
|
||||
pattern '\d*(\.\d*){1,127}';
|
||||
}
|
||||
description
|
||||
"This type represents object-identifiers restricted to 128
|
||||
sub-identifiers.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the OBJECT IDENTIFIER type of the SMIv2.";
|
||||
reference
|
||||
"RFC 2578: Structure of Management Information Version 2
|
||||
(SMIv2)";
|
||||
}
|
||||
|
||||
typedef yang-identifier {
|
||||
type string {
|
||||
length "1..max";
|
||||
pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
|
||||
pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
|
||||
}
|
||||
description
|
||||
"A YANG identifier string as defined by the 'identifier'
|
||||
rule in Section 12 of RFC 6020. An identifier must
|
||||
start with an alphabetic character or an underscore
|
||||
followed by an arbitrary sequence of alphabetic or
|
||||
numeric characters, underscores, hyphens, or dots.
|
||||
|
||||
A YANG identifier MUST NOT start with any possible
|
||||
combination of the lowercase or uppercase character
|
||||
sequence 'xml'.";
|
||||
reference
|
||||
"RFC 6020: YANG - A Data Modeling Language for the Network
|
||||
Configuration Protocol (NETCONF)";
|
||||
}
|
||||
|
||||
/*** collection of types related to date and time***/
|
||||
|
||||
typedef date-and-time {
|
||||
type string {
|
||||
pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
|
||||
+ '(Z|[\+\-]\d{2}:\d{2})';
|
||||
}
|
||||
description
|
||||
"The date-and-time type is a profile of the ISO 8601
|
||||
standard for representation of dates and times using the
|
||||
Gregorian calendar. The profile is defined by the
|
||||
date-time production in Section 5.6 of RFC 3339.
|
||||
|
||||
The date-and-time type is compatible with the dateTime XML
|
||||
schema type with the following notable exceptions:
|
||||
|
||||
(a) The date-and-time type does not allow negative years.
|
||||
|
||||
(b) The date-and-time time-offset -00:00 indicates an unknown
|
||||
time zone (see RFC 3339) while -00:00 and +00:00 and Z
|
||||
all represent the same time zone in dateTime.
|
||||
|
||||
(c) The canonical format (see below) of data-and-time values
|
||||
differs from the canonical format used by the dateTime XML
|
||||
schema type, which requires all times to be in UTC using
|
||||
the time-offset 'Z'.
|
||||
|
||||
This type is not equivalent to the DateAndTime textual
|
||||
convention of the SMIv2 since RFC 3339 uses a different
|
||||
separator between full-date and full-time and provides
|
||||
higher resolution of time-secfrac.
|
||||
|
||||
The canonical format for date-and-time values with a known time
|
||||
zone uses a numeric time zone offset that is calculated using
|
||||
the device's configured known offset to UTC time. A change of
|
||||
the device's offset to UTC time will cause date-and-time values
|
||||
to change accordingly. Such changes might happen periodically
|
||||
in case a server follows automatically daylight saving time
|
||||
(DST) time zone offset changes. The canonical format for
|
||||
date-and-time values with an unknown time zone (usually
|
||||
referring to the notion of local time) uses the time-offset
|
||||
-00:00.";
|
||||
reference
|
||||
"RFC 3339: Date and Time on the Internet: Timestamps
|
||||
RFC 2579: Textual Conventions for SMIv2
|
||||
XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
|
||||
}
|
||||
|
||||
typedef timeticks {
|
||||
type uint32;
|
||||
description
|
||||
"The timeticks type represents a non-negative integer that
|
||||
represents the time, modulo 2^32 (4294967296 decimal), in
|
||||
hundredths of a second between two epochs. When a schema
|
||||
node is defined that uses this type, the description of
|
||||
the schema node identifies both of the reference epochs.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the TimeTicks type of the SMIv2.";
|
||||
reference
|
||||
"RFC 2578: Structure of Management Information Version 2
|
||||
(SMIv2)";
|
||||
}
|
||||
|
||||
typedef timestamp {
|
||||
type yang:timeticks;
|
||||
description
|
||||
"The timestamp type represents the value of an associated
|
||||
timeticks schema node at which a specific occurrence
|
||||
happened. The specific occurrence must be defined in the
|
||||
description of any schema node defined using this type. When
|
||||
the specific occurrence occurred prior to the last time the
|
||||
associated timeticks attribute was zero, then the timestamp
|
||||
value is zero. Note that this requires all timestamp values
|
||||
to be reset to zero when the value of the associated timeticks
|
||||
attribute reaches 497+ days and wraps around to zero.
|
||||
|
||||
The associated timeticks schema node must be specified
|
||||
in the description of any schema node using this type.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the TimeStamp textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 2579: Textual Conventions for SMIv2";
|
||||
}
|
||||
|
||||
/*** collection of generic address types ***/
|
||||
|
||||
typedef phys-address {
|
||||
type string {
|
||||
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
|
||||
}
|
||||
|
||||
description
|
||||
"Represents media- or physical-level addresses represented
|
||||
as a sequence octets, each octet represented by two hexadecimal
|
||||
numbers. Octets are separated by colons. The canonical
|
||||
representation uses lowercase characters.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the PhysAddress textual convention of the SMIv2.";
|
||||
reference
|
||||
"RFC 2579: Textual Conventions for SMIv2";
|
||||
}
|
||||
|
||||
typedef mac-address {
|
||||
type string {
|
||||
pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
|
||||
}
|
||||
description
|
||||
"The mac-address type represents an IEEE 802 MAC address.
|
||||
The canonical representation uses lowercase characters.
|
||||
|
||||
In the value set and its semantics, this type is equivalent
|
||||
to the MacAddress textual convention of the SMIv2.";
|
||||
reference
|
||||
"IEEE 802: IEEE Standard for Local and Metropolitan Area
|
||||
Networks: Overview and Architecture
|
||||
RFC 2579: Textual Conventions for SMIv2";
|
||||
}
|
||||
|
||||
/*** collection of XML-specific types ***/
|
||||
|
||||
typedef xpath1.0 {
|
||||
type string;
|
||||
description
|
||||
"This type represents an XPATH 1.0 expression.
|
||||
|
||||
When a schema node is defined that uses this type, the
|
||||
description of the schema node MUST specify the XPath
|
||||
context in which the XPath expression is evaluated.";
|
||||
reference
|
||||
"XPATH: XML Path Language (XPath) Version 1.0";
|
||||
}
|
||||
|
||||
/*** collection of string types ***/
|
||||
|
||||
typedef hex-string {
|
||||
type string {
|
||||
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
|
||||
}
|
||||
description
|
||||
"A hexadecimal string with octets represented as hex digits
|
||||
separated by colons. The canonical representation uses
|
||||
lowercase characters.";
|
||||
}
|
||||
|
||||
typedef uuid {
|
||||
type string {
|
||||
pattern '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-'
|
||||
+ '[0-9a-fA-F]{4}-[0-9a-fA-F]{12}';
|
||||
}
|
||||
description
|
||||
"A Universally Unique IDentifier in the string representation
|
||||
defined in RFC 4122. The canonical representation uses
|
||||
lowercase characters.
|
||||
|
||||
The following is an example of a UUID in string representation:
|
||||
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
|
||||
";
|
||||
reference
|
||||
"RFC 4122: A Universally Unique IDentifier (UUID) URN
|
||||
Namespace";
|
||||
}
|
||||
|
||||
typedef dotted-quad {
|
||||
type string {
|
||||
pattern
|
||||
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
|
||||
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])';
|
||||
}
|
||||
description
|
||||
"An unsigned 32-bit number expressed in the dotted-quad
|
||||
notation, i.e., four octets written as decimal numbers
|
||||
and separated with the '.' (full stop) character.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
module infix-system {
|
||||
prefix "infix-sys";
|
||||
yang-version 1.1;
|
||||
namespace "urn:infix:params:xml:ns:yang:infix-system";
|
||||
|
||||
import ietf-system {
|
||||
prefix "sys";
|
||||
}
|
||||
|
||||
revision 2014-08-06 {
|
||||
description "Initial revision.";
|
||||
}
|
||||
|
||||
augment "/sys:system" {
|
||||
leaf motd {
|
||||
type string;
|
||||
description "Set the MotD (Message of the Day), which is shown after login";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
module kernelkit-infix-deviations {
|
||||
yang-version 1.1;
|
||||
namespace "urn:kernelkit:params:xml:ns:yang:infix";
|
||||
prefix "kkit";
|
||||
import ietf-system {
|
||||
prefix sys;
|
||||
}
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Infix deviations in standard yang models.";
|
||||
|
||||
revision "2023-04-03" {
|
||||
description "Initial revision.";
|
||||
}
|
||||
|
||||
deviation /sys:system/sys:clock/sys:timezone/sys:timezone-utc-offset/sys:timezone-utc-offset {
|
||||
deviate not-supported;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
*~
|
||||
*.o
|
||||
*.la
|
||||
*.lo
|
||||
*.so
|
||||
.deps
|
||||
.libs
|
||||
|
||||
/aclocal.m4
|
||||
/autom4te.cache/
|
||||
/aux
|
||||
/clixon.xml
|
||||
/compile
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.guess
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/depcomp
|
||||
/install-sh
|
||||
/libtool
|
||||
/ltmain.sh
|
||||
/m4
|
||||
/missing
|
||||
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
SUBDIRS = src xml
|
||||
DISTCLEANFILES = *~ *.d
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
@@ -0,0 +1,74 @@
|
||||
Infix Extensions to klish-plugin-sysrepo
|
||||
----------------------------------------
|
||||
|
||||
Tailor `klish` and `klish-plugin-sysrepo` to suit Infix. The resulting
|
||||
CLI is, in many respects, still very similar to Juniper's JunOS, since
|
||||
that is also the primary inspiration for klish, with some additions
|
||||
and modifications.
|
||||
|
||||
Broadly speaking, the CLI is split up in two major modes:
|
||||
|
||||
- Admin/Exec: This is the default mode, where operational commands can
|
||||
be issued.
|
||||
- Configure: Where a new candidate configuration is prepared.
|
||||
|
||||
|
||||
### Admin/Exec Mode
|
||||
|
||||
The following table lists the available commands:
|
||||
|
||||
| Command | Description | Hotkey |
|
||||
|--------------------|---------------------------------------|--------|
|
||||
| `configure` | Enter configuration mode | |
|
||||
| `copy <src> <dst>` | Copy `<src>` to `<dst>` | |
|
||||
| `exit` | Exit | `C-d` |
|
||||
| `logout` | Alias for `exit` | |
|
||||
| `shell` | Start system shell | |
|
||||
| `show <item>` | Show various configuration and status | |
|
||||
|
||||
#### Copy Command
|
||||
|
||||
`copy <src> <dst>`
|
||||
|
||||
Where `<src>` is one of:
|
||||
- `factory-config`
|
||||
- `startup-config`
|
||||
- `running-config`
|
||||
|
||||
And `<dst>` is one of:
|
||||
- `startup-config`
|
||||
- `running-config`
|
||||
|
||||
#### Show Command
|
||||
|
||||
`show <item>`
|
||||
|
||||
The following table lists the available items:
|
||||
|
||||
| Item | Description |
|
||||
|------------------|--------------------------------------|
|
||||
| `running-config` | Show the active system configuration |
|
||||
| | |
|
||||
|
||||
|
||||
### Configure
|
||||
|
||||
The following table lists the available commands:
|
||||
|
||||
| Command | Description | Hotkey |
|
||||
|------------|--------------------------------------------------------------|--------|
|
||||
| `abort` | Abandon candidate | `C-d` |
|
||||
| `check` | Validate candidate | |
|
||||
| `commit` | Commit current candidate to running-config | |
|
||||
| `delete` | Delete configuration setting(s) | |
|
||||
| `diff` | Summarize uncommitted changes | |
|
||||
| `do` | Execute operational mode command | |
|
||||
| `edit` | Descend to the specified configuration node | |
|
||||
| `exit` | Ascend to the parent configuration node, or abort (from top) | |
|
||||
| `leave` | Finalize candidate and apply to running-config | `C-z` |
|
||||
| `no` | Alias for delete | |
|
||||
| `rollback` | Restore candidate to running-config | |
|
||||
| `set` | Set configuration setting | |
|
||||
| `show` | Show configuration | |
|
||||
| `top` | Ascend to the configuration root | |
|
||||
| `up` | Ascend to the parent configuration node | `C-c` |
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
autoreconf -W portability -vifm
|
||||
@@ -0,0 +1,33 @@
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([klinfix], [1.0.0],
|
||||
[https://github.com/kernelkit/infix/issues])
|
||||
AM_INIT_AUTOMAKE(1.11 foreign subdir-objects)
|
||||
AM_SILENT_RULES(yes)
|
||||
|
||||
LT_INIT
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
xml/Makefile
|
||||
])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
|
||||
# Check for pkg-config first, warn if it's not installed
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
PKG_CHECK_MODULES([sysrepo], [sysrepo >= 2.2.60])
|
||||
AC_CHECK_LIB([klish], [kplugin_new],, AC_MSG_ERROR([Klish not found]))
|
||||
|
||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
||||
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
|
||||
|
||||
KLISHLIBDIR=`eval echo $libdir/klish`
|
||||
AC_SUBST(KLISHLIBDIR)
|
||||
|
||||
KLISHCONFDIR=`eval echo $sysconfdir/klish`
|
||||
AC_SUBST(KLISHCONFDIR)
|
||||
|
||||
AC_OUTPUT
|
||||
@@ -0,0 +1,9 @@
|
||||
CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter
|
||||
|
||||
pluginsdir = $(KLISHLIBDIR)/plugins
|
||||
plugins_LTLIBRARIES = kplugin-klinfix.la
|
||||
|
||||
kplugin_klinfix_la_CFLAGS = $(sysrepo_CFLAGS) $(klish_CFLAGS) $(CFLAGS)
|
||||
kplugin_klinfix_la_LIBADD = $(sysrepo_LIBS) $(klish_LIBS)
|
||||
kplugin_klinfix_la_LDFLAGS = -module -avoid-version -shared
|
||||
kplugin_klinfix_la_SOURCES = klinfix.c
|
||||
@@ -0,0 +1,155 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sysrepo.h>
|
||||
#include <sysrepo_types.h>
|
||||
|
||||
#include <klish/kplugin.h>
|
||||
#include <klish/kcontext.h>
|
||||
|
||||
const uint8_t kplugin_klinfix_major = 1;
|
||||
const uint8_t kplugin_klinfix_minor = 0;
|
||||
|
||||
int klix_ds_from_str(const char *text, sr_datastore_t *ds)
|
||||
{
|
||||
size_t len = strlen(text);
|
||||
|
||||
if (!strncmp("startup-config", text, len))
|
||||
*ds = SR_DS_STARTUP;
|
||||
else if (!strncmp("running-config", text, len))
|
||||
*ds = SR_DS_RUNNING;
|
||||
else if (!strncmp("candidate-config", text, len))
|
||||
*ds = SR_DS_CANDIDATE;
|
||||
else if (!strncmp("operational-config", text, len))
|
||||
*ds = SR_DS_OPERATIONAL;
|
||||
else if (!strncmp("factory-config", text, len))
|
||||
*ds = SR_DS_FACTORY_DEFAULT;
|
||||
else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int klix_copy(kcontext_t *ctx)
|
||||
{
|
||||
kpargv_t *pargv = kcontext_pargv(ctx);
|
||||
sr_datastore_t srcds, dstds;
|
||||
kparg_t *srcarg, *dstarg;
|
||||
sr_session_ctx_t *sess;
|
||||
sr_conn_ctx_t *conn;
|
||||
int err;
|
||||
|
||||
srcarg = kpargv_find(pargv, "src");
|
||||
dstarg = kpargv_find(pargv, "dst");
|
||||
if (!srcarg || !dstarg)
|
||||
goto err;
|
||||
|
||||
if (klix_ds_from_str(kparg_value(srcarg), &srcds)) {
|
||||
fprintf(stderr,
|
||||
"Error: \"%s\" is not the name of any known datastore\n",
|
||||
kparg_value(srcarg));
|
||||
goto err;
|
||||
}
|
||||
if (klix_ds_from_str(kparg_value(dstarg), &dstds)) {
|
||||
fprintf(stderr,
|
||||
"Error: \"%s\" is not the name of any known datastore\n",
|
||||
kparg_value(dstarg));
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (srcds) {
|
||||
case SR_DS_STARTUP:
|
||||
case SR_DS_RUNNING:
|
||||
case SR_DS_FACTORY_DEFAULT:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"Error: \"%s\" is not a valid source datastore\n",
|
||||
kparg_value(srcarg));
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (dstds) {
|
||||
case SR_DS_STARTUP:
|
||||
case SR_DS_RUNNING:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"Error: \"%s\" is not a valid destination datastore\n",
|
||||
kparg_value(dstarg));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sr_connect(SR_CONN_DEFAULT, &conn)) {
|
||||
fprintf(stderr, "Error: Connection to datastore failed\n");
|
||||
goto err;
|
||||
}
|
||||
if (sr_session_start(conn, dstds, &sess)) {
|
||||
fprintf(stderr, "Error: Unable to open transaction to %s\n",
|
||||
kparg_value(dstarg));
|
||||
goto err_disconnect;
|
||||
}
|
||||
|
||||
err = sr_copy_config(sess, NULL, srcds, 0);
|
||||
if (err) {
|
||||
fprintf(stderr, "Error: Unable to copy configuration (%d)\n",
|
||||
err);
|
||||
goto err_disconnect;
|
||||
}
|
||||
|
||||
sr_disconnect(conn);
|
||||
return 0;
|
||||
|
||||
err_disconnect:
|
||||
sr_disconnect(conn);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int klix_commit(kcontext_t *ctx)
|
||||
{
|
||||
sr_session_ctx_t *sess;
|
||||
sr_conn_ctx_t *conn;
|
||||
int err;
|
||||
|
||||
if (sr_connect(SR_CONN_DEFAULT, &conn)) {
|
||||
fprintf(stderr, "Error: Connection to datastore failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sr_session_start(conn, SR_DS_RUNNING, &sess)) {
|
||||
fprintf(stderr,
|
||||
"Error: Unable to open transaction to running-config\n");
|
||||
goto err_disconnect;
|
||||
}
|
||||
|
||||
err = sr_copy_config(sess, NULL, SR_DS_CANDIDATE, 0);
|
||||
if (err) {
|
||||
fprintf(stderr,
|
||||
"Error: Unable to commit candidate to running (%d)\n",
|
||||
err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
sr_disconnect(conn);
|
||||
return 0;
|
||||
|
||||
err_disconnect:
|
||||
sr_disconnect(conn);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int kplugin_klinfix_fini(kcontext_t *ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kplugin_klinfix_init(kcontext_t *ctx)
|
||||
{
|
||||
kplugin_t *plugin = kcontext_plugin(ctx);
|
||||
|
||||
kplugin_add_syms(plugin, ksym_new("klix_copy", klix_copy));
|
||||
kplugin_add_syms(plugin, ksym_new("klix_commit", klix_commit));
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
klishconfdir = $(KLISHCONFDIR)
|
||||
klishconf_DATA = $(wildcard *.xml)
|
||||
@@ -0,0 +1,215 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<KLISH
|
||||
xmlns="https://klish.libcode.org/klish3"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://src.libcode.org/pkun/klish/src/master/klish.xsd">
|
||||
|
||||
<PLUGIN name="klish"/>
|
||||
<PLUGIN name="klinfix"/>
|
||||
<PLUGIN name="script"/>
|
||||
|
||||
<PLUGIN name="sysrepo">
|
||||
ShowBrackets = y
|
||||
ShowSemicolons = y
|
||||
FirstKeyWithStatement = n
|
||||
MultiKeysWithStatement = y
|
||||
Colorize = y
|
||||
Indent = 2
|
||||
</PLUGIN>
|
||||
|
||||
<PTYPE name="DATASTORE">
|
||||
<COMPL>
|
||||
<ACTION sym="printl">factory-config</ACTION>
|
||||
<ACTION sym="printl">startup-config</ACTION>
|
||||
<ACTION sym="printl">running-config</ACTION>
|
||||
</COMPL>
|
||||
<ACTION sym="STRING"/>
|
||||
</PTYPE>
|
||||
|
||||
<PTYPE name="RW_DATASTORE">
|
||||
<COMPL>
|
||||
<ACTION sym="printl">startup-config</ACTION>
|
||||
<ACTION sym="printl">running-config</ACTION>
|
||||
</COMPL>
|
||||
<ACTION sym="STRING"/>
|
||||
</PTYPE>
|
||||
|
||||
<PTYPE name="PLINE_SET">
|
||||
<COMPL>
|
||||
<ACTION sym="srp_compl@sysrepo"/>
|
||||
</COMPL>
|
||||
<HELP>
|
||||
<ACTION sym="srp_help@sysrepo"/>
|
||||
</HELP>
|
||||
<ACTION sym="PLINE_SET@sysrepo"/>
|
||||
</PTYPE>
|
||||
|
||||
<PTYPE name="PLINE_DEL">
|
||||
<COMPL>
|
||||
<ACTION sym="srp_compl@sysrepo"/>
|
||||
</COMPL>
|
||||
<HELP>
|
||||
<ACTION sym="srp_help@sysrepo"/>
|
||||
</HELP>
|
||||
<ACTION sym="PLINE_DEL@sysrepo"/>
|
||||
</PTYPE>
|
||||
|
||||
<PTYPE name="PLINE_EDIT">
|
||||
<COMPL>
|
||||
<ACTION sym="srp_compl@sysrepo"/>
|
||||
</COMPL>
|
||||
<HELP>
|
||||
<ACTION sym="srp_help@sysrepo"/>
|
||||
</HELP>
|
||||
<ACTION sym="PLINE_EDIT@sysrepo"/>
|
||||
</PTYPE>
|
||||
|
||||
<PTYPE name="PLINE_INSERT_FROM">
|
||||
<COMPL>
|
||||
<ACTION sym="srp_compl@sysrepo"/>
|
||||
</COMPL>
|
||||
<HELP>
|
||||
<ACTION sym="srp_help@sysrepo"/>
|
||||
</HELP>
|
||||
<ACTION sym="PLINE_INSERT_FROM@sysrepo"/>
|
||||
</PTYPE>
|
||||
|
||||
<PTYPE name="PLINE_INSERT_TO">
|
||||
<COMPL>
|
||||
<ACTION sym="srp_compl_insert_to@sysrepo"/>
|
||||
</COMPL>
|
||||
<HELP>
|
||||
<ACTION sym="srp_help_insert_to@sysrepo"/>
|
||||
</HELP>
|
||||
<ACTION sym="PLINE_INSERT_TO@sysrepo"/>
|
||||
</PTYPE>
|
||||
|
||||
|
||||
<VIEW name="main">
|
||||
<HOTKEY key="^D" cmd="exit"/>
|
||||
|
||||
<PROMPT>
|
||||
<ACTION sym="prompt" exec_on="always">%u@%h:exec> </ACTION>
|
||||
</PROMPT>
|
||||
|
||||
<COMMAND name="shell" help="Enter system shell">
|
||||
<ACTION sym="script" interactive="true">/bin/sh -l</ACTION>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="exit" help="Exit">
|
||||
<ACTION sym="nav">pop</ACTION>
|
||||
</COMMAND>
|
||||
<COMMAND name="logout" help="Alias for exit">
|
||||
<ACTION sym="nav">pop</ACTION>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="configure" help="Create new candidate-config based on running-config">
|
||||
<ACTION sym="nav">replace configure</ACTION>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="copy" help="Copy">
|
||||
<PARAM name="src" ptype="/DATASTORE" help="Source datastore"/>
|
||||
<PARAM name="dst" ptype="/RW_DATASTORE" help="Destination datastore"/>
|
||||
<ACTION sym="klix_copy@klinfix"/>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="show" help="Show" mode="switch">
|
||||
<COMMAND name="running-config" help="Show running-config">
|
||||
<ACTION sym="srp_show_running@sysrepo"/>
|
||||
</COMMAND>
|
||||
</COMMAND>
|
||||
|
||||
</VIEW>
|
||||
|
||||
<VIEW name="configure">
|
||||
|
||||
<PROMPT>
|
||||
<ACTION sym="srp_prompt_edit_path@sysrepo"/>
|
||||
<ACTION sym="prompt" exec_on="always">%u@%h:configure> </ACTION>
|
||||
</PROMPT>
|
||||
|
||||
<HOTKEY key="^C" cmd="up"/>
|
||||
<HOTKEY key="^D" cmd="abort"/>
|
||||
<HOTKEY key="^Z" cmd="leave"/>
|
||||
|
||||
<!-- Move -->
|
||||
|
||||
<COMMAND name="abort" help="Abandon candidate">
|
||||
<ACTION sym="srp_rollback@sysrepo"/>
|
||||
<ACTION sym="nav">replace main</ACTION>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="leave" help="Finalize candidate and apply to running-config">
|
||||
<ACTION sym="klix_commit@klinfix"/>
|
||||
<ACTION sym="nav" exec_on="success">replace main</ACTION>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="exit" help="Ascend to the parent configuration node, or abort (from top)">
|
||||
<ACTION sym="srp_up@sysrepo"/>
|
||||
<ACTION sym="klix_commit@klinfix" exec_on="fail"/>
|
||||
<ACTION sym="nav" exec_on="success">replace main</ACTION>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="up" help="Ascend to the parent configuration node">
|
||||
<ACTION sym="srp_up@sysrepo"/>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="top" help="Ascend to the configuration root">
|
||||
<ACTION sym="srp_top@sysrepo"/>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="edit" help="Descend to the specified configuration node">
|
||||
<PARAM name="path" ptype="/PLINE_EDIT" max="100"/>
|
||||
<ACTION sym="srp_edit@sysrepo"/>
|
||||
</COMMAND>
|
||||
|
||||
<!-- Edit -->
|
||||
|
||||
<COMMAND name="set" help="Set configuration setting">
|
||||
<PARAM name="path" ptype="/PLINE_SET" max="100"/>
|
||||
<ACTION sym="srp_set@sysrepo"/>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="delete" help="Delete configuration setting(s)">
|
||||
<PARAM name="path" ptype="/PLINE_DEL" max="100"/>
|
||||
<ACTION sym="srp_del@sysrepo"/>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="no" help="Alias for delete">
|
||||
<PARAM name="path" ptype="/PLINE_DEL" max="100"/>
|
||||
<ACTION sym="srp_del@sysrepo"/>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="commit" help="Commit current candidate to running-config">
|
||||
<ACTION sym="klix_commit@klinfix"/>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="rollback" help="Restore candidate to running-config">
|
||||
<ACTION sym="srp_rollback@sysrepo"/>
|
||||
</COMMAND>
|
||||
|
||||
<!-- Display -->
|
||||
|
||||
<COMMAND name="check" help="Validate candidate">
|
||||
<ACTION sym="srp_verify@sysrepo"/>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="show" help="Show configuration">
|
||||
<PARAM name="path" ptype="/PLINE_EDIT" min="0" max="100"/>
|
||||
<ACTION sym="srp_show@sysrepo"/>
|
||||
</COMMAND>
|
||||
|
||||
<COMMAND name="diff" help="Summarize uncommitted changes">
|
||||
<PARAM name="path" ptype="/PLINE_EDIT" min="0" max="100"/>
|
||||
<ACTION sym="srp_diff@sysrepo"/>
|
||||
</COMMAND>
|
||||
|
||||
<!-- Misc -->
|
||||
|
||||
<COMMAND name="do" help="Execute operational mode command">
|
||||
<VIEW name="operational" ref="/main"/>
|
||||
</COMMAND>
|
||||
|
||||
</VIEW>
|
||||
|
||||
</KLISH>
|
||||
@@ -0,0 +1,2 @@
|
||||
*.o
|
||||
net
|
||||
@@ -0,0 +1,14 @@
|
||||
LDLIBS = -lite
|
||||
EXEC = net
|
||||
|
||||
net: main.o
|
||||
$(CC) -o $@ $^ $(LDLIBS)
|
||||
|
||||
check: $(EXEC)
|
||||
./test.sh
|
||||
|
||||
clean:
|
||||
$(RM) net
|
||||
|
||||
distclean: clean
|
||||
$(RM) *.o *~
|
||||
@@ -0,0 +1,158 @@
|
||||
net - an iproute2 wrapper
|
||||
=========================
|
||||
|
||||
The net tool is a wrapper around the iproute2 and ethtool programs to
|
||||
set up networking on a Linux system. It also handles transitions from
|
||||
a previously configured state to the next while attempting to keep the
|
||||
amount of changes needed to a minimum.
|
||||
|
||||
|
||||
Concept Overview
|
||||
----------------
|
||||
|
||||
net applies a configuration from `/run/net/next`, where `next` is a file
|
||||
that holds the number of the current generation. It is up to the user,
|
||||
i.e., sysrepo, to create the below tree structure with commands to run.
|
||||
|
||||
The setup we start with and later move `eth4` from `lag0` to `br0`.
|
||||
|
||||
vlan1
|
||||
______/____
|
||||
[____br0____]
|
||||
/ / \ \
|
||||
eth1 eth2 eth3 lag0
|
||||
/ \
|
||||
eth4 eth5
|
||||
|
||||
Consider the case when `next` contains `0`, net reads all interfaces, in
|
||||
dependency order, from `/run/net/0/` running all `ip-link` and `ip-addr`
|
||||
commands. When done, it writes `0` to the file `/run/net/gen` and then
|
||||
removes the `next` file to confirm the generation has been activated.
|
||||
|
||||
**Note:** it is currently up to the user to remove any old generation.
|
||||
|
||||
/run/net/0/
|
||||
|-- lo/
|
||||
| |-- deps/
|
||||
| |-- ip-link.up
|
||||
| `-- ip-addr.up
|
||||
|-- br0/
|
||||
| |-- deps/
|
||||
| | |-- eth1 -> ../../eth1
|
||||
| | |-- eth2 -> ../../eth2
|
||||
| | |-- eth3 -> ../../eth3
|
||||
| | `-- lag0 -> ../../lag0
|
||||
| |-- ip-link.up
|
||||
| `-- ip-addr.up
|
||||
|-- eth0/
|
||||
| |-- deps/
|
||||
| |-- ip-link.up
|
||||
| `-- ip-addr.up
|
||||
|-- ethX/
|
||||
| |-- ...
|
||||
: :
|
||||
|-- lag0/
|
||||
| |-- deps/
|
||||
| | |-- eth4 -> ../../eth4
|
||||
| | `-- eth5 -> ../../eth5
|
||||
| |-- ip-link.up
|
||||
| `-- ip-addr.up
|
||||
`-- vlan1/
|
||||
|-- deps/
|
||||
| `-- br0 -> ../../br0
|
||||
|-- ip-link.up
|
||||
`-- ip-addr.up
|
||||
|
||||
The `deps/` sub-directory for each of the interfaces contains symlinks
|
||||
to any interfaces this interface may depend on. I.e., those interfaces
|
||||
are evaluated first.
|
||||
|
||||
Essentially, all leaves must be set up before their parents. Moving a
|
||||
leaf from one parent to another, e.g., from lag0 to br0, is tricky, it
|
||||
involves traversing the previous dependency order when removing leaves,
|
||||
and traversing the next dependency order when addning, see next section
|
||||
for an example.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
net is built to complement sysrepo. The idea is to listen to any added,
|
||||
deleted, modified states in sysrepo changes to a candidate configuration
|
||||
and generate the `next` generation. However, as mentioned previously,
|
||||
when moving leaves between parents we must do so in the dependency order
|
||||
of the current generation.
|
||||
|
||||
So, the user (sysrepo) needs to add `.dn` scripts in the current tree,
|
||||
and `.up` scripts in the next.
|
||||
|
||||
In our example, interface `eth4` is moved from `lag0` to `br0`, so we
|
||||
need to run `eth4/ip-link.dn` in the current generation first to remove
|
||||
`eth4` from `lag0` before its `ip-link.up` script in the next generation
|
||||
sets `eth4` as a bridge member instead.
|
||||
|
||||
We traverse the current generation and execute all `.dn` scripts:
|
||||
|
||||
/run/net/<GEN>/
|
||||
|-- lo/
|
||||
| `-- deps/
|
||||
|-- br0/
|
||||
| |-- deps/
|
||||
| | |-- eth1 -> ../../eth1
|
||||
| | |-- eth2 -> ../../eth2
|
||||
| | |-- eth3 -> ../../eth3
|
||||
| | `-- lag0 -> ../../lag0
|
||||
| `-- ip-link.up
|
||||
|-- eth0/
|
||||
| |-- deps/
|
||||
| |-- ip-link.up
|
||||
| `-- ip-addr.up
|
||||
|-- eth4/
|
||||
| |-- deps/
|
||||
| |-- ip-link.dn
|
||||
| `-- ip-link.up
|
||||
|-- lag0/
|
||||
| |-- deps/
|
||||
| | |-- eth4 -> ../../eth4
|
||||
| | `-- eth5 -> ../../eth5
|
||||
| `-- ip-link.up
|
||||
`-- vlan1/
|
||||
|-- deps/
|
||||
| `-- br0 -> ../../br0
|
||||
|-- ip-link.up
|
||||
`-- ip-addr.up
|
||||
|
||||
Now we can run all the `.up` scripts in the next generation:
|
||||
|
||||
/run/net/<GEN+1>/
|
||||
|-- lo/
|
||||
| |-- deps/
|
||||
| |-- ip-link.up
|
||||
| `-- ip-addr.up
|
||||
|-- br0/
|
||||
| |-- deps/
|
||||
| | |-- eth1 -> ../../eth1
|
||||
| | |-- eth2 -> ../../eth2
|
||||
| | |-- eth3 -> ../../eth3
|
||||
| | |-- eth4 -> ../../eth4
|
||||
| | `-- lag0 -> ../../lag0
|
||||
| `-- ip-link.up
|
||||
|-- eth0/
|
||||
| |-- deps/
|
||||
| |-- ip-link.up
|
||||
| `-- ip-addr.up
|
||||
|-- eth4/
|
||||
| |-- deps/
|
||||
| |-- ip-link.dn
|
||||
| `-- ip-link.up
|
||||
|-- lag0/
|
||||
| |-- deps/
|
||||
| | `-- eth5 -> ../../eth5
|
||||
| `-- ip-link.up
|
||||
`-- vlan1/
|
||||
|-- deps/
|
||||
| `-- br0 -> ../../br0
|
||||
|-- ip-link.up
|
||||
`-- ip-addr.up
|
||||
|
||||
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
#include <err.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <sysexits.h>
|
||||
#include <net/if.h>
|
||||
#include <libite/lite.h>
|
||||
|
||||
#define _PATH_NET "/run/net"
|
||||
#define DEBUG 0
|
||||
#define dbg(fmt, args...) if (DEBUG) warnx(fmt, ##args)
|
||||
|
||||
static char **handled;
|
||||
static int if_num;
|
||||
|
||||
|
||||
static void if_alloc(int num)
|
||||
{
|
||||
handled = calloc(num, sizeof(char *));
|
||||
if (!handled)
|
||||
err(1, "calloc");
|
||||
if_num = num;
|
||||
}
|
||||
|
||||
static void if_free()
|
||||
{
|
||||
for (int i = 0; i < if_num; i++) {
|
||||
if (handled[i])
|
||||
free(handled[i]);
|
||||
}
|
||||
free(handled);
|
||||
}
|
||||
|
||||
static void if_done(char *ifname)
|
||||
{
|
||||
for (int i = 0; i < if_num; i++) {
|
||||
if (handled[i]) {
|
||||
if (strcmp(handled[i], ifname))
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
handled[i] = strdup(ifname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int if_find(char *ifname)
|
||||
{
|
||||
for (int i = 0; i < if_num; i++) {
|
||||
if (handled[i] && !strcmp(handled[i], ifname))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int deps(char *ipath, char *ifname, const char *action)
|
||||
{
|
||||
char path[strlen(ipath) + 42];
|
||||
int num, rc = -1;
|
||||
char **files;
|
||||
char *cmd;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/deps", ipath);
|
||||
num = dir(path, NULL, NULL, &files, 0);
|
||||
for (int i = 0; i < num; i++) {
|
||||
char dpath[sizeof(path) + strlen(files[i])];
|
||||
char *ifnm = files[i];
|
||||
char *rp;
|
||||
|
||||
snprintf(dpath, sizeof(dpath), "%s/%s", path, ifnm);
|
||||
rp = realpath(dpath, NULL);
|
||||
if (!rp)
|
||||
continue;
|
||||
|
||||
deps(rp, ifnm, action);
|
||||
free(ifnm);
|
||||
free(rp);
|
||||
}
|
||||
|
||||
if (if_find(ifname))
|
||||
return 0;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", ipath, action);
|
||||
cmd = realpath(path, NULL);
|
||||
if (!cmd || access(cmd, X_OK)) {
|
||||
if (errno == ENOENT)
|
||||
rc = 0; /* no action for this interface */
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = systemf("%s", cmd);
|
||||
done:
|
||||
free(cmd);
|
||||
if_done(ifname);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int iter(char *path, size_t len, const char *action)
|
||||
{
|
||||
char **files;
|
||||
int rc = 0;
|
||||
int num;
|
||||
|
||||
num = dir(path, NULL, NULL, &files, 0);
|
||||
if_alloc(num);
|
||||
|
||||
for (int j = 0; j < num; j++) {
|
||||
char *ifname = files[j];
|
||||
char ipath[len];
|
||||
|
||||
snprintf(ipath, sizeof(ipath), "%s/%s", path, ifname);
|
||||
dbg("Calling deps(%s, %s, %s)", ipath, ifname, action);
|
||||
rc += deps(ipath, ifname, action);
|
||||
free(ifname);
|
||||
}
|
||||
|
||||
if_free();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int deactivate(const char *net, char *gen)
|
||||
{
|
||||
char path[strlen(net) + strlen(gen) + 5 + IFNAMSIZ];
|
||||
char *action[] = {
|
||||
"ip-addr.dn",
|
||||
"ip-link.dn",
|
||||
};
|
||||
int rc = 0;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", net, gen);
|
||||
for (size_t i = 0; i < NELEMS(action); i++)
|
||||
rc += iter(path, sizeof(path), action[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int activate(const char *net, char *gen)
|
||||
{
|
||||
char path[strlen(net) + strlen(gen) + 5 + IFNAMSIZ];
|
||||
char *action[] = {
|
||||
"ip-link.up",
|
||||
"ip-addr.up",
|
||||
};
|
||||
int rc = 0;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", net, gen);
|
||||
for (size_t i = 0; i < NELEMS(action); i++)
|
||||
rc += iter(path, sizeof(path), action[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int load_gen(const char *net, char *gen, char *buf, size_t len)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopenf("r", "%s/%s", net, gen);
|
||||
if (!fp)
|
||||
return EX_OSFILE;
|
||||
if (!fgets(buf, len, fp))
|
||||
return EX_IOERR;
|
||||
fclose(fp);
|
||||
chomp(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int save_gen(const char *net, char *gen, char *buf)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopenf("w", "%s/%s", net, gen);
|
||||
if (!fp)
|
||||
return -1;
|
||||
fprintf(fp, "%s\n", buf);
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const char *net = _PATH_NET;
|
||||
char curr[512], next[512];
|
||||
int rc;
|
||||
|
||||
if (getenv("NET_DIR"))
|
||||
net = getenv("NET_DIR");
|
||||
if (access(net, X_OK)) {
|
||||
if (makedir(net, 0755))
|
||||
err(1, "makedir");
|
||||
}
|
||||
|
||||
if ((rc = load_gen(net, "next", next, sizeof(next)))) {
|
||||
if (rc == EX_IOERR)
|
||||
warnx("missing next generation");
|
||||
exit(0); /* nothing to do */
|
||||
}
|
||||
|
||||
if ((rc = load_gen(net, "gen", curr, sizeof(curr)))) {
|
||||
if (rc == EX_IOERR)
|
||||
errx(rc, "missing current generation");
|
||||
/* no current generation */
|
||||
} else {
|
||||
rc = deactivate(net, curr);
|
||||
if (rc)
|
||||
err(1, "failed deactivating current generation");
|
||||
}
|
||||
|
||||
rc = activate(net, next);
|
||||
if (rc)
|
||||
err(1, "failed activating next generation");
|
||||
|
||||
if (save_gen(net, "gen", next))
|
||||
err(1, "next generation applied, failed current");
|
||||
|
||||
if (fremove("%s/next", net))
|
||||
err(1, "failed removing %s/next", net);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
#!/bin/sh
|
||||
# Generate test directory structure for verifying the net tool
|
||||
set -e
|
||||
|
||||
NET_DIR=/tmp/net
|
||||
export NET_DIR
|
||||
|
||||
gensh()
|
||||
{
|
||||
cat <<-EOF >"$1"
|
||||
#!/bin/sh
|
||||
echo "Running \$0 ..."
|
||||
EOF
|
||||
chmod +x "$1"
|
||||
}
|
||||
|
||||
check()
|
||||
{
|
||||
if ./net; then
|
||||
printf "\n[\033[1;32m OK \033[0m] Checking %s\n" "$1"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf "\n[\033[1;31FAIL\033[0m] Checking %s\n" "$1"
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "Verify that all leaves and dependencies are"
|
||||
echo "evaluated first:"
|
||||
echo " vlan1"
|
||||
echo " ______/____"
|
||||
echo " [____br0____]"
|
||||
echo " / / \\ \\"
|
||||
echo "lo eth0 eth1 eth2 eth3 lag0"
|
||||
echo " / \\"
|
||||
echo " eth4 eth5"
|
||||
printf "_______________________________________________\n\n"
|
||||
|
||||
mkdir -p $NET_DIR/0
|
||||
echo 0 > $NET_DIR/next
|
||||
|
||||
mkdir -p $NET_DIR/0/lo/deps
|
||||
gensh $NET_DIR/0/lo/ip-link.up
|
||||
|
||||
mkdir -p $NET_DIR/0/eth0/deps
|
||||
mkdir -p $NET_DIR/0/eth1/deps
|
||||
mkdir -p $NET_DIR/0/eth2/deps
|
||||
mkdir -p $NET_DIR/0/eth3/deps
|
||||
mkdir -p $NET_DIR/0/eth4/deps
|
||||
|
||||
gensh $NET_DIR/0/eth0/ip-link.up
|
||||
gensh $NET_DIR/0/eth1/ip-link.up
|
||||
gensh $NET_DIR/0/eth2/ip-link.up
|
||||
gensh $NET_DIR/0/eth3/ip-link.up
|
||||
gensh $NET_DIR/0/eth4/ip-link.up
|
||||
|
||||
mkdir -p $NET_DIR/0/lag0/deps
|
||||
ln -sf ../../eth3 $NET_DIR/0/lag0/deps/
|
||||
ln -sf ../../eth4 $NET_DIR/0/lag0/deps/
|
||||
gensh $NET_DIR/0/lag0/ip-link.up
|
||||
|
||||
mkdir -p $NET_DIR/0/br0/deps
|
||||
ln -sf ../../eth1 $NET_DIR/0/br0/deps/
|
||||
ln -sf ../../eth2 $NET_DIR/0/br0/deps/
|
||||
ln -sf ../../lag0 $NET_DIR/0/br0/deps/
|
||||
gensh $NET_DIR/0/br0/ip-link.up
|
||||
|
||||
mkdir -p $NET_DIR/0/vlan1/deps
|
||||
ln -sf ../../br0 $NET_DIR/0/vlan1/deps/
|
||||
gensh $NET_DIR/0/vlan1/ip-link.up
|
||||
|
||||
check "initial startup, gen 0"
|
||||
|
||||
printf "_______________________________________________\n\n"
|
||||
mkdir -p $NET_DIR/1
|
||||
|
||||
mkdir -p $NET_DIR/1/lo/deps
|
||||
mkdir -p $NET_DIR/1/eth0/deps
|
||||
mkdir -p $NET_DIR/1/eth1/deps
|
||||
mkdir -p $NET_DIR/1/eth2/deps
|
||||
mkdir -p $NET_DIR/1/eth3/deps
|
||||
mkdir -p $NET_DIR/1/eth4/deps
|
||||
|
||||
mkdir -p $NET_DIR/1/lag0/deps
|
||||
ln -sf ../../eth4 $NET_DIR/1/lag0/deps/
|
||||
|
||||
mkdir -p $NET_DIR/1/br0/deps
|
||||
ln -sf ../../eth1 $NET_DIR/1/br0/deps/
|
||||
ln -sf ../../eth2 $NET_DIR/1/br0/deps/
|
||||
ln -sf ../../eth3 $NET_DIR/1/br0/deps/
|
||||
|
||||
mkdir -p $NET_DIR/1/vlan1/deps
|
||||
ln -sf ../../br0 $NET_DIR/1/vlan1/deps/
|
||||
|
||||
gensh $NET_DIR/0/eth3/ip-link.dn
|
||||
gensh $NET_DIR/1/eth3/ip-link.up
|
||||
echo 1 > $NET_DIR/next
|
||||
|
||||
check "move eth3 from lag0 to br0"
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user