mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-26 02:33:02 +02:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc064c53f3 |
@@ -1,37 +0,0 @@
|
||||
<!--- **Summarize** your changes in the title above -->
|
||||
|
||||
## Description
|
||||
|
||||
<!--
|
||||
-- A description of changes, detailing *why* changes are made.
|
||||
-- Remember: assign a reviewer, or use @mentions if org. member.
|
||||
-->
|
||||
|
||||
|
||||
## Other information
|
||||
|
||||
<!-- Other relevant info, e.g., before/after screenshots -->
|
||||
|
||||
|
||||
## Checklist
|
||||
|
||||
Tick relevant boxes, this PR is-a or has-a:
|
||||
|
||||
- [ ] Bugfix
|
||||
- [ ] Regression tests
|
||||
- [ ] ChangeLog updates (for next release)
|
||||
- [ ] Feature
|
||||
- [ ] YANG model change => revision updated?
|
||||
- [ ] Regression tests added?
|
||||
- [ ] ChangeLog updates (for next release)
|
||||
- [ ] Documentation added?
|
||||
- [ ] Code style update (formatting, renaming)
|
||||
- [ ] Refactoring (please detail in commit messages)
|
||||
- [ ] Build related changes
|
||||
- [ ] Documentation content changes
|
||||
- [ ] Other (please describe):
|
||||
|
||||
|
||||
## References
|
||||
|
||||
<!-- Please list references to related issue(s) -->
|
||||
+25
-18
@@ -8,65 +8,72 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Infix ${{ matrix.platform }}
|
||||
runs-on: self-hosted
|
||||
name: Build ${{ matrix.platform }} ${{ matrix.variant }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [aarch64, x86_64]
|
||||
variant: [netconf, classic]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Maintenance
|
||||
run: |
|
||||
docker image prune -af
|
||||
docker volume prune -f
|
||||
docker container prune -f
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set Build Variables
|
||||
id: vars
|
||||
run: |
|
||||
target=${{ matrix.platform }}
|
||||
if [ "${{ matrix.variant }}" = "netconf" ]; then
|
||||
target=${{ matrix.platform }}
|
||||
else
|
||||
target=${{ matrix.platform }}-${{ matrix.variant }}
|
||||
fi
|
||||
echo "dir=infix-$target" >> $GITHUB_OUTPUT
|
||||
echo "tgz=infix-$target.tar.gz" >> $GITHUB_OUTPUT
|
||||
- name: Restore Cache of dl/
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: dl/
|
||||
key: dl-${{ hashFiles('.git/modules/buildroot/HEAD', 'configs/*', 'package/*/*.hash') }}
|
||||
key: dl-${{ matrix.platform }}-${{ matrix.variant }}-${{ hashFiles('.git/modules/buildroot/HEAD', 'configs/*', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
dl-${{ matrix.platform }}-${{ matrix.variant }}-
|
||||
dl-${{ matrix.platform }}-
|
||||
dl-
|
||||
- name: Restore Cache of .ccache/
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .ccache/
|
||||
key: ccache-${{ matrix.platform }}-${{ hashFiles('.git/modules/buildroot/HEAD', 'package/*/*.hash') }}
|
||||
key: ccache-${{ matrix.platform }}-${{ matrix.variant }}-${{ hashFiles('.git/modules/buildroot/HEAD', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
ccache-${{ matrix.platform }}-${{ matrix.variant }}-
|
||||
ccache-${{ matrix.platform }}-
|
||||
ccache-
|
||||
- name: Configure & Build
|
||||
run: |
|
||||
target=${{ matrix.platform }}_defconfig
|
||||
echo "Building $target ..."
|
||||
if [ "${{ matrix.variant }}" = "netconf" ]; then
|
||||
target=${{ matrix.platform }}_defconfig
|
||||
else
|
||||
target=${{ matrix.platform }}_${{ matrix.variant }}_defconfig
|
||||
fi
|
||||
echo "Buildring $target ..."
|
||||
make $target
|
||||
make
|
||||
- name: Prepare Artifact
|
||||
run: |
|
||||
cd output/
|
||||
cd output
|
||||
mv images ${{ steps.vars.outputs.dir }}
|
||||
ln -s ${{ steps.vars.outputs.dir }} images
|
||||
tar chfz ${{ steps.vars.outputs.tgz }} ${{ steps.vars.outputs.dir }}
|
||||
- name: Test
|
||||
if: matrix.platform == 'x86_64'
|
||||
if: matrix.platform == 'x86_64' && matrix.variant == 'netconf'
|
||||
run: |
|
||||
make test
|
||||
make test-qeneth
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: output/${{ steps.vars.outputs.tgz }}
|
||||
name: artifact-${{ matrix.platform }}
|
||||
name: artifact-${{ matrix.variant }}-${{ matrix.platform }}
|
||||
release:
|
||||
if: ${{github.repository_owner == 'kernelkit' && github.ref_name == 'main'}}
|
||||
name: Upload Latest Build
|
||||
needs: build
|
||||
runs-on: self-hosted
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
@@ -83,7 +90,7 @@ jobs:
|
||||
prerelease: true
|
||||
tag: "latest"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
artifacts: "*.tar.gz"
|
||||
artifacts: "artifact/*"
|
||||
- name: Summary
|
||||
run: |
|
||||
cat <<EOF >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
@@ -12,7 +12,7 @@ env:
|
||||
jobs:
|
||||
coverity:
|
||||
if: ${{github.repository_owner == 'kernelkit'}}
|
||||
runs-on: self-hosted
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Fetch latest Coverity Scan MD5
|
||||
@@ -50,9 +50,8 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config libjansson-dev libev-dev \
|
||||
libaugeas-dev libglib2.0-dev libpcre2-dev \
|
||||
libuev-dev libite-dev
|
||||
sudo apt-get -y install pkg-config libjansson-dev libev-dev libite-dev \
|
||||
libaugeas-dev libglib2.0-dev libpcre2-dev
|
||||
- name: Build dependencies
|
||||
run: |
|
||||
git clone https://github.com/CESNET/libyang.git
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
name: Manny the Manager
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
checkout:
|
||||
required: true
|
||||
type: boolean
|
||||
cleanup:
|
||||
required: true
|
||||
type: boolean
|
||||
peek:
|
||||
required: true
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
inventory:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Disk usage ...
|
||||
run: |
|
||||
cd
|
||||
du -hs .[^.]*
|
||||
- name: Disk inventory (1/2) ...
|
||||
run: |
|
||||
echo "df -h ========================================================================="
|
||||
df -h
|
||||
echo "mounts ========================================================================"
|
||||
mount
|
||||
- name: File inventory (1/2) ...
|
||||
run: |
|
||||
echo "Current directory: $(pwd)"
|
||||
echo "Files in $HOME ================================================================"
|
||||
ls $HOME
|
||||
echo "Find $HOME ===================================================================="
|
||||
find $HOME
|
||||
- name: Container inventory ...
|
||||
run: |
|
||||
echo "Available container images: ==================================================="
|
||||
docker images
|
||||
echo "Available containers: ========================================================="
|
||||
docker ps -a
|
||||
|
||||
checkout:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Restore Cache of dl/
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: dl/
|
||||
key: dl-netconf-${{ hashFiles('.git/modules/buildroot/HEAD', 'configs/*', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
dl-netconf-
|
||||
dl-
|
||||
- name: Restore Cache of .ccache/
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .ccache/
|
||||
key: ccache-x86_64-${{ hashFiles('.git/modules/buildroot/HEAD', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
ccache-x86_64-
|
||||
ccache-
|
||||
- name: Disk inventory (2/2) ...
|
||||
run: |
|
||||
echo "df -h ========================================================================="
|
||||
df -h
|
||||
echo "mounts ========================================================================"
|
||||
mount
|
||||
- name: File inventory (2/2) ...
|
||||
run: |
|
||||
echo "Current directory: $(pwd)"
|
||||
echo "Files in $HOME ================================================================"
|
||||
ls $HOME
|
||||
echo "Find $HOME ===================================================================="
|
||||
find $HOME
|
||||
|
||||
peeky:
|
||||
if: ${{ inputs.peek }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Peek & Poke ...
|
||||
run: |
|
||||
whoami
|
||||
ls -l /mnt/
|
||||
cat /mnt/DATALOSS_WARNING_README.txt
|
||||
sudo mkdir /mnt/x-aarch64
|
||||
sudo chown $(id -un):$(id -gn) /mnt/x-aarch64
|
||||
ls -l /mnt/
|
||||
|
||||
cleanup:
|
||||
if: ${{ inputs.cleanup }}
|
||||
needs: [inventory, peeky]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cleaning up cruft ...
|
||||
run: |
|
||||
docker image prune -af
|
||||
docker volume prune -f
|
||||
docker container prune -f
|
||||
@@ -16,15 +16,11 @@ concurrency:
|
||||
jobs:
|
||||
build:
|
||||
name: Regression Testing
|
||||
runs-on: self-hosted
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
- name: Clean up cruft ...
|
||||
run: |
|
||||
./test/env -c
|
||||
- name: Set Build Variables
|
||||
id: vars
|
||||
run: |
|
||||
@@ -35,16 +31,18 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: dl/
|
||||
key: dl-netconf-${{ hashFiles('.git/modules/buildroot/refs/heads/master', 'package/*/*.hash') }}
|
||||
key: dl-x86_64-netconf-${{ hashFiles('.git/modules/buildroot/refs/heads/master', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
dl-netconf-
|
||||
dl-x86_64-netconf-
|
||||
dl-x86_64-
|
||||
dl-
|
||||
- name: Restore Cache of .ccache/
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .ccache/
|
||||
key: ccache-x86_64-${{ hashFiles('.git/modules/buildroot/refs/head/master', 'package/*/*.hash') }}
|
||||
key: ccache-x86_64-netconf-${{ hashFiles('.git/modules/buildroot/refs/head/master', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
ccache-x86_64-netconf-
|
||||
ccache-x86_64-
|
||||
ccache-
|
||||
- name: Configure NETCONF
|
||||
@@ -56,7 +54,7 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
make -j
|
||||
make
|
||||
- name: Prepare Artifact
|
||||
run: |
|
||||
cd output
|
||||
|
||||
@@ -20,21 +20,17 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository == 'kernelkit/infix' && startsWith(github.ref, 'refs/tags/')
|
||||
name: Build Infix ${{ github.ref_name }} [${{ matrix.platform }}]
|
||||
runs-on: self-hosted
|
||||
name: Build Infix ${{ github.ref_name }} [${{ matrix.platform }}-${{ matrix.variant }}]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [aarch64, x86_64]
|
||||
variant: [netconf, classic]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Maintenance
|
||||
run: |
|
||||
docker image prune -af
|
||||
docker volume prune -f
|
||||
docker container prune -f
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set Release Variables
|
||||
id: vars
|
||||
id: build
|
||||
run: |
|
||||
if [ -n "${{ inputs.version }}" ]; then
|
||||
ver=${{ inputs.version }}
|
||||
@@ -42,91 +38,69 @@ jobs:
|
||||
ver=${GITHUB_REF#refs/tags/}
|
||||
fi
|
||||
echo "ver=${ver}" >> $GITHUB_OUTPUT
|
||||
if echo $ver | grep -qE 'v[0-9\.]+(-alpha|-beta|-rc)[0-9]*'; then
|
||||
echo "pre=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "pre=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fver=${ver#v}
|
||||
target=${{ matrix.platform }}-${fver}
|
||||
if [ "${{ matrix.variant }}" = "netconf" ]; then
|
||||
target=${{ matrix.platform }}-${fver}
|
||||
else
|
||||
target=${{ matrix.platform }}-${{ matrix.variant }}-${fver}
|
||||
fi
|
||||
echo "dir=infix-$target" >> $GITHUB_OUTPUT
|
||||
echo "tgz=infix-$target.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "out=/mnt/x-$target" >> $GITHUB_OUTPUT
|
||||
- name: Restore Cache of dl/
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: dl/
|
||||
key: dl-${{ hashFiles('.git/modules/buildroot/HEAD', 'configs/*', 'package/*/*.hash') }}
|
||||
key: dl-${{ matrix.platform }}-${{ matrix.variant }}-${{ hashFiles('.git/modules/buildroot/HEAD', 'configs/*', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
dl-${{ matrix.platform }}-${{ matrix.variant }}-
|
||||
dl-${{ matrix.platform }}-
|
||||
dl-
|
||||
- name: Restore Cache of .ccache/
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .ccache/
|
||||
key: ccache-${{ matrix.platform }}-${{ hashFiles('.git/modules/buildroot/HEAD', 'package/*/*.hash') }}
|
||||
key: ccache-${{ matrix.platform }}-${{ matrix.variant }}-${{ hashFiles('.git/modules/buildroot/HEAD', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
ccache-${{ matrix.platform }}-${{ matrix.variant }}-
|
||||
ccache-${{ matrix.platform }}-
|
||||
ccache-
|
||||
- name: Configure & Build
|
||||
env:
|
||||
INFIX_RELEASE: ${{ steps.vars.outputs.ver }}
|
||||
INFIX_RELEASE: ${{ steps.build.outputs.ver }}
|
||||
run: |
|
||||
target=${{ matrix.platform }}_defconfig
|
||||
echo "Building $target ..."
|
||||
sudo mkdir ${{ steps.vars.outputs.out }}
|
||||
sudo chown $(id -un):$(id -gn) ${{ steps.vars.outputs.out }}
|
||||
export O=${{ steps.vars.outputs.out }}
|
||||
if [ "${{ matrix.variant }}" = "netconf" ]; then
|
||||
target=${{ matrix.platform }}_defconfig
|
||||
else
|
||||
target=${{ matrix.platform }}_${{ matrix.variant }}_defconfig
|
||||
fi
|
||||
echo "Buildring $target ..."
|
||||
make $target
|
||||
make
|
||||
- name: Generate SBOM from Build
|
||||
- name: Prepare Artifact
|
||||
run: |
|
||||
make legal-info
|
||||
- name: Prepare Artifacts
|
||||
run: |
|
||||
cd ${{ steps.vars.outputs.out }}
|
||||
mv images ${{ steps.vars.outputs.dir }}
|
||||
ln -s ${{ steps.vars.outputs.dir }} images
|
||||
tar chfz ${{ steps.vars.outputs.tgz }} ${{ steps.vars.outputs.dir }}
|
||||
|
||||
mv legal-info legal-info-$target
|
||||
tar chfz legal-info-$target.tar.gz legal-info-$target
|
||||
cd output
|
||||
mv images ${{ steps.build.outputs.dir }}
|
||||
ln -s ${{ steps.build.outputs.dir }} images
|
||||
tar chfz ${{ steps.build.outputs.tgz }} ${{ steps.build.outputs.dir }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifact-${{ matrix.platform }}
|
||||
path: ${{ steps.vars.outputs.out }}/*.tar.gz
|
||||
path: output/${{ steps.build.outputs.tgz }}
|
||||
name: artifact-${{ matrix.variant }}-${{ matrix.platform }}
|
||||
release:
|
||||
name: Release Infix ${{ github.ref_name }}
|
||||
needs: build
|
||||
runs-on: self-hosted
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set Release Variables
|
||||
id: rel
|
||||
run: |
|
||||
if [ -n "${{ inputs.version }}" ]; then
|
||||
ver=${{ inputs.version }}
|
||||
else
|
||||
ver=${GITHUB_REF#refs/tags/}
|
||||
fi
|
||||
echo "ver=${ver}" >> $GITHUB_OUTPUT
|
||||
if echo $ver | grep -qE 'v[0-9.]+(-alpha|-beta|-rc)[0-9]*'; then
|
||||
echo "pre=true" >> $GITHUB_OUTPUT
|
||||
echo "latest=false" >> $GITHUB_OUTPUT
|
||||
elif echo $ver | grep -qE '^v[0-9.]+\.[0-9.]+(\.[0-9]+)?$'; then
|
||||
echo "pre=false" >> $GITHUB_OUTPUT
|
||||
echo "latest=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "pre=false" >> $GITHUB_OUTPUT
|
||||
echo "latest=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
echo "pre=${{ steps.rel.outputs.pre }}"
|
||||
echo "latest=${{ steps.rel.outputs.latest }}"
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: "artifact-*"
|
||||
merge-multiple: true
|
||||
- name: Create checksums ...
|
||||
run: |
|
||||
for file in *.tar.gz; do
|
||||
sha256sum $file > $file.sha256
|
||||
done
|
||||
- name: Extract ChangeLog entry ...
|
||||
run: |
|
||||
awk '/^-----*$/{if (x == 1) exit; x=1;next}x' doc/ChangeLog.md \
|
||||
@@ -135,10 +109,9 @@ jobs:
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: Infix ${{ github.ref_name }}
|
||||
prerelease: ${{ steps.rel.outputs.pre }}
|
||||
makeLatest: ${{ steps.rel.outputs.latest }}
|
||||
prerelease: ${{ needs.build.outputs.pre }}
|
||||
bodyFile: release.md
|
||||
artifacts: "*.tar.gz*"
|
||||
artifacts: artifact/*
|
||||
- name: Summary
|
||||
run: |
|
||||
cat <<EOF >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
@@ -54,7 +54,7 @@ config INFIX_IMAGE_ID
|
||||
|
||||
config INFIX_TAGLINE
|
||||
string "Operating system tagline"
|
||||
default "Infix -- a Network Operating System"
|
||||
default "Infix — a Network Operating System"
|
||||
help
|
||||
Mandatory. Used for identifying the OS, e.g. as PRETTY_NAME in
|
||||
/etc/os-release and description in the GNS3 appliance.
|
||||
@@ -112,6 +112,25 @@ config INFIX_ARCH
|
||||
default "riscv64" if BR2_riscv
|
||||
default "x86_64" if BR2_x86_64
|
||||
|
||||
# For /etc/os-release, VARIANT & VARIANT_ID used, e.g., in mnt script
|
||||
choice
|
||||
prompt "Select variant/flavor"
|
||||
default INFIX_VARIANT_NETCONF
|
||||
|
||||
config INFIX_VARIANT_NETCONF
|
||||
bool "NETCONF"
|
||||
help
|
||||
Managed NETCONF mode, /etc is a ramdisk, all configuration is
|
||||
generated by sysrepo plugins using NETCONF (xml) or RESTCONF.
|
||||
|
||||
config INFIX_VARIANT_CLASSIC
|
||||
bool "Classic /etc mode"
|
||||
help
|
||||
User managed mode, read-write configuration files in /etc that
|
||||
is saved across reboots.
|
||||
|
||||
endchoice
|
||||
|
||||
menu "Packages"
|
||||
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/Config.in"
|
||||
|
||||
@@ -22,17 +22,12 @@ $(config):
|
||||
@echo "'make <board>_defconfig' before building an image."
|
||||
@exit 1
|
||||
|
||||
|
||||
%: | buildroot/Makefile
|
||||
@+$(call bmake,$@)
|
||||
|
||||
legal-info: | buildroot/Makefile
|
||||
$(call bmake,legal-info LINUX_LICENSE_FILES=COPYING)
|
||||
|
||||
# Workaround, see board/x86_64/board.mk
|
||||
test:
|
||||
@+$(call bmake,$@)
|
||||
|
||||
buildroot/Makefile:
|
||||
@git submodule update --init
|
||||
|
||||
.PHONY: all check test
|
||||
.PHONY: all check
|
||||
|
||||
|
||||
@@ -1,43 +1,28 @@
|
||||
[![License Badge][]][License] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan] [![Discord][discord-badge]][discord-url]
|
||||
[![License Badge][]][License] [![Coverity Status][]][Coverity Scan] [![Discord][discord-badge]][discord-url]
|
||||
|
||||
<img align="right" src="doc/logo.png" alt="Infix - Linux <3 NETCONF" width=480 border=10>
|
||||
<details><summary><b>Documentation</b></summary>
|
||||
|
||||
Infix is a free, Linux based, immutable Network Operating System (NOS)
|
||||
built on [Buildroot][1], and [sysrepo][2]. A powerful mix that ease
|
||||
porting to different platforms, simplify long-term maintenance, and
|
||||
provide made-easy management using NETCONF[^1] or the built-in command
|
||||
line interface (CLI) from a console or SSH login.
|
||||
- **Infix In-Depth**
|
||||
- [Infix Variants](doc/variant.md)
|
||||
- [Boot Procedure](doc/boot.md)
|
||||
- [Containers in Infix](doc/container.md)
|
||||
- [Developer's Guide](doc/developers-guide.md)
|
||||
- [Discover Your Device](doc/discovery.md)
|
||||
- [Virtual Environments](doc/virtual.md)
|
||||
- [Origin & Licensing](doc/license.md)
|
||||
- **CLI Topics**
|
||||
- [Introduction to the CLI](doc/cli/introduction.md)
|
||||
- [CLI User's Guide](doc/cli/tutorial.md)
|
||||
- [Quick Overview](doc/cli/quick.md)
|
||||
|
||||
> Click the **▶ Example CLI Session** foldout below for an example, or
|
||||
> head on over to the [Infix Documentation](doc/README.md) for more
|
||||
> information on how to set up the system.
|
||||
</details>
|
||||
|
||||
Although primarily focused on switches and routers, the core values
|
||||
may be appealing for other use-cases as well:
|
||||
|
||||
- Runs from a squashfs image on a read-only partition
|
||||
- Single configuration file on a separate partition
|
||||
- Built around YANG with standard IETF models
|
||||
- Linux switchdev provides open switch APIs
|
||||
- Atomic upgrades to secondary partition
|
||||
- Highly security focused
|
||||
|
||||
An immutable[^2] operating system enhances security and inherently makes
|
||||
it maintenance-free. Configuration and data, e.g, containers, is stored
|
||||
on separate partitions to ensure complete separation from system files
|
||||
and allow for seamless backup, restore, and provisioning.
|
||||
|
||||
In itself Infix is perfectly suited for dedicated networking tasks and
|
||||
native support for Docker containers provides a versatile platform that
|
||||
can easily be adapted to any customer need. Be it legacy applications,
|
||||
network protocols, process monitoring, or edge data analysis, it can run
|
||||
close to end equipment. Either directly connected on dedicated Ethernet
|
||||
ports or indirectly using virtual network cables to exist on the same
|
||||
LAN as other connected equipment.
|
||||
|
||||
The simple design of Infix provides complete control over both system
|
||||
and data, minimal cognitive burden, and makes it incredibly easy to get
|
||||
started.
|
||||
Infix is a Linux Network Operating System (NOS) based on [Buildroot][1],
|
||||
and [sysrepo][2]. A powerful mix that ease porting to different
|
||||
platforms, simplify long-term maintenance, and provide made-easy
|
||||
management using NETCONF[^1] (remote) or the built-in [command
|
||||
line interface (CLI)][3] (click the foldout for an example).
|
||||
|
||||
<details><summary><b>Example CLI Session</b></summary>
|
||||
|
||||
@@ -93,7 +78,6 @@ The [following boards](board/aarch64/README.md) are fully supported:
|
||||
- Marvell CN9130 CRB
|
||||
- Marvell EspressoBIN
|
||||
- Microchip SparX-5i PCB135 (eMMC)
|
||||
- NanoPi R2S
|
||||
|
||||
An x86_64 build is also available, primarily intended for development
|
||||
and testing, but can also be used for evaluation and demo purposes. For
|
||||
@@ -105,21 +89,14 @@ more information, see: [Infix in Virtual Environments](doc/virtual.md).
|
||||
>
|
||||
> For *customer specific builds* of Infix, see your product repository.
|
||||
|
||||
[^1]: NETCONF or RESTCONF, <https://datatracker.ietf.org/doc/html/rfc8040>
|
||||
|
||||
[^2]: An immutable operating system is one with read-only file systems,
|
||||
atomic updates, rollbacks, declarative configuration, and workload
|
||||
isolation. All to improve reliability, scalability, and security.
|
||||
For more information, see <https://ceur-ws.org/Vol-3386/paper9.pdf>
|
||||
and <https://www.zdnet.com/article/what-is-immutable-linux-heres-why-youd-run-an-immutable-linux-distro/>.
|
||||
[^1]: NETCONF or RESTCONF, <https://datatracker.ietf.org/doc/html/rfc8040>,
|
||||
for more information, see [Infix Variants](doc/variant.md).
|
||||
|
||||
[1]: https://buildroot.org/
|
||||
[2]: https://www.sysrepo.org/
|
||||
[3]: doc/cli/introduction.md
|
||||
[License]: https://en.wikipedia.org/wiki/GPL_license
|
||||
[License Badge]: https://img.shields.io/badge/License-GPL%20v2-blue.svg
|
||||
[GitHub]: https://github.com/kernelkit/infix/actions/workflows/build.yml/
|
||||
[GitHub Status]: https://github.com/kernelkit/infix/actions/workflows/build.yml/badge.svg
|
||||
[Coverity Scan]: https://scan.coverity.com/projects/29393
|
||||
[Coverity Status]: https://scan.coverity.com/projects/29393/badge.svg
|
||||
[discord-badge]: https://img.shields.io/discord/1182652155618918411.svg?logo=discord
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
|
||||
infix {
|
||||
vpds = <&vpd_cpu &vpd_product &vpd_power>;
|
||||
usb-ports = <&cp0_usb3_1>;
|
||||
usb-port-names = "USB";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -270,7 +268,7 @@
|
||||
};
|
||||
|
||||
&cp0_usb3_1 {
|
||||
status = "okay";
|
||||
status = "disabled";
|
||||
usb-phy = <&cp0_usb3_0_phy1>;
|
||||
phys = <&cp0_utmi1>, <&cp0_comphy3 1>;
|
||||
phy-names = "usb", "usb3";
|
||||
@@ -354,7 +352,6 @@
|
||||
#define XSWP(_n, _label, _mac_offs, _phy) \
|
||||
port@_n { \
|
||||
SWP_COMMON(_n, _label, _mac_offs, "usxgmii", _phy); \
|
||||
managed = "in-band-status"; \
|
||||
}
|
||||
|
||||
#define GSWP(_n, _label, _mac_offs, _phy) \
|
||||
|
||||
@@ -6,7 +6,3 @@
|
||||
compatible = "marvell,cp115-standalone-pinctrl";
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_xmdio {
|
||||
clock-names = "gop_clk", "mg_clk", "mg_core_clk", "axi_clk";
|
||||
};
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
#ifndef _STYX_MPP_H
|
||||
#define _STYX_MPP_H
|
||||
|
||||
#define SFP0_TX_DISABLE(X) X( "mpp0", cp0_gpio1, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)
|
||||
#define SFP1_TX_DISABLE(X) X( "mpp1", cp0_gpio1, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)
|
||||
#define SFP2_TX_DISABLE(X) X( "mpp2", cp0_gpio1, 2, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)
|
||||
#define SFP3_TX_DISABLE(X) X( "mpp3", cp0_gpio1, 3, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)
|
||||
#define SFP0_RS0(X) X( "mpp4", cp0_gpio1, 4, GPIO_ACTIVE_HIGH)
|
||||
#define SFP1_RS0(X) X( "mpp5", cp0_gpio1, 5, GPIO_ACTIVE_HIGH)
|
||||
#define SFP2_RS0(X) X( "mpp6", cp0_gpio1, 6, GPIO_ACTIVE_HIGH)
|
||||
#define SFP3_RS0(X) X( "mpp7", cp0_gpio1, 7, GPIO_ACTIVE_HIGH)
|
||||
#define SFP0_RS1(X) X( "mpp8", cp0_gpio1, 8, GPIO_ACTIVE_HIGH)
|
||||
#define SFP1_RS1(X) X( "mpp9", cp0_gpio1, 9, GPIO_ACTIVE_HIGH)
|
||||
#define SFP2_RS1(X) X("mpp10", cp0_gpio1, 10, GPIO_ACTIVE_HIGH)
|
||||
#define SFP3_RS1(X) X("mpp11", cp0_gpio1, 11, GPIO_ACTIVE_HIGH)
|
||||
/* mpp12: Unused */
|
||||
#define CP_SPI1_MISO(X) X("mpp13", none, 0, 0)
|
||||
#define CP_SPI1_CS0(X) X("mpp14", none, 0, 0)
|
||||
#define CP_SPI1_MOSI(X) X("mpp15", none, 0, 0)
|
||||
#define CP_SPI1_SCK(X) X("mpp16", none, 0, 0)
|
||||
/* mpp17: Unused */
|
||||
/* mpp18: Unused */
|
||||
/* mpp19: Unused */
|
||||
/* mpp20: Unused */
|
||||
/* mpp21: Unused */
|
||||
/* mpp22: Unused */
|
||||
/* mpp23: Unused */
|
||||
/* mpp24: Unused */
|
||||
/* mpp25: Unused */
|
||||
/* mpp26: Unused */
|
||||
#define SFP0_RX_LOS(X) X("mpp27", cp0_gpio1, 27, GPIO_ACTIVE_HIGH)
|
||||
#define SFP1_RX_LOS(X) X("mpp28", cp0_gpio1, 28, GPIO_ACTIVE_HIGH)
|
||||
#define SFP2_RX_LOS(X) X("mpp29", cp0_gpio1, 29, GPIO_ACTIVE_HIGH)
|
||||
#define SFP3_RX_LOS(X) X("mpp30", cp0_gpio1, 30, GPIO_ACTIVE_HIGH)
|
||||
#define SFP0_TX_FAULT(X) X("mpp31", cp0_gpio1, 31, GPIO_ACTIVE_HIGH)
|
||||
#define SFP1_TX_FAULT(X) X("mpp32", cp0_gpio2, 0, GPIO_ACTIVE_HIGH)
|
||||
#define SFP2_TX_FAULT(X) X("mpp33", cp0_gpio2, 1, GPIO_ACTIVE_HIGH)
|
||||
#define SFP3_TX_FAULT(X) X("mpp34", cp0_gpio2, 2, GPIO_ACTIVE_HIGH)
|
||||
#define CP_I2C1_SDA(X) X("mpp35", none, 0, 0)
|
||||
#define CP_I2C1_SCK(X) X("mpp36", none, 0, 0)
|
||||
#define CP_I2C0_SCK(X) X("mpp37", none, 0, 0)
|
||||
#define CP_I2C0_SDA(X) X("mpp38", none, 0, 0)
|
||||
/* mpp39: Unused */
|
||||
#define CP_SMI_MDIO(X) X("mpp40", none, 0, 0)
|
||||
#define CP_SMI_MDC(X) X("mpp41", none, 0, 0)
|
||||
/* mpp42: Unused */
|
||||
/* mpp43: Unused */
|
||||
/* mpp44: Unused */
|
||||
/* mpp45: Unused */
|
||||
/* mpp46: Unused */
|
||||
#define CP_UA1_TXD(X) X("mpp47", none, 0, 0)
|
||||
/* mpp48: Unused */
|
||||
#define SW1_RESETn(X) X("mpp49", cp0_gpio2, 17, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)
|
||||
#define SW2_RESETn(X) X("mpp50", cp0_gpio2, 18, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)
|
||||
#define SW3_RESETn(X) X("mpp51", cp0_gpio2, 19, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)
|
||||
/* mpp52: Unused */
|
||||
#define CP_UA1_RXD(X) X("mpp53", none, 0, 0)
|
||||
#define SFP0_MOD_ABS(X) X("mpp54", cp0_gpio2, 22, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)
|
||||
#define SFP1_MOD_ABS(X) X("mpp55", cp0_gpio2, 23, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)
|
||||
#define SFP2_MOD_ABS(X) X("mpp56", cp0_gpio2, 24, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)
|
||||
#define SFP3_MOD_ABS(X) X("mpp57", cp0_gpio2, 25, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)
|
||||
#define SW1_INTn(X) X("mpp58", cp0_gpio2, 26, IRQ_TYPE_LEVEL_LOW)
|
||||
#define SW2_INTn(X) X("mpp59", cp0_gpio2, 27, IRQ_TYPE_LEVEL_LOW)
|
||||
#define SW3_INTn(X) X("mpp60", cp0_gpio2, 28, IRQ_TYPE_LEVEL_LOW)
|
||||
/* mpp61: Unused */
|
||||
#define DDR_TEN(X) X("mpp62", cp0_gpio2, 30, GPIO_ACTIVE_HIGH)
|
||||
|
||||
/* Macros to extract MPP info in different formats */
|
||||
#define MPP_ID(_mpp, _chip, _no, _flags) _mpp
|
||||
#define MPP_GPIO_CHIP(_mpp, _chip, _no, _flags) _chip
|
||||
|
||||
#define MPP_GPIO_REF(_mpp, _chip, _no, _flags) <&_chip _no (_flags)>
|
||||
#define MPP_GPIO_REF_NO_CHIP(_mpp, _chip, _no, _flags) <_no (_flags)>
|
||||
#define MPP_IRQ_REF(_mpp, _chip, _no, _flags) <&_chip _no (_flags)>
|
||||
|
||||
#endif /* _STYX_MPP_H */
|
||||
@@ -1,9 +0,0 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
/*
|
||||
* Copyright (C) 2021 Marvell International Ltd.
|
||||
* Copyright (C) 2023 Addiva Elektronik AB
|
||||
*
|
||||
* Device tree for Styx board
|
||||
*/
|
||||
|
||||
#include "styx.dtsi"
|
||||
@@ -1,566 +0,0 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
/*
|
||||
* Copyright (C) 2021 Marvell International Ltd.
|
||||
* Copyright (C) 2023 Addiva Elektronik AB
|
||||
*
|
||||
* Device tree for Styx board
|
||||
*/
|
||||
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
#include "../marvell/cn9130-patched.dtsi"
|
||||
|
||||
#include "styx-mpp.h"
|
||||
|
||||
/ {
|
||||
model = "Styx";
|
||||
compatible = "styx,styx",
|
||||
"marvell,armada-ap807-quad",
|
||||
"marvell,armada-ap807";
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
|
||||
infix {
|
||||
/* "admin" */
|
||||
factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A";
|
||||
vpds = <&vpd>;
|
||||
};
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x0 0x0 0x80000000>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* UART0 (Console) */
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
/* UART1 (Auxiliary) */
|
||||
|
||||
&cp0_pinctrl {
|
||||
cp0_uart1_pins: cp0-uart1-pins {
|
||||
marvell,pins = CP_UA1_RXD(MPP_ID), CP_UA1_TXD(MPP_ID);
|
||||
marvell,function = "uart1";
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_uart1 {
|
||||
/* TODO: Figure out how to enable this without affecting
|
||||
* /chosen/stdout-path
|
||||
*/
|
||||
status = "disabled";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp0_uart1_pins>;
|
||||
};
|
||||
|
||||
|
||||
/* GPIO */
|
||||
|
||||
&cp0_gpio1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp0_gpio2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
/* I2C0 (EEPROM) */
|
||||
|
||||
&cp0_pinctrl {
|
||||
cp0_i2c0_pins: cp0-i2c0-pins {
|
||||
marvell,pins = CP_I2C0_SCK(MPP_ID), CP_I2C0_SDA(MPP_ID);
|
||||
marvell,function = "i2c0";
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_i2c0 {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp0_i2c0_pins>;
|
||||
|
||||
vpd: eeprom@50 {
|
||||
compatible = "atmel,24c256";
|
||||
reg = <0x50>;
|
||||
|
||||
infix,board = "cpu";
|
||||
infix,trusted;
|
||||
|
||||
nvmem-layout {
|
||||
compatible = "onie,tlv-layout";
|
||||
|
||||
base_mac: mac-address {
|
||||
#nvmem-cell-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
spd: eeprom@53 {
|
||||
compatible = "spd";
|
||||
reg = <0x53>;
|
||||
};
|
||||
|
||||
eeprom@57 {
|
||||
compatible = "atmel,24c256";
|
||||
reg = <0x57>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* I2C1 (Mux) */
|
||||
|
||||
&cp0_pinctrl {
|
||||
cp0_i2c1_pins: cp0-i2c1-pins {
|
||||
marvell,pins = CP_I2C1_SCK(MPP_ID), CP_I2C1_SDA(MPP_ID);
|
||||
marvell,function = "i2c1";
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_i2c1 {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp0_i2c1_pins>;
|
||||
|
||||
i2cmux@77 {
|
||||
compatible = "nxp,pca9548";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x77>;
|
||||
|
||||
i2c_sfp0: i2c@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
i2c_sfp1: i2c@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
i2c_sfp2: i2c@2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <2>;
|
||||
};
|
||||
|
||||
i2c_sfp3: i2c@3 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* SPI1 (Boot FLASH) */
|
||||
|
||||
&cp0_pinctrl {
|
||||
cp0_spi1_pins: cp0-spi-pins-0 {
|
||||
marvell,pins = \
|
||||
CP_SPI1_MISO(MPP_ID), CP_SPI1_CS0(MPP_ID), \
|
||||
CP_SPI1_MOSI(MPP_ID), CP_SPI1_SCK(MPP_ID);
|
||||
marvell,function = "spi1";
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_spi1 {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp0_spi1_pins>;
|
||||
|
||||
/* Boot flash */
|
||||
spi-flash@0 {
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x1>;
|
||||
compatible = "jedec,spi-nor", "spi-flash";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <90000000>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
boot0@0 {
|
||||
label = "boot0";
|
||||
reg = <0x0 0x200000>;
|
||||
};
|
||||
|
||||
boot1@200000 {
|
||||
label = "boot1";
|
||||
reg = <0x200000 0x200000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* AP SDHCI (eMMC) */
|
||||
|
||||
&ap_sdhci0 {
|
||||
status = "okay";
|
||||
bus-width = <8>;
|
||||
mmc-ddr-1_8v;
|
||||
mmc-hs400-1_8v;
|
||||
};
|
||||
|
||||
|
||||
&cp0_crypto {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp0_ethernet {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
/* ETH1 (Connection to BMC) */
|
||||
|
||||
&cp0_eth2 {
|
||||
status = "okay";
|
||||
phy-mode = "sgmii";
|
||||
phys = <&cp0_comphy5 2>;
|
||||
managed = "in-band-status";
|
||||
|
||||
nvmem-cells = <&base_mac 0>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
|
||||
/* ETH0 (DSA connection to switch tree) */
|
||||
|
||||
&cp0_eth0 {
|
||||
status = "okay";
|
||||
phy-mode = "10gbase-r";
|
||||
phys = <&cp0_comphy2 0>;
|
||||
managed = "in-band-status";
|
||||
|
||||
nvmem-cells = <&base_mac 0>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
|
||||
/* MDIO (Switch Tree) */
|
||||
|
||||
&cp0_pinctrl {
|
||||
cp0_mdio_pins: cp0-mdio-pins-0 {
|
||||
marvell,pins = CP_SMI_MDIO(MPP_ID), CP_SMI_MDC(MPP_ID);
|
||||
marvell,function = "ge";
|
||||
};
|
||||
};
|
||||
|
||||
#define SWP_LED(_func) \
|
||||
leds { \
|
||||
#address-cells = <1>; \
|
||||
#size-cells = <0>; \
|
||||
\
|
||||
led@0 { \
|
||||
reg = <0>; \
|
||||
function = _func; \
|
||||
color = <LED_COLOR_ID_GREEN>; \
|
||||
default-state = "keep"; \
|
||||
}; \
|
||||
led@1 { \
|
||||
reg = <1>; \
|
||||
function = _func; \
|
||||
color = <LED_COLOR_ID_YELLOW>; \
|
||||
default-state = "off"; \
|
||||
}; \
|
||||
}
|
||||
|
||||
#define XSWP(_n, _label, _mac_offs, _sfp) \
|
||||
port@_n { \
|
||||
reg = <0x ## _n>; \
|
||||
label = _label; \
|
||||
nvmem-cells = <&base_mac _mac_offs>; \
|
||||
nvmem-cell-names = "mac-address"; \
|
||||
phy-mode = "10gbase-r"; \
|
||||
managed = "in-band-status"; \
|
||||
sfp = <&_sfp>; \
|
||||
SWP_LED("sfp"); \
|
||||
}
|
||||
|
||||
#define GSWP(_n, _label, _mac_offs, _phy) \
|
||||
port@_n { \
|
||||
reg = <0x ## _n>; \
|
||||
label = _label; \
|
||||
nvmem-cells = <&base_mac _mac_offs>; \
|
||||
nvmem-cell-names = "mac-address"; \
|
||||
phy-mode = "gmii"; \
|
||||
phy-handle = <&_phy>; \
|
||||
SWP_LED("tp"); \
|
||||
}
|
||||
|
||||
#define GPHY(_n) \
|
||||
ethernet-phy@_n { \
|
||||
compatible = "ethernet-phy-ieee802.3-c22"; \
|
||||
reg = <_n>; \
|
||||
eee-broken-100tx; \
|
||||
eee-broken-1000t; \
|
||||
}
|
||||
|
||||
&cp0_mdio {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp0_mdio_pins>;
|
||||
|
||||
sw3: switch@6 {
|
||||
compatible = "marvell,mv88e6190";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <6>;
|
||||
|
||||
reset-gpios = SW3_RESETn(MPP_GPIO_REF);
|
||||
|
||||
interrupts-extended = SW3_INTn(MPP_IRQ_REF);
|
||||
interrupt-controller;
|
||||
|
||||
dsa,member = <0 0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@9 {
|
||||
reg = <0x9>;
|
||||
label = "cpu";
|
||||
ethernet = <&cp0_eth0>;
|
||||
phy-mode = "10gbase-r";
|
||||
fixed-link {
|
||||
speed = <10000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
sw3p10: port@a {
|
||||
reg = <0xa>;
|
||||
link = <&sw2p10 &sw1p0>;
|
||||
phy-mode = "10gbase-r";
|
||||
fixed-link {
|
||||
speed = <10000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
/* Can't use XSWP macro as port 0 does not have
|
||||
* any LEDs attached to it. LEDs for port 10 seem
|
||||
* to be wired to the corresponding SFP cage. Maybe
|
||||
* we can apply a static workaround by binding port
|
||||
* 10's green LED to "Special LED 1", so we can at
|
||||
* least see link/act.
|
||||
*/
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "e16";
|
||||
nvmem-cells = <&base_mac 16>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
phy-mode = "10gbase-r";
|
||||
managed = "in-band-status";
|
||||
sfp = <&sfp3>;
|
||||
};
|
||||
|
||||
GSWP(1, "e22", 22, sw3phy1);
|
||||
GSWP(2, "e21", 21, sw3phy2);
|
||||
GSWP(3, "e24", 24, sw3phy3);
|
||||
GSWP(4, "e23", 23, sw3phy4);
|
||||
GSWP(5, "e26", 26, sw3phy5);
|
||||
GSWP(6, "e25", 25, sw3phy6);
|
||||
GSWP(7, "e28", 28, sw3phy7);
|
||||
GSWP(8, "e27", 27, sw3phy8);
|
||||
};
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sw3phy1: GPHY(1);
|
||||
sw3phy2: GPHY(2);
|
||||
sw3phy3: GPHY(3);
|
||||
sw3phy4: GPHY(4);
|
||||
sw3phy5: GPHY(5);
|
||||
sw3phy6: GPHY(6);
|
||||
sw3phy7: GPHY(7);
|
||||
sw3phy8: GPHY(8);
|
||||
};
|
||||
};
|
||||
|
||||
sw2: switch@4 {
|
||||
compatible = "marvell,mv88e6190";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <4>;
|
||||
|
||||
reset-gpios = SW2_RESETn(MPP_GPIO_REF);
|
||||
|
||||
interrupts-extended = SW2_INTn(MPP_IRQ_REF);
|
||||
interrupt-controller;
|
||||
|
||||
dsa,member = <0 1>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sw2p0: port@0 {
|
||||
reg = <0x0>;
|
||||
link = <&sw1p0>;
|
||||
phy-mode = "10gbase-r";
|
||||
fixed-link {
|
||||
speed = <10000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
sw2p10: port@a {
|
||||
reg = <0xa>;
|
||||
link = <&sw3p10>;
|
||||
phy-mode = "10gbase-r";
|
||||
fixed-link {
|
||||
speed = <10000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
GSWP(1, "e10", 10, sw2phy1);
|
||||
GSWP(2, "e9", 9, sw2phy2);
|
||||
GSWP(3, "e12", 12, sw2phy3);
|
||||
GSWP(4, "e11", 11, sw2phy4);
|
||||
GSWP(5, "e18", 18, sw2phy5);
|
||||
GSWP(6, "e17", 17, sw2phy6);
|
||||
GSWP(7, "e20", 20, sw2phy7);
|
||||
GSWP(8, "e19", 19, sw2phy8);
|
||||
XSWP(9, "e15", 15, sfp2);
|
||||
};
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sw2phy1: GPHY(1);
|
||||
sw2phy2: GPHY(2);
|
||||
sw2phy3: GPHY(3);
|
||||
sw2phy4: GPHY(4);
|
||||
sw2phy5: GPHY(5);
|
||||
sw2phy6: GPHY(6);
|
||||
sw2phy7: GPHY(7);
|
||||
sw2phy8: GPHY(8);
|
||||
};
|
||||
};
|
||||
|
||||
sw1: switch@2 {
|
||||
compatible = "marvell,mv88e6190";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <2>;
|
||||
|
||||
reset-gpios = SW1_RESETn(MPP_GPIO_REF);
|
||||
|
||||
interrupts-extended = SW1_INTn(MPP_IRQ_REF);
|
||||
interrupt-controller;
|
||||
|
||||
dsa,member = <0 2>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sw1p0: port@0 {
|
||||
reg = <0x0>;
|
||||
link = <&sw2p0 &sw3p10>;
|
||||
phy-mode = "10gbase-r";
|
||||
fixed-link {
|
||||
speed = <10000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
GSWP(1, "e2", 2, sw1phy1);
|
||||
GSWP(2, "e1", 1, sw1phy2);
|
||||
GSWP(3, "e4", 4, sw1phy3);
|
||||
GSWP(4, "e3", 3, sw1phy4);
|
||||
GSWP(5, "e6", 6, sw1phy5);
|
||||
GSWP(6, "e5", 5, sw1phy6);
|
||||
GSWP(7, "e8", 8, sw1phy7);
|
||||
GSWP(8, "e7", 7, sw1phy8);
|
||||
XSWP(9, "e14", 14, sfp1);
|
||||
XSWP(a, "e13", 13, sfp0);
|
||||
};
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sw1phy1: GPHY(1);
|
||||
sw1phy2: GPHY(2);
|
||||
sw1phy3: GPHY(3);
|
||||
sw1phy4: GPHY(4);
|
||||
sw1phy5: GPHY(5);
|
||||
sw1phy6: GPHY(6);
|
||||
sw1phy7: GPHY(7);
|
||||
sw1phy8: GPHY(8);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/ {
|
||||
sfp0: sfp@0 {
|
||||
compatible = "sff,sfp";
|
||||
i2c-bus = <&i2c_sfp0>;
|
||||
mod-def0-gpios = SFP0_MOD_ABS(MPP_GPIO_REF);
|
||||
los-gpios = SFP0_RX_LOS(MPP_GPIO_REF);
|
||||
tx-disable-gpios = SFP0_TX_DISABLE(MPP_GPIO_REF);
|
||||
tx-fault-gpios = SFP0_TX_FAULT(MPP_GPIO_REF);
|
||||
rate-select0-gpios = SFP0_RS0(MPP_GPIO_REF);
|
||||
rate-select1-gpios = SFP0_RS1(MPP_GPIO_REF);
|
||||
maximum-power-milliwatt = <3000>;
|
||||
};
|
||||
|
||||
sfp1: sfp@1 {
|
||||
compatible = "sff,sfp";
|
||||
i2c-bus = <&i2c_sfp1>;
|
||||
mod-def0-gpios = SFP1_MOD_ABS(MPP_GPIO_REF);
|
||||
los-gpios = SFP1_RX_LOS(MPP_GPIO_REF);
|
||||
tx-disable-gpios = SFP1_TX_DISABLE(MPP_GPIO_REF);
|
||||
tx-fault-gpios = SFP1_TX_FAULT(MPP_GPIO_REF);
|
||||
rate-select0-gpios = SFP1_RS0(MPP_GPIO_REF);
|
||||
rate-select1-gpios = SFP1_RS1(MPP_GPIO_REF);
|
||||
maximum-power-milliwatt = <3000>;
|
||||
};
|
||||
|
||||
sfp2: sfp@2 {
|
||||
compatible = "sff,sfp";
|
||||
i2c-bus = <&i2c_sfp2>;
|
||||
mod-def0-gpios = SFP2_MOD_ABS(MPP_GPIO_REF);
|
||||
los-gpios = SFP2_RX_LOS(MPP_GPIO_REF);
|
||||
tx-disable-gpios = SFP2_TX_DISABLE(MPP_GPIO_REF);
|
||||
tx-fault-gpios = SFP2_TX_FAULT(MPP_GPIO_REF);
|
||||
rate-select0-gpios = SFP2_RS0(MPP_GPIO_REF);
|
||||
rate-select1-gpios = SFP2_RS1(MPP_GPIO_REF);
|
||||
maximum-power-milliwatt = <3000>;
|
||||
};
|
||||
|
||||
sfp3: sfp@3 {
|
||||
compatible = "sff,sfp";
|
||||
i2c-bus = <&i2c_sfp3>;
|
||||
mod-def0-gpios = SFP3_MOD_ABS(MPP_GPIO_REF);
|
||||
los-gpios = SFP3_RX_LOS(MPP_GPIO_REF);
|
||||
tx-disable-gpios = SFP3_TX_DISABLE(MPP_GPIO_REF);
|
||||
tx-fault-gpios = SFP3_TX_FAULT(MPP_GPIO_REF);
|
||||
rate-select0-gpios = SFP3_RS0(MPP_GPIO_REF);
|
||||
rate-select1-gpios = SFP3_RS1(MPP_GPIO_REF);
|
||||
maximum-power-milliwatt = <3000>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -21,6 +21,7 @@ CONFIG_CFS_BANDWIDTH=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_CGROUP_PIDS=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_HUGETLB=y
|
||||
CONFIG_CPUSETS=y
|
||||
CONFIG_CGROUP_DEVICE=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
@@ -31,6 +32,7 @@ CONFIG_SCHED_AUTOGROUP=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_PROFILING=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_ARCH_SPARX5=y
|
||||
CONFIG_ARCH_MVEBU=y
|
||||
CONFIG_ARCH_VEXPRESS=y
|
||||
@@ -47,6 +49,12 @@ CONFIG_CPUFREQ_DT=y
|
||||
CONFIG_ARM_ARMADA_37XX_CPUFREQ=y
|
||||
CONFIG_ARM_ARMADA_8K_CPUFREQ=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_ARM64_CRYPTO=y
|
||||
CONFIG_CRYPTO_SHA1_ARM64_CE=y
|
||||
CONFIG_CRYPTO_SHA2_ARM64_CE=y
|
||||
CONFIG_CRYPTO_GHASH_ARM64_CE=y
|
||||
CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
|
||||
CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
|
||||
CONFIG_KPROBES=y
|
||||
CONFIG_JUMP_LABEL=y
|
||||
# CONFIG_GCC_PLUGINS is not set
|
||||
@@ -59,8 +67,10 @@ CONFIG_TRANSPARENT_HUGEPAGE=y
|
||||
CONFIG_CMA=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_XDP_SOCKETS=y
|
||||
CONFIG_XDP_SOCKETS_DIAG=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_IP_MULTICAST=y
|
||||
CONFIG_IP_ADVANCED_ROUTER=y
|
||||
CONFIG_IP_MULTIPLE_TABLES=y
|
||||
@@ -102,6 +112,7 @@ CONFIG_NFT_MASQ=m
|
||||
CONFIG_NFT_REDIR=m
|
||||
CONFIG_NFT_NAT=m
|
||||
CONFIG_NFT_TUNNEL=m
|
||||
CONFIG_NFT_OBJREF=m
|
||||
CONFIG_NFT_QUEUE=m
|
||||
CONFIG_NFT_REJECT=m
|
||||
CONFIG_NFT_COMPAT=m
|
||||
@@ -175,7 +186,9 @@ CONFIG_VLAN_8021Q=y
|
||||
CONFIG_VLAN_8021Q_GVRP=y
|
||||
CONFIG_VLAN_8021Q_MVRP=y
|
||||
CONFIG_NET_SCHED=y
|
||||
CONFIG_NET_SCH_CBQ=y
|
||||
CONFIG_NET_CLS_BASIC=y
|
||||
CONFIG_NET_CLS_TCINDEX=y
|
||||
CONFIG_NET_CLS_BPF=y
|
||||
CONFIG_NET_CLS_FLOWER=y
|
||||
CONFIG_NETLINK_DIAG=y
|
||||
@@ -223,6 +236,7 @@ CONFIG_ATA=y
|
||||
CONFIG_SATA_AHCI=y
|
||||
CONFIG_SATA_AHCI_PLATFORM=y
|
||||
CONFIG_AHCI_MVEBU=y
|
||||
CONFIG_PATA_PLATFORM=y
|
||||
CONFIG_PATA_OF_PLATFORM=y
|
||||
CONFIG_MD=y
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
@@ -311,7 +325,6 @@ CONFIG_8139CP=y
|
||||
# CONFIG_NET_VENDOR_WIZNET is not set
|
||||
# CONFIG_NET_VENDOR_XILINX is not set
|
||||
CONFIG_SFP=y
|
||||
CONFIG_AX88796B_PHY=y
|
||||
CONFIG_MARVELL_PHY=y
|
||||
CONFIG_MARVELL_10G_PHY=m
|
||||
CONFIG_MICREL_PHY=y
|
||||
@@ -319,12 +332,12 @@ CONFIG_MICROCHIP_PHY=y
|
||||
CONFIG_MICROCHIP_T1_PHY=y
|
||||
CONFIG_MICROSEMI_PHY=m
|
||||
CONFIG_MDIO_BITBANG=y
|
||||
CONFIG_MDIO_MVUSB=m
|
||||
CONFIG_MDIO_MVUSB=y
|
||||
CONFIG_MDIO_MSCC_MIIM=y
|
||||
CONFIG_MDIO_BUS_MUX_MMIOREG=y
|
||||
CONFIG_USB_RTL8152=m
|
||||
CONFIG_USB_USBNET=m
|
||||
CONFIG_USB_NET_CDC_EEM=m
|
||||
CONFIG_USB_RTL8152=y
|
||||
CONFIG_USB_USBNET=y
|
||||
CONFIG_USB_NET_CDC_EEM=y
|
||||
# CONFIG_USB_NET_CDC_NCM is not set
|
||||
# CONFIG_USB_NET_NET1080 is not set
|
||||
# CONFIG_USB_NET_CDC_SUBSET is not set
|
||||
@@ -358,6 +371,7 @@ CONFIG_I2C_MV64XXX=y
|
||||
CONFIG_I2C_SLAVE=y
|
||||
CONFIG_SPI=y
|
||||
CONFIG_SPI_ARMADA_3700=y
|
||||
CONFIG_SPI_NXP_FLEXSPI=y
|
||||
CONFIG_SPI_ORION=y
|
||||
CONFIG_SPI_PL022=y
|
||||
CONFIG_SPI_MUX=y
|
||||
@@ -413,31 +427,30 @@ CONFIG_REGULATOR_S2MPS11=y
|
||||
# CONFIG_HID_LOGITECH is not set
|
||||
# CONFIG_HID_MICROSOFT is not set
|
||||
# CONFIG_HID_MONTEREY is not set
|
||||
CONFIG_USB_ULPI_BUS=y
|
||||
CONFIG_USB=m
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_OTG=y
|
||||
CONFIG_USB_XHCI_HCD=m
|
||||
CONFIG_USB_XHCI_MVEBU=m
|
||||
CONFIG_USB_EHCI_HCD=m
|
||||
CONFIG_USB_EHCI_HCD_PLATFORM=m
|
||||
CONFIG_USB_OHCI_HCD=m
|
||||
CONFIG_USB_OHCI_HCD_PLATFORM=m
|
||||
CONFIG_USB_STORAGE=m
|
||||
CONFIG_USB_XHCI_HCD=y
|
||||
CONFIG_USB_XHCI_MVEBU=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
CONFIG_USB_EHCI_HCD_PLATFORM=y
|
||||
CONFIG_USB_OHCI_HCD=y
|
||||
CONFIG_USB_OHCI_HCD_PLATFORM=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_USB_DWC3=y
|
||||
CONFIG_USB_DWC2=y
|
||||
CONFIG_USB_CHIPIDEA=m
|
||||
CONFIG_USB_CHIPIDEA=y
|
||||
CONFIG_USB_CHIPIDEA_UDC=y
|
||||
CONFIG_USB_CHIPIDEA_HOST=y
|
||||
CONFIG_USB_ISP1760=y
|
||||
CONFIG_USB_HSIC_USB3503=m
|
||||
CONFIG_USB_HSIC_USB3503=y
|
||||
CONFIG_NOP_USB_XCEIV=y
|
||||
CONFIG_USB_ULPI=y
|
||||
CONFIG_USB_GADGET=y
|
||||
CONFIG_USB_SNP_UDC_PLAT=y
|
||||
CONFIG_TYPEC=y
|
||||
CONFIG_TYPEC_TCPM=m
|
||||
CONFIG_TYPEC_TCPCI=m
|
||||
CONFIG_TYPEC_RT1711H=m
|
||||
CONFIG_TYPEC_TCPM=y
|
||||
CONFIG_TYPEC_TCPCI=y
|
||||
CONFIG_TYPEC_RT1711H=y
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_BLOCK_MINORS=32
|
||||
CONFIG_MMC_ARMMMCI=y
|
||||
@@ -449,6 +462,7 @@ CONFIG_MMC_SPI=y
|
||||
CONFIG_MMC_DW=y
|
||||
CONFIG_MMC_DW_EXYNOS=y
|
||||
CONFIG_MMC_DW_K3=y
|
||||
CONFIG_MMC_CQHCI=y
|
||||
CONFIG_MMC_SDHCI_XENON=y
|
||||
CONFIG_SCSI_UFSHCD=y
|
||||
CONFIG_SCSI_UFSHCD_PLATFORM=y
|
||||
@@ -489,6 +503,7 @@ CONFIG_EXTCON_USB_GPIO=y
|
||||
CONFIG_IIO=y
|
||||
CONFIG_TI_ADC081C=y
|
||||
CONFIG_PWM=y
|
||||
CONFIG_PHY_XGENE=y
|
||||
CONFIG_PHY_MVEBU_CP110_COMPHY=y
|
||||
CONFIG_PHY_MVEBU_CP110_UTMI=y
|
||||
CONFIG_PHY_SAMSUNG_USB2=y
|
||||
@@ -497,11 +512,13 @@ CONFIG_MUX_MMIO=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT3_FS=y
|
||||
CONFIG_EXT4_FS_POSIX_ACL=y
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_BTRFS_FS=y
|
||||
CONFIG_BTRFS_FS_POSIX_ACL=y
|
||||
CONFIG_FANOTIFY=y
|
||||
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
|
||||
CONFIG_QUOTA=y
|
||||
CONFIG_AUTOFS4_FS=y
|
||||
CONFIG_FUSE_FS=y
|
||||
CONFIG_VIRTIO_FS=y
|
||||
CONFIG_OVERLAY_FS=y
|
||||
@@ -519,21 +536,17 @@ CONFIG_SECURITY=y
|
||||
CONFIG_CRYPTO_CCM=m
|
||||
CONFIG_CRYPTO_ECHAINIV=y
|
||||
CONFIG_CRYPTO_ANSI_CPRNG=y
|
||||
CONFIG_CRYPTO_GHASH_ARM64_CE=y
|
||||
CONFIG_CRYPTO_SHA1_ARM64_CE=y
|
||||
CONFIG_CRYPTO_SHA2_ARM64_CE=y
|
||||
CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
|
||||
CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_CMA_SIZE_MBYTES=0
|
||||
CONFIG_IRQ_POLL=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_DEBUG_KERNEL=y
|
||||
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
|
||||
CONFIG_DEBUG_FS=y
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
# CONFIG_SCHED_DEBUG is not set
|
||||
# CONFIG_DEBUG_PREEMPT is not set
|
||||
# CONFIG_RCU_TRACE is not set
|
||||
CONFIG_FUNCTION_TRACER=y
|
||||
# CONFIG_STRICT_DEVMEM is not set
|
||||
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
. "$BR2_CONFIG"
|
||||
|
||||
# Prevent regen of host key at every boot, /etc is saved across reboots
|
||||
if [ -L "$TARGET_DIR/etc/dropbear" ]; then
|
||||
rm "$TARGET_DIR/etc/dropbear"
|
||||
mkdir "$TARGET_DIR/etc/dropbear"
|
||||
fi
|
||||
|
||||
# Classic builds don't have D-Bus
|
||||
if [ -f "$TARGET_DIR/etc/dnsmasq.conf" ]; then
|
||||
sed -i '/enable-dbus/d' "$TARGET_DIR/etc/dnsmasq.conf"
|
||||
fi
|
||||
Executable
+684
@@ -0,0 +1,684 @@
|
||||
#!/bin/sh
|
||||
# COLUMS and ROWS should be set on the console, if not, use fallback
|
||||
if [ -z "$COLUMNS" ]; then
|
||||
if command -v tput; then
|
||||
COLUMNS=$(tput cols)
|
||||
else
|
||||
COLUMNS=80
|
||||
fi
|
||||
fi
|
||||
|
||||
h1()
|
||||
{
|
||||
STR="$*"
|
||||
if [ -n "$plain" ]; then
|
||||
echo "$STR" | tr '[:lower:]' '[:upper:]'
|
||||
echo "$STR" | sed 's/./=/g'
|
||||
else
|
||||
printf "\033[7m%-${COLUMNS}s\033[0m" "$STR"
|
||||
fi
|
||||
}
|
||||
|
||||
h2()
|
||||
{
|
||||
STR="$*"
|
||||
if [ -n "$plain" ]; then
|
||||
echo "$STR"
|
||||
echo "$STR" | sed 's/./-/g'
|
||||
else
|
||||
printf "\033[1m%-${COLUMNS}s\033[0m" "$STR"
|
||||
fi
|
||||
}
|
||||
|
||||
ul()
|
||||
{
|
||||
if [ -n "$plain" ]; then
|
||||
echo "__${*}__"
|
||||
else
|
||||
printf "\033[54%s\033[0m" "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
em()
|
||||
{
|
||||
if [ -n "$plain" ]; then
|
||||
echo "**${*}**"
|
||||
else
|
||||
printf "\033[5m%s\033[0m" "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
overview()
|
||||
{
|
||||
cat <<EOF
|
||||
$(h1 "Help System Press 'Q' to quit | Arrow keys and PgUp/PgDn to scroll")
|
||||
|
||||
$(h2 "See Also")
|
||||
help edit Tutorial on VI and Mg editors
|
||||
help net Network set up introduction
|
||||
setup User friendly setup and diagnostic tool
|
||||
|
||||
$(h2 "General Syntax")
|
||||
cmd [optional arg] E.g., use 'date -h' to get help for date command
|
||||
|
||||
$(h2 "File system")
|
||||
pwd | ls | cd Show directory, contents, or change directory
|
||||
cat file Show file contents
|
||||
vi | mg [file] Edit file with the VI or Micro Emacs editor
|
||||
|
||||
$(h2 "Services")
|
||||
initctl list Lists all configurable services (svc's)
|
||||
initctl enable svc Enable a service 'svc'
|
||||
initctl reload Reload init process' state, start/stop svc's
|
||||
initctl start svc Start a stopped service 'svc'
|
||||
initctl stop svc Stop 'svc'
|
||||
initctl restart svc Restart a running 'svc'
|
||||
initctl status [svc] Display running status of all services, or one 'svc'
|
||||
|
||||
$(h2 "Tools")
|
||||
setup User friendly setup and diagnostic tool
|
||||
date [-h] Display current time, or sets the system date
|
||||
factory Factory reset the device (on the next boot)
|
||||
hwclock [-h] Query or set the hardware clock (RTC)
|
||||
logout | Ctrl-D Log out from TTY
|
||||
mdio | mvls Low-level MDIO access, also for Marvell switch status
|
||||
tail -F file Continuously read from a file Useful for monitoring the
|
||||
health of services, see 'ls /var/log/' for log files
|
||||
less [file] Pagers provding easily scrollable content (q quits) >
|
||||
more [file] > e.g., 'cat very-long-file | less'
|
||||
most [file] > e.g., 'cat very-long-file | most'
|
||||
passwd Change user password
|
||||
pwgen Password generator
|
||||
reboot Restart the device
|
||||
reset Reset the shell prompt if it gets garbled
|
||||
|
||||
$(h2 "Network Tools")
|
||||
ethtool [-h] Ethernet stats, and low-level MAC/PHY settings
|
||||
traceroute [-h] Trace the route ip packets follow going to a host
|
||||
tcpdump [-h] Display network packet headers in real-time
|
||||
arping [-h] Ping hosts by ARP requests/replies
|
||||
fping [-h] Send ICMP ECHO_REQUEST packets to multiple hosts
|
||||
ping [-h] Send ICMP ECHO_REQUEST packets to a network host
|
||||
lynx URL [-h] The text mode web browser
|
||||
netcalc [-h] Calculate IP network settings from a IP address
|
||||
netcat [-h] NetCat - TCP/IP swiss army knife (alias: nc)
|
||||
socat [-h] Multipurpose socket relay program
|
||||
ttyd [-h] Sharing a terminal over the web
|
||||
|
||||
ifconfig [--help] See/Reconfigure available network interfaces
|
||||
route [--help] Edit the kernel's routing tables
|
||||
|
||||
ifup | ifdown IFACE Bring up/down interfaces in /etc/network/interfaces
|
||||
|
||||
ip [link|addr] Manage available network interfaces
|
||||
ip [rule|route] Manage routing tables
|
||||
bridge [link|vlan] Manage bridge ports and VLANs
|
||||
|
||||
scp Securely copy a file to a remote host file system
|
||||
tftp Copy a file to/from a remote host
|
||||
ftpput Store a local file on a remote machine via FTP
|
||||
ftpget Retrieve a remote file via FTP
|
||||
wget Get a file using HTTP or FTP from a remote host
|
||||
|
||||
$(h2 "Overview Commands")
|
||||
df -h List disk usage (in human readable format)
|
||||
free List memory usage
|
||||
ps List running processes
|
||||
show [arg] Show system status, see 'show help' for more info
|
||||
top Displays CPU usage and top list of running tasks
|
||||
|
||||
$(h2 "Interesting Files")
|
||||
/etc/default/svc Command line args for service 'svc' (see above)
|
||||
/etc/rc.local Local setup, runs after all services have started
|
||||
/etc/network/ Directory of networking setup, see 'help net'
|
||||
|
||||
$(h2 "Example Commands")
|
||||
cd /tmp; wget ftp://192.168.55.43/file && cat file
|
||||
cd /var/log; tftp -p -l messages 192.168.55.43
|
||||
cat /proc/net/arp
|
||||
edit /etc/network/interfaces
|
||||
|
||||
$(h2 "See Also")
|
||||
help edit Tutorial on VI and Mg editors
|
||||
help net Network set up introduction
|
||||
setup User friendly setup and diagnostic tool
|
||||
EOF
|
||||
}
|
||||
|
||||
vi()
|
||||
{
|
||||
cat <<EOF
|
||||
$(h1 "Visual Editor (vi)")
|
||||
Vi is the de facto standard editor in UNIX systems. It comes with two modes:
|
||||
|
||||
- $(em "Command mode (default):") administrative tasks such as saving files,
|
||||
executing commands, moving the cursor, cutting and pasting lines or words,
|
||||
as well as finding and replacing. $(em "Return to command mode with Esc")
|
||||
|
||||
- $(em "Insert mode:") Everything that's typed in this mode is interpreted as
|
||||
input and placed in the file.
|
||||
|
||||
$(h2 "Navigation commands")
|
||||
|
||||
h - move the cursor one character to the left
|
||||
j - move the cursor down one character
|
||||
k - mode the cursor up one character
|
||||
l - move the cursor right one character
|
||||
b - move to beginning of word, or previous word
|
||||
w - move to next word
|
||||
0 - move to beginning of line
|
||||
$ - move to end of line
|
||||
:0 - move to beginning of file
|
||||
G - move to end of file
|
||||
|
||||
$(h2 "Editing commands")
|
||||
|
||||
u - undo last operation
|
||||
x - delete the character the cursor is on
|
||||
cw - change word, from position of cursor
|
||||
dw - delete to end of word
|
||||
dd - delete the line the character is on
|
||||
p - paste (line, word, or char) after cursor
|
||||
P - paste (line, word, or char) before cursor
|
||||
|
||||
$(h2 "Saving and quit commands")
|
||||
|
||||
:w - save the current file
|
||||
:w filename - save a copy of the file named filename
|
||||
:w! - try to save the file, even if it is read only
|
||||
:wq - save and quit vi
|
||||
ZZ - save and quit vi
|
||||
:wq! - try to save the file if it is read only, quit if successful
|
||||
:wq filename - save a copy of the file named filename and quit
|
||||
:wq! filename - save a copy of the file named filename and quit,
|
||||
override read only permissions if possible
|
||||
:q - quit vi
|
||||
:q! - quit vi even if the file has unsaved changes
|
||||
|
||||
$(h2 "Enter insert mode")
|
||||
|
||||
a - append new text after the cursor
|
||||
i - insert text before the cursor
|
||||
o - open a new line below the cursor
|
||||
O - open a new line above the cursor
|
||||
|
||||
> Return to command mode with Esc
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
emacs()
|
||||
{
|
||||
cat <<EOF
|
||||
$(h1 "Micro Emacs (mg)")
|
||||
Mg is a bit more user-friendly than vi. It has the same familiar interface
|
||||
as Notepad, but with slightly different keybindings.
|
||||
|
||||
$(h2 "Introduction")
|
||||
|
||||
Most commands involve using the Control ("Ctrl") or the Meta ("Alt") key.
|
||||
The following conventions are used in the online help:
|
||||
|
||||
C-<chr> means hold down the Control key while typing the character <chr>
|
||||
M-<chr> means hold down the Alt key while typing the character <chr>
|
||||
|
||||
If you don't have a Meta/Alt key, you can use Esc instead. Press and release
|
||||
the Esc key and then type <chr>. This is equivalent to M-<chr>.
|
||||
|
||||
$(h2 "Navigation")
|
||||
|
||||
Though arrow keys, Home/End, and PgUp/PgDn usually work, using Mg over serial
|
||||
console can sometimes cause these keys to be mismapped by terminal program.
|
||||
|
||||
C-f Move forward one character (can also use right arrow key)
|
||||
C-b Move backward one character (can also use left arrow key)
|
||||
C-p Move up one line (can also use up arrow key)
|
||||
C-n Move down one line (can also use down arrow key)
|
||||
M-f Move forward one word
|
||||
M-b Move backward one word
|
||||
C-a Move to beginning of line (can also use Home key)
|
||||
C-e Move to end of line (can also use End key)
|
||||
C-v Move forward one page (can also use PgDn/Page Down key)
|
||||
M-v Move backward one page (can also use PgUp/Page Up key)
|
||||
M-< Move to beginning of file
|
||||
M-> Move to end of file
|
||||
C-x g Move to line number
|
||||
|
||||
$(h2 "Editing")
|
||||
|
||||
All edit commands that kill (cut) text is placed in a kill ring (clipboard).
|
||||
Note: when marking text, there is no visual mark.
|
||||
|
||||
C-_ Undo, also C-x u
|
||||
M-% Replace word/string in file, from cursor position
|
||||
M-q Reformat paragraph (set fill column with C-x f)
|
||||
C-s Search forward (type C-s again to find next)
|
||||
C-r Reversed search
|
||||
C-Space Set beginning of mark (beginning of selected text)
|
||||
C-x C-x Jump back and forth between mark and cursor position
|
||||
C-x h Mark whole buffer
|
||||
C-w Wipe (cut) region from mark to cursor position
|
||||
M-w Copy region from mark to cursor position
|
||||
C-y Yank (paste) text from kill ring
|
||||
C-k Kill (cut) to end of line
|
||||
M-Backspace Kill (delete) previous word
|
||||
M-d Kill (delete) next word
|
||||
C-d Delete character to the right
|
||||
C-o Open new line at cursor
|
||||
|
||||
$(h2 "General Commands")
|
||||
|
||||
C-g Abort current command
|
||||
C-l Recenter buffer on current line
|
||||
C-h b List all keybindings
|
||||
M-! Run shell command, output in new buffer
|
||||
C-z Suspend Mg, return to shell, use 'fg' to get back
|
||||
C-x C-f Open file
|
||||
C-x C-i Insert file at cursor position
|
||||
C-x C-s Save file
|
||||
C-x s Save file (interactive)
|
||||
C-x k Kill (close) file
|
||||
C-x C-b List open buffers (files)
|
||||
C-x b Switch to another buffer
|
||||
C-x C-c Exit
|
||||
|
||||
$(h2 "Window Commands")
|
||||
|
||||
C-x 0 Unsplit, keep other window
|
||||
C-x 1 Unsplit, keep this window
|
||||
C-x 2 Split window in two
|
||||
C-x o Go to other window
|
||||
C-x p Go to previous window
|
||||
C-x n Go to next window
|
||||
C-x ^ Enlarge this split
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
editor()
|
||||
{
|
||||
case $1 in
|
||||
vi)
|
||||
vi
|
||||
;;
|
||||
ed* | em* | mg)
|
||||
emacs
|
||||
;;
|
||||
*)
|
||||
vi
|
||||
emacs
|
||||
cat <<EOF
|
||||
$(h1 "Summary")
|
||||
Use Mg or GNU Nano if you are a beginner. The system is set up to so you can
|
||||
use the 'edit' command, which will start GNU Nano:
|
||||
|
||||
edit /etc/rc.local # Starts GNU Nano
|
||||
|
||||
EOF
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
networking()
|
||||
{
|
||||
cat <<EOF
|
||||
$(h1 "Networking")
|
||||
This section details how to set up everything from basic to advanced networking.
|
||||
Topics covered include:
|
||||
|
||||
- Static vs Dynamic Addresses
|
||||
- VLAN Interfaces
|
||||
- Bridging Interfaces
|
||||
- Link Aggregation (bonding)
|
||||
- Persistent Configuration
|
||||
|
||||
Please note, the terms 'port' and 'interface' may be used interchangably in
|
||||
the following text (and elsewher online as well). Usually the term 'port' is
|
||||
reserved for Ethernet links attached to a switch or bridge, while the term
|
||||
'interface' more generically refers to the physical interface in a system.
|
||||
|
||||
|
||||
$(h2 "Static vs Dynamic Addresses")
|
||||
|
||||
An IPv4 address consists of four "octets" separated by periods. A static IPv4
|
||||
address can look like this:
|
||||
|
||||
192.168.1.42
|
||||
|
||||
However, for networking to function properly, a device usually needs a netmask,
|
||||
default route, NTP server, and at least one DNS address. Setting all these up
|
||||
statically is a lot of work to maintain, in particular with many devices.
|
||||
|
||||
For both IPv4 and IPv6 there is an alternative called DHCP. It is a dynamic
|
||||
protocol where a server on request from a client device hands out a "lease" of
|
||||
an IP address, as well as lot of other network parameters, including but not
|
||||
limited to the ones already mentioned. A client device can give hints to the
|
||||
server, e.g., its hostname, MAC address (default), or other client identifier.
|
||||
It is up to the server to honor these hints or not, but it is very common to
|
||||
set up the server to honor the client's hostname and automatically update the
|
||||
central name server (DNS) when the client is online.
|
||||
|
||||
| There are many other interesting aspects to DHCP not covered here.
|
||||
| For instance, DHCP relay servers (proxies), that can be used to
|
||||
| forward DHCP requests from very large networks to a central server.
|
||||
| Some relay "agents" even support something called Option 82, which
|
||||
| when running on a simple switch, can attach port and relay info to
|
||||
| the client's DHCP request -- allowing the server to assign an IP
|
||||
| address per port, even on remote switches (with a relay agent).
|
||||
|
||||
When your interface is setup with DHCP, use the 'ifconfig' or 'ip addr' tools
|
||||
to see which address you got, if needed (see next section).
|
||||
|
||||
In cases when the DHCP client cannot find a DHCP server, and thus not obtain a
|
||||
lesae, the system falls back to set a link-local address (169.254.*.*). This
|
||||
can be disabled by editing the file /etc/dhcpcd.conf, adding:
|
||||
|
||||
noipv4ll
|
||||
|
||||
A link-local address is however very useful, in particular in combination with
|
||||
mDNS to discover and access a device you do not know, or do not want to know,
|
||||
the IP address to. See more in the next section.
|
||||
|
||||
|
||||
$(h2 "DNS and mDNS")
|
||||
|
||||
Managing a central DNS is both painful and time consuming, most networks, and
|
||||
in particular industrial, therefore only set up a DNS for static servers and
|
||||
resources. Leaving end devices, switches, and in many cases even routers,
|
||||
without a human-friendly name on the network. This have misled many to think
|
||||
that they need to know the IP address, and often opt for static addresses on
|
||||
equipment. Meaning many devices out-of-the-box have a static address set that
|
||||
need to be manually changed before the device is deployed on the network.
|
||||
|
||||
A less time consuming, and human-friendly, way is to enable mDNS (multicast
|
||||
DNS). With this protocol the device notifies all neighbors on the same LAN
|
||||
of how to reach it:
|
||||
|
||||
"Hello everyone, my address is 169.254.47.11, you can call me device.local"
|
||||
|
||||
Any other device that also has mDNS enabled can then automaticall update a
|
||||
local database of name-to-address mappings. Usually the name sent out is
|
||||
the device's hostname. (It is up to the device manufacturer to set a useful
|
||||
default hostname, i.e., model-01-02-03, where the suffix is the last octets
|
||||
of the base MAC address, from the product label on the case.)
|
||||
|
||||
As you can see, in combination with a link-local address (previous section)
|
||||
mDNS is a very attractive combination that greatly simplify device management.
|
||||
|
||||
Tools:
|
||||
|
||||
avahi-browse -a
|
||||
ping foo.local
|
||||
|
||||
mDNS, or more correctly mDNS-SD, is also used for *Service Discovery*. E.g.,
|
||||
a printer can publish IPP records with meta data on the printer type and model
|
||||
or donwload URL for drivers. Switches and routers usually publish how they
|
||||
can be reached: HTTP/HTTPS and SSH.
|
||||
|
||||
mDNS is supported in this product and should be enabled by default. To
|
||||
verify that it works, in Windows, macOS, or Linux, open your web browser
|
||||
and point it to <https://hostname-01-02-03.local>. This is the hostname
|
||||
and three last octets of the device's base MAC address. You can also use
|
||||
mDNS browsers or command line tools like mdns-scan
|
||||
|
||||
|
||||
$(h2 "VLAN Interfaces")
|
||||
|
||||
A VLAN interface in Linux is an "upper" interface, e.g., 'eth0.1'. It is
|
||||
where you set an IP address and interact with th rest of the world. The
|
||||
base/raw/lower interface, here 'eth0', is the physical interface on which
|
||||
Ethernet packets ingress and egress with a VLAN tag. To create 'eth0.1':
|
||||
|
||||
ip link add eth0.1 link eth0 vlan id 1
|
||||
|
||||
In Linux a VLAN interface is a "stackable" entity. Many VLAN interfaces
|
||||
can be built on top of each other. When injecting a packet on the top
|
||||
most interface, the kernel adds the corresponding VLAN "tag" when the
|
||||
packet goes down the order of stacked interfaces, and then finally hits
|
||||
the physical interface and proceeds to egress onto the media.
|
||||
|
||||
ip link add eth0.1.2 link eth0.1 vlan id 2
|
||||
|
||||
Injecting a packet on 'eth0.1.2' creates a double-tagged VLAN frame when
|
||||
the packet egresses 'eth0'. The outermost tag has VID 1 and the inner
|
||||
VID is 2.
|
||||
|
||||
VLAN interfaces can be used for many things, here we will focus on their
|
||||
use as upper interface on a bridge.
|
||||
|
||||
|
||||
$(h2 "Bridging Interfaces")
|
||||
|
||||
A bridge is the correct name for a switch. In the context of this text,
|
||||
however, we will use the term to refer to the Linux bridge module in the
|
||||
kernel, which implements an advanced software switch. The Linux bridge
|
||||
supports "offloading" many switching functions to an underlying switching
|
||||
chipset, when available. This greatly simplifies managing that switch since
|
||||
the same tools one use to manage the bridge will, by extension, also be used
|
||||
to manage the switch.
|
||||
|
||||
To create a bridge in Linux:
|
||||
|
||||
ip link add br0 type bridge
|
||||
|
||||
To add three ports (interfaces) to the bridge we use:
|
||||
|
||||
ip link set eth0 master br0
|
||||
ip link set eth1 master br0
|
||||
ip link set eth2 master br0
|
||||
|
||||
Bring all ports and the bridge 'up' and you have a working switch! Any frame
|
||||
injected on eth0 (from the outside) can be switched to either of eth1, eth2,
|
||||
*or* br0. As soon as the bridge has learned where end devices are connected,
|
||||
none of the other ports will see the traffic -- like a regular switch.
|
||||
|
||||
Note: these ports should not (cannot) have any IP address. Instead, any IP
|
||||
address is set on 'br0'. To disable IPv6 link-local address, set the
|
||||
/proc/sys/net/ipv6/conf/eth0/disable_ipv6 sysctl file to '1'.
|
||||
|
||||
|
||||
$(h2 "Bridging and VLANs")
|
||||
|
||||
A VLAN-aware bridge works the same way, only with VLAN separation taken into
|
||||
account. All communication, as well as MAC address learning, is limited to
|
||||
ports in the same VLAN. The syntax is slightly different and requires a few
|
||||
more steps:
|
||||
|
||||
ip link add br0 type bridge vlan_filtering 1
|
||||
ip link set eth0 master br0
|
||||
ip link set eth1 master br0
|
||||
ip link set eth2 master br0
|
||||
ip link set eth3 master br0
|
||||
|
||||
To assign ports to different VLANs, and make sure they are regular "access"
|
||||
ports (untagged). We assign eth0 and eth1 to VLAN 1 and the others to VLAN 2:
|
||||
|
||||
bridge vlan add vid 1 dev eth0 pvid untagged
|
||||
bridge vlan add vid 1 dev eth1 pvid untagged
|
||||
bridge vlan add vid 2 dev eth2 pvid untagged
|
||||
bridge vlan add vid 2 dev eth3 pvid untagged
|
||||
|
||||
Here's the twist, to be able to reach the bridge (switch) itself from each
|
||||
VLAN, we need to ensure the bridge itself is a tagged member of each VLAN:
|
||||
|
||||
bridge vlan add vid 1 dev br0 self
|
||||
bridge vlan add vid 2 dev br0 self
|
||||
|
||||
This way we can add VLAN interfaces on top of br0, which we in turn can set
|
||||
a static or dynamic IP address on:
|
||||
|
||||
ip link add vlan1 link br0 type vlan id 1
|
||||
ip link add vlan2 link br0 type vlan id 2
|
||||
|
||||
The resulting stack of interfaces look like this:
|
||||
|
||||
:
|
||||
vlan1 : vlan2 Layer-3 :: IP Networking
|
||||
\\ : / _________________________
|
||||
.-------------.
|
||||
| br0 | Layer-2 :: Switching
|
||||
'-------------' _________________________
|
||||
/ | : | \\
|
||||
eth0 eth1 : eth2 eth3 Layer-1 :: Link layer
|
||||
:
|
||||
|
||||
|
||||
$(h2 "Persistent Configuration")
|
||||
|
||||
A simple end device can get by with the following in /etc/network/interfaces:
|
||||
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto eth0
|
||||
iface eth0 inet dhcp
|
||||
|
||||
This brings up both the loopback (required for UNIX networking to function),
|
||||
and the (presumed only) Ethernet interface. The loopback gets its standard
|
||||
address, 127.0.0.1, and eth0 will request its IP address using DHCP.
|
||||
|
||||
To set up the bridge example (above), is actually quite a lot easier than
|
||||
using the command line ip and bridge tools. Create the file 'bridge':
|
||||
|
||||
edit /etc/network/interfaces.d/bridge
|
||||
|
||||
Paste in the following content:
|
||||
|
||||
iface e0
|
||||
bridge-access 1
|
||||
iface e1
|
||||
bridge-access 1
|
||||
iface e2
|
||||
bridge-access 2
|
||||
iface e3
|
||||
bridge-access 2
|
||||
|
||||
auto br0
|
||||
iface br0
|
||||
bridge-ports e0 e1 e2 e3
|
||||
bridge-vlan-aware yes
|
||||
bridge-stp on
|
||||
bridge-vids 1 2
|
||||
|
||||
auto vlan1
|
||||
iface vlan1 inet dhcp
|
||||
vlan-id 1
|
||||
vlan-raw-device br0
|
||||
|
||||
auto vlan2
|
||||
iface vlan2 inet static
|
||||
vlan-id 2
|
||||
vlan-raw-device br0
|
||||
address 192.168.2.1/24
|
||||
|
||||
Notice how 'vlan1' only has a DHCP and 'vlan2' uses a static address. It is
|
||||
possible to combine the two if needed. Use 'inet dhcp' and add an 'address'
|
||||
statement to the iface stanza.
|
||||
|
||||
|
||||
$(h2 "Port Classification")
|
||||
|
||||
The bundled 'show' script is a very handy tool. It use several tricks to make
|
||||
information about the system more accessible. On switching capable hardware
|
||||
products, switch ports are identified early at system bootstrap and placed in
|
||||
the 'port' group. See 'ip link' output:
|
||||
|
||||
...
|
||||
4: e0: <BROADCAST,MULTICAST> master br0 state UP $(em "group port")
|
||||
link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
|
||||
...
|
||||
|
||||
When running in Qemu or other hardware it may be useful to manually classify
|
||||
certain interfaces as ports. This can be achieved in many ways, here we show
|
||||
two. First /etc/mactab, which is read at boot to rename interfaces according
|
||||
their matching MAC address, one interface per line:
|
||||
|
||||
e0 52:54:00:12:34:56
|
||||
e1 52:54:00:12:34:57
|
||||
e2 52:54:00:12:34:58
|
||||
e3 52:54:00:12:34:59
|
||||
|
||||
Another way is to add something like this to /etc/rc.local:
|
||||
|
||||
for port in eth0 eth1 eth3 eth4; do
|
||||
ip link set \$port group port
|
||||
done
|
||||
|
||||
|
||||
$(h2 "Interesting Files")
|
||||
|
||||
- /etc/dhcpcd.conf General DHCP and ZeroConf (LL) settings
|
||||
- /etc/network/interfaces The original, useful for small setups
|
||||
- /etc/network/interfaces.d/* Snippets, useful for non-trivial setups
|
||||
- /etc/mactab Rename interfaces: 'NAME16CHARS WHITESPACE MAC'
|
||||
- /etc/sysctl.conf Interface and TCP/IP settings, e.g., routing
|
||||
- /etc/sysctl.d/* Snippets, useful for per-subsystem settings
|
||||
|
||||
|
||||
$(h1 "Summary")
|
||||
All persistent networking is set up in /etc/network/interfaces using the
|
||||
program ifupdown-ng. The tools to reconfigure networking at runtime are:
|
||||
|
||||
ifup [-a] [IFACES]
|
||||
ifdown [-a] [IFACES]
|
||||
|
||||
When changing the configuration at runtime you usually have to bring the
|
||||
affected interfaces down (ifdown e0 e1 e2 e3), if they were set up with
|
||||
/etc/network/interfaces before. Then do the change, and bring it all up
|
||||
again.
|
||||
|
||||
Both tools understand dependencies between interfaces, so when a 'ifup -a'
|
||||
command is received it brings up all interfaces: adding links to br0 before
|
||||
adding VLANs, the vlan1 and vlan2 interfaces on top so it of it all. Then
|
||||
finally it can start the DHCP client on vlan1 and set the static IP address
|
||||
on vlan2.
|
||||
|
||||
$(em ">>> Be careful with these tools when logged in remotely! <<<")
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
topic()
|
||||
{
|
||||
topic=$1
|
||||
[ -n "$1" ] && shift
|
||||
|
||||
case $topic in
|
||||
ed*)
|
||||
# shellcheck disable=SC2068
|
||||
editor $*
|
||||
;;
|
||||
net*)
|
||||
networking
|
||||
;;
|
||||
*)
|
||||
overview
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [ "$1" = "-p" ]; then
|
||||
shift
|
||||
pager="cat"
|
||||
plain="yes"
|
||||
else
|
||||
if command -v most; then
|
||||
pager=most
|
||||
elif command -v less; then
|
||||
pager="less -R"
|
||||
elif command -v more; then
|
||||
pager="more"
|
||||
else
|
||||
pager="cat"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -t 1 ] ; then
|
||||
fn=$(mktemp /tmp/system-help.XXXXXX)
|
||||
# shellcheck disable=SC2086,SC2068
|
||||
topic $@ >"$fn"
|
||||
$pager "$fn"
|
||||
rm "$fn"
|
||||
else
|
||||
topic "$*"
|
||||
fi
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
# Changes hostname in /etc/hostname and /etc/hosts
|
||||
|
||||
current=$(cat /etc/hostname)
|
||||
newname=$1
|
||||
|
||||
[ -n "$newname" ] || exit 1
|
||||
|
||||
sed -i "s/$current/$newname/" /etc/hosts
|
||||
sed -i "s/$current/$newname/" /etc/hostname
|
||||
|
||||
hostname $newname
|
||||
|
||||
initctl touch sysklogd
|
||||
initctl touch dnsmasq
|
||||
initctl reload
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
pdmenu
|
||||
clear
|
||||
Executable
+327
@@ -0,0 +1,327 @@
|
||||
#!/bin/sh
|
||||
# Displays basic information about the system
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
. /etc/os-release
|
||||
|
||||
bopt="-c"
|
||||
opt="-br"
|
||||
all=""
|
||||
plain=""
|
||||
|
||||
TTY=$(resize)
|
||||
eval "$TTY"
|
||||
|
||||
# COLUMS and ROWS should be set on the console, if not, use fallback
|
||||
if [ -z "$COLUMNS" ]; then
|
||||
if command -v tput; then
|
||||
COLUMNS=$(tput cols)
|
||||
else
|
||||
COLUMNS=80
|
||||
fi
|
||||
fi
|
||||
|
||||
h1()
|
||||
{
|
||||
STR="$*"
|
||||
if [ -n "$plain" ]; then
|
||||
echo "$STR" | tr '[:lower:]' '[:upper:]'
|
||||
else
|
||||
printf "\033[7m%-${COLUMNS}s\033[0m\n" "$STR"
|
||||
fi
|
||||
}
|
||||
|
||||
h2()
|
||||
{
|
||||
STR="$*"
|
||||
if [ -n "$plain" ]; then
|
||||
echo "$STR"
|
||||
echo "$STR" | sed 's/./-/g'
|
||||
else
|
||||
printf "\033[1m%-${COLUMNS}s\033[0m\n" "$STR"
|
||||
fi
|
||||
}
|
||||
|
||||
dm()
|
||||
{
|
||||
if [ -n "$plain" ]; then
|
||||
echo "${*}"
|
||||
else
|
||||
printf "\033[2m%s\033[0m\n" "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
ul()
|
||||
{
|
||||
if [ -n "$plain" ]; then
|
||||
printf "__%s__" "$*"
|
||||
else
|
||||
printf "\033[4%s\033[0m" "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
em()
|
||||
{
|
||||
if [ -n "$plain" ]; then
|
||||
printf "**%s**" "$*"
|
||||
else
|
||||
printf "\033[5m%s\033[0m" "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<EOF
|
||||
usage:
|
||||
show [opt] cmd
|
||||
|
||||
options:
|
||||
-a Show all, of something
|
||||
-f Show full output, not brief port/iface listings
|
||||
-h Show this help text
|
||||
-n Show output without any footer
|
||||
-p Show plain output, no bells or whistles
|
||||
|
||||
commands:
|
||||
port PORT Show port configuration and link information
|
||||
ports Show ports available for bridging
|
||||
vlans Show port groups in bridge
|
||||
ifaces Show interfaces and their addresses
|
||||
fdb Show forwarding database (unicast)
|
||||
mdb Show multicast forwarding database
|
||||
ip route Show routing table
|
||||
log [FILE] Show latest entries from syslog, or other FILE
|
||||
rmon PORT Show RMON counters for PORT (when applicable)
|
||||
system Show OS details
|
||||
version Show OS verson
|
||||
EOF
|
||||
}
|
||||
|
||||
# Usage 1: show port eth0
|
||||
# Usage 2: show port
|
||||
# Usage 3: show ports
|
||||
#
|
||||
# The first show ethtool output for 'eth0' (in this case). The latter
|
||||
# two are the same, showing a summary of all interfaces classified as
|
||||
# access ports.
|
||||
ports()
|
||||
{
|
||||
if [ $# -gt 0 ] && [ -e "/sys/class/net/$1" ]; then
|
||||
for port in $*; do
|
||||
ethtool "$port"
|
||||
done
|
||||
return
|
||||
fi
|
||||
|
||||
h1 "PORT STATE MAC ADDRESS FLAGS"
|
||||
if grep -q port /etc/iproute2/group && [ -z "$all" ]; then
|
||||
ip $opt link show group port
|
||||
else
|
||||
ip $opt link show
|
||||
fi
|
||||
|
||||
if [ -z "$plain" ] && [ -z "$nofoot" ]; then
|
||||
dm "______________________________________________________________________________"
|
||||
dm "Use: '[ip|bridge] --help' and '[ip|bridge] link help' for more details."
|
||||
fi
|
||||
}
|
||||
|
||||
vlans()
|
||||
{
|
||||
h1 "INTERFACE VLAN FLAGS"
|
||||
bridge $bopt vlan show |tail +2 | awk 'NF { iface=$1; vid=$2; printf("%-16s %4d ", iface, vid); for (i=3; i <= NF; i++) printf("%s ", $i); printf("\n"); }'
|
||||
if [ -z "$plain" ] && [ -z "$nofoot" ]; then
|
||||
dm "______________________________________________________________________________"
|
||||
dm "See: 'bridge --help' and 'bridge vlan help' for more details."
|
||||
fi
|
||||
}
|
||||
|
||||
ifaces()
|
||||
{
|
||||
h1 "INTERFACE STATE ADDRESS"
|
||||
if [ -n "$all" ]; then
|
||||
ip $opt addr show
|
||||
elif grep -q iface /etc/iproute2/group; then
|
||||
ip $opt addr show group iface
|
||||
else
|
||||
ip $opt addr show |awk '{ if ($1 !~ /eth[0-9]*/ && $1 !~ /.*@NONE/) { print }}'
|
||||
fi
|
||||
if [ -z "$plain" ] && [ -z "$nofoot" ]; then
|
||||
dm "______________________________________________________________________________"
|
||||
dm "See: 'ip --help' and 'ip address help' for more details."
|
||||
fi
|
||||
}
|
||||
|
||||
log()
|
||||
{
|
||||
if [ -n "$1" ] && [ -r "/var/log/$1" ]; then
|
||||
fn="/var/log/$1"
|
||||
else
|
||||
fn="/var/log/syslog"
|
||||
fi
|
||||
if [ -n "$all" ]; then
|
||||
cat $fn
|
||||
else
|
||||
tail -$LINES $fn
|
||||
fi
|
||||
if [ -z "$plain" ] && [ -z "$nofoot" ]; then
|
||||
dm "______________________________________________________________________________"
|
||||
dm "See: 'tail -25 /log/FILE', 'tail -F /log/FILE' to continuously monitor files."
|
||||
fi
|
||||
}
|
||||
|
||||
rmon()
|
||||
{
|
||||
if [ -z "$*" ]; then
|
||||
echo "Missing argument, see 'show port' for available interfaces"
|
||||
exit 1
|
||||
fi
|
||||
for port in $*; do
|
||||
ethtool -S "$port"
|
||||
done
|
||||
if [ -z "$plain" ] && [ -z "$nofoot" ]; then
|
||||
dm "______________________________________________________________________________"
|
||||
dm "See: 'ethtool --help' for more details."
|
||||
fi
|
||||
}
|
||||
|
||||
rstp()
|
||||
{
|
||||
mstpctl showbridge
|
||||
echo "br0 port info"
|
||||
mstpctl showport br0
|
||||
}
|
||||
|
||||
fdb()
|
||||
{
|
||||
bridge $bopt fdb show
|
||||
}
|
||||
|
||||
mdb()
|
||||
{
|
||||
bridge $bopt mdb show
|
||||
}
|
||||
|
||||
routes()
|
||||
{
|
||||
ip $opt route show
|
||||
}
|
||||
|
||||
igmp()
|
||||
{
|
||||
querierctl $@
|
||||
}
|
||||
|
||||
system()
|
||||
{
|
||||
h1 "SYSTEM INFORMATION"
|
||||
echo "System Name : $(uname -n)"
|
||||
echo "System Variant : $VARIANT"
|
||||
echo "System Description : $PRETTY_NAME"
|
||||
echo "System Contact : $HOME_URL"
|
||||
echo "System Timezone : $(cat /etc/timezone)"
|
||||
echo "System Type : $NAME"
|
||||
echo "System Version : $(cat /etc/version)"
|
||||
echo "System Arch : $(uname -m)"
|
||||
echo "Kernel Version : $(uname -sr)"
|
||||
}
|
||||
|
||||
version()
|
||||
{
|
||||
cat /etc/version
|
||||
}
|
||||
|
||||
while [ "$1" != "" ]; do
|
||||
case $1 in
|
||||
-a)
|
||||
all=1
|
||||
;;
|
||||
-f)
|
||||
opt=""
|
||||
if [ -n "$plain" ]; then
|
||||
opt="-color=never"
|
||||
bopt="-color=never"
|
||||
fi
|
||||
;;
|
||||
-n)
|
||||
nofoot="yes"
|
||||
;;
|
||||
-p)
|
||||
plain="yes"
|
||||
opt="$opt -color=never"
|
||||
bopt="$bopt -color=never"
|
||||
;;
|
||||
-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
break
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
cmd=$1
|
||||
if [ -n "$cmd" ]; then
|
||||
shift
|
||||
fi
|
||||
|
||||
case $cmd in
|
||||
help)
|
||||
usage
|
||||
;;
|
||||
port*)
|
||||
ports $*
|
||||
;;
|
||||
vlan*)
|
||||
vlans
|
||||
;;
|
||||
fdb)
|
||||
fdb
|
||||
;;
|
||||
mdb)
|
||||
mdb
|
||||
;;
|
||||
if*)
|
||||
ifaces
|
||||
;;
|
||||
ip)
|
||||
cmd=$1
|
||||
shift
|
||||
case $cmd in
|
||||
addr*)
|
||||
ifaces
|
||||
;;
|
||||
route*)
|
||||
routes
|
||||
;;
|
||||
igmp*)
|
||||
igmp $*
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
log)
|
||||
log $1
|
||||
;;
|
||||
rmon)
|
||||
rmon $*
|
||||
;;
|
||||
route*)
|
||||
routes
|
||||
;;
|
||||
span*)
|
||||
rstp
|
||||
;;
|
||||
sys*)
|
||||
system
|
||||
;;
|
||||
ver*)
|
||||
version
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/bin/sh
|
||||
#set -x
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<EOF
|
||||
usage:
|
||||
yorn [-h] ["Do you want to run command?" command]
|
||||
|
||||
options:
|
||||
-h Show this help text
|
||||
-p Show plain output, no bells or whistles
|
||||
|
||||
Displays the yes-or-no question and runs command on yes.
|
||||
EOF
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-p)
|
||||
plain=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
question=$1
|
||||
shift
|
||||
command=$*
|
||||
if [ -z "$command" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$plain" ]; then
|
||||
if dialog --erase-on-exit --colors --defaultno --yesno "\Zb$question\ZB" 0 0; then
|
||||
yorn=y
|
||||
fi
|
||||
else
|
||||
# shellcheck disable=SC2162,SC3045
|
||||
read -n 1 -p "$question (y/N): " yorn
|
||||
fi
|
||||
|
||||
if [ "$yorn" = "y" ] || [ "$yorn" = "Y" ]; then
|
||||
$command
|
||||
fi
|
||||
@@ -0,0 +1,18 @@
|
||||
# System-wide .bashrc file for interactive bash(1) shells.
|
||||
|
||||
# If not running interactively, don't do anything
|
||||
[ -z "$PS1" ] && return
|
||||
|
||||
# Reevaluate for each line, in case hostname changes
|
||||
function prompt_command
|
||||
{
|
||||
PS1="\u@$(hostname):\w\$ "
|
||||
}
|
||||
export PROMPT_COMMAND=prompt_command
|
||||
|
||||
# check the window size after each command and, if necessary,
|
||||
# update the values of LINES and COLUMNS.
|
||||
shopt -s checkwinsize
|
||||
|
||||
# Disble built-ins
|
||||
enable -n help
|
||||
@@ -0,0 +1,51 @@
|
||||
# Infix's configuration for dhcpcd.
|
||||
# See dhcpcd.conf(5) for details.
|
||||
|
||||
# Allow users of this group to interact with dhcpcd via the control socket.
|
||||
#controlgroup wheel
|
||||
|
||||
# Inform the DHCP server of our hostname for DDNS.
|
||||
#hostname
|
||||
|
||||
# Use the hardware address of the interface for the Client ID.
|
||||
#clientid
|
||||
# or
|
||||
# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361.
|
||||
# Some non-RFC compliant DHCP servers do not reply with this set.
|
||||
# In this case, comment out duid and enable clientid above.
|
||||
duid
|
||||
|
||||
# Persist interface configuration when dhcpcd exits.
|
||||
persistent
|
||||
|
||||
# vendorclassid is set to blank to avoid sending the default of
|
||||
# dhcpcd-<version>:<os>:<machine>:<platform>
|
||||
vendorclassid
|
||||
|
||||
# A list of options to request from the DHCP server.
|
||||
option domain_name_servers, domain_name, domain_search
|
||||
option classless_static_routes
|
||||
# Respect the network MTU. This is applied to DHCP routes.
|
||||
option interface_mtu
|
||||
|
||||
# Request a hostname from the network
|
||||
option host_name
|
||||
|
||||
# Most distributions have NTP support.
|
||||
#option ntp_servers
|
||||
|
||||
# Rapid commit support.
|
||||
# Safe to enable by default because it requires the equivalent option set
|
||||
# on the server to actually work.
|
||||
option rapid_commit
|
||||
|
||||
# A ServerID is required by RFC2131.
|
||||
require dhcp_server_identifier
|
||||
|
||||
# Generate SLAAC address using the Hardware Address of the interface
|
||||
#slaac hwaddr
|
||||
# OR generate Stable Private IPv6 Addresses based from the DUID
|
||||
slaac private
|
||||
|
||||
# Background immediately, do not wait for DHCP lease (speed up boot process)
|
||||
background
|
||||
@@ -0,0 +1,144 @@
|
||||
#
|
||||
# Run-time configuration file for dialog
|
||||
#
|
||||
# Automatically generated by "dialog --create-rc <file>"
|
||||
#
|
||||
#
|
||||
# Types of values:
|
||||
#
|
||||
# Number - <number>
|
||||
# String - "string"
|
||||
# Boolean - <ON|OFF>
|
||||
# Attribute - (foreground,background,highlight?,underline?,reverse?)
|
||||
|
||||
# Set aspect-ration.
|
||||
aspect = 0
|
||||
|
||||
# Set separator (for multiple widgets output).
|
||||
separate_widget = ""
|
||||
|
||||
# Set tab-length (for textbox tab-conversion).
|
||||
tab_len = 0
|
||||
|
||||
# Make tab-traversal for checklist, etc., include the list.
|
||||
visit_items = OFF
|
||||
|
||||
# Shadow dialog boxes? This also turns on color.
|
||||
use_shadow = ON
|
||||
|
||||
# Turn color support ON or OFF
|
||||
use_colors = ON
|
||||
|
||||
# Screen color
|
||||
screen_color = (WHITE,BLUE,OFF)
|
||||
|
||||
# Shadow color
|
||||
shadow_color = (BLACK,BLACK,OFF)
|
||||
|
||||
# Dialog box color
|
||||
dialog_color = (BLACK,CYAN,OFF)
|
||||
|
||||
# Dialog box title color
|
||||
title_color = (BLACK,CYAN,ON)
|
||||
|
||||
# Dialog box border color
|
||||
border_color = dialog_color
|
||||
|
||||
# Active button color
|
||||
button_active_color = (CYAN,BLACK,ON)
|
||||
|
||||
# Inactive button color
|
||||
button_inactive_color = dialog_color
|
||||
|
||||
# Active button key color
|
||||
button_key_active_color = (WHITE,BLACK,ON)
|
||||
|
||||
# Inactive button key color
|
||||
button_key_inactive_color = (WHITE,CYAN,ON)
|
||||
|
||||
# Active button label color
|
||||
button_label_active_color = button_active_color
|
||||
|
||||
# Inactive button label color
|
||||
button_label_inactive_color = dialog_color
|
||||
|
||||
# Input box color
|
||||
inputbox_color = (BLACK,CYAN,OFF)
|
||||
|
||||
# Input box border color
|
||||
inputbox_border_color = inputbox_color
|
||||
|
||||
# Search box color
|
||||
searchbox_color = inputbox_color
|
||||
|
||||
# Search box title color
|
||||
searchbox_title_color = (BLUE,WHITE,ON)
|
||||
|
||||
# Search box border color
|
||||
searchbox_border_color = (WHITE,WHITE,ON)
|
||||
|
||||
# File position indicator color
|
||||
position_indicator_color = searchbox_title_color
|
||||
|
||||
# Menu box color
|
||||
menubox_color = dialog_color
|
||||
|
||||
# Menu box border color
|
||||
menubox_border_color = dialog_color
|
||||
|
||||
# Item color
|
||||
item_color = inputbox_color
|
||||
|
||||
# Selected item color
|
||||
item_selected_color = button_key_active_color
|
||||
|
||||
# Tag color
|
||||
tag_color = button_inactive_color
|
||||
|
||||
# Selected tag color
|
||||
tag_selected_color = (CYAN,BLACK,OFF)
|
||||
|
||||
# Tag key color
|
||||
tag_key_color = button_key_inactive_color
|
||||
|
||||
# Selected tag key color
|
||||
tag_key_selected_color = (WHITE,BLACK,ON)
|
||||
|
||||
# Check box color
|
||||
check_color = inputbox_color
|
||||
|
||||
# Selected check box color
|
||||
check_selected_color = button_key_active_color
|
||||
|
||||
# Up arrow color
|
||||
uarrow_color = (GREEN,WHITE,ON)
|
||||
|
||||
# Down arrow color
|
||||
darrow_color = uarrow_color
|
||||
|
||||
# Item help-text color
|
||||
itemhelp_color = (WHITE,BLACK,OFF)
|
||||
|
||||
# Active form text color
|
||||
form_active_text_color = button_key_active_color
|
||||
|
||||
# Form text color
|
||||
form_text_color = (WHITE,CYAN,ON)
|
||||
|
||||
# Readonly form item color
|
||||
form_item_readonly_color = (CYAN,WHITE,ON)
|
||||
|
||||
# Dialog box gauge color
|
||||
gauge_color = searchbox_title_color
|
||||
|
||||
# Dialog box border2 color
|
||||
border2_color = dialog_color
|
||||
|
||||
# Input box border2 color
|
||||
inputbox_border2_color = inputbox_color
|
||||
|
||||
# Search box border2 color
|
||||
searchbox_border2_color = inputbox_color
|
||||
|
||||
# Menu box border2 color
|
||||
menubox_border2_color = dialog_color
|
||||
@@ -0,0 +1 @@
|
||||
run [S] /libexec/infix/swup --
|
||||
@@ -0,0 +1,112 @@
|
||||
# NetBox mdev.conf based on https://github.com/slashbeast/mdev-like-a-boss/
|
||||
|
||||
# Syntax:
|
||||
# [-]devicename_regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...]
|
||||
# [-]$ENVVAR=regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...]
|
||||
# [-]@maj,min[-min2] user:group mode [=path]|[>path]|[!] [@|$|*cmd args...]
|
||||
#
|
||||
# [-]: do not stop on this match, continue reading mdev.conf
|
||||
# =: move, >: move and create a symlink
|
||||
# !: do not create device node
|
||||
# @|$|*: run cmd if $ACTION=remove, @cmd if $ACTION=add, *cmd in all cases
|
||||
|
||||
# support module loading on hotplug
|
||||
$MODALIAS=.* root:root 660 @modprobe -b "$MODALIAS"
|
||||
|
||||
# null may already exist; therefore ownership has to be changed with command
|
||||
null root:root 666 @chmod 666 $MDEV
|
||||
zero root:root 666
|
||||
full root:root 666
|
||||
random root:root 444
|
||||
urandom root:root 444
|
||||
hwrandom root:root 444
|
||||
grsec root:root 660
|
||||
|
||||
# Kernel-based Virtual Machine.
|
||||
#kvm root:kvm 660
|
||||
|
||||
# vhost-net, to be used with kvm.
|
||||
#vhost-net root:kvm 660
|
||||
|
||||
kmem root:root 640
|
||||
mem root:root 640
|
||||
port root:root 640
|
||||
# console may already exist; therefore ownership has to be changed with command
|
||||
console root:tty 600 @chmod 600 $MDEV
|
||||
ptmx root:tty 666
|
||||
pty.* root:tty 660
|
||||
|
||||
# Typical devices
|
||||
tty root:tty 666
|
||||
tty[0-9]* root:tty 660
|
||||
vcsa*[0-9]* root:tty 660
|
||||
ttyS[0-9]* root:dialout 660
|
||||
|
||||
# block devices
|
||||
ram([0-9]*) root:disk 660 >rd/%1
|
||||
loop([0-9]+) root:disk 660 >loop/%1
|
||||
sr[0-9]* root:cdrom 660 @ln -sf $MDEV cdrom
|
||||
fd[0-9]* root:floppy 660
|
||||
#SUBSYSTEM=block;.* root:disk 660 */libexec/infix/storage-device
|
||||
|
||||
# Run settle-nics every time new NIC appear.
|
||||
# If you don't want to auto-populate /etc/mactab with NICs,
|
||||
# run 'settle-nis' without '--write-mactab' param.
|
||||
#-SUBSYSTEM=net;DEVPATH=.*/net/.*;.* root:root 600 @/libexec/infix/settle-nics --write-mactab
|
||||
|
||||
net/tun[0-9]* root:netdev 660
|
||||
net/tap[0-9]* root:root 600
|
||||
|
||||
# alsa sound devices and audio stuff
|
||||
#SUBSYSTEM=sound;.* root:audio 660 @/libexec/infix/sound-control
|
||||
|
||||
adsp root:audio 660 >sound/
|
||||
audio root:audio 660 >sound/
|
||||
dsp root:audio 660 >sound/
|
||||
mixer root:audio 660 >sound/
|
||||
sequencer.* root:audio 660 >sound/
|
||||
|
||||
|
||||
# raid controllers
|
||||
cciss!(.*) root:disk 660 =cciss/%1
|
||||
ida!(.*) root:disk 660 =ida/%1
|
||||
rd!(.*) root:disk 660 =rd/%1
|
||||
|
||||
|
||||
fuse root:root 666
|
||||
|
||||
card[0-9] root:video 660 =dri/
|
||||
|
||||
agpgart root:root 660 >misc/
|
||||
psaux root:root 660 >misc/
|
||||
rtc root:root 664 >misc/
|
||||
|
||||
# input stuff
|
||||
SUBSYSTEM=input;.* root:plugdev 660
|
||||
|
||||
# v4l stuff
|
||||
vbi[0-9] root:video 660 >v4l/
|
||||
video[0-9] root:video 660 >v4l/
|
||||
|
||||
# dvb stuff
|
||||
dvb.* root:video 660
|
||||
|
||||
# drm etc
|
||||
dri/.* root:video 660
|
||||
|
||||
# Don't create old usbdev* devices.
|
||||
usbdev[0-9].[0-9]* root:root 660 !
|
||||
|
||||
# Stop creating x:x:x:x which looks like /dev/dm-*
|
||||
[0-9]+\:[0-9]+\:[0-9]+\:[0-9]+ root:root 660 !
|
||||
|
||||
# /dev/cpu support.
|
||||
microcode root:root 600 =cpu/
|
||||
cpu([0-9]+) root:root 600 =cpu/%1/cpuid
|
||||
msr([0-9]+) root:root 600 =cpu/%1/msr
|
||||
|
||||
# Populate /dev/bus/usb.
|
||||
#SUBSYSTEM=usb;DEVTYPE=usb_device;.* root:root 660 */libexec/infix/dev-bus-usb
|
||||
|
||||
# Catch-all other devices, Right now useful only for debuging.
|
||||
#.* root:root 660 */libexec/infix/catch-all
|
||||
@@ -0,0 +1 @@
|
||||
[2m[1mNote:[0m[2m use help, show, and setup commands to set up and diagnose the system.[0m
|
||||
@@ -0,0 +1,6 @@
|
||||
# interfaces(5) file used by ifup(8) and ifdown(8)
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
source-directory /etc/network/interfaces.d
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/pdmenu
|
||||
|
||||
title:Setup & Diagnostics
|
||||
|
||||
color:desktop:blue:blue
|
||||
color:title:blue:white
|
||||
color:base:blue:white
|
||||
|
||||
menu:main:Main Menu:Use arrow keys, Enter, Escape, and Q to navigate
|
||||
show:_System Settings..::system
|
||||
show:_Network Settings..::network
|
||||
show:_Tools..::tools
|
||||
nop
|
||||
exec:Show _fdb:truncate:show -p fdb
|
||||
exec:Show _mdb:truncate:show -p mdb
|
||||
exec:Show _ports:truncate:show -p ports
|
||||
exec:Show _vlans:truncate:show -p vlans
|
||||
exec:Show _interfaces:truncate:show -p iface
|
||||
exec:Show _routes:truncate:show -p route
|
||||
nop
|
||||
exec:Show _online users:truncate:w
|
||||
exec:Show _CPU Load::top
|
||||
nop
|
||||
show:_Help..::help
|
||||
exit:_Quit
|
||||
|
||||
menu:help:Help:Help Menu
|
||||
exec:Introduction:truncate:/bin/help -p
|
||||
exec:Editors:truncate:/bin/help -p edit
|
||||
exec:Networking:truncate:/bin/help -p net
|
||||
nop
|
||||
exit:_Main menu..
|
||||
|
||||
menu:network:Network:Network Settings
|
||||
exec:Show all _links:truncated:ip -br link
|
||||
exec:Show all _addresses:truncated:ip -br address
|
||||
exec:Show managed _interfaces:truncated:ifparse --all
|
||||
nop
|
||||
exec:Take _interface down:edit:ifdown ~Enter name of interface to take down:~
|
||||
exec:Take _interface up:edit:ifup ~Enter name of interface to take up:~
|
||||
nop
|
||||
exec:Edit _dhcpcd.conf::edit /etc/dhcpcd.conf
|
||||
exec:Edit _dnsmasq.conf::edit /etc/dnsmasq.conf
|
||||
exec:Edit _interfaces::edit /etc/network/interfaces
|
||||
exec:Edit _mactab::edit /etc/mactab
|
||||
exec:Edit _sysctl.conf::edit /etc/sysctl.conf
|
||||
nop
|
||||
exit:_Main menu..
|
||||
|
||||
menu:system:System:System Settings
|
||||
exec:List _log files:truncate:ls -l /var/log
|
||||
exec:Show _log file:edit,truncate:show -p -a log ~Show logfile, Enter for syslog:syslog~
|
||||
exec:Change _hostname:edit:hostnm ~Enter new hostname \[-a-zA-Z0-9\]:~
|
||||
exec:Change your _password::passwd
|
||||
exec:Edit _rc.local::edit /etc/rc.local
|
||||
nop
|
||||
exec:_Show State of Services:truncate:initctl -p
|
||||
exec:_Reload services:truncate:initctl reload;sleep 2;initctl -p
|
||||
exec:Show _available services:truncate:initctl -p ls
|
||||
exec:_Enable service:edit:initctl enable ~Enter name of service (filename) to enable:~
|
||||
exec:_Disable service:edit:initctl disable ~Enter name of service (filename) to disable:~
|
||||
nop
|
||||
exec:_Factory Reset::yorn "Factory reset device (reboots), are you sure?" factory -y
|
||||
nop
|
||||
exit:_Main menu..
|
||||
|
||||
menu:tools:Tools:Tools
|
||||
exec:_Ping:edit,pause:ping ~Enter address (IP or name) to ping:~
|
||||
exec:_Shell Prompt::/bin/bash --login
|
||||
exec:_SSH:edit,pause:ssh ~Enter [username@]address (IP or name) to SSH to:~
|
||||
exec:_Telnet:edit,pause:telnet ~Enter address (IP or name) to telnet to:~
|
||||
exec:_Traceroute:edit,pause:mtr ~Enter address (IP or name) to traceroute to:~
|
||||
exec:Browse _WWW:edit,pause:lynx ~Enter URL to browse:~
|
||||
nop
|
||||
exit:_Main menu..
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
# This file is run at the very end of runlevel S (bootstrap)
|
||||
#
|
||||
# Note: 1) not all initctl commands are allowed here
|
||||
# 2) to enable IP forwarding, use /etc/sysctl.conf, or /etc/sysctl.d/
|
||||
# 3) ensure the script calls `exit 0` at the end
|
||||
#
|
||||
|
||||
# Uncomment to classify all interfaces starting with 'eth' as ports.
|
||||
#for port in $(ip -br link |awk '/eth/{print $1}'); do
|
||||
# ip link set $port group port
|
||||
#done
|
||||
|
||||
# Uncomment to enable IP masquerading (NAT) of all traffic egressing
|
||||
# the WAN interface, here eth0. E.g., if you are a router for your
|
||||
# LAN on eth1.
|
||||
#iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
|
||||
|
||||
exit 0
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
# Factory default:
|
||||
# 1) all switch ports in VLAN 1 of br0
|
||||
# 2) no switch ports => DHCP on eth0
|
||||
# 3) no eth0
|
||||
|
||||
create_bridge()
|
||||
{
|
||||
nm=$1
|
||||
shift
|
||||
ports=$@
|
||||
|
||||
touch "/etc/network/interfaces.d/$nm"
|
||||
for port in $ports; do
|
||||
cat <<-EOF >>"/etc/network/interfaces.d/$nm"
|
||||
iface $port
|
||||
bridge-access 1
|
||||
post-up ip link set $port group port
|
||||
EOF
|
||||
done
|
||||
cat <<-EOF >> "/etc/network/interfaces.d/$nm"
|
||||
|
||||
auto $nm
|
||||
iface $nm
|
||||
bridge-ports $ports
|
||||
bridge-vlan-aware yes
|
||||
bridge-stp on
|
||||
bridge-vids 1
|
||||
|
||||
auto vlan1
|
||||
iface vlan1 inet dhcp
|
||||
vlan-id 1
|
||||
vlan-raw-device $nm
|
||||
post-up ip link set vlan1 group iface
|
||||
EOF
|
||||
ip link set vlan1 group iface
|
||||
}
|
||||
|
||||
# Check if already set up
|
||||
[ -z "$(ls -A /etc/network/interfaces.d/)" ] || exit 0
|
||||
|
||||
# Check for custom hostname from Qemu/Qeneth
|
||||
nm=$(cat /sys/firmware/qemu_fw_cfg/by_name/opt/hostname/raw)
|
||||
if [ -n "$nm" ]; then
|
||||
hostnm "$nm"
|
||||
fi
|
||||
|
||||
# need to check for 'length > 0' because ip command
|
||||
# outputs empty json objects for non-port group ifs
|
||||
ports=$(ip -json link show group port | jq -r '.[].ifname | select(length > 0)' | tr "\n" " ")
|
||||
if [ -n "$ports" ]; then
|
||||
create_bridge br0 $ports
|
||||
else
|
||||
ifaces=$(ip -json addr show |jq -r '.[] | select(.link_type=="ether").ifname')
|
||||
for iface in $ifaces; do
|
||||
cat <<-EOF > "/etc/network/interfaces.d/$iface"
|
||||
auto $iface
|
||||
iface $iface inet dhcp
|
||||
pre-up ip link set $iface group iface
|
||||
EOF
|
||||
done
|
||||
fi
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
# Probe for various types of harware features
|
||||
|
||||
if dmesg |grep -q QEMU || test -d /sys/module/qemu_fw_cfg; then
|
||||
initctl -nbq cond set qemu
|
||||
fi
|
||||
+2
-21
@@ -18,27 +18,7 @@ endchoice
|
||||
config SIGN_KEY
|
||||
string "Signing key"
|
||||
depends on SIGN_ENABLED
|
||||
default "${BR2_EXTERNAL_INFIX_PATH}/board/common/signing-keys/development" if SIGN_SRC_DIR
|
||||
|
||||
menuconfig TRUSTED_KEYS
|
||||
bool "Trusted keys for image"
|
||||
depends on SIGN_ENABLED
|
||||
help
|
||||
Keys that will be accepted for this image
|
||||
|
||||
|
||||
config TRUSTED_KEYS_DEVELOPMENT
|
||||
bool "Development key"
|
||||
depends on TRUSTED_KEYS
|
||||
|
||||
config TRUSTED_KEYS_DEVELOPMENT_PATH
|
||||
string
|
||||
depends on TRUSTED_KEYS_DEVELOPMENT
|
||||
default "${BR2_EXTERNAL_INFIX_PATH}/board/common/signing-keys/development/infix.crt"
|
||||
|
||||
config TRUSTED_KEYS_EXTRA_PATH
|
||||
string "Path to extra keys to include in image"
|
||||
depends on TRUSTED_KEYS
|
||||
default "${BR2_EXTERNAL_INFIX_PATH}/board/common/dev-key" if SIGN_SRC_DIR
|
||||
|
||||
menuconfig DISK_IMAGE
|
||||
bool "Disk image"
|
||||
@@ -160,3 +140,4 @@ config FIT_ARCH
|
||||
config FIT_KERNEL_LOAD_ADDR
|
||||
string "Kernel load address"
|
||||
depends on FIT_IMAGE
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Busybox version: 1.36.0
|
||||
# Thu Feb 8 08:22:32 2024
|
||||
# Tue Oct 3 18:00:40 2023
|
||||
#
|
||||
CONFIG_HAVE_DOT_CONFIG=y
|
||||
|
||||
@@ -1132,9 +1132,9 @@ CONFIG_SV_DEFAULT_SERVICE_DIR=""
|
||||
CONFIG_SH_IS_ASH=y
|
||||
# CONFIG_SH_IS_HUSH is not set
|
||||
# CONFIG_SH_IS_NONE is not set
|
||||
# CONFIG_BASH_IS_ASH is not set
|
||||
CONFIG_BASH_IS_ASH=y
|
||||
# CONFIG_BASH_IS_HUSH is not set
|
||||
CONFIG_BASH_IS_NONE=y
|
||||
# CONFIG_BASH_IS_NONE is not set
|
||||
CONFIG_SHELL_ASH=y
|
||||
CONFIG_ASH=y
|
||||
CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
ifeq ($(SIGN_ENABLED),y)
|
||||
include $(BR2_EXTERNAL_INFIX_PATH)/board/common/uboot/uboot.mk
|
||||
|
||||
TRUSTED_KEYS=$(TRUSTED_KEYS_DEVELOPMENT_PATH) $(TRUSTED_KEYS_EXTRA_PATH)
|
||||
define RAUC_POST_BUILD_INSTALL_CERT
|
||||
@$(call IXMSG,"Installing signing cert for RAUC")
|
||||
mkdir -p $(TARGET_DIR)/etc/rauc/keys
|
||||
$(foreach crt,$(shell ls $(TRUSTED_KEYS)), \
|
||||
$(foreach crt,$(shell ls $(SIGN_KEY)/*.crt), \
|
||||
cp $(crt) $(TARGET_DIR)/etc/rauc/keys/$(shell openssl x509 -hash -noout <$(crt)).0;)
|
||||
|
||||
endef
|
||||
RAUC_POST_BUILD_HOOKS += RAUC_POST_BUILD_INSTALL_CERT
|
||||
endif
|
||||
|
||||
@@ -44,19 +44,16 @@ image @DISKIMG@ {
|
||||
partition aux {
|
||||
offset = @AUXOFFS@
|
||||
image = "aux.ext4"
|
||||
partition-uuid = @AUXUUID@
|
||||
}
|
||||
|
||||
partition primary {
|
||||
image = "rootfs.squashfs"
|
||||
size = @IMGSIZE@
|
||||
partition-uuid = @PRIMARYUUID@
|
||||
}
|
||||
|
||||
partition secondary {
|
||||
image = "rootfs.squashfs"
|
||||
size = @IMGSIZE@
|
||||
partition-uuid = @SECONDARYUUID@
|
||||
}
|
||||
|
||||
partition cfg {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
. $BR2_EXTERNAL_INFIX_PATH/board/common/rootfs/etc/partition-uuid
|
||||
set -e
|
||||
|
||||
K=10
|
||||
M=20
|
||||
@@ -158,9 +157,6 @@ genboot
|
||||
# Use awk over sed because replacement text may contain newlines,
|
||||
# which sed does not approve of.
|
||||
awk \
|
||||
-vauxuuid=$AUX_UUID \
|
||||
-vprimaryuuid=$PRIMARY_UUID \
|
||||
-vsecondaryuuid=$SECONDARY_UUID \
|
||||
-vtotal=$total \
|
||||
-vauxsize=$auxsize -vauxoffs=$auxoffs \
|
||||
-vimgsize=$imgsize \
|
||||
@@ -178,10 +174,6 @@ awk \
|
||||
sub(/@DISKIMG@/, diskimg);
|
||||
sub(/@BOOTIMG@/, bootimg);
|
||||
sub(/@BOOTPART@/, bootpart);
|
||||
sub(/@AUXUUID@/, auxuuid);
|
||||
sub(/@PRIMARYUUID@/, primaryuuid);
|
||||
sub(/@SECONDARYUUID@/, secondaryuuid);
|
||||
|
||||
}1' \
|
||||
< $common/genimage.cfg.in >$root/genimage.cfg
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ cat <<EOF >"$BINARIES_DIR/${NM}.gns3a"
|
||||
"status": "stable",
|
||||
"maintainer": "$VENDOR_NAME",
|
||||
"maintainer_email": "${SUPPORT_URL#mailto:}",
|
||||
"usage": "Default login, user/pass: admin/admin\n\nType 'cli' (and Enter) followed by 'help' for an overview of commands and relevant configuration files.",
|
||||
"usage": "Default login, user/pass: admin/admin\n\nType 'help' for an overview of commands and relevant configuration files.\n\nFor Classic builds the following applies: the /etc directory is writable, use the passwd tool after login as part of your set up.\nFor networking, classify interfaces as switchports with /etc/mactab, syntax: 'MAC-address eN', where N is the port number (1-MAX).\nTo set up bridging and management interfaces, use /etc/network/interfaces, and /etc/network/interfaces.d/",
|
||||
"port_name_format": "eth{0}",
|
||||
"linked_clone": true,
|
||||
"qemu": {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
common=$(dirname "$(readlink -f "$0")")
|
||||
. "$BR2_CONFIG" 2>/dev/null
|
||||
. "$TARGET_DIR/usr/lib/os-release"
|
||||
|
||||
@@ -32,7 +31,6 @@ rm -f "$TARGET_DIR/etc/os-release"
|
||||
echo "ID=$INFIX_ID"
|
||||
echo "PRETTY_NAME=\"$INFIX_TAGLINE $VERSION\""
|
||||
echo "ID_LIKE=\"${ID}\""
|
||||
echo "DEFAULT_HOSTNAME=$BR2_TARGET_GENERIC_HOSTNAME"
|
||||
echo "VERSION=\"${VERSION}\""
|
||||
echo "VERSION_ID=${VERSION}"
|
||||
echo "BUILD_ID=\"${GIT_VERSION}\""
|
||||
@@ -42,6 +40,13 @@ rm -f "$TARGET_DIR/etc/os-release"
|
||||
if [ -n "$INFIX_RELEASE" ]; then
|
||||
echo "IMAGE_VERSION=\"$INFIX_RELEASE\""
|
||||
fi
|
||||
if [ "$INFIX_VARIANT_NETCONF" = "y" ]; then
|
||||
echo "VARIANT=\"Managed NETCONF\""
|
||||
echo "VARIANT_ID=netconf"
|
||||
else
|
||||
echo "VARIANT=\"Classic, writable /etc\""
|
||||
echo "VARIANT_ID=classic"
|
||||
fi
|
||||
echo "ARCHITECTURE=\"${INFIX_ARCH}\""
|
||||
echo "HOME_URL=$INFIX_HOME"
|
||||
if [ -n "$INFIX_VENDOR" ]; then
|
||||
@@ -63,12 +68,6 @@ rm -f "$TARGET_DIR/etc/os-release"
|
||||
|
||||
echo "$INFIX_TAGLINE $VERSION -- $(date +"%b %e %H:%M %Z %Y")" > "$TARGET_DIR/etc/version"
|
||||
|
||||
# Drop Buildroot default symlink to /tmp
|
||||
if [ -L "$TARGET_DIR/var/lib/avahi-autoipd" ]; then
|
||||
rm "$TARGET_DIR/var/lib/avahi-autoipd"
|
||||
mkdir "$TARGET_DIR/var/lib/avahi-autoipd"
|
||||
fi
|
||||
|
||||
# Allow pdmenu (setup) and bash to be login shells, bash is added
|
||||
# automatically when selected in menuyconfig, but not when BusyBox
|
||||
# provides a symlink (for ash). The /bin/{true,false} are old UNIX
|
||||
@@ -81,7 +80,3 @@ grep -qsE '^/bin/true$$' "$TARGET_DIR/etc/shells" \
|
||||
|| echo "/bin/true" >> "$TARGET_DIR/etc/shells"
|
||||
grep -qsE '^/bin/false$$' "$TARGET_DIR/etc/shells" \
|
||||
|| echo "/bin/false" >> "$TARGET_DIR/etc/shells"
|
||||
|
||||
# Allow clish (symlink to /usr/bin/klish) to be a login shell
|
||||
grep -qsE '^/bin/clish$$' "$TARGET_DIR/etc/shells" \
|
||||
|| echo "/bin/clish" >> "$TARGET_DIR/etc/shells"
|
||||
|
||||
@@ -22,7 +22,7 @@ diskimg=disk.img
|
||||
ver()
|
||||
{
|
||||
if [ -n "$INFIX_RELEASE" ]; then
|
||||
printf -- "-%s" "${INFIX_RELEASE#v}"
|
||||
printf -- "-%s" "$INFIX_RELEASE"
|
||||
return
|
||||
fi
|
||||
}
|
||||
@@ -42,7 +42,7 @@ fi
|
||||
load_cfg DISK_IMAGE
|
||||
if [ "$DISK_IMAGE" = "y" ]; then
|
||||
ixmsg "Creating Disk Image"
|
||||
diskimg="${NAME}-disk$(ver).img"
|
||||
diskimg="${NAME}-disk.img"
|
||||
bootcfg=
|
||||
if [ "$DISK_IMAGE_BOOT_DATA" ]; then
|
||||
bootcfg="-b $DISK_IMAGE_BOOT_DATA -B $DISK_IMAGE_BOOT_OFFSET"
|
||||
|
||||
@@ -54,16 +54,17 @@ choice
|
||||
|
||||
config QEMU_CONSOLE_VIRTIO
|
||||
bool "Virtio (hvc0)"
|
||||
depends on QEMU_LOADER_KERNEL
|
||||
|
||||
config QEMU_CONSOLE_SERIAL
|
||||
bool "Serial (ttyS0/ttyAMA0)"
|
||||
depends on !QEMU_LOADER_OVMF
|
||||
|
||||
endchoice
|
||||
|
||||
config QEMU_MACHINE
|
||||
string "Select emulated machine"
|
||||
default "qemu-system-aarch64 -M virt,accel=kvm:tcg -cpu max" if QEMU_aarch64
|
||||
default "qemu-system-x86_64 -M pc,accel=kvm:tcg -cpu max" if QEMU_x86_64
|
||||
default "qemu-system-aarch64 -M virt -cpu cortex-a72" if QEMU_aarch64
|
||||
default "qemu-system-x86_64 -M q35,accel=kvm -cpu host" if QEMU_x86_64
|
||||
help
|
||||
You should not have to change this setting, although you may
|
||||
want to tweak it, or change the acceleration.
|
||||
@@ -74,11 +75,11 @@ config QEMU_MACHINE
|
||||
|
||||
config QEMU_MACHINE_RAM
|
||||
string "RAM size (k/M/G)"
|
||||
default "384M"
|
||||
default "256M"
|
||||
help
|
||||
The default, 384 MiB, works for most configurations. However,
|
||||
if you get kernel panic with: "System is deadlocked on memory",
|
||||
try increasing this one.
|
||||
The default, 255 MiB, works for most configurations, even less for
|
||||
the Infix Classic builds. However, if you get kernel panic with:
|
||||
"System is deadlocked on memory", try increasing this one.
|
||||
|
||||
config QEMU_KERNEL
|
||||
string
|
||||
|
||||
@@ -24,22 +24,11 @@ prognm=$(basename "$0")
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "Usage:"
|
||||
echo " $prognm [opts] [ARGS]"
|
||||
echo "usage: $prognm [opts]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -c Run menuconfig to change Qemu settings"
|
||||
echo " -h This help text"
|
||||
echo " -c Run menuconfig to change Qemu settings"
|
||||
echo " -h This help text"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " ARGS1 Args before the '--' separator are for kernel space"
|
||||
echo " -- Separator"
|
||||
echo " ARGS2 Args after the '--' separator are for the init process"
|
||||
echo " Also, qemu.cfg has QEMU_APPEND which can affect this."
|
||||
echo
|
||||
echo "Example:"
|
||||
echo " qemu.sh -- finit.debug"
|
||||
echo "___________________________________________________________________"
|
||||
echo "Note: 'kconfig-frontends' package (Debian/Ubuntu) must be installed"
|
||||
echo " for -c to work: sudo apt install kconfig-frontents"
|
||||
|
||||
@@ -117,7 +106,7 @@ rootfs_args()
|
||||
echo -n "-device sd-card,drive=mmc "
|
||||
echo -n "-drive id=mmc,file=$CONFIG_QEMU_ROOTFS,if=none,format=raw "
|
||||
elif [ "$CONFIG_QEMU_ROOTFS_VSCSI" = "y" ]; then
|
||||
echo -n "-drive file=$CONFIG_QEMU_ROOTFS.qcow2,if=virtio,format=qcow2,bus=0,unit=0 "
|
||||
echo -n "-drive file=$CONFIG_QEMU_ROOTFS,if=virtio,format=raw,bus=0,unit=0 "
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -141,21 +130,9 @@ serial_args()
|
||||
echo -n "-device virtconsole,nr=1,name=gdbserver,chardev=gdbserver "
|
||||
}
|
||||
|
||||
usb_args()
|
||||
{
|
||||
USBSTICK="usb.vfat"
|
||||
if ! [ -f $USBSTICK ]; then
|
||||
dd if=/dev/zero of=${USBSTICK} bs=8M count=1 >/dev/null 2>&1
|
||||
mkfs.vfat $USBSTICK >/dev/null 2>&1
|
||||
fi
|
||||
echo -n "-drive if=none,id=usbstick,format=raw,file=$USBSTICK "
|
||||
echo -n "-usb "
|
||||
echo -n "-device usb-ehci,id=ehci "
|
||||
echo -n "-device usb-storage,bus=ehci.0,drive=usbstick "
|
||||
}
|
||||
rw_args()
|
||||
{
|
||||
[ "$CONFIG_QEMU_RW" ] || return
|
||||
[ "$CONFIG_QEMU_RW" ] || return
|
||||
|
||||
if ! [ -f "$CONFIG_QEMU_RW" ]; then
|
||||
dd if=/dev/zero of="$CONFIG_QEMU_RW" bs=16M count=1 >/dev/null 2>&1
|
||||
@@ -251,9 +228,6 @@ wdt_args()
|
||||
|
||||
run_qemu()
|
||||
{
|
||||
if [ "$CONFIG_QEMU_ROOTFS_VSCSI" = "y" ]; then
|
||||
qemu-img create -f qcow2 -o backing_file=$CONFIG_QEMU_ROOTFS -F raw $CONFIG_QEMU_ROOTFS.qcow2 > /dev/null
|
||||
fi
|
||||
local qemu
|
||||
read qemu <<EOF
|
||||
$CONFIG_QEMU_MACHINE -m $CONFIG_QEMU_MACHINE_RAM \
|
||||
@@ -261,7 +235,6 @@ run_qemu()
|
||||
$(rootfs_args) \
|
||||
$(serial_args) \
|
||||
$(rw_args) \
|
||||
$(usb_args) \
|
||||
$(host_args) \
|
||||
$(net_args) \
|
||||
$(wdt_args) \
|
||||
@@ -373,10 +346,6 @@ else
|
||||
load_qemucfg qemu.cfg
|
||||
fi
|
||||
|
||||
if [ -z "$QEMU_EXTRA_APPEND" ]; then
|
||||
QEMU_EXTRA_APPEND="$*"
|
||||
fi
|
||||
|
||||
generate_dot
|
||||
|
||||
echo "Starting Qemu :: Ctrl-a x -- exit | Ctrl-a c -- toggle console/monitor"
|
||||
@@ -384,3 +353,4 @@ line=$(stty -g)
|
||||
stty raw
|
||||
run_qemu $(dtb_args)
|
||||
stty "$line"
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC3045
|
||||
|
||||
OUTPUT=$1
|
||||
|
||||
read -r -s -p "New password: " password
|
||||
>&2 echo
|
||||
read -r -s -p "Retype password: " password_again
|
||||
>&2 echo
|
||||
|
||||
if [ "$password" != "$password_again" ]; then
|
||||
echo "Passwords do not match, try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$OUTPUT" ]; then
|
||||
echo "$password"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
umask 0177
|
||||
echo "$password" | mkpasswd > "$OUTPUT"
|
||||
exit 0
|
||||
@@ -1,67 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# Generate a self signed certificate with unlimited expire time
|
||||
|
||||
import argparse
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.x509.oid import NameOID
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# Generate private key
|
||||
private_key = rsa.generate_private_key(
|
||||
public_exponent=65537,
|
||||
key_size=2048,
|
||||
backend=default_backend()
|
||||
|
||||
)
|
||||
|
||||
parser = argparse.ArgumentParser(description="Generate a self signed certificate")
|
||||
parser.add_argument('--country', required=True, help="Set country")
|
||||
parser.add_argument('--state', required=True, help="Set state or province name")
|
||||
parser.add_argument('--city', required=True, help="Set city name")
|
||||
parser.add_argument('--organisation', required=True, help="Set organisation name")
|
||||
parser.add_argument('--organisation-unit', required=True, help="Set organisation unit name")
|
||||
parser.add_argument('--common-name', required=True, help="Set common name")
|
||||
parser.add_argument('--out-certificate', required=True, help="Output certificate")
|
||||
parser.add_argument('--out-key', required=True, help="Output key")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Builder for certificate
|
||||
subject = issuer = x509.Name([
|
||||
x509.NameAttribute(NameOID.COUNTRY_NAME, args.country),
|
||||
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, args.state),
|
||||
x509.NameAttribute(NameOID.LOCALITY_NAME, args.city),
|
||||
x509.NameAttribute(NameOID.ORGANIZATION_NAME, args.organisation),
|
||||
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, args.organisation_unit),
|
||||
x509.NameAttribute(NameOID.COMMON_NAME, args.common_name),
|
||||
])
|
||||
certificate = x509.CertificateBuilder().subject_name(
|
||||
subject
|
||||
).issuer_name(
|
||||
issuer
|
||||
).public_key(
|
||||
private_key.public_key()
|
||||
).serial_number(
|
||||
x509.random_serial_number()
|
||||
).not_valid_before(
|
||||
datetime(2000, 1, 1)
|
||||
).not_valid_after(
|
||||
datetime(9999, 1, 1)
|
||||
).add_extension(
|
||||
x509.SubjectAlternativeName([x509.DNSName(args.common_name)]),
|
||||
critical=False,
|
||||
).sign(private_key, hashes.SHA256(), default_backend())
|
||||
|
||||
# Serialize certificate and private key
|
||||
with open(args.out_certificate, "wb") as f:
|
||||
f.write(certificate.public_bytes(serialization.Encoding.PEM))
|
||||
with open(args.out_key, "wb") as f:
|
||||
f.write(private_key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
))
|
||||
@@ -1 +0,0 @@
|
||||
/usr/bin/mg
|
||||
@@ -43,7 +43,7 @@ if [ -x /bin/ip -o -x /sbin/ip ] ; then
|
||||
BIND)
|
||||
ip addr flush dev "$2" label "$2:avahi"
|
||||
ip addr add "$3"/16 brd 169.254.255.255 label "$2:avahi" scope link dev "$2" proto 6
|
||||
ip route add default dev "$2" metric "$METRIC" scope link proto zeroconf ||:
|
||||
ip route add default dev "$2" metric "$METRIC" scope link ||:
|
||||
;;
|
||||
|
||||
CONFLICT|UNBIND|STOP)
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
# managed by openresolv. DHCP lease, VPN tunnel establishment,
|
||||
# and similar events feed servers and configuration to dnsmasq.
|
||||
domain-needed
|
||||
|
||||
# Only listen to loopback (local system)
|
||||
interface=lo
|
||||
bind-dynamic
|
||||
#listen-address=127.0.0.1,::1
|
||||
|
||||
#interface=lo
|
||||
listen-address=127.0.0.1
|
||||
enable-dbus
|
||||
|
||||
# Generated by openresolv
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
set COLORTERM=yes
|
||||
rlimit soft core infinity
|
||||
@@ -1,4 +0,0 @@
|
||||
service :%i pid:!/run/k8s-logger-%i.pid <usr/container:%i> \
|
||||
[2345] k8s-logger -cni %i -f local1 /run/containers/%i.fifo -- Logger for container %i
|
||||
sysv :%i pid:!/run/container:%i.pid <pid/k8s-logger:%i> kill:10 \
|
||||
[2345] container -n %i -- container %i
|
||||
@@ -1 +0,0 @@
|
||||
task [S] <service/confd/ready> /libexec/infix/mkcert -- Verifying self-signed https certificate
|
||||
@@ -1 +0,0 @@
|
||||
service [2345] <!> ttyd -i lo -p 8001 login -- Web terminal daemon (ttyd)
|
||||
@@ -1 +0,0 @@
|
||||
../available/mkcert.conf
|
||||
@@ -1,6 +0,0 @@
|
||||
# Sourced by mkcert at boot
|
||||
country=SE
|
||||
state=Vastmanland
|
||||
city=Vasteras
|
||||
org=KernelKit
|
||||
unit=Infix
|
||||
@@ -1,3 +0,0 @@
|
||||
# Do not authorize usb ports before they have been checked in in the device-tree
|
||||
options usbcore authorized_default=0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.-------.
|
||||
| . . | Infix -- a Network Operating System
|
||||
|-. v .-| https://kernelkit.github.io
|
||||
'-'---'-'
|
||||
'-'---'-'
|
||||
@@ -1,27 +0,0 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name _;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
server_name _;
|
||||
include ssl.conf;
|
||||
|
||||
#error_page 404 /404.html;
|
||||
|
||||
# redirect server error pages to the static page /50x.html
|
||||
#
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root html;
|
||||
}
|
||||
|
||||
location / {
|
||||
root html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
server_name network.local;
|
||||
include ssl.conf;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_redirect off;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
server {
|
||||
listen 7681 ssl;
|
||||
listen [::]:7681 ssl;
|
||||
server_name _;
|
||||
|
||||
include ssl.conf;
|
||||
|
||||
location / {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_pass http://127.0.0.1:8001;
|
||||
proxy_redirect off;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
../available/default.conf
|
||||
@@ -1,24 +0,0 @@
|
||||
user www-data www-data;
|
||||
worker_processes 1;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
#keepalive_timeout 0;
|
||||
keepalive_timeout 65;
|
||||
|
||||
#gzip on;
|
||||
|
||||
include /etc/nginx/enabled/*.conf;
|
||||
|
||||
access_log syslog:server=unix:/dev/log,nohostname,facility=local7,severity=info;
|
||||
error_log syslog:server=unix:/dev/log,nohostname,facility=local7 info;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
ssl_certificate /etc/ssl/certs/self-signed.crt;
|
||||
ssl_certificate_key /etc/ssl/private/self-signed.key;
|
||||
|
||||
ssl_protocols TLSv1.3 TLSv1.2;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
ssl_session_cache shared:SSL:1m;
|
||||
ssl_session_timeout 5m;
|
||||
@@ -1,3 +0,0 @@
|
||||
AUX_UUID="78460f84-de84-4fe7-89bd-4c1f433b2230"
|
||||
PRIMARY_UUID="107ae911-a97b-4380-975c-7ce1a2dde1e0"
|
||||
SECONDARY_UUID="352bd9b2-2ca9-44e2-bdc7-edbc87ba1e02"
|
||||
@@ -1 +0,0 @@
|
||||
kernel.core_pattern=/var/crash/core-%e
|
||||
@@ -1 +0,0 @@
|
||||
local1.* -/var/log/container
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
KEY=/cfg/ssl/private/self-signed.key
|
||||
CRT=/cfg/ssl/certs/self-signed.crt
|
||||
|
||||
country=US
|
||||
state=California
|
||||
city=Berkeley
|
||||
org="Acme, Inc."
|
||||
unit=Second
|
||||
|
||||
if [ -f /etc/mkcert.conf ]; then
|
||||
. /etc/mkcert.conf
|
||||
fi
|
||||
|
||||
if [ -z "$cn" ]; then
|
||||
cn=$1
|
||||
if [ -z "$cn" ]; then
|
||||
cn=$(hostname).local
|
||||
fi
|
||||
fi
|
||||
|
||||
generate()
|
||||
{
|
||||
mkdir -p /cfg/ssl/private /cfg/ssl/certs
|
||||
chmod 700 /cfg/ssl/private
|
||||
|
||||
gencert --country "$country" --state "$state" --city "$city" --organisation "$org" \
|
||||
--organisation-unit "$unit" --common-name "$cn" \
|
||||
--out-certificate $CRT --out-key $KEY
|
||||
}
|
||||
|
||||
CN=$(openssl x509 -noout -subject -in "${CRT}" 2>/dev/null |sed 's/.*CN=//')
|
||||
if [ -z "$CN" ] || [ "$CN" != "$cn" ]; then
|
||||
generate "$cn"
|
||||
fi
|
||||
|
||||
cp "${KEY}" "/etc/ssl/private/"
|
||||
cp "${CRT}" "/etc/ssl/certs/"
|
||||
initctl cond set mkcert
|
||||
|
||||
exit 0
|
||||
@@ -126,6 +126,11 @@ if ! mount_rw cfg >/dev/null 2>&1; then
|
||||
# Even if /mnt/var isn't available, if /mnt/cfg isn't either, then
|
||||
# there's no point in overlaying one ramdisk on top of another.
|
||||
vlibsrc=
|
||||
else
|
||||
# Classic Infix has read-write /etc across boots
|
||||
if [ "$VARIANT_ID" != "netconf" ]; then
|
||||
etcsrc=/mnt/cfg
|
||||
fi
|
||||
fi
|
||||
|
||||
if check_factory; then
|
||||
|
||||
@@ -1 +1 @@
|
||||
/etc/alternatives/editor
|
||||
mg
|
||||
@@ -1 +1 @@
|
||||
/etc/alternatives/editor
|
||||
mg
|
||||
@@ -1,15 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<style>
|
||||
html { color-scheme: light dark; }
|
||||
body { width: 35em; margin: 0 auto;
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>An error occurred.</h1>
|
||||
<p>Sorry, the page you are looking for is currently unavailable.</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Generate index.html from Infix README.md
|
||||
|
||||
BASE=../../../../..
|
||||
TITLE="Welcome to Infix :-)"
|
||||
|
||||
cp $BASE/doc/logo.png .
|
||||
cat $BASE/README.md \
|
||||
| tail +2 \
|
||||
| sed 's/doc\/logo.png/logo.png/' \
|
||||
| pandoc -f markdown+implicit_figures+link_attributes -o index.html \
|
||||
--metadata pagetitle="$TITLE" --template=hpstr-template.html
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
@@ -1,637 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
all=""
|
||||
env=""
|
||||
port=""
|
||||
force=
|
||||
|
||||
log()
|
||||
{
|
||||
logger -I $PPID -t container -p local1.notice -- "$*"
|
||||
}
|
||||
|
||||
# Unpacks a given oci-archive.tar[.gz] in the current directory. Sanity
|
||||
# checks, at least one index.json in the top-level dir of the archive.
|
||||
# If there are more index files, this function does not handle them.
|
||||
unpack_archive()
|
||||
{
|
||||
image=$1
|
||||
name=$2
|
||||
|
||||
# Supported transports for load and create
|
||||
case "$image" in
|
||||
oci:*) # Unpacked OCI image
|
||||
file=${image#oci:}
|
||||
;;
|
||||
oci-archive:*) # Packed OCI image, .tar or .tar.gz format
|
||||
file=${image#oci-archive:}
|
||||
;;
|
||||
*) # docker://*, docker-archive:*, or URL
|
||||
echo "$image"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ ! -e "$file" ]; then
|
||||
if [ -e "/var/lib/conatainers/oci/$file" ]; then
|
||||
file="/var/lib/conatainers/oci/$file"
|
||||
elif [ -e "/lib/oci/$file" ]; then
|
||||
file="/lib/oci/$file"
|
||||
else
|
||||
log "Error: cannot find OCI archive $file in search path."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d "$file" ]; then
|
||||
index=$(find "$file" -name index.json)
|
||||
if [ -z "$index" ]; then
|
||||
log "Error: cannot find index.json in OCI image $file"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
index=$(tar tf "$file" |grep index.json)
|
||||
if [ -z "$index" ]; then
|
||||
log "Error: invalid OCI archive, cannot find index.json in $file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -n "$quiet" ] || log "Extracting OCI archive $file ..."
|
||||
tar xf "$file" || (log "Error: failed unpacking $file in $(pwd)"; exit 1)
|
||||
fi
|
||||
|
||||
dir=$(dirname "$index")
|
||||
[ -n "$quiet" ] || log "Loading OCI image $dir ..."
|
||||
podman load -qi "$dir" >/dev/null
|
||||
|
||||
# Rename image from podman default $dir:latest
|
||||
if [ -n "$name" ]; then
|
||||
podman tag "$dir" "$name" >/dev/null
|
||||
podman rmi "$dir" >/dev/null
|
||||
else
|
||||
name=$dir
|
||||
fi
|
||||
|
||||
echo "$name"
|
||||
}
|
||||
|
||||
running()
|
||||
{
|
||||
run=$(podman inspect "$1" 2>/dev/null |jq .[].State.Running)
|
||||
[ "$run" = "true" ] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
create()
|
||||
{
|
||||
name=$1
|
||||
image=$2
|
||||
shift 2
|
||||
|
||||
if [ -z "$name" ] || [ -z "$image" ]; then
|
||||
echo "Usage:"
|
||||
echo " container create NAME IMAGE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Unpack and load docker-archive/oci/oci-archive, returning image
|
||||
# name, or return docker:// URL for download.
|
||||
image=$(unpack_archive "$image")
|
||||
|
||||
if [ -z "$logging" ]; then
|
||||
logging="--log-driver k8s-file --log-opt path=/run/containers/$name.fifo"
|
||||
fi
|
||||
|
||||
args="$args --replace --quiet --cgroup-parent=containers $caps"
|
||||
args="$args --restart=$restart --systemd=false --tz=local $privileged"
|
||||
args="$args $ro $vol $mount $hostname $entrypoint $env $port $logging"
|
||||
pidfn=/run/container:${name}.pid
|
||||
|
||||
[ -n "$quiet" ] || log "---------------------------------------"
|
||||
[ -n "$quiet" ] || log "Got name: $name image: $image"
|
||||
[ -n "$quiet" ] || log "Got networks: $network"
|
||||
|
||||
if [ -n "$network" ]; then
|
||||
for net in $network; do
|
||||
args="$args --net=$net"
|
||||
done
|
||||
|
||||
for srv in $dns; do
|
||||
args="$args --dns=$srv"
|
||||
done
|
||||
|
||||
for domain in $search; do
|
||||
args="$args --dns-search=$domain"
|
||||
done
|
||||
else
|
||||
args="$args --network=none"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2048
|
||||
log "Calling podman create --name $name --conmon-pidfile=$pidfn $args $image $*"
|
||||
if podman create --name "$name" --conmon-pidfile="$pidfn" $args "$image" $*; then
|
||||
[ -n "$quiet" ] || log "Successfully created container $name from $image"
|
||||
rm -f "/run/containers/env/${name}.env"
|
||||
[ -n "$manual" ] || start "$name"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "Error: failed creating container $name, please check the configuration."
|
||||
exit 1
|
||||
}
|
||||
|
||||
delete()
|
||||
{
|
||||
name=$1
|
||||
image=$2
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo "Usage:"
|
||||
echo " container delete NAME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
podman rm -vif "$name" >/dev/null 2>&1
|
||||
[ -n "$quiet" ] || log "Container $name has been removed."
|
||||
}
|
||||
|
||||
waitfor()
|
||||
{
|
||||
timeout=$2
|
||||
while [ ! -f "$1" ]; do
|
||||
_=$((timeout -= 1))
|
||||
if [ $timeout -le 0 ]; then
|
||||
log "Timeout waiting for $1, aborting!"
|
||||
exit 1
|
||||
fi
|
||||
sleep 1;
|
||||
done
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
name=$1
|
||||
|
||||
if running "$name"; then
|
||||
[ -n "$quiet" ] || echo "$name: already running."
|
||||
return
|
||||
fi
|
||||
|
||||
initctl -bq cond set "container:$name"
|
||||
# Real work is done by wrap() courtesy of finit sysv emulation
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
name=$1
|
||||
|
||||
if ! running "$name"; then
|
||||
[ -n "$quiet" ] || echo "$name: not running."
|
||||
return
|
||||
fi
|
||||
|
||||
initctl -bq cond clr "container:$name"
|
||||
# Real work is done by wrap() courtesy of finit sysv emulation
|
||||
}
|
||||
|
||||
wrap()
|
||||
{
|
||||
name=$1
|
||||
cmd=$2
|
||||
|
||||
podman "$cmd" "$name"
|
||||
}
|
||||
|
||||
# Removes network $1 from all containers
|
||||
netwrm()
|
||||
{
|
||||
net=$1
|
||||
|
||||
for c in $(podman ps $all --format "{{.Names}}"); do
|
||||
for n in $(podman inspect "$c" |jq -r '.[].NetworkSettings.Networks | keys[]'); do
|
||||
if [ "$n" = "$net" ]; then
|
||||
podman network disconnect $force "$n" "$c" >/dev/null
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# Schedule restart of (any) container using network $1 to activate network changes
|
||||
netrestart()
|
||||
{
|
||||
net=$1
|
||||
|
||||
for c in $(podman ps $all --format "{{.Names}}"); do
|
||||
for n in $(podman inspect "$c" |jq -r '.[].NetworkSettings.Networks | keys[]'); do
|
||||
if [ "$n" = "$net" ]; then
|
||||
initctl -nbq touch "container@$c"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<EOF
|
||||
usage:
|
||||
container [opt] cmd [arg]
|
||||
|
||||
options:
|
||||
-a, --all Show all, of something
|
||||
--dns NAMESERVER Set nameserver(s) when creating a container
|
||||
--dns-search LIST Set host lookup search list when creating container
|
||||
--cap-add CAP Add capability to unprivileged container
|
||||
--cap-drop CAP Drop capability, for privileged containter
|
||||
-c, --creds USR[:PWD] Credentials to pass to curl -u for remote ops
|
||||
-d, --detach Detach a container started with 'run IMG [CMD]'
|
||||
-e, --env FILE Environment variables when creating container
|
||||
--entrypoint Disable container image's ENTRYPOINT, run cmd + arg
|
||||
-f, --force Force operation, e.g. remove
|
||||
-h, --help Show this help text
|
||||
--hostname NAME Set hostname when creating container
|
||||
--net NETWORK Network interface(s) when creating or finding container
|
||||
-l, --log-driver DRV Log driver to use
|
||||
--log-opt OPT Logging options to log driver
|
||||
--log-path PATH Path for k8s-file log pipe
|
||||
-m, --mount HOST:DEST Bind mount a read-only file inside a container
|
||||
--manual Do not start container automatically after creation
|
||||
-n, --name NAME Alternative way of supplying name to start/stop/restart
|
||||
--privileged Give container extended privileges
|
||||
-p, --publish PORT Publish ports when creating container
|
||||
Syntax: [[ip:][hostPort]:]containerPort[/protocol]
|
||||
-q, --quiet Quiet operation, called from confd
|
||||
-r, --restart POLICY One of "no", "always", or "on-failure:NUM"
|
||||
--read-only Do not create a writable layer
|
||||
-s, --simple Show output in simplified format
|
||||
-v, --volume NAME:PATH Create named volume mounted inside container on PATH
|
||||
|
||||
commands:
|
||||
create NAME IMAGE NET Create container NAME using IMAGE with networks NET
|
||||
delete [network] NAME Remove container NAME or network NAME from all containers
|
||||
exec NAME CMD Run a command inside a container
|
||||
find [ifname PID] Find PID of container where '--net IFNAME' currently lives
|
||||
or, find the name of our IFNAME inside the container @PID
|
||||
help Show this help text
|
||||
list [image | oci] List names (only) of containers, images, or OCI archives
|
||||
load [NAME | URL] NM Load OCI tarball fileNAME or URL to image NM
|
||||
remove IMAGE Remove an (unused) container image
|
||||
restart [network] NAME Restart a (crashed) container or container(s) using network
|
||||
run NAME [CMD] Run a container interactively, with an optional command
|
||||
save IMAGE FILE Save a container image to an OCI tarball FILE[.tar.gz]
|
||||
shell Start a shell inside a container
|
||||
show [image | volume] Show containers, images, or volumes
|
||||
stat Show continuous stats about containers (Ctrl-C aborts)
|
||||
start [NAME] Start a container, see -n
|
||||
stop [NAME] Stop a container, see -n
|
||||
volume [prune] Prune unused volumes
|
||||
EOF
|
||||
}
|
||||
|
||||
while [ "$1" != "" ]; do
|
||||
case $1 in
|
||||
-a | --all)
|
||||
all="-a"
|
||||
;;
|
||||
--cap-add)
|
||||
shift
|
||||
caps="$caps --cap-add=$1"
|
||||
;;
|
||||
--cap-drop)
|
||||
shift
|
||||
caps="$caps --cap-drop=$1"
|
||||
;;
|
||||
-c | --creds)
|
||||
shift
|
||||
creds="-u $1"
|
||||
;;
|
||||
-d | --detach)
|
||||
detach="-d"
|
||||
;;
|
||||
--dns)
|
||||
shift
|
||||
dns="$dns $1"
|
||||
;;
|
||||
--dns-search)
|
||||
shift
|
||||
search="$search $1"
|
||||
;;
|
||||
-e | --env)
|
||||
shift
|
||||
env="$env --env-file=$1"
|
||||
;;
|
||||
--entrypoint)
|
||||
entrypoint="--entrypoint=\"\""
|
||||
;;
|
||||
-f | --force)
|
||||
force="-f"
|
||||
;;
|
||||
-h | --help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--hostname)
|
||||
shift
|
||||
hostname="--hostname $1"
|
||||
;;
|
||||
-l | --log-driver)
|
||||
shift
|
||||
logging=" --log-driver=$1"
|
||||
;;
|
||||
--log-opt)
|
||||
shift
|
||||
logging="$logging --log-opt $1"
|
||||
;;
|
||||
--log-path)
|
||||
shift
|
||||
logging="$logging --log-opt path=$1"
|
||||
log_path="$1"
|
||||
;;
|
||||
-m | --mount)
|
||||
shift
|
||||
mount="--mount=$1"
|
||||
;;
|
||||
--manual)
|
||||
manual=true
|
||||
;;
|
||||
-n | --name)
|
||||
shift
|
||||
name="$1"
|
||||
;;
|
||||
--net)
|
||||
shift
|
||||
if [ -n "$network" ]; then
|
||||
network="$network $1"
|
||||
else
|
||||
network=$1
|
||||
fi
|
||||
;;
|
||||
--privileged)
|
||||
privileged="--privileged=true"
|
||||
;;
|
||||
-p | --publish)
|
||||
shift
|
||||
port="$port -p $1"
|
||||
;;
|
||||
-q | --quiet)
|
||||
quiet="-q"
|
||||
;;
|
||||
-r | --restart)
|
||||
shift
|
||||
restart=$1
|
||||
;;
|
||||
--read-only)
|
||||
ro="--read-only=true"
|
||||
;;
|
||||
-s | --simple)
|
||||
simple=true
|
||||
;;
|
||||
-v | --volume)
|
||||
shift
|
||||
vol="$vol -v $1"
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
cmd=$1
|
||||
if [ -n "$cmd" ]; then
|
||||
shift
|
||||
fi
|
||||
|
||||
case $cmd in
|
||||
# Does not work atm., cannot attach to TTY because
|
||||
# we monitor 'podman start -ai foo' with Finit.
|
||||
# attach)
|
||||
# podman attach "$1"
|
||||
# ;;
|
||||
create)
|
||||
[ -n "$quiet" ] || log "Got create args: $*"
|
||||
create "$@"
|
||||
;;
|
||||
delete)
|
||||
cmd=$1
|
||||
name=$2
|
||||
if [ "$cmd" = "network" ] && [ -n "$name" ]; then
|
||||
netwrm "$name"
|
||||
else
|
||||
delete "$@"
|
||||
fi
|
||||
;;
|
||||
exec)
|
||||
podman exec -it "$@"
|
||||
;;
|
||||
find)
|
||||
cmd=$1
|
||||
pid=$2
|
||||
if [ "$cmd" = "ifname" ] && [ -n "$pid" ]; then
|
||||
nsenter -t "$pid" -n ip -d -j link | \
|
||||
jq --arg ifname "$network" -r '.[] | select(.ifalias==$ifname) | .ifname'
|
||||
else
|
||||
containers=$(podman ps $all --format "{{.Names}}")
|
||||
for c in $containers; do
|
||||
json=$(podman inspect "$c")
|
||||
nets=$(echo "$json" |jq -r '.[].NetworkSettings.Networks | keys[]' 2>/dev/null)
|
||||
for n in $nets; do
|
||||
if [ "$network" = "$n" ]; then
|
||||
pid=$(echo "$json" | jq .[].State.Pid)
|
||||
echo "$pid"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
;;
|
||||
help)
|
||||
usage
|
||||
;;
|
||||
load)
|
||||
url=$1
|
||||
name=$2
|
||||
# shellcheck disable=SC2086
|
||||
if echo "$url" | grep -q "://"; then
|
||||
file=$(basename "$url")
|
||||
curl -k $creds -Lo "$file" "$url"
|
||||
else
|
||||
file="$url"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
name=$(unpack_archive "$file" $name)
|
||||
|
||||
# Show resulting image(s) matching $name
|
||||
if [ -n "$name" ]; then
|
||||
podman images -n "$name"
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
ls | list)
|
||||
cmd=$1
|
||||
[ -n "$cmd" ] && shift
|
||||
case $cmd in
|
||||
image*)
|
||||
podman images $all --format "{{.Repository}}:{{.Tag}}"
|
||||
;;
|
||||
oci)
|
||||
find /lib/oci /var/lib/containers/oci -type f 2>/dev/null
|
||||
;;
|
||||
*)
|
||||
podman ps $all --format "{{.Names}}"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
pull)
|
||||
podman pull "$@"
|
||||
;;
|
||||
remove)
|
||||
podman rmi $all $force -i "$1"
|
||||
;;
|
||||
run)
|
||||
img=$1
|
||||
cmd=$2
|
||||
[ -n "$port" ] || port="-P"
|
||||
if [ -n "$cmd" ]; then
|
||||
shift 2
|
||||
[ -n "$detach" ] || echo "Starting $img ENTRYPOINT $cmd :: use Ctrl-p Ctrl-q to detach"
|
||||
podman run -it --rm $detach $port --entrypoint="$cmd" "$img" "$@"
|
||||
else
|
||||
[ -n "$detach" ] || echo "Starting $img :: use Ctrl-p Ctrl-q to detach"
|
||||
podman run -it --rm $detach $port "$img"
|
||||
fi
|
||||
;;
|
||||
save)
|
||||
name=$1
|
||||
file=$2
|
||||
if echo "$file" | grep -q ".gz"; then
|
||||
file=${file%%.gz}
|
||||
gzip=true
|
||||
fi
|
||||
if ! echo "$file" | grep -q ".tar"; then
|
||||
file=${file}.tar
|
||||
gzip=true
|
||||
fi
|
||||
podman save -o "$file" "$name"
|
||||
if [ -s "$file" ] && [ -n "$gzip" ]; then
|
||||
gzip "$file"
|
||||
fi
|
||||
;;
|
||||
shell)
|
||||
podman exec -it "$1" sh -l
|
||||
;;
|
||||
show)
|
||||
cmd=$1
|
||||
[ -n "$cmd" ] && shift
|
||||
case $cmd in
|
||||
image*)
|
||||
if [ -n "$simple" ]; then
|
||||
podman images $all --format "{{.Names}} {{.Size}}" \
|
||||
| sed 's/\[\(.*\)\] /\1 /g' \
|
||||
| awk '{ printf "%-60s %s %s\n", $1, $2, $3}'
|
||||
else
|
||||
podman images $all
|
||||
fi
|
||||
;;
|
||||
volume*)
|
||||
printf "%-20s CONTAINER\n" "VOLUME"
|
||||
for v in $(podman volume ls --format "{{.Name}}"); do
|
||||
printf "%-20s" "$v"
|
||||
podman ps -a --filter volume="$v" --format '{{.Names}}' | sed 's/^/ /'
|
||||
done
|
||||
;;
|
||||
*)
|
||||
if [ -n "$simple" ]; then
|
||||
podman ps $all --format "{{.ID}} {{.Names}} {{.Image}}" \
|
||||
| awk '{ printf "%s %-30s %s\n", $1, $2, $3}'
|
||||
else
|
||||
podman ps $all
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
start)
|
||||
if [ -n "$name" ]; then
|
||||
wrap "$name" start
|
||||
elif [ -n "$1" ]; then
|
||||
start "$1"
|
||||
else
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
restart)
|
||||
if [ -n "$name" ]; then
|
||||
wrap "$name" restart
|
||||
elif [ -n "$1" ]; then
|
||||
cmd=$1
|
||||
name=$2
|
||||
if [ "$cmd" = "network" ] && [ -n "$name" ]; then
|
||||
netrestart "$name"
|
||||
else
|
||||
name=$1
|
||||
stop "$name"
|
||||
timeout=20
|
||||
while running "$name"; do
|
||||
_=$((timeoute -= 1))
|
||||
if [ $timeout -le 0 ]; then
|
||||
log "Timeout waiting for container $1 to stop before restarting it."
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
start "$name"
|
||||
fi
|
||||
else
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
if [ -n "$name" ]; then
|
||||
wrap "$name" stop
|
||||
elif [ -n "$1" ]; then
|
||||
stop "$1"
|
||||
else
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
stat*)
|
||||
podman stats -i 2
|
||||
;;
|
||||
upgrade)
|
||||
img=$(podman inspect "$1" | jq -r .[].ImageName)
|
||||
if [ -z "$img" ]; then
|
||||
echo "No such container ($1), or invalid ImageName. Cannot upgrade."
|
||||
exit 1;
|
||||
fi
|
||||
if echo "$img" | grep -Eq '^localhost/'; then
|
||||
# Likely an OCI archive, or local directory, assume user has updated image.
|
||||
file=$(awk '{s=$NF} END{print s}' "/var/lib/containers/active/${1}.sh")
|
||||
echo "Upgrading container ${1} with local archive: $file ..."
|
||||
else
|
||||
podman stop "$1"
|
||||
podman pull "$img" || (echo "Failed fetching $img, check your network (settings)."; exit 1)
|
||||
fi
|
||||
"/var/lib/containers/active/${1}.sh" || (echo "Failed recreating container $1"; exit 1)
|
||||
;;
|
||||
volume)
|
||||
cmd=$1
|
||||
[ -n "$cmd" ] && shift
|
||||
case $cmd in
|
||||
prune)
|
||||
podman volume $force prune
|
||||
;;
|
||||
*)
|
||||
false
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,5 +1,3 @@
|
||||
# Allow users in wheel group to reboot and perform a factory reset
|
||||
/sbin/initctl f 4750 root wheel - - - - -
|
||||
/sbin/factory f 4750 root wheel - - - - -
|
||||
|
||||
/var/lib/avahi-autoipd d 0755 avahi avahi - - - - -
|
||||
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC1090
|
||||
. "$BR2_CONFIG" 2>/dev/null
|
||||
|
||||
# Drop Buildroot default symlink to /tmp
|
||||
if [ -L "$TARGET_DIR/var/lib/avahi-autoipd" ]; then
|
||||
rm "$TARGET_DIR/var/lib/avahi-autoipd"
|
||||
mkdir "$TARGET_DIR/var/lib/avahi-autoipd"
|
||||
fi
|
||||
|
||||
# Allow clish (symlink to /usr/bin/klish) to be a login shell
|
||||
grep -qsE '^/bin/clish$$' "$TARGET_DIR/etc/shells" \
|
||||
|| echo "/bin/clish" >> "$TARGET_DIR/etc/shells"
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This file is part of avahi.
|
||||
#
|
||||
# avahi is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# avahi is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
# License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with avahi; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
# USA.
|
||||
|
||||
set -e
|
||||
|
||||
# Command line arguments:
|
||||
# $1 event that happened:
|
||||
# BIND: Successfully claimed address
|
||||
# CONFLICT: An IP address conflict happened
|
||||
# UNBIND: The IP address is no longer needed
|
||||
# STOP: The daemon is terminating
|
||||
# $2 interface name
|
||||
# $3 IP adddress
|
||||
|
||||
PATH="$PATH:/usr/bin:/usr/sbin:/bin:/sbin"
|
||||
|
||||
# Use a different metric for each interface, so that we can set
|
||||
# identical routes to multiple interfaces.
|
||||
|
||||
METRIC=$((1000 + `cat "/sys/class/net/$2/ifindex" 2>/dev/null || echo 0`))
|
||||
|
||||
if [ -x /bin/ip -o -x /sbin/ip ] ; then
|
||||
|
||||
# We have the Linux ip tool from the iproute package
|
||||
|
||||
case "$1" in
|
||||
BIND)
|
||||
ip addr flush dev "$2" label "$2:avahi"
|
||||
ip addr add "$3"/16 brd 169.254.255.255 label "$2:avahi" scope link dev "$2" proto 6
|
||||
ip route add default dev "$2" metric "$METRIC" scope link proto 17 ||:
|
||||
;;
|
||||
|
||||
CONFLICT|UNBIND|STOP)
|
||||
ip route del default dev "$2" metric "$METRIC" scope link ||:
|
||||
ip addr del "$3"/16 brd 169.254.255.255 label "$2:avahi" scope link dev "$2"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown event $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
elif [ -x /bin/ifconfig -o -x /sbin/ifconfig ] ; then
|
||||
|
||||
# We have the old ifconfig tool
|
||||
|
||||
case "$1" in
|
||||
BIND)
|
||||
ifconfig "$2:avahi" inet "$3" netmask 255.255.0.0 broadcast 169.254.255.255 up
|
||||
route add default dev "$2:avahi" metric "$METRIC" ||:
|
||||
;;
|
||||
|
||||
CONFLICT|STOP|UNBIND)
|
||||
route del default dev "$2:avahi" metric "$METRIC" ||:
|
||||
ifconfig "$2:avahi" down
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown event $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
else
|
||||
|
||||
echo "No network configuration tool found." >&2
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
exit 0
|
||||
+33
-203
@@ -1,8 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import argparse
|
||||
import sys
|
||||
import re
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="JSON CLI Pretty Printer")
|
||||
parser.add_argument("module", help="IETF Module")
|
||||
parser.add_argument("-n", "--name", help="Focus on specific name")
|
||||
args = parser.parse_args()
|
||||
|
||||
class Pad:
|
||||
iface = 16
|
||||
@@ -10,12 +14,6 @@ class Pad:
|
||||
state = 12
|
||||
data = 41
|
||||
|
||||
class PadMdb:
|
||||
bridge = 7
|
||||
vlan = 6
|
||||
group = 20
|
||||
ports = 20
|
||||
|
||||
class PadRoute:
|
||||
prefix = 30
|
||||
protocol = 10
|
||||
@@ -29,12 +27,6 @@ class PadSoftware:
|
||||
state = 10
|
||||
version = 23
|
||||
|
||||
|
||||
class PadUsbPort:
|
||||
title = 30
|
||||
name = 20
|
||||
state = 10
|
||||
|
||||
class Decore():
|
||||
@staticmethod
|
||||
def decorate(sgr, txt, restore="0"):
|
||||
@@ -52,14 +44,6 @@ class Decore():
|
||||
def green(txt):
|
||||
return Decore.decorate("32", txt, "39")
|
||||
|
||||
@staticmethod
|
||||
def yellow(txt):
|
||||
return Decore.decorate("33", txt, "39")
|
||||
|
||||
@staticmethod
|
||||
def underline(txt):
|
||||
return Decore.decorate("4", txt, "24")
|
||||
|
||||
def get_json_data(default, indata, *args):
|
||||
data = indata
|
||||
for arg in args:
|
||||
@@ -70,12 +54,6 @@ def get_json_data(default, indata, *args):
|
||||
|
||||
return data
|
||||
|
||||
def remove_yang_prefix(key):
|
||||
parts = key.split(":", 1)
|
||||
if len(parts) > 1:
|
||||
return parts[1]
|
||||
return key
|
||||
|
||||
class Route:
|
||||
def __init__(self,data,ip):
|
||||
self.data = data
|
||||
@@ -149,18 +127,6 @@ class Software:
|
||||
print(f"SHA-256 : {self.hash}")
|
||||
print(f"Installed : {self.date}")
|
||||
|
||||
class USBport:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.name = data.get('name', '')
|
||||
self.state = get_json_data('', self.data, 'state', 'admin-state')
|
||||
|
||||
def print(self):
|
||||
#print(self.name)
|
||||
row = f"{self.name:<{PadUsbPort.name}}"
|
||||
row += f"{self.state:<{PadUsbPort.state}}"
|
||||
print(row)
|
||||
|
||||
class Iface:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
@@ -174,12 +140,6 @@ class Iface:
|
||||
self.speed = get_json_data('', self.data, 'ieee802-ethernet-interface:ethernet', 'speed')
|
||||
self.phys_address = data.get('phys-address', '')
|
||||
|
||||
self.br_mdb = get_json_data({}, self.data, 'infix-interfaces:bridge', 'multicast-filters')
|
||||
self.br_vlans = get_json_data({}, self.data, 'infix-interfaces:bridge', 'vlans', "vlan")
|
||||
self.bridge = get_json_data('', self.data, 'infix-interfaces:bridge-port', 'bridge')
|
||||
self.pvid = get_json_data('', self.data, 'infix-interfaces:bridge-port', 'pvid')
|
||||
self.stp_state = get_json_data('', self.data, 'infix-interfaces:bridge-port', 'stp-state')
|
||||
|
||||
if data.get('statistics'):
|
||||
self.in_octets = data.get('statistics').get('in-octets', '')
|
||||
self.out_octets = data.get('statistics').get('out-octets', '')
|
||||
@@ -199,6 +159,10 @@ class Iface:
|
||||
else:
|
||||
self.ipv6_addr = []
|
||||
|
||||
if self.data.get('infix-interfaces:bridge-port'):
|
||||
self.bridge = self.data.get('infix-interfaces:bridge-port').get('bridge', None)
|
||||
else:
|
||||
self.bridge = ''
|
||||
|
||||
if self.data.get('infix-interfaces:vlan'):
|
||||
self.lower_if = self.data.get('infix-interfaces:vlan', None).get('lower-layer-if',None)
|
||||
@@ -214,15 +178,10 @@ class Iface:
|
||||
def is_veth(self):
|
||||
return self.data['type'] == "infix-if-type:veth"
|
||||
|
||||
def oper(self, detail=False):
|
||||
"""Remap in brief overview to fit column widths."""
|
||||
if not detail and self.oper_status == "lower-layer-down":
|
||||
return "lower-down"
|
||||
return self.oper_status
|
||||
|
||||
def pr_name(self, pipe=""):
|
||||
print(f"{pipe}{self.name:<{Pad.iface - len(pipe)}}", end="")
|
||||
|
||||
|
||||
def pr_proto_ipv4(self, pipe=''):
|
||||
for addr in self.ipv4_addr:
|
||||
origin = f"({addr['origin']})" if addr.get('origin') else ""
|
||||
@@ -241,54 +200,17 @@ class Iface:
|
||||
row += f"{'':<{Pad.state}}{addr['ip']}/{addr['prefix-length']} {origin}"
|
||||
print(row)
|
||||
|
||||
def pr_proto_eth(self, pipe=''):
|
||||
row = ""
|
||||
if len(pipe) > 0:
|
||||
row = f"{pipe:<{Pad.iface}}"
|
||||
|
||||
row += f"{'ethernet':<{Pad.proto}}"
|
||||
dec = Decore.green if self.oper() == "up" else Decore.red
|
||||
row += dec(f"{self.oper().upper():<{Pad.state}}")
|
||||
def pr_proto_eth(self):
|
||||
row = f"{'ethernet':<{Pad.proto}}"
|
||||
dec = Decore.green if self.oper_status == "up" else Decore.red
|
||||
row += dec(f"{self.oper_status.upper():<{Pad.state}}")
|
||||
row += f"{self.phys_address:<{Pad.data}}"
|
||||
print(row)
|
||||
|
||||
def pr_proto_br(self, br_vlans):
|
||||
data_str = ""
|
||||
|
||||
row = f"{'bridge':<{Pad.proto}}"
|
||||
|
||||
if self.oper() == "up":
|
||||
dec = Decore.green if self.stp_state == "forwarding" else Decore.yellow
|
||||
row += dec(f"{self.stp_state.upper():<{Pad.state}}")
|
||||
else:
|
||||
row += Decore.red(f"{self.oper().upper():<{Pad.state}}")
|
||||
|
||||
for vlan in br_vlans:
|
||||
if 'tagged' in vlan:
|
||||
for tagged in vlan['tagged']:
|
||||
if tagged == self.name:
|
||||
if data_str:
|
||||
data_str += f",{vlan['vid']}t"
|
||||
else:
|
||||
data_str += f"vlan:{vlan['vid']}t"
|
||||
if 'untagged' in vlan:
|
||||
for untagged in vlan['untagged']:
|
||||
if untagged == self.name:
|
||||
if data_str:
|
||||
data_str += f",{vlan['vid']}u"
|
||||
else:
|
||||
data_str += f"vlan:{vlan['vid']}u"
|
||||
if self.pvid:
|
||||
data_str += f" pvid:{self.pvid}"
|
||||
|
||||
if data_str:
|
||||
row += f"{data_str:<{Pad.data}}"
|
||||
|
||||
print(row)
|
||||
|
||||
def pr_bridge(self, _ifaces):
|
||||
self.pr_name(pipe="")
|
||||
self.pr_proto_br(self.br_vlans)
|
||||
self.pr_proto_eth()
|
||||
|
||||
|
||||
lowers = []
|
||||
for _iface in [Iface(data) for data in _ifaces]:
|
||||
@@ -296,18 +218,16 @@ class Iface:
|
||||
lowers.append(_iface)
|
||||
|
||||
if lowers:
|
||||
self.pr_proto_eth(pipe='│')
|
||||
self.pr_proto_ipv4(pipe='│')
|
||||
self.pr_proto_ipv6(pipe='│')
|
||||
else:
|
||||
self.pr_proto_eth(pipe=' ')
|
||||
self.pr_proto_ipv4()
|
||||
self.pr_proto_ipv6()
|
||||
|
||||
for i, lower in enumerate(lowers):
|
||||
pipe = '└ ' if (i == len(lowers) -1) else '├ '
|
||||
lower.pr_name(pipe)
|
||||
lower.pr_proto_br(self.br_vlans)
|
||||
lower.pr_proto_eth()
|
||||
|
||||
def pr_veth(self, _ifaces):
|
||||
self.pr_name(pipe="")
|
||||
@@ -347,8 +267,8 @@ class Iface:
|
||||
print(f"{'index':<{20}}: {self.index}")
|
||||
if self.mtu:
|
||||
print(f"{'mtu':<{20}}: {self.mtu}")
|
||||
if self.oper():
|
||||
print(f"{'operational status':<{20}}: {self.oper(detail=True)}")
|
||||
if self.oper_status:
|
||||
print(f"{'operational status':<{20}}: {self.oper_status}")
|
||||
|
||||
if self.lower_if:
|
||||
print(f"{'lower-layer-if':<{20}}: {self.lower_if}")
|
||||
@@ -400,36 +320,10 @@ class Iface:
|
||||
frame = get_json_data([], self.data,'ieee802-ethernet-interface:ethernet',
|
||||
'statistics', 'frame')
|
||||
if frame:
|
||||
print("")
|
||||
print(f"")
|
||||
for key, val in frame.items():
|
||||
key = remove_yang_prefix(key)
|
||||
print(f"eth-{key:<{25}}: {val}")
|
||||
|
||||
def pr_mdb(self, bridge):
|
||||
for group in self.br_mdb.get("multicast-filter", {}):
|
||||
row = f"{bridge:<{PadMdb.bridge}}"
|
||||
row += f"{'':<{PadMdb.vlan}}"
|
||||
row += f"{group['group']:<{PadMdb.group}}"
|
||||
if (group.get("ports")):
|
||||
ports = ", ".join(port_dict["port"] for port_dict in group["ports"])
|
||||
else:
|
||||
ports = ""
|
||||
row += f"{ports}"
|
||||
print(row)
|
||||
|
||||
def pr_vlans_mdb(self, bridge):
|
||||
for vlan in self.br_vlans:
|
||||
filters=vlan.get("multicast-filters", {})
|
||||
for group in filters.get("multicast-filter", []):
|
||||
row = f"{bridge:<{PadMdb.bridge}}"
|
||||
row += f"{vlan['vid']:<{PadMdb.vlan}}"
|
||||
row += f"{group['group']:<{PadMdb.group}}"
|
||||
if (group.get("ports")):
|
||||
ports = ", ".join(port_dict["port"] for port_dict in group["ports"])
|
||||
else:
|
||||
ports = ""
|
||||
row += f"{ports}"
|
||||
print(row)
|
||||
|
||||
def find_iface(_ifaces, name):
|
||||
for _iface in [Iface(data) for data in _ifaces]:
|
||||
@@ -439,9 +333,6 @@ def find_iface(_ifaces, name):
|
||||
return False
|
||||
|
||||
|
||||
def version_sort(iface):
|
||||
return [int(x) if x.isdigit() else x for x in re.split(r'(\d+)', iface['name'])]
|
||||
|
||||
def pr_interface_list(json):
|
||||
hdr = (f"{'INTERFACE':<{Pad.iface}}"
|
||||
f"{'PROTOCOL':<{Pad.proto}}"
|
||||
@@ -450,7 +341,7 @@ def pr_interface_list(json):
|
||||
|
||||
print(Decore.invert(hdr))
|
||||
|
||||
ifaces = sorted(json["ietf-interfaces:interfaces"]["interface"], key=version_sort)
|
||||
ifaces = sorted(json["ietf-interfaces:interfaces"]["interface"], key=lambda x: x['name'])
|
||||
|
||||
for iface in [Iface(data) for data in ifaces]:
|
||||
if iface.is_bridge():
|
||||
@@ -476,7 +367,7 @@ def pr_interface_list(json):
|
||||
iface.pr_proto_ipv4()
|
||||
iface.pr_proto_ipv6()
|
||||
|
||||
def show_interfaces(json, name):
|
||||
def ietf_interfaces(json, name):
|
||||
if name:
|
||||
if not json.get("ietf-interfaces:interfaces"):
|
||||
print(f"No interface data found for \"{name}\"")
|
||||
@@ -485,34 +376,14 @@ def show_interfaces(json, name):
|
||||
if not iface:
|
||||
print(f"Interface \"{name}\" not found")
|
||||
sys.exit(1)
|
||||
else:
|
||||
iface.pr_iface()
|
||||
iface.pr_iface()
|
||||
else:
|
||||
if not json.get("ietf-interfaces:interfaces"):
|
||||
print(f"Error, top level \"ietf-interfaces:interfaces\" missing")
|
||||
sys.exit(1)
|
||||
pr_interface_list(json)
|
||||
|
||||
def show_bridge_mdb(json):
|
||||
header_printed = False
|
||||
if not json.get("ietf-interfaces:interfaces"):
|
||||
print(f"Error, top level \"ietf-interfaces:interface\" missing")
|
||||
sys.exit(1)
|
||||
ifaces = sorted(json["ietf-interfaces:interfaces"]["interface"], key=version_sort)
|
||||
for iface in [Iface(data) for data in ifaces]:
|
||||
if iface.type != "infix-if-type:bridge":
|
||||
continue
|
||||
if not header_printed:
|
||||
hdr = (f"{'BRIDGE':<{PadMdb.bridge}}"
|
||||
f"{'VID':<{PadMdb.vlan}}"
|
||||
f"{'GROUP':<{PadMdb.group}}"
|
||||
f"{'PORTS':<{PadMdb.ports}}")
|
||||
print(Decore.invert(hdr))
|
||||
header_printed = True
|
||||
iface.pr_mdb(iface.name)
|
||||
iface.pr_vlans_mdb(iface.name)
|
||||
|
||||
def show_routing_table(json, ip):
|
||||
def ietf_routing(json, ip="ipv4"):
|
||||
if not json.get("ietf-routing:routing"):
|
||||
print(f"Error, top level \"ietf-routing:routing\" missing")
|
||||
sys.exit(1)
|
||||
@@ -538,7 +409,7 @@ def find_slot(_slots, name):
|
||||
|
||||
return False
|
||||
|
||||
def show_software(json, name):
|
||||
def infix_system(json, name):
|
||||
if not json.get("ietf-system:system-state", "infix-system:software"):
|
||||
print("Error, cannot find infix-system:software")
|
||||
sys.exit(1)
|
||||
@@ -559,24 +430,6 @@ def show_software(json, name):
|
||||
if slot.is_rootfs():
|
||||
slot.print()
|
||||
|
||||
def show_hardware(json):
|
||||
if not json.get("ietf-hardware:hardware"):
|
||||
print(f"Error, top level \"ietf-hardware:component\" missing")
|
||||
sys.exit(1)
|
||||
|
||||
hdr = (f"{'USB PORTS':<{PadUsbPort.title}}")
|
||||
print(Decore.invert(hdr))
|
||||
hdr = (f"{'NAME':<{PadUsbPort.name}}"
|
||||
f"{'STATE':<{PadUsbPort.state}}")
|
||||
print(Decore.invert(hdr))
|
||||
|
||||
components = get_json_data({}, json, "ietf-hardware:hardware", "component")
|
||||
|
||||
for component in components:
|
||||
if component.get("class") == "infix-hardware:usb":
|
||||
port = USBport(component)
|
||||
port.print()
|
||||
|
||||
def main():
|
||||
try:
|
||||
json_data = json.load(sys.stdin)
|
||||
@@ -587,38 +440,15 @@ def main():
|
||||
print("Error, unexpected error parsing JSON")
|
||||
sys.exit(1)
|
||||
|
||||
parser = argparse.ArgumentParser(description="JSON CLI Pretty Printer")
|
||||
subparsers = parser.add_subparsers(dest='command', help='Commands')
|
||||
|
||||
parser_show_routing_table = subparsers.add_parser('show-routing-table', help='Show the routing table')
|
||||
parser_show_routing_table.add_argument('-i', '--ip', required=True, help='IPv4 or IPv6 address')
|
||||
|
||||
parser_show_interfaces = subparsers.add_parser('show-interfaces', help='Show interfaces')
|
||||
parser_show_interfaces.add_argument('-n', '--name', help='Interface name')
|
||||
|
||||
parser_show_bridge_mdb = subparsers.add_parser('show-bridge-mdb', help='Show bridge MDB')
|
||||
|
||||
parser_show_software = subparsers.add_parser('show-software', help='Show software versions')
|
||||
parser_show_software.add_argument('-n', '--name', help='Slotname')
|
||||
|
||||
parser_show_routing_table = subparsers.add_parser('show-hardware', help='Show USB ports')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == "show-interfaces":
|
||||
show_interfaces(json_data, args.name)
|
||||
elif args.command == "show-routing-table":
|
||||
show_routing_table(json_data, args.ip)
|
||||
elif args.command == "show-software":
|
||||
show_software(json_data, args.name)
|
||||
elif args.command == "show-bridge-mdb":
|
||||
show_bridge_mdb(json_data)
|
||||
elif args.command == "show-hardware":
|
||||
show_hardware(json_data)
|
||||
if args.module == "ietf-interfaces":
|
||||
sys.exit(ietf_interfaces(json_data, args.name))
|
||||
if args.module == "ietf-routing":
|
||||
sys.exit(ietf_routing(json_data, args.name))
|
||||
if args.module == "infix-system":
|
||||
sys.exit(infix_system(json_data, args.name))
|
||||
else:
|
||||
print(f"Error, unknown command {args.command}")
|
||||
print(f"Error, unknown module {args.module}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import json
|
||||
|
||||
def get_ethtool_output(interface):
|
||||
try:
|
||||
output = subprocess.check_output(['ethtool', interface], stderr=subprocess.DEVNULL, text=True)
|
||||
return output.splitlines()
|
||||
except subprocess.CalledProcessError:
|
||||
print("Error: Failed to run ethtool on interface", interface)
|
||||
sys.exit(1)
|
||||
|
||||
def parse_ethtool_output(lines, keys):
|
||||
result = {}
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
key = line.split(':', 1)[0].strip()
|
||||
if key in keys:
|
||||
key, value = line.split(':', 1)
|
||||
result[key.strip()] = value.strip()
|
||||
return result
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 2:
|
||||
print(f"Usage: {sys.argv[0]} INTERFACE")
|
||||
sys.exit(1)
|
||||
|
||||
interface = sys.argv[1]
|
||||
keys = ["Duplex", "Auto-negotiation"]
|
||||
|
||||
lines = get_ethtool_output(interface)
|
||||
parsed_data = parse_ethtool_output(lines, keys)
|
||||
|
||||
print(json.dumps(parsed_data, indent=4))
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/python3
|
||||
# This script is used to transform the output from the show ip ospf commands and order
|
||||
# them to match the ietf-ospf YANG model. For example, interfaces is ordered under
|
||||
# area but FRR has areas in interfaces.
|
||||
#
|
||||
# This makes the parsing for the operational parts of YANG model more easy
|
||||
#
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
iface_out=subprocess.check_output("vtysh -c 'show ip ospf interface json'", shell=True)
|
||||
ospf_out=subprocess.check_output("vtysh -c 'show ip ospf json'", shell=True)
|
||||
neighbor_out=subprocess.check_output("vtysh -c 'show ip ospf neighbor detail json'", shell=True)
|
||||
interfaces=json.loads(iface_out)
|
||||
ospf=json.loads(ospf_out)
|
||||
neighbors=json.loads(neighbor_out)
|
||||
|
||||
for ifname,iface in interfaces["interfaces"].items():
|
||||
iface["name"] = ifname
|
||||
iface["neighbors"] = []
|
||||
for area_id in ospf["areas"]:
|
||||
area_type=""
|
||||
|
||||
stub=False
|
||||
if("NSSA" in iface["area"]):
|
||||
iface_area_id = iface["area"][:-7]
|
||||
area_type = "nssa-area"
|
||||
elif("Stub" in iface["area"]):
|
||||
iface_area_id = iface["area"][:-7]
|
||||
iface["areaId"] = iface["area"][:-7]
|
||||
area_type = "stub-area"
|
||||
else:
|
||||
iface_area_id = iface["area"]
|
||||
area_type = "normal-area"
|
||||
|
||||
if(iface_area_id != area_id):
|
||||
continue
|
||||
|
||||
ospf["areas"][area_id]["area-type"] = area_type
|
||||
iface["area"] = iface_area_id
|
||||
|
||||
for nbrAddress,nbrDatas in neighbors["neighbors"].items():
|
||||
for nbrData in nbrDatas:
|
||||
nbrIfname=nbrData["ifaceName"].split(":")[0]
|
||||
if(("NSSA" in nbrData.get("areaId", {})) or ("Stub" in nbrData.get("areaId", {}))):
|
||||
nbrData["areaId"] = nbrData["areaId"][:-7]
|
||||
|
||||
if ((nbrIfname != ifname) and (area_id != nbrData.get("areaId"))):
|
||||
#print(f'Continute {ifname} {nbrData.get("areaId")}')
|
||||
continue
|
||||
nbrData["neighborIp"] = nbrAddress
|
||||
iface["neighbors"].append(nbrData)
|
||||
|
||||
if(not ospf["areas"][area_id].get("interfaces", None)):
|
||||
ospf["areas"][area_id]["interfaces"] = []
|
||||
ospf["areas"][area_id]["interfaces"].append(iface)
|
||||
|
||||
print(json.dumps(ospf))
|
||||
|
||||
@@ -40,13 +40,10 @@ class DTSystem:
|
||||
continue
|
||||
|
||||
ph, = struct.unpack(">L", open(phandle, "rb").read())
|
||||
if ph not in sys:
|
||||
sys[ph] = []
|
||||
sys[ph].append(root)
|
||||
sys[ph] = root
|
||||
|
||||
phs = set(list(dt.keys()) + list(sys.keys()))
|
||||
|
||||
self.devs = { ph: [Device(ph, dt.get(ph), s if s is not None else "") for s in (sys.get(ph) or []) if ph is not None] for ph in phs }
|
||||
self.devs = { ph: Device(ph, dt.get(ph), sys.get(ph)) for ph in phs }
|
||||
self.base = Device(0, None, DTSystem.BASE)
|
||||
self.infix = Device(0, None, DTSystem.INFIX)
|
||||
|
||||
@@ -59,7 +56,7 @@ class DTSystem:
|
||||
elems = len(data) // struct.calcsize(">L")
|
||||
return struct.unpack(">" + elems * "L", data)
|
||||
|
||||
def devices_from_ph(self, ph):
|
||||
def device_from_ph(self, ph):
|
||||
return self.devs.get(ph)
|
||||
|
||||
def into_vpd(self, dev):
|
||||
@@ -82,23 +79,12 @@ class DTSystem:
|
||||
"data": parse(),
|
||||
}
|
||||
|
||||
def infix_usb_devices(self, out):
|
||||
names=self.infix.str_array("usb-port-names", ())
|
||||
phs=self.__get_phandle_array("usb-ports")
|
||||
data=dict(zip(names,phs))
|
||||
if data != {}:
|
||||
out["usb-ports"] = []
|
||||
for name,ph in data.items():
|
||||
[out["usb-ports"].extend([{"name": name, "path": dev.attrpath("authorized")}, {"name": name, "path": dev.attrpath("authorized_default")}]) for dev in self.devices_from_ph(ph)]
|
||||
|
||||
|
||||
def infix_devices(self, kind):
|
||||
phs = self.__get_phandle_array(kind)
|
||||
return [[d for d in self.devices_from_ph(ph)] for ph in phs]
|
||||
return [self.device_from_ph(ph) for ph in phs]
|
||||
|
||||
def infix_vpds(self):
|
||||
flat_devices = [device for sublist in self.infix_devices("vpds") for device in sublist]
|
||||
return [self.into_vpd(device) for device in flat_devices]
|
||||
return [self.into_vpd(dev) for dev in self.infix_devices("vpds")]
|
||||
|
||||
class QEMUSystem:
|
||||
BASE = "/sys/firmware/qemu_fw_cfg"
|
||||
@@ -123,28 +109,6 @@ class QEMUSystem:
|
||||
def vpds(self):
|
||||
return [self.product_vpd()]
|
||||
|
||||
def usb_ports(self):
|
||||
ports = [
|
||||
{
|
||||
"name": "USB",
|
||||
"path": "/sys/bus/usb/devices/usb1/authorized"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "USB",
|
||||
"path": "/sys/bus/usb/devices/usb1/authorized_default"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "USB2",
|
||||
"path": "/sys/bus/usb/devices/usb2/authorized"
|
||||
},
|
||||
{
|
||||
"name": "USB2",
|
||||
"path": "/sys/bus/usb/devices/usb2/authorized_default"
|
||||
|
||||
}]
|
||||
return ports
|
||||
class Device:
|
||||
def __init__(self, ph, dtpath, syspath):
|
||||
self.ph, self.dtpath, self.syspath = ph, dtpath, syspath
|
||||
@@ -179,9 +143,6 @@ class Device:
|
||||
val = self.attr(attr)
|
||||
return val.decode("utf-8").strip("\0") if val else default
|
||||
|
||||
def str_array(self, attr, default=None):
|
||||
val = self.attr(attr)
|
||||
return val.decode("utf-8").strip("\0").split("\0") if val else default
|
||||
|
||||
def dtattrpath(self, attr):
|
||||
return os.path.join(self.dtpath, attr)
|
||||
@@ -238,9 +199,8 @@ def probe_qemusystem(out):
|
||||
|
||||
qsys = QEMUSystem()
|
||||
vpds = qsys.vpds()
|
||||
usb_ports = qsys.usb_ports()
|
||||
vpd_inject(out, vpds)
|
||||
out["usb-ports"] = usb_ports
|
||||
|
||||
for (attr, default) in (
|
||||
("vendor", "QEMU"),
|
||||
("product-name", "VM"),
|
||||
@@ -261,7 +221,7 @@ def probe_qemusystem(out):
|
||||
def probe_dtsystem(out):
|
||||
dtsys = DTSystem()
|
||||
vpds = dtsys.infix_vpds()
|
||||
dtsys.infix_usb_devices(out)
|
||||
|
||||
model = dtsys.base.str("model")
|
||||
if model:
|
||||
out["product-name"] = model
|
||||
+5
-6
@@ -1,7 +1,6 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
. /etc/partion-uuid
|
||||
set -e
|
||||
|
||||
disk=$1
|
||||
bootoffs=$2
|
||||
@@ -9,7 +8,7 @@ bootoffs=$2
|
||||
bootsize=8M
|
||||
auxsize=8M
|
||||
|
||||
total=$(awk -vdisk="$(basename $disk)" '$4 == disk { print(int($3 / 1024)); }' /proc/partitions)
|
||||
total=$(awk -vdisk="$(basename $disk)" '$4 == disk { print($3 / 1024); }' /proc/partitions)
|
||||
if [ "$total" -ge 4096 ]; then
|
||||
imgsize=1024M
|
||||
cfgsize=512M
|
||||
@@ -30,9 +29,9 @@ fi
|
||||
sgdisk \
|
||||
-o \
|
||||
-n1:${bootoffs}:+${bootsize} -t1:8301 -c1:boot \
|
||||
-n2::+${auxsize} -t2:8301 -c2:aux -u2:${AUX_UUID}\
|
||||
-n3::+${imgsize} -t3:8300 -c3:primary -u3:${PRIMARY_UUID} \
|
||||
-n4::+${imgsize} -t4:8300 -c4:secondary -u4:${SECONDARY_UUID}\
|
||||
-n2::+${auxsize} -t2:8301 -c2:aux \
|
||||
-n3::+${imgsize} -t3:8300 -c3:primary \
|
||||
-n4::+${imgsize} -t4:8300 -c4:secondary \
|
||||
-n5::+${cfgsize} -t5:8302 -c5:cfg \
|
||||
-n6:: -t6:8310 -c6:var \
|
||||
-p \
|
||||
Executable
+633
@@ -0,0 +1,633 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import sys # (built-in module)
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
|
||||
def json_get_yang_type(iface_in):
|
||||
if iface_in['link_type'] == "loopback":
|
||||
return "infix-if-type:loopback"
|
||||
|
||||
if iface_in['link_type'] != "ether":
|
||||
return "infix-if-type:other";
|
||||
|
||||
if not 'linkinfo' in iface_in:
|
||||
return "infix-if-type:ethernet"
|
||||
|
||||
if not 'info_kind' in iface_in['linkinfo']:
|
||||
return "infix-if-type:ethernet";
|
||||
|
||||
if iface_in['linkinfo']['info_kind'] == "veth":
|
||||
return "infix-if-type:veth";
|
||||
|
||||
if iface_in['linkinfo']['info_kind'] == "vlan":
|
||||
return "infix-if-type:vlan";
|
||||
|
||||
if iface_in['linkinfo']['info_kind'] == "bridge":
|
||||
return "infix-if-type:bridge";
|
||||
|
||||
if iface_in['linkinfo']['info_kind'] == "dsa":
|
||||
return "infix-if-type:ethernet";
|
||||
|
||||
# Fallback
|
||||
return "infix-if-type:ethernet";
|
||||
|
||||
def json_get_yang_origin(addr):
|
||||
map = {
|
||||
"kernel_ll": "link-layer",
|
||||
"kernel_ra": "link-layer",
|
||||
"static": "static",
|
||||
"dhcp": "dhcp",
|
||||
"random": "random",
|
||||
}
|
||||
proto = addr['protocol']
|
||||
|
||||
if proto == "kernel_ll" or proto == "kernel_ra":
|
||||
if "stable-privacy" in addr:
|
||||
return "random"
|
||||
|
||||
return map.get(proto, "other")
|
||||
|
||||
def get_proc_value(procfile):
|
||||
try:
|
||||
with open(procfile, 'r') as file:
|
||||
data = file.read().strip()
|
||||
return data
|
||||
except FileNotFoundError:
|
||||
# This is considered OK
|
||||
return None
|
||||
except IOError:
|
||||
print(f"Error: reading from {procfile}", file=sys.stderr)
|
||||
|
||||
# This function returns a value from a nested json dict
|
||||
def lookup(json, *keys):
|
||||
curr = json
|
||||
for key in keys:
|
||||
if isinstance(curr, dict) and key in curr:
|
||||
curr = curr[key]
|
||||
else:
|
||||
return None
|
||||
return curr
|
||||
|
||||
# This function inserts a value into a nested json dict
|
||||
def insert(json, *path_and_value):
|
||||
if len(path_and_value) < 2:
|
||||
raise ValueError("Error: insert() takes at least two args")
|
||||
|
||||
*path, value = path_and_value
|
||||
|
||||
curr = json
|
||||
for key in path[:-1]:
|
||||
if key not in curr or not isinstance(curr[key], dict):
|
||||
curr[key] = {}
|
||||
curr = curr[key]
|
||||
|
||||
curr[path[-1]] = value
|
||||
|
||||
def run_cmd(cmd):
|
||||
try:
|
||||
output = subprocess.check_output(cmd, stderr=subprocess.DEVNULL, text=True)
|
||||
return output.splitlines()
|
||||
except subprocess.CalledProcessError:
|
||||
print(f"Error: command returned error", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def run_json_cmd(cmd):
|
||||
try:
|
||||
result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, text=True)
|
||||
output = result.stdout
|
||||
data = json.loads(output)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error: unable to get data:", file=sys.stderr)
|
||||
print(f"{e.stderr}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Error: parsing JSON output: {e.msg}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return data
|
||||
|
||||
def iface_is_dsa(iface_in):
|
||||
if not "linkinfo" in iface_in:
|
||||
return False
|
||||
if not "info_kind" in iface_in['linkinfo']:
|
||||
return False
|
||||
if iface_in['linkinfo']['info_kind'] != "dsa":
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_vpd_vendor_extensions(data):
|
||||
vendor_extensions=[]
|
||||
for ext in data:
|
||||
vendor_extension = {}
|
||||
vendor_extension["iana-enterprise-number"] = ext[0]
|
||||
vendor_extension["extension-data"] = ext[1]
|
||||
vendor_extensions.append(vendor_extension)
|
||||
return vendor_extensions
|
||||
|
||||
def get_vpd_data(vpd):
|
||||
component={}
|
||||
component["name"]=vpd.get("board")
|
||||
component["infix-hardware:vpd-data"] = {}
|
||||
|
||||
if vpd.get("data"):
|
||||
if vpd["data"].get("manufacture-date"):
|
||||
component["mfg-date"]=datetime.strptime(vpd["data"]["manufacture-date"],"%m/%d/%Y %H:%M:%S").strftime("%Y-%m-%-dT%H:%M:%SZ")
|
||||
if vpd["data"].get("manufacter"):
|
||||
component["mfg-name"]=vpd["data"]["manufacturer"]
|
||||
if vpd["data"].get("product-name"):
|
||||
component["model-name"]=vpd["data"]["product-name"]
|
||||
if vpd["data"].get("serial-number"):
|
||||
component["serial-num"]=vpd["data"]["serial-number"]
|
||||
|
||||
# Set VPD-data entrys
|
||||
for k,v in vpd["data"].items():
|
||||
if vpd["data"].get(k):
|
||||
if k != "vendor-extension":
|
||||
component["infix-hardware:vpd-data"][k] = v
|
||||
else:
|
||||
vendor_extensions=get_vpd_vendor_extensions(v)
|
||||
component["infix-hardware:vpd-data"]["infix-hardware:vendor-extension"] = vendor_extensions
|
||||
return component
|
||||
|
||||
def add_hardware(hw_out, test):
|
||||
cmd = ['cat', "/run/system.json"]
|
||||
data = run_json_cmd(cmd)
|
||||
components=[]
|
||||
for _,vpd in data.get("vpd").items():
|
||||
component=get_vpd_data(vpd)
|
||||
components.append(component)
|
||||
insert(hw_out, "component", components)
|
||||
|
||||
def get_routes(routes, proto, data):
|
||||
out={}
|
||||
out["route"] = []
|
||||
|
||||
if(proto == "ipv4"):
|
||||
default = "0.0.0.0/0"
|
||||
host_prefix_length="32"
|
||||
else:
|
||||
default = "::/0"
|
||||
host_prefix_length="128"
|
||||
for d in data:
|
||||
new = {}
|
||||
if(d['dst'] == "default"):
|
||||
d['dst'] = default
|
||||
if(d['dst'].find('/') == -1):
|
||||
d['dst'] = d['dst']+"/"+host_prefix_length
|
||||
new[f'ietf-{proto}-unicast-routing:destination-prefix'] = d['dst']
|
||||
new['source-protocol'] = "infix-routing:"+d['protocol']
|
||||
if d.get("metric"):
|
||||
new['route-preference'] = d['metric']
|
||||
else:
|
||||
new['route-preference'] = 0
|
||||
|
||||
if d.get('nexthops'):
|
||||
next_hops = []
|
||||
for n in d.get('nexthops'):
|
||||
next_hop = {}
|
||||
if(n.get("dev")):
|
||||
next_hop['outgoing-interface'] = n['dev']
|
||||
if(n.get("gateway")):
|
||||
next_hop[f'ietf-{proto}-unicast-routing:address'] = n['gateway']
|
||||
next_hops.append(next_hop)
|
||||
insert(new,'next-hop','next-hop-list','next-hop',next_hops)
|
||||
else:
|
||||
next_hop = {}
|
||||
if d['type'] == "blackhole":
|
||||
next_hop['special-next-hop'] = "blackhole"
|
||||
if d['type'] == "unreachable":
|
||||
next_hop['special-next-hop'] = "unreachable"
|
||||
if d['type'] == "unicast":
|
||||
if(d.get("dev")):
|
||||
next_hop['outgoing-interface'] = d['dev']
|
||||
if(d.get("gateway")):
|
||||
next_hop[f'ietf-{proto}-unicast-routing:next-hop-address'] = d['gateway']
|
||||
new['next-hop'] = next_hop
|
||||
|
||||
out['route'].append(new)
|
||||
insert(routes, 'routes', out)
|
||||
|
||||
def add_ipv4_route(routes, test):
|
||||
if test:
|
||||
cmd = ['cat', f"{test}/ip-4-route.json"]
|
||||
else:
|
||||
cmd = ['ip', '-4', '-s', '-d', '-j', 'route']
|
||||
|
||||
data = run_json_cmd(cmd)
|
||||
get_routes(routes, "ipv4", data)
|
||||
|
||||
def add_ipv6_route(routes, test):
|
||||
if test:
|
||||
cmd = ['cat', f"{test}/ip-6-route.json"]
|
||||
else:
|
||||
cmd = ['ip', '-6', '-s', '-d', '-j', 'route']
|
||||
data = run_json_cmd(cmd)
|
||||
get_routes(routes, "ipv6", data)
|
||||
|
||||
def frr_to_ietf_neighbor_state(state):
|
||||
state=state.split("/")[0]
|
||||
if(state == "TwoWay"):
|
||||
return "2-way"
|
||||
return state.lower()
|
||||
|
||||
def add_ospf_routes(ospf):
|
||||
cmd = ['vtysh', '-c', "show ip ospf rout json"]
|
||||
data = run_json_cmd(cmd)
|
||||
routes=[]
|
||||
for prefix,info in data.items():
|
||||
if(prefix.find("/") == -1): # Ignore router IDs
|
||||
continue
|
||||
|
||||
route={}
|
||||
route["prefix"] = prefix
|
||||
|
||||
nexthops=[]
|
||||
routetype=info["routeType"].split(" ")
|
||||
if(len(routetype) > 1):
|
||||
if(routetype[1]=="E1"):
|
||||
route["route-type"] = "external-1"
|
||||
elif(routetype[1]=="E2"):
|
||||
route["route-type"] = "external-2"
|
||||
elif(routetype[1]=="IA"):
|
||||
route["route-type"] = "inter-area"
|
||||
elif(routetype[0] == "N"):
|
||||
route["route-type"] = "intra-area"
|
||||
for hop in info["nexthops"]:
|
||||
nexthop={}
|
||||
if(hop["ip"] != " "):
|
||||
nexthop["next-hop"] = hop["ip"]
|
||||
else:
|
||||
nexthop["outgoing-interface"] = hop["directlyAttachedTo"]
|
||||
nexthops.append(nexthop)
|
||||
route["next-hops"] = {}
|
||||
route["next-hops"]["next-hop"] = nexthops
|
||||
routes.append(route)
|
||||
insert(ospf, "ietf-ospf:local-rib", "ietf-ospf:route", routes)
|
||||
|
||||
def add_ospf(ospf):
|
||||
cmd = ['/libexec/infix/ospf-status']
|
||||
data = run_json_cmd(cmd)
|
||||
ospf["ietf-ospf:router-id"] = data["routerId"]
|
||||
ospf["ietf-ospf:address-family"] = "ipv4"
|
||||
areas=[]
|
||||
|
||||
for area_id,values in data["areas"].items():
|
||||
area={}
|
||||
area["ietf-ospf:area-id"] = area_id
|
||||
area["ietf-ospf:interfaces"] = {}
|
||||
if values.get("area-type"):
|
||||
area["ietf-ospf:area-type"] = values["area-type"]
|
||||
interfaces=[]
|
||||
for iface in values.get("interfaces", {}):
|
||||
interface={}
|
||||
interface["ietf-ospf:neighbors"] = {}
|
||||
interface["name"]=iface["name"]
|
||||
if(iface.get("drId")):
|
||||
interface["dr-router-id"]=iface["drId"]
|
||||
if(iface.get("drAddress")):
|
||||
interface["dr-ip-addr"]=iface["drAddress"]
|
||||
if(iface.get("bdrId")):
|
||||
interface["bdr-router-id"]=iface["bdrId"]
|
||||
if(iface.get("bdrAddress")):
|
||||
interface["bdr-ip-addr"]=iface["bdrAddress"]
|
||||
if(iface.get("timerPassiveIface")):
|
||||
interface["passive"] = True
|
||||
else:
|
||||
interface["passive"] = False
|
||||
interface["enabled"] = iface["ospfEnabled"]
|
||||
if(iface["networkType"] == "POINTOPOINT"):
|
||||
interface["interface-type"] = "point-to-point"
|
||||
if(iface["networkType"] == "BROADCAST"):
|
||||
interface["interface-type"] = "broadcast"
|
||||
|
||||
if iface.get("state"):
|
||||
map = {
|
||||
"DependUpon": "down", # Do not know what this is, never seen it and no entry in yang, but it listed before down in list in frr
|
||||
"Down": "down",
|
||||
"Waiting": "waiting",
|
||||
"Loopback": "loopback",
|
||||
"Point-To-Point": "point-to-point",
|
||||
"DROther": "dr-other",
|
||||
"Backup": "bdr",
|
||||
"DR": "dr"
|
||||
}
|
||||
val = map.get(iface["state"], "unknown")
|
||||
interface["state"] = val
|
||||
|
||||
neighbors = []
|
||||
for neigh in iface["neighbors"]:
|
||||
neighbor={}
|
||||
neighbor["neighbor-router-id"] = neigh["neighborIp"]
|
||||
neighbor["address"] = neigh["ifaceAddress"]
|
||||
neighbor["dr-router-id"] = neigh["routerDesignatedId"]
|
||||
neighbor["bdr-router-id"] = neigh["routerDesignatedBackupId"]
|
||||
neighbor["dead-timer"] = neigh["routerDeadIntervalTimerDueMsec"]
|
||||
neighbor["state"]=frr_to_ietf_neighbor_state(neigh["nbrState"])
|
||||
neighbors.append(neighbor)
|
||||
interface["ietf-ospf:neighbors"] = {}
|
||||
interface["ietf-ospf:neighbors"]["ietf-ospf:neighbor"] = neighbors
|
||||
interfaces.append(interface)
|
||||
area["ietf-ospf:interfaces"]["ietf-ospf:interface"] = interfaces
|
||||
areas.append(area)
|
||||
insert(ospf, "ietf-ospf:areas", "area", areas)
|
||||
add_ospf_routes(ospf)
|
||||
|
||||
def add_ip_link(ifname, iface_out, test):
|
||||
if test:
|
||||
cmd = ['cat', f"{test}/ip-link-show-dev-{ifname}.json"]
|
||||
else:
|
||||
cmd = ['ip', '-s', '-d', '-j', 'link', 'show', 'dev', ifname]
|
||||
|
||||
data = run_json_cmd(cmd)
|
||||
if len(data) != 1:
|
||||
print(f"Error: expected ip link output to be array with length 1", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
iface_in = data[0]
|
||||
|
||||
if 'ifname' in iface_in:
|
||||
iface_out['name'] = iface_in['ifname']
|
||||
|
||||
if 'ifindex' in iface_in:
|
||||
iface_out['if-index'] = iface_in['ifindex']
|
||||
|
||||
if 'address' in iface_in:
|
||||
iface_out['phys-address'] = iface_in['address']
|
||||
|
||||
if 'master' in iface_in:
|
||||
insert(iface_out, "infix-interfaces:bridge-port", "bridge", iface_in['master'])
|
||||
|
||||
if 'link' in iface_in and not iface_is_dsa(iface_in):
|
||||
insert(iface_out, "infix-interfaces:vlan", "lower-layer-if", iface_in['link'])
|
||||
|
||||
if 'operstate' in iface_in:
|
||||
map = {
|
||||
"DOWN": "down",
|
||||
"UP": "up",
|
||||
"DORMANT": "dormant",
|
||||
"TESTING": "testing",
|
||||
"LOWERLAYERDOWN": "lower-layer-down",
|
||||
"NOTPRESENT": "not-present"
|
||||
}
|
||||
val = map.get(iface_in['operstate'], "unknown")
|
||||
iface_out['oper-status'] = val
|
||||
|
||||
if 'link_type' in iface_in:
|
||||
val = json_get_yang_type(iface_in)
|
||||
iface_out['type'] = val
|
||||
|
||||
val = lookup(iface_in, "stats64", "rx", "bytes")
|
||||
if val is not None:
|
||||
insert(iface_out, "statistics", "out-octets", str(val))
|
||||
|
||||
val = lookup(iface_in, "stats64", "tx", "bytes")
|
||||
if val is not None:
|
||||
insert(iface_out, "statistics", "in-octets", str(val))
|
||||
|
||||
def add_ip_addr(ifname, iface_out, test):
|
||||
if test:
|
||||
cmd = ['cat', f"{test}/ip-addr-show-dev-{ifname}.json"]
|
||||
else:
|
||||
cmd = ['ip', '-j', 'addr', 'show', 'dev', ifname]
|
||||
|
||||
data = run_json_cmd(cmd)
|
||||
if len(data) != 1:
|
||||
print(f"Error: expected ip addr output to be array with length 1", file=sys.stderr)
|
||||
sys,exit(1)
|
||||
|
||||
iface_in = data[0]
|
||||
|
||||
if 'mtu' in iface_in and ifname != "lo":
|
||||
insert(iface_out, "ietf-ip:ipv4", "mtu", iface_in['mtu'])
|
||||
|
||||
# We avoid importing os to check if the file exists (for performance)
|
||||
val = get_proc_value(f"/proc/sys/net/ipv6/conf/{ifname}/mtu")
|
||||
if val is not None:
|
||||
insert(iface_out, "ietf-ip:ipv6", "mtu", int(val))
|
||||
|
||||
if 'addr_info' in iface_in:
|
||||
inet = []
|
||||
inet6 = []
|
||||
|
||||
for addr in iface_in['addr_info']:
|
||||
new = {}
|
||||
|
||||
if not 'family' in addr:
|
||||
print(f"Error: 'family' missing from 'addr_info'", file=sys.stderr)
|
||||
continue
|
||||
|
||||
if 'local' in addr:
|
||||
new['ip'] = addr['local']
|
||||
if 'prefixlen' in addr:
|
||||
new['prefix-length'] = addr['prefixlen']
|
||||
if 'protocol' in addr:
|
||||
new['origin'] = json_get_yang_origin(addr)
|
||||
|
||||
if addr['family'] == "inet":
|
||||
inet.append(new)
|
||||
elif addr['family'] == "inet6":
|
||||
inet6.append(new)
|
||||
else:
|
||||
print(f"Error: invalid 'family' in 'addr_info'", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
insert(iface_out, "ietf-ip:ipv4", "address", inet)
|
||||
insert(iface_out, "ietf-ip:ipv6", "address", inet6)
|
||||
|
||||
def add_ethtool_groups(ifname, iface_out, test):
|
||||
if test:
|
||||
cmd = ['cat', f"{test}/ethtool-groups-{ifname}.json"]
|
||||
else:
|
||||
cmd = ['ethtool', '--json', '-S', ifname, '--all-groups']
|
||||
|
||||
data = run_json_cmd(cmd)
|
||||
if len(data) != 1:
|
||||
print(f"Error: expected ethtool groups output to be array with length 1", file=sys.stderr)
|
||||
sys,exit(1)
|
||||
|
||||
iface_in = data[0]
|
||||
|
||||
# TODO: room for improvement here, the "frame" creation could be more dynamic.
|
||||
if "eth-mac" in iface_in or "rmon" in iface_in:
|
||||
insert(iface_out, "ieee802-ethernet-interface:ethernet", "statistics", "frame", {})
|
||||
frame = iface_out['ieee802-ethernet-interface:ethernet']['statistics']['frame']
|
||||
|
||||
if "eth-mac" in iface_in:
|
||||
mac_in = iface_in['eth-mac']
|
||||
|
||||
if "FramesTransmittedOK" in mac_in:
|
||||
frame['out-frames'] = str(mac_in['FramesTransmittedOK'])
|
||||
if "MulticastFramesXmittedOK" in mac_in:
|
||||
frame['out-multicast-frames'] = str(mac_in['MulticastFramesXmittedOK'])
|
||||
if "BroadcastFramesXmittedOK" in mac_in:
|
||||
frame['out-broadcast-frames'] = str(mac_in['BroadcastFramesXmittedOK'])
|
||||
if "FramesReceivedOK" in mac_in:
|
||||
frame['in-frames'] = str(mac_in['FramesReceivedOK'])
|
||||
if "MulticastFramesReceivedOK" in mac_in:
|
||||
frame['in-multicast-frames'] = str(mac_in['MulticastFramesReceivedOK'])
|
||||
if "BroadcastFramesReceivedOK" in mac_in:
|
||||
frame['in-broadcast-frames'] = str(mac_in['BroadcastFramesReceivedOK'])
|
||||
if "FrameCheckSequenceErrors" in mac_in:
|
||||
frame['in-error-fcs-frames'] = str(mac_in['FrameCheckSequenceErrors'])
|
||||
if "FramesLostDueToIntMACRcvError" in mac_in:
|
||||
frame['in-error-mac-internal-frames'] = str(mac_in['FramesLostDueToIntMACRcvError'])
|
||||
|
||||
tot = 0
|
||||
found = False
|
||||
if "FramesReceivedOK" in mac_in:
|
||||
tot += mac_in['FramesReceivedOK']
|
||||
found = True
|
||||
if "FrameCheckSequenceErrors" in mac_in:
|
||||
tot += mac_in['FrameCheckSequenceErrors']
|
||||
found = True
|
||||
if "FramesLostDueToIntMACRcvError" in mac_in:
|
||||
tot += mac_in['FramesLostDueToIntMACRcvError']
|
||||
found = True
|
||||
if "AlignmentErrors" in mac_in:
|
||||
tot += mac_in['AlignmentErrors']
|
||||
found = True
|
||||
if "etherStatsOversizePkts" in mac_in:
|
||||
tot += mac_in['etherStatsOversizePkts']
|
||||
found = True
|
||||
if "etherStatsJabbers" in mac_in:
|
||||
tot += mac_in['etherStatsJabbers']
|
||||
found = True
|
||||
if found:
|
||||
frame['in-total-frames'] = str(tot)
|
||||
|
||||
if "rmon" in iface_in:
|
||||
rmon_in = iface_in['rmon']
|
||||
|
||||
if "undersize_pkts" in rmon_in:
|
||||
frame['in-error-undersize-frames'] = str(rmon_in['undersize_pkts'])
|
||||
|
||||
tot = 0
|
||||
found = False
|
||||
if "etherStatsJabbers" in rmon_in:
|
||||
tot += rmon_in['etherStatsJabbers']
|
||||
found = True
|
||||
if "etherStatsOversizePkts" in rmon_in:
|
||||
tot += rmon_in['etherStatsOversizePkts']
|
||||
found = True
|
||||
if found:
|
||||
frame['in-error-oversize-frames'] = str(tot)
|
||||
|
||||
def add_ethtool_std(ifname, iface_out, test):
|
||||
keys = ['Speed', 'Duplex', 'Auto-negotiation']
|
||||
result = {}
|
||||
|
||||
if test:
|
||||
cmd = ['cat', f"{test}/ethtool-{ifname}.txt"]
|
||||
else:
|
||||
cmd = ['ethtool', ifname]
|
||||
|
||||
lines = run_cmd(cmd)
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
key = line.split(':', 1)[0].strip()
|
||||
if key in keys:
|
||||
key, value = line.split(':', 1)
|
||||
result[key.strip()] = value.strip()
|
||||
|
||||
if "Auto-negotiation" in result:
|
||||
if result['Auto-negotiation'] == "on":
|
||||
insert(iface_out, "ieee802-ethernet-interface:ethernet", "auto-negotiation", "enable", True)
|
||||
else:
|
||||
insert(iface_out, "ieee802-ethernet-interface:ethernet", "auto-negotiation", "enable", False)
|
||||
|
||||
if "Duplex" in result:
|
||||
if result['Duplex'] == "Half":
|
||||
insert(iface_out, "ieee802-ethernet-interface:ethernet", "duplex", "half")
|
||||
elif result['Duplex'] == "Full":
|
||||
insert(iface_out, "ieee802-ethernet-interface:ethernet", "duplex", "full")
|
||||
else:
|
||||
insert(iface_out, "ieee802-ethernet-interface:ethernet", "duplex", "unknown")
|
||||
|
||||
if "Speed" in result and result['Speed'] != "Unknown!":
|
||||
# Avoid importing re (performance)
|
||||
num = ''.join(filter(str.isdigit, result['Speed']))
|
||||
if num:
|
||||
num = round((int(num) / 1000), 3)
|
||||
insert(iface_out, "ieee802-ethernet-interface:ethernet", "speed", str(num))
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
parser = argparse.ArgumentParser(description="YANG data creator")
|
||||
parser.add_argument("model", help="IETF Model")
|
||||
parser.add_argument("-p", "--param", default=None, help="Model dependant parameter")
|
||||
parser.add_argument("-t", "--test", default=None, help="Test data base path")
|
||||
args = parser.parse_args()
|
||||
|
||||
if (args.model == 'ietf-interfaces'):
|
||||
# For now, we handle each interface separately, as this is how it's
|
||||
# currently implemented in sysrepo. I.e sysrepo will subscribe to
|
||||
# each individual interface and query it for YANG data.
|
||||
|
||||
if not args.param:
|
||||
print(f"usage: yanger ietf-interfaces -p INTERFACE", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
yang_data = {
|
||||
"ietf-interfaces:interfaces": {
|
||||
"interface": [{}]
|
||||
}
|
||||
}
|
||||
|
||||
ifname = args.param
|
||||
iface_out = yang_data['ietf-interfaces:interfaces']['interface'][0]
|
||||
|
||||
add_ip_link(ifname, iface_out, args.test)
|
||||
add_ip_addr(ifname, iface_out, args.test)
|
||||
add_ethtool_groups(ifname, iface_out, args.test)
|
||||
add_ethtool_std(ifname, iface_out, args.test)
|
||||
elif (args.model == 'ietf-routing'):
|
||||
yang_data = {
|
||||
"ietf-routing:routing": {
|
||||
"ribs": {
|
||||
"rib": [{
|
||||
"name": "ipv4",
|
||||
"address-family": "ipv4"
|
||||
},
|
||||
{
|
||||
"name": "ipv6",
|
||||
"address-family": "ipv6"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ipv4routes = yang_data['ietf-routing:routing']['ribs']['rib'][0]
|
||||
ipv6routes = yang_data['ietf-routing:routing']['ribs']['rib'][1]
|
||||
add_ipv4_route(ipv4routes, args.test)
|
||||
add_ipv6_route(ipv6routes, args.test)
|
||||
elif (args.model == 'ietf-ospf'):
|
||||
yang_data = {
|
||||
"ietf-routing:routing": {
|
||||
"control-plane-protocols": {
|
||||
"control-plane-protocol": [
|
||||
{
|
||||
"type": "ietf-ospf:ospfv2",
|
||||
"name": "default",
|
||||
"ietf-ospf:ospf": {
|
||||
"ietf-ospf:areas":
|
||||
{
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
add_ospf(yang_data['ietf-routing:routing']['control-plane-protocols']['control-plane-protocol'][0]["ietf-ospf:ospf"])
|
||||
elif (args.model == 'ietf-hardware'):
|
||||
yang_data = {
|
||||
"ietf-hardware:hardware": {
|
||||
}
|
||||
}
|
||||
add_hardware(yang_data["ietf-hardware:hardware"], args.test)
|
||||
else:
|
||||
print(f"Unsupported model {args.model}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
print(json.dumps(yang_data, indent=2))
|
||||
@@ -0,0 +1 @@
|
||||
/var/lib/avahi-autoipd d 0755 avahi avahi - - - - -
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user