mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-26 18:53:01 +02:00
Compare commits
204
Commits
v24.04.2
...
v24.06.0-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a672074cef | ||
|
|
8f8766c340 | ||
|
|
46598a875d | ||
|
|
d523e588d6 | ||
|
|
269c0f2b00 | ||
|
|
53c079e1b2 | ||
|
|
10744c5116 | ||
|
|
edaaa33ddc | ||
|
|
31a30c736a | ||
|
|
5a3897b1aa | ||
|
|
1fac47a728 | ||
|
|
f1585476da | ||
|
|
d27153ea95 | ||
|
|
e3cd981830 | ||
|
|
3b8505f8c4 | ||
|
|
3feea4d9e2 | ||
|
|
91c55ddeb8 | ||
|
|
4a3559d88f | ||
|
|
d340ba7407 | ||
|
|
b790c46dc4 | ||
|
|
b57353294f | ||
|
|
c05ed73ff5 | ||
|
|
4cc23092b2 | ||
|
|
2919c23fde | ||
|
|
df7dab5951 | ||
|
|
dd0f1610ab | ||
|
|
29f56eb384 | ||
|
|
ba4d4caeb3 | ||
|
|
0595628e97 | ||
|
|
095b256971 | ||
|
|
ef09c65f40 | ||
|
|
2ecb6922a0 | ||
|
|
4c3a46b288 | ||
|
|
95a5f153df | ||
|
|
afbe5ca20b | ||
|
|
0edc2d5b70 | ||
|
|
56a5388242 | ||
|
|
4202c07926 | ||
|
|
3e045e62b1 | ||
|
|
773b229749 | ||
|
|
dcdc2ba24d | ||
|
|
3e7340cb52 | ||
|
|
ed88a92fac | ||
|
|
3aead122ee | ||
|
|
067c911640 | ||
|
|
935bb0d808 | ||
|
|
170392cdb1 | ||
|
|
2c81c7cdb6 | ||
|
|
0d0d97ad3f | ||
|
|
32ef120928 | ||
|
|
e5820e1e55 | ||
|
|
fb424709d7 | ||
|
|
99117fc90f | ||
|
|
8851b279f5 | ||
|
|
86a962795a | ||
|
|
3a40bbca39 | ||
|
|
4deeacd0ad | ||
|
|
1361d02e59 | ||
|
|
173e6040fe | ||
|
|
3cbafd8ef4 | ||
|
|
75d560440e | ||
|
|
174bf7dc6f | ||
|
|
83d2e1b0ae | ||
|
|
b251cb56f0 | ||
|
|
fec19e1808 | ||
|
|
aa529242c7 | ||
|
|
03a8ea9500 | ||
|
|
2b1543ba11 | ||
|
|
b92276bfac | ||
|
|
ee0b035e4b | ||
|
|
ac70c6bffc | ||
|
|
61b9e6307c | ||
|
|
f0f8b7e06a | ||
|
|
dadf81baf7 | ||
|
|
f819279aea | ||
|
|
6ce0fe7607 | ||
|
|
7d9257f5f6 | ||
|
|
8baca7df03 | ||
|
|
34a6a0ecc4 | ||
|
|
97c38ee024 | ||
|
|
ba73f3e832 | ||
|
|
ccb17b1c91 | ||
|
|
0b643f1a78 | ||
|
|
6eb8a41103 | ||
|
|
60118fad0d | ||
|
|
3b77db13c5 | ||
|
|
81f05d1539 | ||
|
|
ec5af122f6 | ||
|
|
b536f0c874 | ||
|
|
640ccea288 | ||
|
|
68b1632f19 | ||
|
|
c39f122014 | ||
|
|
ab8cb7a3ac | ||
|
|
20d7f901a2 | ||
|
|
f0098059a7 | ||
|
|
de6c624b95 | ||
|
|
d9b14c457a | ||
|
|
366cc4c8e7 | ||
|
|
e358e6bc1f | ||
|
|
a5d98e9351 | ||
|
|
dfdd3b1090 | ||
|
|
b4e3c955d8 | ||
|
|
91148de095 | ||
|
|
fe036049b8 | ||
|
|
d2d1562c8c | ||
|
|
eebba3b3cb | ||
|
|
310563abda | ||
|
|
37506bcdd9 | ||
|
|
23585486de | ||
|
|
78153e62cf | ||
|
|
a37dd412e1 | ||
|
|
f9bbb86d49 | ||
|
|
59eb73bf24 | ||
|
|
44465b679f | ||
|
|
4f3ae3b9a4 | ||
|
|
3339fc5738 | ||
|
|
90b35affe2 | ||
|
|
ff10f4ee2f | ||
|
|
96cdc7c628 | ||
|
|
189ecd8fb0 | ||
|
|
23dd84a690 | ||
|
|
b5eb566c35 | ||
|
|
21ef50ebfb | ||
|
|
47ee01be96 | ||
|
|
eea5f77be9 | ||
|
|
5f07fc9d9f | ||
|
|
43d68289b9 | ||
|
|
50e068ef10 | ||
|
|
2218901dc7 | ||
|
|
8eb67c1d13 | ||
|
|
8fdd147d1e | ||
|
|
f29ad88b16 | ||
|
|
3f36c4541d | ||
|
|
9f8b27ae4a | ||
|
|
b5af266953 | ||
|
|
0b3816473d | ||
|
|
b9a8d65e61 | ||
|
|
b1a6606728 | ||
|
|
453afeb2d7 | ||
|
|
c3128c4080 | ||
|
|
6e07f5b6f8 | ||
|
|
d47cc76ab5 | ||
|
|
a4b1d37763 | ||
|
|
c4d567f994 | ||
|
|
05a46475ed | ||
|
|
2096d93282 | ||
|
|
dfe0a507fc | ||
|
|
05f063d81b | ||
|
|
fe06bea056 | ||
|
|
4975a16446 | ||
|
|
8022bd31dc | ||
|
|
58541177aa | ||
|
|
d3b102d46e | ||
|
|
3354effc53 | ||
|
|
bef44b725e | ||
|
|
115f5c8f52 | ||
|
|
6df2c90d85 | ||
|
|
06742cf825 | ||
|
|
c7c1b5b12d | ||
|
|
2f4cdd0d9c | ||
|
|
f1e7fda956 | ||
|
|
7bb48ece49 | ||
|
|
508e2287b8 | ||
|
|
03d48e9aab | ||
|
|
d7c41489e0 | ||
|
|
897faf08d9 | ||
|
|
3ad20dfd5b | ||
|
|
3f2ae3f3fc | ||
|
|
f94815cf46 | ||
|
|
2190c3bc52 | ||
|
|
e65625e32f | ||
|
|
af65bbe7f9 | ||
|
|
1dbe09b428 | ||
|
|
232c2329af | ||
|
|
772019db22 | ||
|
|
52c6c2274e | ||
|
|
e53f3362be | ||
|
|
c3945a996c | ||
|
|
c2d357a185 | ||
|
|
74b0679cf0 | ||
|
|
dc6dffbff9 | ||
|
|
4c6dfdf600 | ||
|
|
b62fd627f0 | ||
|
|
177b65587b | ||
|
|
b5679aa603 | ||
|
|
fb2bd2c2b7 | ||
|
|
b9907fa7ae | ||
|
|
7d6792a638 | ||
|
|
b6cf866f52 | ||
|
|
2c72aaf6e1 | ||
|
|
b5f2252650 | ||
|
|
ca026a37fc | ||
|
|
abd8621e92 | ||
|
|
0df778a5f6 | ||
|
|
0a7f8ce216 | ||
|
|
7e2d433857 | ||
|
|
413470569e | ||
|
|
b2adf639ff | ||
|
|
3ac1dfbf4c | ||
|
|
975a7b466c | ||
|
|
bdefe9452c | ||
|
|
9211fba6d5 | ||
|
|
1d58d2058d | ||
|
|
23dc237403 |
+36
-20
@@ -11,7 +11,7 @@ Talking about code and problems first is often the best way to get started
|
||||
before submitting a pull request.
|
||||
|
||||
When submitting a bug report, patch, or pull request, please start by
|
||||
stating the version the change is made against, what it does, and why.
|
||||
stating the version the change is made against, what it does, *and why*.
|
||||
|
||||
Please take care to ensure you follow the project coding style and the
|
||||
commit message format. If you follow these recommendations you help
|
||||
@@ -21,13 +21,28 @@ the maintainer(s) and make it easier for them to include your code.
|
||||
Coding Style
|
||||
------------
|
||||
|
||||
> **Tip:** Always submit code that follows the style of surrounding code!
|
||||
Before jumping into code, remember to **document new features** and bug
|
||||
fixes. Both the manual and ChangeLog are in the `doc/` sub-directory
|
||||
and it is expected that you provide a human-readable summary for the
|
||||
release notes (ChangeLog) and at least a configuration example in the
|
||||
manual for new features.
|
||||
|
||||
First of all, lines are allowed to be longer than 72 characters these
|
||||
days. In fact, there exist no enforced maximum, but keeping it around
|
||||
100 chars is OK.
|
||||
> **Tip:** consider ["Readme driven development"][RDD] for new features.
|
||||
> It is amazing how many flaws in your own bright ideas come to bare
|
||||
> when you suddenly have to explain them to someone else!
|
||||
|
||||
The coding style itself is otherwise strictly Linux [KNF][].
|
||||
We expect code contributions for:
|
||||
|
||||
- C code in [Linux Coding Style][Linux]
|
||||
- Python code should follow [PEP-8][]
|
||||
|
||||
> **However,** always submit code that follows the style of surrounding
|
||||
> code! Legacy takes precedence, and remember, we read code a lot more
|
||||
> than write it, so legibility is important.
|
||||
|
||||
As a final note, lines are allowed to be longer than 72 characters these
|
||||
days. There is no enforced maximum, but the team usually keep it around
|
||||
100 characters for both C and Python.
|
||||
|
||||
|
||||
Commit Messages
|
||||
@@ -37,22 +52,21 @@ Commit messages exist to track *why* a change was made. Try to be as
|
||||
clear and concise as possible in your commit messages, and always, be
|
||||
proud of your work and set up a proper GIT identity for your commits:
|
||||
|
||||
git config --global user.name "Jane Doe"
|
||||
git config --global user.email jane.doe@example.com
|
||||
$ git config --global user.name "Jacky Linker"
|
||||
$ git config --global user.email jacky.linker@example.com
|
||||
|
||||
Example commit message from the [Pro Git][gitbook] online book, notice
|
||||
how `git commit -s` is used to automatically add a `Signed-off-by`:
|
||||
|
||||
Brief, but clear and concise summary of changes
|
||||
subsystem: brief, but clear and concise summary of changes
|
||||
|
||||
More detailed explanatory text, if necessary. Wrap it to about 72
|
||||
characters or so. In some contexts, the first line is treated as
|
||||
the subject of an email and the rest of the text as the body. The
|
||||
blank line separating the ummary from the body is critical (unless
|
||||
you omit the body entirely); tools like rebase can get confused if
|
||||
you run the two together.
|
||||
empty line separating summary from body is critical. Tools like
|
||||
rebase can get confused if the empty line is missing.
|
||||
|
||||
Further paragraphs come after blank lines.
|
||||
Further paragraphs should be separated with empty lines.
|
||||
|
||||
- Bullet points are okay, too
|
||||
|
||||
@@ -60,17 +74,19 @@ how `git commit -s` is used to automatically add a `Signed-off-by`:
|
||||
by a single space, with blank lines in between, but conventions
|
||||
vary here
|
||||
|
||||
Signed-off-by: Jane Doe <jane.doe@example.com>
|
||||
Signed-off-by: Jacky Linker <jacky.linker@example.com>
|
||||
|
||||
|
||||
Code of Conduct
|
||||
---------------
|
||||
|
||||
It is expected of everyone to respect the [Code of Conduct][conduct].
|
||||
The *"maintainers have the right and responsibility to remove, edit,
|
||||
or reject comments, commits, code, wiki edits, issues, and other
|
||||
contributions that are not aligned to this Code of Conduct."*
|
||||
The *"maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, discussion forum threads, issues, and
|
||||
other contributions that are not aligned to this Code of Conduct."*
|
||||
|
||||
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
|
||||
[gitbook]: https://git-scm.com/book/ch5-2.html
|
||||
[conduct]: CODE-OF-CONDUCT.md
|
||||
[Linux]: https://www.kernel.org/doc/html/v6.9/process/coding-style.html
|
||||
[PEP-8]: https://peps.python.org/pep-0008/
|
||||
[RDD]: https://tom.preston-werner.com/2010/08/23/readme-driven-development
|
||||
[gitbook]: https://git-scm.com/book/ch5-2.html
|
||||
[conduct]: CODE-OF-CONDUCT.md
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
|
||||
name: "\U0001F41E Bug report"
|
||||
description: Create a bug report
|
||||
labels:
|
||||
- "bug"
|
||||
- "triage"
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**Thank :heart: you for taking the time to fill out this bug report!**
|
||||
|
||||
We kindly ask that you search to see if an issue [already exists](https://github.com/kernelkit/infix/issues?q=is%3Aissue+sort%3Acreated-desc+) for the bug you encountered.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: |
|
||||
A clear and concise description of the issue you're experiencing.
|
||||
value: |
|
||||
For code snippets, logs, commands, etc., please use triple backticks:
|
||||
```
|
||||
admin@infix-c0-ff-ee:/> show log
|
||||
May 15 07:21:02 infix-00-00-00 container[3192]: Failed creating container test from curios-httpd-v24.03.0
|
||||
- (press h for help or q to quit)
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: |
|
||||
A clear and concise description of what you expected to happen.
|
||||
value: |
|
||||
```
|
||||
admin@infix-c0-ff-ee:/> show log
|
||||
May 15 07:21:02 infix-c0-ff-ee container[3192]: Successfully created container test from curios-httpd-v24.03.0
|
||||
- (press h for help or q to quit)
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps To Reproduce
|
||||
description: |
|
||||
Steps to reproduce the issue. For example:
|
||||
|
||||
1. Built from source
|
||||
2. Upgrade to latest release, vYY.MM.P
|
||||
3. Factory reset
|
||||
4. Enable feature
|
||||
5. Check the logs/show command/operational status
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: |
|
||||
- Relevant parts of `startup-config`
|
||||
- Output from `show interfaces`, if applicable
|
||||
- Other observations, screenshots, log files ...
|
||||
|
||||
**Tip:** You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,7 @@
|
||||
contact_links:
|
||||
- name: "🔍 Look for my Issue"
|
||||
url: https://github.com/kernelkit/infix/issues?q=is%3Aissue+sort%3Acreated-desc+
|
||||
about: Thank ❤️ you for your time! We kindly ask that you first check if an issue already exists.
|
||||
- name: "💬 Discussions and Q&A"
|
||||
url: https://github.com/kernelkit/infix/discussions
|
||||
about: Discussions are perfect for quick questions, bouncing ideas, and things that may be a bug.
|
||||
@@ -0,0 +1,45 @@
|
||||
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
|
||||
name: "\U0001F6E0️ Feature request"
|
||||
description: Suggest a new feature, idea or improvement of the OS
|
||||
labels:
|
||||
- "feature"
|
||||
- "triage"
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**Thank :heart: you for taking the time to fill out this feature request!**
|
||||
|
||||
We kindly ask that you search to see if an issue [already exists](https://github.com/kernelkit/infix/issues?q=is%3Aissue+sort%3Acreated-desc+) for your feature. We are also happy to accept contributions from our users. For details see [CONTRIBUTING](https://github.com/kernelkit/infix/blob/master/.github/CONTRIBUTING.md).
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
A clear and concise description of the problem or missing feature.
|
||||
**Example:** *I'm always frustrated when [...]*, or *I'd like to see support for [...]*
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional Information
|
||||
description: |
|
||||
Any other related information, e.g. existing YANG model(s), or possibly screenshots about the feature request here.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: General Information
|
||||
description: |
|
||||
Appended to all feature requests for future readers.
|
||||
value: |
|
||||
Anyone can help out by [sponsoring][1] development of new features or [contributing][2] pull requests.
|
||||
Please use this issue for discussions related to the feature.
|
||||
|
||||
[1]: https://github.com/kernelkit/infix/blob/main/.github/SUPPORT.md
|
||||
[2]: https://github.com/kernelkit/infix/blob/main/.github/CONTRIBUTING.md
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,5 +1,3 @@
|
||||
<!--- **Summarize** your changes in the title above -->
|
||||
|
||||
## Description
|
||||
|
||||
<!--
|
||||
@@ -15,7 +13,7 @@
|
||||
|
||||
## Checklist
|
||||
|
||||
Tick relevant boxes, this PR is-a or has-a:
|
||||
Tick *relevant* boxes, this PR is-a or has-a:
|
||||
|
||||
- [ ] Bugfix
|
||||
- [ ] Regression tests
|
||||
@@ -31,7 +29,3 @@ Tick relevant boxes, this PR is-a or has-a:
|
||||
- [ ] Documentation content changes
|
||||
- [ ] Other (please describe):
|
||||
|
||||
|
||||
## References
|
||||
|
||||
<!-- Please list references to related issue(s) -->
|
||||
|
||||
+66
-19
@@ -1,6 +1,7 @@
|
||||
name: Bob the Builder
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
@@ -8,21 +9,22 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Infix ${{ matrix.platform }}
|
||||
name: Build Infix ${{ matrix.target }}
|
||||
runs-on: [ self-hosted, latest ]
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [aarch64, x86_64]
|
||||
target: [aarch64, x86_64]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
clean: true
|
||||
submodules: recursive
|
||||
|
||||
- name: Set Build Variables
|
||||
id: vars
|
||||
run: |
|
||||
target=${{ matrix.platform }}
|
||||
target=${{ matrix.target }}
|
||||
echo "dir=infix-$target" >> $GITHUB_OUTPUT
|
||||
echo "tgz=infix-$target.tar.gz" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -38,39 +40,78 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .ccache/
|
||||
key: ccache-${{ matrix.platform }}-${{ hashFiles('.git/modules/buildroot/HEAD', 'package/*/*.hash') }}
|
||||
key: ccache-${{ matrix.target }}-${{ hashFiles('.git/modules/buildroot/HEAD', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
ccache-${{ matrix.platform }}-
|
||||
ccache-${{ matrix.target }}-
|
||||
ccache-
|
||||
|
||||
- name: Configure & Build
|
||||
- name: Configure ${{ matrix.target }}
|
||||
run: |
|
||||
target=${{ matrix.platform }}_defconfig
|
||||
echo "Building $target ..."
|
||||
make $target
|
||||
make ${{ matrix.target }}_defconfig
|
||||
|
||||
- name: Unit Test ${{ matrix.target }}
|
||||
run: |
|
||||
make test-unit
|
||||
|
||||
- name: Build ${{ matrix.target }}
|
||||
run: |
|
||||
echo "Building ${{ matrix.target }}_defconfig ..."
|
||||
make
|
||||
|
||||
- name: Prepare Artifact
|
||||
- name: Prepare ${{ matrix.target }} Artifact
|
||||
run: |
|
||||
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'
|
||||
run: |
|
||||
make test
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: output/${{ steps.vars.outputs.tgz }}
|
||||
name: artifact-${{ matrix.platform }}
|
||||
name: artifact-${{ matrix.target }}
|
||||
|
||||
test:
|
||||
name: Regression Test of Infix x86_64
|
||||
needs: build
|
||||
runs-on: [ self-hosted, regression ]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
clean: true
|
||||
submodules: recursive
|
||||
|
||||
- name: Configure x86_64
|
||||
run: |
|
||||
make x86_64_defconfig
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: "artifact-*"
|
||||
merge-multiple: true
|
||||
|
||||
- name: Restore x86-64 output/
|
||||
run: |
|
||||
ls -l
|
||||
mkdir -p output
|
||||
mv infix-x86_64.tar.gz output/
|
||||
cd output/
|
||||
tar xf infix-x86_64.tar.gz
|
||||
ln -s infix-x86_64 images
|
||||
|
||||
- name: Regression Test
|
||||
run: |
|
||||
make test
|
||||
|
||||
- name: Publish Test Result
|
||||
# Ensure this runs even if Regression Test fails
|
||||
if: always()
|
||||
run: cat test/.log/last/result-gh.md >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
release:
|
||||
if: ${{github.repository_owner == 'kernelkit' && github.ref_name == 'main'}}
|
||||
name: Upload Latest Build
|
||||
needs: build
|
||||
runs-on: [ self-hosted, latest ]
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
@@ -79,6 +120,12 @@ jobs:
|
||||
pattern: "artifact-*"
|
||||
merge-multiple: true
|
||||
|
||||
- name: Create checksums ...
|
||||
run: |
|
||||
for file in *.tar.gz; do
|
||||
sha256sum $file > $file.sha256
|
||||
done
|
||||
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
allowUpdates: true
|
||||
@@ -88,7 +135,7 @@ jobs:
|
||||
prerelease: true
|
||||
tag: "latest"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
artifacts: "*.tar.gz"
|
||||
artifacts: "*.tar.gz*"
|
||||
|
||||
- name: Summary
|
||||
run: |
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config libjansson-dev libev-dev \
|
||||
libaugeas-dev libglib2.0-dev libpcre2-dev \
|
||||
libcrypt-dev libglib2.0-dev libpcre2-dev \
|
||||
libuev-dev libite-dev
|
||||
|
||||
- name: Build dependencies
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
name: Reggie Regression
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Regression Testing
|
||||
runs-on: [ self-hosted, regression ]
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
|
||||
- name: Clean up cruft ...
|
||||
run: |
|
||||
./test/env -c
|
||||
|
||||
- name: Set Build Variables
|
||||
id: vars
|
||||
run: |
|
||||
target=x86_64
|
||||
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-netconf-${{ hashFiles('.git/modules/buildroot/refs/heads/master', '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/refs/head/master', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
ccache-x86_64-
|
||||
ccache-
|
||||
|
||||
- name: Configure NETCONF
|
||||
run: |
|
||||
make x86_64_defconfig
|
||||
|
||||
- name: Unit Test
|
||||
run: |
|
||||
make test-unit
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
make
|
||||
|
||||
- name: Prepare Artifact
|
||||
run: |
|
||||
cd output/
|
||||
mv images ${{ steps.vars.outputs.dir }}
|
||||
ln -s ${{ steps.vars.outputs.dir }} images
|
||||
tar cfz ${{ steps.vars.outputs.tgz }} ${{ steps.vars.outputs.dir }}
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: output/${{ steps.vars.outputs.tgz }}
|
||||
|
||||
- name: Regression Test
|
||||
run: |
|
||||
make test
|
||||
|
||||
- name: Publish Test Result
|
||||
# Ensure this runs even if Regression Test fails
|
||||
if: always()
|
||||
run: cat test/.log/last/result-gh.md >> $GITHUB_STEP_SUMMARY
|
||||
@@ -20,16 +20,17 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository == 'kernelkit/infix' && startsWith(github.ref, 'refs/tags/')
|
||||
name: Build Infix ${{ github.ref_name }} [${{ matrix.platform }}]
|
||||
name: Build Infix ${{ github.ref_name }} [${{ matrix.target }}]
|
||||
runs-on: [ self-hosted, release ]
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [aarch64, x86_64]
|
||||
target: [aarch64, x86_64]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
clean: true
|
||||
submodules: recursive
|
||||
|
||||
- name: Set Release Variables
|
||||
id: vars
|
||||
@@ -41,7 +42,7 @@ jobs:
|
||||
fi
|
||||
echo "ver=${ver}" >> $GITHUB_OUTPUT
|
||||
fver=${ver#v}
|
||||
target=${{ matrix.platform }}-${fver}
|
||||
target=${{ matrix.target }}-${fver}
|
||||
echo "dir=infix-$target" >> $GITHUB_OUTPUT
|
||||
echo "tgz=infix-$target.tar.gz" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -57,16 +58,16 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .ccache/
|
||||
key: ccache-${{ matrix.platform }}-${{ hashFiles('.git/modules/buildroot/HEAD', 'package/*/*.hash') }}
|
||||
key: ccache-${{ matrix.target }}-${{ hashFiles('.git/modules/buildroot/HEAD', 'package/*/*.hash') }}
|
||||
restore-keys: |
|
||||
ccache-${{ matrix.platform }}-
|
||||
ccache-${{ matrix.target }}-
|
||||
ccache-
|
||||
|
||||
- name: Configure & Build
|
||||
env:
|
||||
INFIX_RELEASE: ${{ steps.vars.outputs.ver }}
|
||||
run: |
|
||||
target=${{ matrix.platform }}_defconfig
|
||||
target=${{ matrix.target }}_defconfig
|
||||
echo "Building $target ..."
|
||||
make $target
|
||||
make
|
||||
@@ -87,7 +88,7 @@ jobs:
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifact-${{ matrix.platform }}
|
||||
name: artifact-${{ matrix.target }}
|
||||
path: output/*.tar.gz
|
||||
|
||||
release:
|
||||
|
||||
@@ -112,10 +112,6 @@ config INFIX_ARCH
|
||||
default "riscv64" if BR2_riscv
|
||||
default "x86_64" if BR2_x86_64
|
||||
|
||||
menu "Packages"
|
||||
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/Config.in"
|
||||
|
||||
endmenu
|
||||
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/Config.in.host"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/board/common/Config.in"
|
||||
|
||||
@@ -2,7 +2,12 @@ export BR2_EXTERNAL := $(CURDIR)
|
||||
export PATH := $(CURDIR)/bin:$(PATH)
|
||||
|
||||
ARCH ?= $(shell uname -m)
|
||||
O ?= $(CURDIR)/output
|
||||
O ?= output
|
||||
|
||||
# If a relative output path is specified, we have to translate it to
|
||||
# an absolute one before handing over control to Buildroot, which will
|
||||
# otherwise treat it as relative to ./buildroot.
|
||||
override O := $(if $(filter /%,$O),$O,$(CURDIR)/$O)
|
||||
|
||||
config := $(O)/.config
|
||||
bmake = $(MAKE) -C buildroot O=$(O) $1
|
||||
|
||||
@@ -100,7 +100,7 @@ and testing, but can also be used for evaluation and demo purposes. For
|
||||
more information, see: [Infix in Virtual Environments](doc/virtual.md).
|
||||
|
||||
> See the [GitHub Releases](https://github.com/kernelkit/infix/releases)
|
||||
> page for our pre-built images. The *Latest Build* has the bleeding
|
||||
> page for our pre-built images. The *[Latest Build][]* has bleeding
|
||||
> edge images, if possible we recommend using a versioned release.
|
||||
>
|
||||
> For *customer specific builds* of Infix, see your product repository.
|
||||
@@ -116,6 +116,7 @@ more information, see: [Infix in Virtual Environments](doc/virtual.md).
|
||||
[1]: https://buildroot.org/
|
||||
[2]: https://www.sysrepo.org/
|
||||
[3]: doc/cli/introduction.md
|
||||
[Latest Build]: https://github.com/kernelkit/infix/releases/tag/latest
|
||||
[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/
|
||||
|
||||
@@ -16,7 +16,12 @@ run ixboot
|
||||
";
|
||||
boot_targets = "mmc1";
|
||||
ethprime = "eth1";
|
||||
bootdelay = "1";
|
||||
|
||||
/* This is a development platform, keep
|
||||
* developer mode statically enabled.
|
||||
*/
|
||||
ixbtn-devmode = "setenv dev_mode yes; echo Enabled";
|
||||
ixbtn-factory = "echo \"No button available, use bootmenu\"";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -175,9 +175,14 @@ CONFIG_VLAN_8021Q=y
|
||||
CONFIG_VLAN_8021Q_GVRP=y
|
||||
CONFIG_VLAN_8021Q_MVRP=y
|
||||
CONFIG_NET_SCHED=y
|
||||
CONFIG_NET_SCH_MQPRIO=y
|
||||
CONFIG_NET_CLS_BASIC=y
|
||||
CONFIG_NET_CLS_BPF=y
|
||||
CONFIG_NET_CLS_FLOWER=y
|
||||
CONFIG_NET_CLS_ACT=y
|
||||
CONFIG_NET_ACT_GACT=y
|
||||
CONFIG_NET_ACT_MIRRED=y
|
||||
CONFIG_NET_ACT_SKBEDIT=y
|
||||
CONFIG_DCB=y
|
||||
CONFIG_NETLINK_DIAG=y
|
||||
CONFIG_MPLS=y
|
||||
|
||||
@@ -4,6 +4,37 @@ common=$(dirname "$(readlink -f "$0")")
|
||||
. "$BR2_CONFIG" 2>/dev/null
|
||||
. "$TARGET_DIR/usr/lib/os-release"
|
||||
|
||||
# Extract list of loaded YANG modules and their features for yangdoc.html
|
||||
mkyangdoc()
|
||||
{
|
||||
cmd="yangdoc -o $1 -p $TARGET_DIR/usr/share/yang"
|
||||
|
||||
# shellcheck disable=SC2155
|
||||
export SYSREPO_SHM_PREFIX="yangdoc"
|
||||
while IFS= read -r line; do
|
||||
if echo "$line" | grep -q '^[a-z]'; then
|
||||
module=$(echo "$line" | awk '{print $1}')
|
||||
cmd="$cmd -m $module"
|
||||
feature=$(echo "$line" | awk -F'|' '{print $8}' | sed 's/^ *//;s/ *$//')
|
||||
if [ -n "$feature" ]; then
|
||||
feature_list=$(echo "$feature" | tr ' ' '\n')
|
||||
for feat in $feature_list; do
|
||||
cmd="$cmd -e $feat"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done <<EOF
|
||||
$(sysrepoctl -l; rm -f /dev/shm/${SYSREPO_SHM_PREFIX}*)
|
||||
EOF
|
||||
|
||||
# Ignore a few top-level oddballs not used by core Infix
|
||||
cmd="$cmd -x supported-algorithms"
|
||||
|
||||
# Execute the command
|
||||
echo "Calling: $cmd"
|
||||
$cmd
|
||||
}
|
||||
|
||||
if [ -n "${ID_LIKE}" ]; then
|
||||
ID="${ID} ${ID_LIKE}"
|
||||
fi
|
||||
@@ -85,3 +116,8 @@ grep -qsE '^/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"
|
||||
|
||||
# Create YANG documentation
|
||||
if [ "$BR2_PACKAGE_HOST_PYTHON_YANGDOC" = "y" ]; then
|
||||
mkyangdoc "$BINARIES_DIR/yangdoc.html"
|
||||
fi
|
||||
|
||||
@@ -108,10 +108,12 @@ config QEMU_RW
|
||||
default "cfg.ext4"
|
||||
|
||||
config QEMU_RW_VAR_OPT
|
||||
bool "Separate writable /var (256MB)"
|
||||
bool "Separate writable /var"
|
||||
|
||||
if QEMU_RW_VAR_OPT
|
||||
|
||||
config QEMU_RW_VAR_SIZE
|
||||
string "Size of /var"
|
||||
default "256M"
|
||||
config QEMU_RW_VAR
|
||||
string "Writable /var layer"
|
||||
default "var.ext4"
|
||||
|
||||
@@ -172,7 +172,7 @@ rw_args()
|
||||
|
||||
if [ "$CONFIG_QEMU_RW_VAR_OPT" ]; then
|
||||
if ! [ -f "$CONFIG_QEMU_RW_VAR" ]; then
|
||||
dd if=/dev/zero of="$CONFIG_QEMU_RW_VAR" bs=256M count=1 >/dev/null 2>&1
|
||||
dd if=/dev/zero of="$CONFIG_QEMU_RW_VAR" bs=$CONFIG_QEMU_RW_VAR_SIZE count=1 >/dev/null 2>&1
|
||||
mkfs.ext4 -L var "$CONFIG_QEMU_RW_VAR" >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
@@ -255,6 +255,12 @@ wdt_args()
|
||||
echo -n "-device i6300esb -rtc clock=host"
|
||||
}
|
||||
|
||||
gdb_args()
|
||||
{
|
||||
echo -n "-chardev socket,id=gdbqemu,path=gdbqemu.sock,server=on,wait=off "
|
||||
echo -n "-gdb chardev:gdbqemu"
|
||||
}
|
||||
|
||||
run_qemu()
|
||||
{
|
||||
if [ "$CONFIG_QEMU_ROOTFS_VSCSI" = "y" ]; then
|
||||
@@ -272,6 +278,7 @@ run_qemu()
|
||||
$(net_args) \
|
||||
$(wdt_args) \
|
||||
$(vpd_args) \
|
||||
$(gdb_args) \
|
||||
$CONFIG_QEMU_EXTRA
|
||||
EOF
|
||||
|
||||
@@ -312,10 +319,10 @@ generate_dot()
|
||||
{
|
||||
[ "$CONFIG_QEMU_NET_TAP" = "y" ] || return
|
||||
|
||||
hostports="<qtap0> qtap0"
|
||||
targetports="<e0> e0"
|
||||
edges="host:qtap0 -- target:e0 [kind=mgmt];"
|
||||
for tap in $(seq 1 $(($CONFIG_QEMU_NET_TAP_N - 1))); do
|
||||
hostports="<qtap1> qtap1"
|
||||
targetports="<e1> e1"
|
||||
edges="host:qtap1 -- target:e1 [kind=mgmt];"
|
||||
for tap in $(seq 2 $(($CONFIG_QEMU_NET_TAP_N - 1))); do
|
||||
hostports="$hostports | <qtap$tap> qtap$tap "
|
||||
targetports="$targetports | <e$tap> e$tap "
|
||||
edges="$edges host:qtap$tap -- target:e$tap;"
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
run [S] log:console /libexec/infix/probe -- Probing system information
|
||||
run [S] <pid/syslogd> /libexec/infix/sysctl-sync-ip-conf --
|
||||
run [S] <pid/syslogd> /libexec/infix/nameif -- Probing network interfaces
|
||||
task name:ixinit log:tag:ixinit [S] <pid/syslogd> /libexec/finit/runparts -bp /libexec/infix/init.d -- Probing system
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
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 \
|
||||
sysv :%i pid:!/run/container:%i.pid <pid/k8s-logger:%i> log kill:10 \
|
||||
[2345] container -n %i -- container %i
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
service name:rousette notify:none log <pid/confd> \
|
||||
[12345] rousette --syslog -t 60 \
|
||||
-- RESTCONF server
|
||||
@@ -1,3 +1,7 @@
|
||||
0 unspec
|
||||
1 kernel_lo
|
||||
2 kernel_ra
|
||||
3 kernel_ll
|
||||
4 static
|
||||
5 dhcp
|
||||
6 random
|
||||
|
||||
@@ -24,4 +24,6 @@ server {
|
||||
root html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
include /etc/nginx/app/*.conf;
|
||||
}
|
||||
|
||||
@@ -5,14 +5,6 @@ server {
|
||||
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;
|
||||
include /etc/nginx/netbrowse.conf;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
location /netbrowse/ {
|
||||
return 301 /netbrowse;
|
||||
}
|
||||
location /netbrowse {
|
||||
include /etc/nginx/netbrowse.conf;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
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;
|
||||
@@ -0,0 +1,8 @@
|
||||
# /telemetry/optics is for streaming (not used atm)
|
||||
location ~ ^/(restconf|yang|.well-known)/ {
|
||||
grpc_pass grpc://[::1]:10080;
|
||||
grpc_set_header Host $host;
|
||||
grpc_set_header X-Real-IP $remote_addr;
|
||||
grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
grpc_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#%PAM-1.0
|
||||
auth requisite pam_nologin.so
|
||||
auth [success=1 default=ignore] pam_unix.so nullok
|
||||
auth requisite pam_deny.so
|
||||
auth required pam_permit.so
|
||||
|
||||
account requisite pam_nologin.so
|
||||
account [success=1 default=ignore] pam_unix.so
|
||||
account requisite pam_deny.so
|
||||
account required pam_permit.so
|
||||
|
||||
password [success=1 default=ignore] pam_unix.so
|
||||
password requisite pam_deny.so
|
||||
password required pam_permit.so
|
||||
|
||||
session required pam_loginuid.so
|
||||
session include common-session
|
||||
session optional pam_keyinit.so force revoke
|
||||
session optional pam_lastlog.so showfailed
|
||||
session optional pam_motd.so
|
||||
@@ -0,0 +1,20 @@
|
||||
#%PAM-1.0
|
||||
auth requisite pam_nologin.so
|
||||
auth [success=1 default=ignore] pam_unix.so nullok
|
||||
auth requisite pam_deny.so
|
||||
auth required pam_permit.so
|
||||
|
||||
account requisite pam_nologin.so
|
||||
account [success=1 default=ignore] pam_unix.so
|
||||
account requisite pam_deny.so
|
||||
account required pam_permit.so
|
||||
|
||||
password [success=1 default=ignore] pam_unix.so
|
||||
password requisite pam_deny.so
|
||||
password required pam_permit.so
|
||||
|
||||
session required pam_loginuid.so
|
||||
session include common-session
|
||||
session optional pam_keyinit.so force revoke
|
||||
session optional pam_lastlog.so showfailed
|
||||
session optional pam_motd.so
|
||||
@@ -0,0 +1 @@
|
||||
UsePAM yes
|
||||
@@ -1,2 +1,3 @@
|
||||
net.ipv4.ip_forward=1
|
||||
net.ipv4.ip_forward_update_priority=0
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
# Find and install any product specific files in /etc before bootstrap
|
||||
ident=$(basename "$0")
|
||||
|
||||
PREFIXD=/usr/share/product
|
||||
PRODUCT=$(jq -r '."product-name" | ascii_downcase' /run/system.json)
|
||||
|
||||
note()
|
||||
{
|
||||
logger -k -p user.notice -t "$ident" "$1"
|
||||
}
|
||||
|
||||
DIR="$PREFIXD/$PRODUCT"
|
||||
if [ -z "$PRODUCT" ] || [ ! -d "$DIR" ]; then
|
||||
note "No vendor/product specific directory found, using built-in defaults."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
note "Using vendor/product specific defaults."
|
||||
for dir in "$DIR"/*; do
|
||||
[ -d "$dir" ] && cp -a "$dir" /
|
||||
done
|
||||
+1
-2
@@ -10,8 +10,7 @@ sysctl net.ipv4.conf.default >$tmp
|
||||
sysctl net.ipv6.conf.default >>$tmp
|
||||
|
||||
for iface in $(ip -j link show | jq -r .[].ifname); do
|
||||
sed -e "s/.default./.${iface}./g" $tmp | sysctl -p -
|
||||
sed -e "s/.default./.${iface}./g" $tmp | sysctl -q -p -
|
||||
done
|
||||
|
||||
rm $tmp
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
#!/bin/sh
|
||||
# Opportunistically look for interfaces with multiple transmit queues
|
||||
# and hardware support for the mqprio queuing discipline. For every
|
||||
# matching interface, set up mappings from kernel-internal packet
|
||||
# priorities, via traffic classes, to transmit queues such that as
|
||||
# many high priorities as possible are scheduled on separate queues.
|
||||
|
||||
set -e
|
||||
|
||||
map()
|
||||
{
|
||||
case "$1" in
|
||||
2)
|
||||
echo "map 0 0 0 0 0 0 1 1";;
|
||||
3)
|
||||
echo "map 0 0 0 0 1 1 2 2";;
|
||||
4)
|
||||
echo "map 0 0 1 1 2 2 3 3";;
|
||||
5)
|
||||
echo "map 0 0 1 1 2 2 3 4";;
|
||||
6)
|
||||
echo "map 0 0 1 1 2 3 4 5";;
|
||||
7)
|
||||
echo "map 0 0 1 2 3 4 5 6";;
|
||||
8)
|
||||
echo "map 0 1 2 3 4 5 6 7";;
|
||||
esac
|
||||
}
|
||||
|
||||
queues()
|
||||
{
|
||||
out="queues "
|
||||
for tc in $(seq 0 $(($1 - 1))); do
|
||||
out="$out 1@$tc"
|
||||
done
|
||||
|
||||
echo "$out"
|
||||
}
|
||||
|
||||
set $(ip -j -d link show | jq -r '.[] | .ifname, .num_tx_queues')
|
||||
while [ "$1" ]; do
|
||||
iface="$1"
|
||||
txqs="$2"
|
||||
shift 2
|
||||
|
||||
[ $txqs -lt 2 ] && continue
|
||||
[ $txqs -gt 8 ] && txqs=8
|
||||
|
||||
tc qdisc add dev $iface root mqprio hw 1 \
|
||||
num_tc $txqs $(map $txqs) $(queues $txqs) || true
|
||||
done
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
#!/bin/sh
|
||||
# Run .cfg migration jq scripts to backup and transform older .cfg files
|
||||
ident=$(basename "$0")
|
||||
|
||||
MIGRATIONS_DIR="/usr/share/confd/migrate"
|
||||
CONFIG_FILE="/cfg/startup-config.cfg"
|
||||
BACKUP_DIR="/cfg/backup"
|
||||
|
||||
note()
|
||||
{
|
||||
logger -k -p user.notice -t "$ident" "$1"
|
||||
}
|
||||
|
||||
err()
|
||||
{
|
||||
logger -k -p user.err -t "$ident" "$1"
|
||||
}
|
||||
|
||||
file_version()
|
||||
{
|
||||
jq -r '
|
||||
if .["infix-meta:meta"] | has("version") then
|
||||
.["infix-meta:meta"]["version"]
|
||||
else
|
||||
"0.0"
|
||||
end
|
||||
' "$1"
|
||||
}
|
||||
|
||||
atoi()
|
||||
{
|
||||
echo "$1" | awk -F. '{print $1 * 1000 + $2}'
|
||||
}
|
||||
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
# Nothing to migrate
|
||||
note "No $(basename "$CONFIG_FILE" .cfg) yet, likely factory reset."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cfg_version=$(file_version "$CONFIG_FILE")
|
||||
current_version=$(atoi "$cfg_version")
|
||||
|
||||
# Find the latest version by examining the highest numbered directory
|
||||
sys_version=$(find "$MIGRATIONS_DIR" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -n1 | xargs -n1 basename)
|
||||
latest_version=$(atoi "$sys_version")
|
||||
|
||||
# Check for downgrade
|
||||
if [ "$current_version" -gt "$latest_version" ]; then
|
||||
err "Configuration file $CONFIG_FILE version ($cfg_version) is newer than the latest supported version ($sys_version). Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If the current version is already the latest, exit the script
|
||||
if [ "$current_version" -eq "$latest_version" ]; then
|
||||
note "Configuration is already at the latest version ($sys_version). No migration needed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
note "Configuration file $CONFIG_FILE is of version $cfg_version, migrating ..."
|
||||
|
||||
# Create the backup directory if it doesn't exist
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# Create a backup of the current configuration file
|
||||
nm=$(basename "$CONFIG_FILE" .cfg)
|
||||
BACKUP_FILE="$BACKUP_DIR/${nm}-${cfg_version}.cfg"
|
||||
if cp "$CONFIG_FILE" "$BACKUP_FILE"; then
|
||||
note "Backup created: $BACKUP_FILE"
|
||||
else
|
||||
err "Failed creating backup: $BACKUP_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Apply the scripts for each version directory in sequence
|
||||
for version_dir in $(find "$MIGRATIONS_DIR" -mindepth 1 -maxdepth 1 -type d | sort -V); do
|
||||
dir=$(basename "$version_dir")
|
||||
version=$(atoi "$dir")
|
||||
|
||||
# Step by step upgrade file to latest version
|
||||
if [ "$current_version" -lt "$version" ]; then
|
||||
note "Applying migrations for version $dir ..."
|
||||
|
||||
# Apply all scripts in the version directory in order
|
||||
for script in $(find "$version_dir" -type f -name '*.sh' | sort -V); do
|
||||
note "Calling $script for $CONFIG_FILE ..."
|
||||
sh "$script" "$CONFIG_FILE"
|
||||
done
|
||||
|
||||
# File now at $version ...
|
||||
current_version="$version"
|
||||
fi
|
||||
done
|
||||
|
||||
# Update the JSON file to the latest version
|
||||
if jq --arg version "$sys_version" '.["infix-meta:meta"]["infix-meta:version"] = $version' "$CONFIG_FILE" \
|
||||
> "${CONFIG_FILE}.tmp" && mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE"; then
|
||||
note "Configuration updated to version $sys_version."
|
||||
else
|
||||
err "Failed updating configuration to version $sys_version!"
|
||||
exit 1
|
||||
fi
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec initctl -bq cond set ixinit-done
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
# Generate NETCONF SSH host key pair
|
||||
set -e
|
||||
|
||||
BIT=2048
|
||||
KEY=$1
|
||||
PUB=$2
|
||||
|
||||
mkdir -p "$(dirname "$KEY")" "$(dirname "$PUB")"
|
||||
|
||||
openssl genpkey -quiet -algorithm RSA -pkeyopt rsa_keygen_bits:$BIT -outform PEM > "$KEY"
|
||||
openssl rsa -RSAPublicKey_out < "$KEY" > "$PUB"
|
||||
|
||||
exit 0
|
||||
@@ -58,6 +58,7 @@ unpack_archive()
|
||||
|
||||
[ -n "$quiet" ] || log "Extracting OCI archive $file ..."
|
||||
tar xf "$file" || (log "Error: failed unpacking $file in $(pwd)"; exit 1)
|
||||
remove=true
|
||||
fi
|
||||
|
||||
dir=$(dirname "$index")
|
||||
@@ -72,6 +73,10 @@ unpack_archive()
|
||||
name=$dir
|
||||
fi
|
||||
|
||||
if [ "$remove" = "true" ]; then
|
||||
rm -rf "$file"
|
||||
fi
|
||||
|
||||
echo "$name"
|
||||
}
|
||||
|
||||
@@ -575,7 +580,7 @@ case $cmd in
|
||||
stop "$name"
|
||||
timeout=20
|
||||
while running "$name"; do
|
||||
_=$((timeoute -= 1))
|
||||
_=$((timeout -= 1))
|
||||
if [ $timeout -le 0 ]; then
|
||||
log "Timeout waiting for container $1 to stop before restarting it."
|
||||
exit 1
|
||||
|
||||
@@ -119,7 +119,7 @@ case "$ACTION" in
|
||||
if [ -n "$hostname" ]; then
|
||||
log "setting new hostname: $hostname"
|
||||
hostname "$hostname"
|
||||
augtool -s "set /files/etc/hosts/*[ipaddr='127.0.1.1']/canonical $hostname"
|
||||
sed -i -E "s/^(127\.0\.1\.1\s+).*/\1$hostname/" /etc/hosts
|
||||
fi
|
||||
|
||||
# drop info from this interface
|
||||
|
||||
@@ -7,16 +7,19 @@
|
||||
|
||||
&env {
|
||||
vendor = "infix";
|
||||
preboot = "run ixpreboot";
|
||||
ixbootdelay = "0.5";
|
||||
bootdelay = "-2";
|
||||
bootcmd = "run ixbtn";
|
||||
bootmenu_delay = "10";
|
||||
boot_targets = "virtio mmc";
|
||||
bootcmd = "run ixboot";
|
||||
|
||||
ixpreboot = /incbin/("scripts/ixpreboot.sh");
|
||||
ixbtn-devmode = /incbin/("scripts/ixbtn-devmode.sh");
|
||||
ixbtn-factory = /incbin/("scripts/ixbtn-factory.sh");
|
||||
ixfactory = /incbin/("scripts/ixfactory.sh");
|
||||
|
||||
ixbtn = /incbin/("scripts/ixbtn.sh");
|
||||
ixdevmode = /incbin/("scripts/ixdevmode.sh");
|
||||
ixfactory = /incbin/("scripts/ixfactory.sh");
|
||||
ixbtn = /incbin/("scripts/ixbtn.sh");
|
||||
ixboot = /incbin/("scripts/ixboot.sh");
|
||||
ixbootmedia = /incbin/("scripts/ixbootmedia.sh");
|
||||
ixbootslot = /incbin/("scripts/ixbootslot.sh");
|
||||
ixprepblk = /incbin/("scripts/ixprepblk.sh");
|
||||
ixprepdhcp = /incbin/("scripts/ixprepdhcp.sh");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# CONFIG_OF_OMIT_DTB is not set
|
||||
CONFIG_DEVICE_TREE_INCLUDES="infix-env.dtsi infix-key.dtsi"
|
||||
CONFIG_SYS_PROMPT="(ixboot) "
|
||||
|
||||
CONFIG_ENV_IMPORT_FDT=y
|
||||
|
||||
@@ -16,6 +17,7 @@ CONFIG_DISTRO_DEFAULTS=y
|
||||
CONFIG_CMD_SETEXPR=y
|
||||
CONFIG_CMD_SETEXPR_FMT=y
|
||||
|
||||
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_PCI=y
|
||||
@@ -24,3 +26,11 @@ CONFIG_CMD_MMC=y
|
||||
CONFIG_FS_SQUASHFS=y
|
||||
CONFIG_CMD_SQUASHFS=y
|
||||
|
||||
CONFIG_PROT_TCP=y
|
||||
CONFIG_PROT_TCP_SACK=y
|
||||
CONFIG_CMD_WGET=y
|
||||
|
||||
CONFIG_USE_PREBOOT=y
|
||||
CONFIG_CMD_BOOTMENU=y
|
||||
CONFIG_CMD_PAUSE=y
|
||||
# CONFIG_CMD_BOOTEFI_BOOTMGR is not set
|
||||
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
From 4aef55d1b8cc24187f12f83a2f4d9bfc41ba12ee Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Mon, 30 Jan 2023 15:54:56 +0100
|
||||
Subject: [PATCH v2 1/9] image: Fix script execution from FIT images with
|
||||
external data
|
||||
|
||||
Update the script loading code to recognize when script data is stored
|
||||
externally from the FIT metadata (i.e., built with `mkimage -E`).
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Reviewed-by: Simon Glass <sjg@chromium.org>
|
||||
---
|
||||
boot/image-board.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/boot/image-board.c b/boot/image-board.c
|
||||
index 25b60ec30b..af693c9c08 100644
|
||||
--- a/boot/image-board.c
|
||||
+++ b/boot/image-board.c
|
||||
@@ -1111,7 +1111,8 @@ fallback:
|
||||
}
|
||||
|
||||
/* get script subimage data address and length */
|
||||
- if (fit_image_get_data(fit_hdr, noffset, &fit_data, &fit_len)) {
|
||||
+ if (fit_image_get_data_and_size(fit_hdr, noffset,
|
||||
+ &fit_data, &fit_len)) {
|
||||
puts("Could not find script subimage data\n");
|
||||
return 1;
|
||||
}
|
||||
--
|
||||
2.34.1
|
||||
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
From 74f121de98a1614a4068960445b8355cb3e5fa04 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Tue, 24 Jan 2023 14:00:04 +0100
|
||||
Subject: [PATCH v2 2/9] cmd: blk: Allow generic read/write operations to work
|
||||
in sandbox
|
||||
|
||||
Ensure that the memory destination/source addresses of block
|
||||
read/write operations are mapped in before access. Currently, this is
|
||||
only needed on sandbox builds.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Reviewed-by: Simon Glass <sjg@chromium.org>
|
||||
---
|
||||
cmd/blk_common.c | 15 +++++++++++----
|
||||
1 file changed, 11 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/cmd/blk_common.c b/cmd/blk_common.c
|
||||
index 75a072caf5..9f9d4327a9 100644
|
||||
--- a/cmd/blk_common.c
|
||||
+++ b/cmd/blk_common.c
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <common.h>
|
||||
#include <blk.h>
|
||||
#include <command.h>
|
||||
+#include <mapmem.h>
|
||||
|
||||
int blk_common_cmd(int argc, char *const argv[], enum uclass_id uclass_id,
|
||||
int *cur_devnump)
|
||||
@@ -63,31 +64,37 @@ int blk_common_cmd(int argc, char *const argv[], enum uclass_id uclass_id,
|
||||
|
||||
default: /* at least 4 args */
|
||||
if (strcmp(argv[1], "read") == 0) {
|
||||
- ulong addr = hextoul(argv[2], NULL);
|
||||
+ phys_addr_t paddr = hextoul(argv[2], NULL);
|
||||
lbaint_t blk = hextoul(argv[3], NULL);
|
||||
ulong cnt = hextoul(argv[4], NULL);
|
||||
+ void *vaddr;
|
||||
ulong n;
|
||||
|
||||
printf("\n%s read: device %d block # "LBAFU", count %lu ... ",
|
||||
if_name, *cur_devnump, blk, cnt);
|
||||
|
||||
+ vaddr = map_sysmem(paddr, 512 * cnt);
|
||||
n = blk_read_devnum(uclass_id, *cur_devnump, blk, cnt,
|
||||
- (ulong *)addr);
|
||||
+ vaddr);
|
||||
+ unmap_sysmem(vaddr);
|
||||
|
||||
printf("%ld blocks read: %s\n", n,
|
||||
n == cnt ? "OK" : "ERROR");
|
||||
return n == cnt ? 0 : 1;
|
||||
} else if (strcmp(argv[1], "write") == 0) {
|
||||
- ulong addr = hextoul(argv[2], NULL);
|
||||
+ phys_addr_t paddr = hextoul(argv[2], NULL);
|
||||
lbaint_t blk = hextoul(argv[3], NULL);
|
||||
ulong cnt = hextoul(argv[4], NULL);
|
||||
+ void *vaddr;
|
||||
ulong n;
|
||||
|
||||
printf("\n%s write: device %d block # "LBAFU", count %lu ... ",
|
||||
if_name, *cur_devnump, blk, cnt);
|
||||
|
||||
+ vaddr = map_sysmem(paddr, 512 * cnt);
|
||||
n = blk_write_devnum(uclass_id, *cur_devnump, blk, cnt,
|
||||
- (ulong *)addr);
|
||||
+ vaddr);
|
||||
+ unmap_sysmem(vaddr);
|
||||
|
||||
printf("%ld blocks written: %s\n", n,
|
||||
n == cnt ? "OK" : "ERROR");
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,501 +0,0 @@
|
||||
From 104a2ab39ac72c402d7463bec05aae4a6d09cfbf Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Thu, 16 Feb 2023 15:06:12 +0100
|
||||
Subject: [PATCH v2 3/9] blk: blkmap: Add basic infrastructure
|
||||
|
||||
blkmaps are loosely modeled on Linux's device mapper subsystem. The
|
||||
basic idea is that you can create virtual block devices whose blocks
|
||||
can be backed by a plethora of sources that are user configurable.
|
||||
|
||||
This change just adds the basic infrastructure for creating and
|
||||
removing blkmap devices. Subsequent changes will extend this to add
|
||||
support for actual mappings.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
MAINTAINERS | 6 +
|
||||
drivers/block/Kconfig | 18 ++
|
||||
drivers/block/Makefile | 1 +
|
||||
drivers/block/blk-uclass.c | 1 +
|
||||
drivers/block/blkmap.c | 343 +++++++++++++++++++++++++++++++++++++
|
||||
include/blkmap.h | 35 ++++
|
||||
include/dm/uclass-id.h | 1 +
|
||||
7 files changed, 405 insertions(+)
|
||||
create mode 100644 drivers/block/blkmap.c
|
||||
create mode 100644 include/blkmap.h
|
||||
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 6f53f9c2f6..3e47c9b34c 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -793,6 +793,12 @@ M: Alper Nebi Yasak <alpernebiyasak@gmail.com>
|
||||
S: Maintained
|
||||
F: tools/binman/
|
||||
|
||||
+BLKMAP
|
||||
+M: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
+S: Maintained
|
||||
+F: drivers/block/blkmap.c
|
||||
+F: include/blkmap.h
|
||||
+
|
||||
BOOTDEVICE
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
S: Maintained
|
||||
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
|
||||
index e95da48bdc..5a1aeb3d2b 100644
|
||||
--- a/drivers/block/Kconfig
|
||||
+++ b/drivers/block/Kconfig
|
||||
@@ -67,6 +67,24 @@ config BLOCK_CACHE
|
||||
it will prevent repeated reads from directory structures and other
|
||||
filesystem data structures.
|
||||
|
||||
+config BLKMAP
|
||||
+ bool "Composable virtual block devices (blkmap)"
|
||||
+ depends on BLK
|
||||
+ help
|
||||
+ Create virtual block devices that are backed by various sources,
|
||||
+ e.g. RAM, or parts of an existing block device. Though much more
|
||||
+ rudimentary, it borrows a lot of ideas from Linux's device mapper
|
||||
+ subsystem.
|
||||
+
|
||||
+ Example use-cases:
|
||||
+ - Treat a region of RAM as a block device, i.e. a RAM disk. This let's
|
||||
+ you extract files from filesystem images stored in RAM (perhaps as a
|
||||
+ result of a TFTP transfer).
|
||||
+ - Create a virtual partition on an existing device. This let's you
|
||||
+ access filesystems that aren't stored at an exact partition
|
||||
+ boundary. A common example is a filesystem image embedded in an FIT
|
||||
+ image.
|
||||
+
|
||||
config SPL_BLOCK_CACHE
|
||||
bool "Use block device cache in SPL"
|
||||
depends on SPL_BLK
|
||||
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
|
||||
index f12447d78d..a161d145fd 100644
|
||||
--- a/drivers/block/Makefile
|
||||
+++ b/drivers/block/Makefile
|
||||
@@ -14,6 +14,7 @@ obj-$(CONFIG_IDE) += ide.o
|
||||
endif
|
||||
obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
|
||||
+obj-$(CONFIG_BLKMAP) += blkmap.o
|
||||
|
||||
obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o
|
||||
obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o
|
||||
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
|
||||
index c69fc4d518..cb73faaeda 100644
|
||||
--- a/drivers/block/blk-uclass.c
|
||||
+++ b/drivers/block/blk-uclass.c
|
||||
@@ -32,6 +32,7 @@ static struct {
|
||||
{ UCLASS_EFI_LOADER, "efiloader" },
|
||||
{ UCLASS_VIRTIO, "virtio" },
|
||||
{ UCLASS_PVBLOCK, "pvblock" },
|
||||
+ { UCLASS_BLKMAP, "blkmap" },
|
||||
};
|
||||
|
||||
static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
|
||||
diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c
|
||||
new file mode 100644
|
||||
index 0000000000..acfc002ceb
|
||||
--- /dev/null
|
||||
+++ b/drivers/block/blkmap.c
|
||||
@@ -0,0 +1,343 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (c) 2023 Addiva Elektronik
|
||||
+ * Author: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
+ */
|
||||
+
|
||||
+#include <common.h>
|
||||
+#include <blk.h>
|
||||
+#include <blkmap.h>
|
||||
+#include <dm.h>
|
||||
+#include <malloc.h>
|
||||
+#include <mapmem.h>
|
||||
+#include <part.h>
|
||||
+#include <dm/device-internal.h>
|
||||
+#include <dm/lists.h>
|
||||
+#include <dm/root.h>
|
||||
+
|
||||
+struct blkmap;
|
||||
+
|
||||
+/**
|
||||
+ * struct blkmap_slice - Region mapped to a blkmap
|
||||
+ *
|
||||
+ * Common data for a region mapped to a blkmap, specialized by each
|
||||
+ * map type.
|
||||
+ *
|
||||
+ * @node: List node used to associate this slice with a blkmap
|
||||
+ * @blknr: Start block number of the mapping
|
||||
+ * @blkcnt: Number of blocks covered by this mapping
|
||||
+ */
|
||||
+struct blkmap_slice {
|
||||
+ struct list_head node;
|
||||
+
|
||||
+ lbaint_t blknr;
|
||||
+ lbaint_t blkcnt;
|
||||
+
|
||||
+ /**
|
||||
+ * @read: - Read from slice
|
||||
+ *
|
||||
+ * @read.bm: Blkmap to which this slice belongs
|
||||
+ * @read.bms: This slice
|
||||
+ * @read.blknr: Start block number to read from
|
||||
+ * @read.blkcnt: Number of blocks to read
|
||||
+ * @read.buffer: Buffer to store read data to
|
||||
+ */
|
||||
+ ulong (*read)(struct blkmap *bm, struct blkmap_slice *bms,
|
||||
+ lbaint_t blknr, lbaint_t blkcnt, void *buffer);
|
||||
+
|
||||
+ /**
|
||||
+ * @write: - Write to slice
|
||||
+ *
|
||||
+ * @write.bm: Blkmap to which this slice belongs
|
||||
+ * @write.bms: This slice
|
||||
+ * @write.blknr: Start block number to write to
|
||||
+ * @write.blkcnt: Number of blocks to write
|
||||
+ * @write.buffer: Data to be written
|
||||
+ */
|
||||
+ ulong (*write)(struct blkmap *bm, struct blkmap_slice *bms,
|
||||
+ lbaint_t blknr, lbaint_t blkcnt, const void *buffer);
|
||||
+
|
||||
+ /**
|
||||
+ * @destroy: - Tear down slice
|
||||
+ *
|
||||
+ * @read.bm: Blkmap to which this slice belongs
|
||||
+ * @read.bms: This slice
|
||||
+ */
|
||||
+ void (*destroy)(struct blkmap *bm, struct blkmap_slice *bms);
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct blkmap - Block map
|
||||
+ *
|
||||
+ * Data associated with a blkmap.
|
||||
+ *
|
||||
+ * @label: Human readable name of this blkmap
|
||||
+ * @blk: Underlying block device
|
||||
+ * @slices: List of slices associated with this blkmap
|
||||
+ */
|
||||
+struct blkmap {
|
||||
+ char *label;
|
||||
+ struct udevice *blk;
|
||||
+ struct list_head slices;
|
||||
+};
|
||||
+
|
||||
+static bool blkmap_slice_contains(struct blkmap_slice *bms, lbaint_t blknr)
|
||||
+{
|
||||
+ return (blknr >= bms->blknr) && (blknr < (bms->blknr + bms->blkcnt));
|
||||
+}
|
||||
+
|
||||
+static bool blkmap_slice_available(struct blkmap *bm, struct blkmap_slice *new)
|
||||
+{
|
||||
+ struct blkmap_slice *bms;
|
||||
+ lbaint_t first, last;
|
||||
+
|
||||
+ first = new->blknr;
|
||||
+ last = new->blknr + new->blkcnt - 1;
|
||||
+
|
||||
+ list_for_each_entry(bms, &bm->slices, node) {
|
||||
+ if (blkmap_slice_contains(bms, first) ||
|
||||
+ blkmap_slice_contains(bms, last) ||
|
||||
+ blkmap_slice_contains(new, bms->blknr) ||
|
||||
+ blkmap_slice_contains(new, bms->blknr + bms->blkcnt - 1))
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static int blkmap_slice_add(struct blkmap *bm, struct blkmap_slice *new)
|
||||
+{
|
||||
+ struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
|
||||
+ struct list_head *insert = &bm->slices;
|
||||
+ struct blkmap_slice *bms;
|
||||
+
|
||||
+ if (!blkmap_slice_available(bm, new))
|
||||
+ return -EBUSY;
|
||||
+
|
||||
+ list_for_each_entry(bms, &bm->slices, node) {
|
||||
+ if (bms->blknr < new->blknr)
|
||||
+ continue;
|
||||
+
|
||||
+ insert = &bms->node;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ list_add_tail(&new->node, insert);
|
||||
+
|
||||
+ /* Disk might have grown, update the size */
|
||||
+ bms = list_last_entry(&bm->slices, struct blkmap_slice, node);
|
||||
+ bd->lba = bms->blknr + bms->blkcnt;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static ulong blkmap_blk_read_slice(struct blkmap *bm, struct blkmap_slice *bms,
|
||||
+ lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ void *buffer)
|
||||
+{
|
||||
+ lbaint_t nr, cnt;
|
||||
+
|
||||
+ nr = blknr - bms->blknr;
|
||||
+ cnt = (blkcnt < bms->blkcnt) ? blkcnt : bms->blkcnt;
|
||||
+ return bms->read(bm, bms, nr, cnt, buffer);
|
||||
+}
|
||||
+
|
||||
+static ulong blkmap_blk_read(struct udevice *dev, lbaint_t blknr,
|
||||
+ lbaint_t blkcnt, void *buffer)
|
||||
+{
|
||||
+ struct blk_desc *bd = dev_get_uclass_plat(dev);
|
||||
+ struct blkmap *bm = dev_get_plat(dev->parent);
|
||||
+ struct blkmap_slice *bms;
|
||||
+ lbaint_t cnt, total = 0;
|
||||
+
|
||||
+ list_for_each_entry(bms, &bm->slices, node) {
|
||||
+ if (!blkmap_slice_contains(bms, blknr))
|
||||
+ continue;
|
||||
+
|
||||
+ cnt = blkmap_blk_read_slice(bm, bms, blknr, blkcnt, buffer);
|
||||
+ blknr += cnt;
|
||||
+ blkcnt -= cnt;
|
||||
+ buffer += cnt << bd->log2blksz;
|
||||
+ total += cnt;
|
||||
+ }
|
||||
+
|
||||
+ return total;
|
||||
+}
|
||||
+
|
||||
+static ulong blkmap_blk_write_slice(struct blkmap *bm, struct blkmap_slice *bms,
|
||||
+ lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ const void *buffer)
|
||||
+{
|
||||
+ lbaint_t nr, cnt;
|
||||
+
|
||||
+ nr = blknr - bms->blknr;
|
||||
+ cnt = (blkcnt < bms->blkcnt) ? blkcnt : bms->blkcnt;
|
||||
+ return bms->write(bm, bms, nr, cnt, buffer);
|
||||
+}
|
||||
+
|
||||
+static ulong blkmap_blk_write(struct udevice *dev, lbaint_t blknr,
|
||||
+ lbaint_t blkcnt, const void *buffer)
|
||||
+{
|
||||
+ struct blk_desc *bd = dev_get_uclass_plat(dev);
|
||||
+ struct blkmap *bm = dev_get_plat(dev->parent);
|
||||
+ struct blkmap_slice *bms;
|
||||
+ lbaint_t cnt, total = 0;
|
||||
+
|
||||
+ list_for_each_entry(bms, &bm->slices, node) {
|
||||
+ if (!blkmap_slice_contains(bms, blknr))
|
||||
+ continue;
|
||||
+
|
||||
+ cnt = blkmap_blk_write_slice(bm, bms, blknr, blkcnt, buffer);
|
||||
+ blknr += cnt;
|
||||
+ blkcnt -= cnt;
|
||||
+ buffer += cnt << bd->log2blksz;
|
||||
+ total += cnt;
|
||||
+ }
|
||||
+
|
||||
+ return total;
|
||||
+}
|
||||
+
|
||||
+static const struct blk_ops blkmap_blk_ops = {
|
||||
+ .read = blkmap_blk_read,
|
||||
+ .write = blkmap_blk_write,
|
||||
+};
|
||||
+
|
||||
+U_BOOT_DRIVER(blkmap_blk) = {
|
||||
+ .name = "blkmap_blk",
|
||||
+ .id = UCLASS_BLK,
|
||||
+ .ops = &blkmap_blk_ops,
|
||||
+};
|
||||
+
|
||||
+int blkmap_dev_bind(struct udevice *dev)
|
||||
+{
|
||||
+ struct blkmap *bm = dev_get_plat(dev);
|
||||
+ struct blk_desc *bd;
|
||||
+ int err;
|
||||
+
|
||||
+ err = blk_create_devicef(dev, "blkmap_blk", "blk", UCLASS_BLKMAP,
|
||||
+ dev_seq(dev), 512, 0, &bm->blk);
|
||||
+ if (err)
|
||||
+ return log_msg_ret("blk", err);
|
||||
+
|
||||
+ INIT_LIST_HEAD(&bm->slices);
|
||||
+
|
||||
+ bd = dev_get_uclass_plat(bm->blk);
|
||||
+ snprintf(bd->vendor, BLK_VEN_SIZE, "U-Boot");
|
||||
+ snprintf(bd->product, BLK_PRD_SIZE, "blkmap");
|
||||
+ snprintf(bd->revision, BLK_REV_SIZE, "1.0");
|
||||
+
|
||||
+ /* EFI core isn't keen on zero-sized disks, so we lie. This is
|
||||
+ * updated with the correct size once the user adds a
|
||||
+ * mapping.
|
||||
+ */
|
||||
+ bd->lba = 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int blkmap_dev_unbind(struct udevice *dev)
|
||||
+{
|
||||
+ struct blkmap *bm = dev_get_plat(dev);
|
||||
+ struct blkmap_slice *bms, *tmp;
|
||||
+ int err;
|
||||
+
|
||||
+ list_for_each_entry_safe(bms, tmp, &bm->slices, node) {
|
||||
+ list_del(&bms->node);
|
||||
+ free(bms);
|
||||
+ }
|
||||
+
|
||||
+ err = device_remove(bm->blk, DM_REMOVE_NORMAL);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ return device_unbind(bm->blk);
|
||||
+}
|
||||
+
|
||||
+U_BOOT_DRIVER(blkmap_root) = {
|
||||
+ .name = "blkmap_dev",
|
||||
+ .id = UCLASS_BLKMAP,
|
||||
+ .bind = blkmap_dev_bind,
|
||||
+ .unbind = blkmap_dev_unbind,
|
||||
+ .plat_auto = sizeof(struct blkmap),
|
||||
+};
|
||||
+
|
||||
+struct udevice *blkmap_from_label(const char *label)
|
||||
+{
|
||||
+ struct udevice *dev;
|
||||
+ struct uclass *uc;
|
||||
+ struct blkmap *bm;
|
||||
+
|
||||
+ uclass_id_foreach_dev(UCLASS_BLKMAP, dev, uc) {
|
||||
+ bm = dev_get_plat(dev);
|
||||
+ if (bm->label && !strcmp(label, bm->label))
|
||||
+ return dev;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+int blkmap_create(const char *label, struct udevice **devp)
|
||||
+{
|
||||
+ char *hname, *hlabel;
|
||||
+ struct udevice *dev;
|
||||
+ struct blkmap *bm;
|
||||
+ size_t namelen;
|
||||
+ int err;
|
||||
+
|
||||
+ dev = blkmap_from_label(label);
|
||||
+ if (dev) {
|
||||
+ err = -EBUSY;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ hlabel = strdup(label);
|
||||
+ if (!hlabel) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ namelen = strlen("blkmap-") + strlen(label) + 1;
|
||||
+ hname = malloc(namelen);
|
||||
+ if (!hname) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto err_free_hlabel;
|
||||
+ }
|
||||
+
|
||||
+ strlcpy(hname, "blkmap-", namelen);
|
||||
+ strlcat(hname, label, namelen);
|
||||
+
|
||||
+ err = device_bind_driver(dm_root(), "blkmap_dev", hname, &dev);
|
||||
+ if (err)
|
||||
+ goto err_free_hname;
|
||||
+
|
||||
+ device_set_name_alloced(dev);
|
||||
+ bm = dev_get_plat(dev);
|
||||
+ bm->label = hlabel;
|
||||
+
|
||||
+ if (devp)
|
||||
+ *devp = dev;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_free_hname:
|
||||
+ free(hname);
|
||||
+err_free_hlabel:
|
||||
+ free(hlabel);
|
||||
+err:
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+int blkmap_destroy(struct udevice *dev)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ err = device_remove(dev, DM_REMOVE_NORMAL);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ return device_unbind(dev);
|
||||
+}
|
||||
+
|
||||
+UCLASS_DRIVER(blkmap) = {
|
||||
+ .id = UCLASS_BLKMAP,
|
||||
+ .name = "blkmap",
|
||||
+};
|
||||
diff --git a/include/blkmap.h b/include/blkmap.h
|
||||
new file mode 100644
|
||||
index 0000000000..3c7e36efab
|
||||
--- /dev/null
|
||||
+++ b/include/blkmap.h
|
||||
@@ -0,0 +1,35 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+/*
|
||||
+ * Copyright (c) 2023 Addiva Elektronik
|
||||
+ * Author: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
+ */
|
||||
+
|
||||
+#ifndef _BLKMAP_H
|
||||
+#define _BLKMAP_H
|
||||
+
|
||||
+/**
|
||||
+ * blkmap_from_label() - Find blkmap from label
|
||||
+ *
|
||||
+ * @label: Label of the requested blkmap
|
||||
+ * Returns: A pointer to the blkmap on success, NULL on failure
|
||||
+ */
|
||||
+struct udevice *blkmap_from_label(const char *label);
|
||||
+
|
||||
+/**
|
||||
+ * blkmap_create() - Create new blkmap
|
||||
+ *
|
||||
+ * @label: Label of the new blkmap
|
||||
+ * @devp: If not NULL, updated with the address of the resulting device
|
||||
+ * Returns: 0 on success, negative error code on failure
|
||||
+ */
|
||||
+int blkmap_create(const char *label, struct udevice **devp);
|
||||
+
|
||||
+/**
|
||||
+ * blkmap_destroy() - Destroy blkmap
|
||||
+ *
|
||||
+ * @dev: The blkmap to be destroyed
|
||||
+ * Returns: 0 on success, negative error code on failure
|
||||
+ */
|
||||
+int blkmap_destroy(struct udevice *dev);
|
||||
+
|
||||
+#endif /* _BLKMAP_H */
|
||||
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
|
||||
index 33e43c20db..576237b954 100644
|
||||
--- a/include/dm/uclass-id.h
|
||||
+++ b/include/dm/uclass-id.h
|
||||
@@ -37,6 +37,7 @@ enum uclass_id {
|
||||
UCLASS_AUDIO_CODEC, /* Audio codec with control and data path */
|
||||
UCLASS_AXI, /* AXI bus */
|
||||
UCLASS_BLK, /* Block device */
|
||||
+ UCLASS_BLKMAP, /* Composable virtual block device */
|
||||
UCLASS_BOOTCOUNT, /* Bootcount backing store */
|
||||
UCLASS_BOOTDEV, /* Boot device for locating an OS to boot */
|
||||
UCLASS_BOOTMETH, /* Bootmethod for booting an OS */
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
From 77fd2a74a5f7a14f42b5c7acd175a9c1519c4f16 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Thu, 16 Feb 2023 15:08:00 +0100
|
||||
Subject: [PATCH v2 4/9] blk: blkmap: Add memory mapping support
|
||||
|
||||
Allow a slice of RAM to be mapped to a blkmap. This means that RAM can
|
||||
now be accessed as if it was a block device, meaning that existing
|
||||
filesystem drivers can now be used to access ramdisks.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
drivers/block/blkmap.c | 105 +++++++++++++++++++++++++++++++++++++++++
|
||||
include/blkmap.h | 29 ++++++++++++
|
||||
2 files changed, 134 insertions(+)
|
||||
|
||||
diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c
|
||||
index acfc002ceb..6d6eed889e 100644
|
||||
--- a/drivers/block/blkmap.c
|
||||
+++ b/drivers/block/blkmap.c
|
||||
@@ -130,6 +130,111 @@ static int blkmap_slice_add(struct blkmap *bm, struct blkmap_slice *new)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * struct blkmap_mem - Memory mapping
|
||||
+ *
|
||||
+ * @slice: Common map data
|
||||
+ * @addr: Target memory region of this mapping
|
||||
+ * @remapped: True if @addr is backed by a physical to virtual memory
|
||||
+ * mapping that must be torn down at the end of this mapping's
|
||||
+ * lifetime.
|
||||
+ */
|
||||
+struct blkmap_mem {
|
||||
+ struct blkmap_slice slice;
|
||||
+ void *addr;
|
||||
+ bool remapped;
|
||||
+};
|
||||
+
|
||||
+static ulong blkmap_mem_read(struct blkmap *bm, struct blkmap_slice *bms,
|
||||
+ lbaint_t blknr, lbaint_t blkcnt, void *buffer)
|
||||
+{
|
||||
+ struct blkmap_mem *bmm = container_of(bms, struct blkmap_mem, slice);
|
||||
+ struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
|
||||
+ char *src;
|
||||
+
|
||||
+ src = bmm->addr + (blknr << bd->log2blksz);
|
||||
+ memcpy(buffer, src, blkcnt << bd->log2blksz);
|
||||
+ return blkcnt;
|
||||
+}
|
||||
+
|
||||
+static ulong blkmap_mem_write(struct blkmap *bm, struct blkmap_slice *bms,
|
||||
+ lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ const void *buffer)
|
||||
+{
|
||||
+ struct blkmap_mem *bmm = container_of(bms, struct blkmap_mem, slice);
|
||||
+ struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
|
||||
+ char *dst;
|
||||
+
|
||||
+ dst = bmm->addr + (blknr << bd->log2blksz);
|
||||
+ memcpy(dst, buffer, blkcnt << bd->log2blksz);
|
||||
+ return blkcnt;
|
||||
+}
|
||||
+
|
||||
+static void blkmap_mem_destroy(struct blkmap *bm, struct blkmap_slice *bms)
|
||||
+{
|
||||
+ struct blkmap_mem *bmm = container_of(bms, struct blkmap_mem, slice);
|
||||
+
|
||||
+ if (bmm->remapped)
|
||||
+ unmap_sysmem(bmm->addr);
|
||||
+}
|
||||
+
|
||||
+int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ void *addr, bool remapped)
|
||||
+{
|
||||
+ struct blkmap *bm = dev_get_plat(dev);
|
||||
+ struct blkmap_mem *bmm;
|
||||
+ int err;
|
||||
+
|
||||
+ bmm = malloc(sizeof(*bmm));
|
||||
+ if (!bmm)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ *bmm = (struct blkmap_mem) {
|
||||
+ .slice = {
|
||||
+ .blknr = blknr,
|
||||
+ .blkcnt = blkcnt,
|
||||
+
|
||||
+ .read = blkmap_mem_read,
|
||||
+ .write = blkmap_mem_write,
|
||||
+ .destroy = blkmap_mem_destroy,
|
||||
+ },
|
||||
+
|
||||
+ .addr = addr,
|
||||
+ .remapped = remapped,
|
||||
+ };
|
||||
+
|
||||
+ err = blkmap_slice_add(bm, &bmm->slice);
|
||||
+ if (err)
|
||||
+ free(bmm);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+int blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ void *addr)
|
||||
+{
|
||||
+ return __blkmap_map_mem(dev, blknr, blkcnt, addr, false);
|
||||
+}
|
||||
+
|
||||
+int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ phys_addr_t paddr)
|
||||
+{
|
||||
+ struct blkmap *bm = dev_get_plat(dev);
|
||||
+ struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
|
||||
+ void *addr;
|
||||
+ int err;
|
||||
+
|
||||
+ addr = map_sysmem(paddr, blkcnt << bd->log2blksz);
|
||||
+ if (!addr)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ err = __blkmap_map_mem(dev, blknr, blkcnt, addr, true);
|
||||
+ if (err)
|
||||
+ unmap_sysmem(addr);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static ulong blkmap_blk_read_slice(struct blkmap *bm, struct blkmap_slice *bms,
|
||||
lbaint_t blknr, lbaint_t blkcnt,
|
||||
void *buffer)
|
||||
diff --git a/include/blkmap.h b/include/blkmap.h
|
||||
index 3c7e36efab..74baeb19f8 100644
|
||||
--- a/include/blkmap.h
|
||||
+++ b/include/blkmap.h
|
||||
@@ -7,6 +7,35 @@
|
||||
#ifndef _BLKMAP_H
|
||||
#define _BLKMAP_H
|
||||
|
||||
+/**
|
||||
+ * blkmap_map_mem() - Map region of memory
|
||||
+ *
|
||||
+ * @dev: Blkmap to create the mapping on
|
||||
+ * @blknr: Start block number of the mapping
|
||||
+ * @blkcnt: Number of blocks to map
|
||||
+ * @addr: The target memory address of the mapping
|
||||
+ * Returns: 0 on success, negative error code on failure
|
||||
+ */
|
||||
+int blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ void *addr);
|
||||
+
|
||||
+/**
|
||||
+ * blkmap_map_pmem() - Map region of physical memory
|
||||
+ *
|
||||
+ * Ensures that a valid physical to virtual memory mapping for the
|
||||
+ * requested region is valid for the lifetime of the mapping, on
|
||||
+ * architectures that require it (sandbox).
|
||||
+ *
|
||||
+ * @dev: Blkmap to create the mapping on
|
||||
+ * @blknr: Start block number of the mapping
|
||||
+ * @blkcnt: Number of blocks to map
|
||||
+ * @paddr: The target physical memory address of the mapping
|
||||
+ * Returns: 0 on success, negative error code on failure
|
||||
+ */
|
||||
+int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ phys_addr_t paddr);
|
||||
+
|
||||
+
|
||||
/**
|
||||
* blkmap_from_label() - Find blkmap from label
|
||||
*
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
From 29ed14e1a427c4e308413bccdc75084c1c1ec75a Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Thu, 16 Feb 2023 15:09:21 +0100
|
||||
Subject: [PATCH v2 5/9] blk: blkmap: Add linear device mapping support
|
||||
|
||||
Allow a slice of an existing block device to be mapped to a
|
||||
blkmap. This means that filesystems that are not stored at exact
|
||||
partition boundaries can be accessed by remapping a slice of the
|
||||
existing device to a blkmap device.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
drivers/block/blkmap.c | 71 ++++++++++++++++++++++++++++++++++++++++++
|
||||
include/blkmap.h | 13 ++++++++
|
||||
2 files changed, 84 insertions(+)
|
||||
|
||||
diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c
|
||||
index 6d6eed889e..2bb0acc20f 100644
|
||||
--- a/drivers/block/blkmap.c
|
||||
+++ b/drivers/block/blkmap.c
|
||||
@@ -130,6 +130,77 @@ static int blkmap_slice_add(struct blkmap *bm, struct blkmap_slice *new)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * struct blkmap_linear - Linear mapping to other block device
|
||||
+ *
|
||||
+ * @slice: Common map data
|
||||
+ * @blk: Target block device of this mapping
|
||||
+ * @blknr: Start block number of the target device
|
||||
+ */
|
||||
+struct blkmap_linear {
|
||||
+ struct blkmap_slice slice;
|
||||
+
|
||||
+ struct udevice *blk;
|
||||
+ lbaint_t blknr;
|
||||
+};
|
||||
+
|
||||
+static ulong blkmap_linear_read(struct blkmap *bm, struct blkmap_slice *bms,
|
||||
+ lbaint_t blknr, lbaint_t blkcnt, void *buffer)
|
||||
+{
|
||||
+ struct blkmap_linear *bml = container_of(bms, struct blkmap_linear, slice);
|
||||
+
|
||||
+ return blk_read(bml->blk, bml->blknr + blknr, blkcnt, buffer);
|
||||
+}
|
||||
+
|
||||
+static ulong blkmap_linear_write(struct blkmap *bm, struct blkmap_slice *bms,
|
||||
+ lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ const void *buffer)
|
||||
+{
|
||||
+ struct blkmap_linear *bml = container_of(bms, struct blkmap_linear, slice);
|
||||
+
|
||||
+ return blk_write(bml->blk, bml->blknr + blknr, blkcnt, buffer);
|
||||
+}
|
||||
+
|
||||
+int blkmap_map_linear(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ struct udevice *lblk, lbaint_t lblknr)
|
||||
+{
|
||||
+ struct blkmap *bm = dev_get_plat(dev);
|
||||
+ struct blkmap_linear *linear;
|
||||
+ struct blk_desc *bd, *lbd;
|
||||
+ int err;
|
||||
+
|
||||
+ bd = dev_get_uclass_plat(bm->blk);
|
||||
+ lbd = dev_get_uclass_plat(lblk);
|
||||
+ if (lbd->blksz != bd->blksz)
|
||||
+ /* We could support block size translation, but we
|
||||
+ * don't yet.
|
||||
+ */
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ linear = malloc(sizeof(*linear));
|
||||
+ if (!linear)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ *linear = (struct blkmap_linear) {
|
||||
+ .slice = {
|
||||
+ .blknr = blknr,
|
||||
+ .blkcnt = blkcnt,
|
||||
+
|
||||
+ .read = blkmap_linear_read,
|
||||
+ .write = blkmap_linear_write,
|
||||
+ },
|
||||
+
|
||||
+ .blk = lblk,
|
||||
+ .blknr = lblknr,
|
||||
+ };
|
||||
+
|
||||
+ err = blkmap_slice_add(bm, &linear->slice);
|
||||
+ if (err)
|
||||
+ free(linear);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* struct blkmap_mem - Memory mapping
|
||||
*
|
||||
diff --git a/include/blkmap.h b/include/blkmap.h
|
||||
index 74baeb19f8..af54583c7d 100644
|
||||
--- a/include/blkmap.h
|
||||
+++ b/include/blkmap.h
|
||||
@@ -7,6 +7,19 @@
|
||||
#ifndef _BLKMAP_H
|
||||
#define _BLKMAP_H
|
||||
|
||||
+/**
|
||||
+ * blkmap_map_linear() - Map region of other block device
|
||||
+ *
|
||||
+ * @dev: Blkmap to create the mapping on
|
||||
+ * @blknr: Start block number of the mapping
|
||||
+ * @blkcnt: Number of blocks to map
|
||||
+ * @lblk: The target block device of the mapping
|
||||
+ * @lblknr: The start block number of the target device
|
||||
+ * Returns: 0 on success, negative error code on failure
|
||||
+ */
|
||||
+int blkmap_map_linear(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
+ struct udevice *lblk, lbaint_t lblknr);
|
||||
+
|
||||
/**
|
||||
* blkmap_map_mem() - Map region of memory
|
||||
*
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,337 +0,0 @@
|
||||
From c20dd0f17a128e65c1f376bf0e1cad9cec1d0336 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Thu, 16 Feb 2023 15:10:49 +0100
|
||||
Subject: [PATCH v2 6/9] cmd: blkmap: Add blkmap command
|
||||
|
||||
Add a frontend for the blkmap subsystem. In addition to the common
|
||||
block device operations, this allows users to create and destroy
|
||||
devices, and map in memory and slices of other block devices.
|
||||
|
||||
With that we support two primary use-cases:
|
||||
|
||||
- Being able to "distro boot" from a RAM disk. I.e., from an image
|
||||
where the kernel is stored in /boot of some filesystem supported
|
||||
by U-Boot.
|
||||
|
||||
- Accessing filesystems not located on exact partition boundaries,
|
||||
e.g. when a filesystem image is wrapped in an FIT image and stored
|
||||
in a disk partition.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
MAINTAINERS | 1 +
|
||||
cmd/Kconfig | 19 +++++
|
||||
cmd/Makefile | 1 +
|
||||
cmd/blkmap.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
disk/part.c | 1 +
|
||||
5 files changed, 255 insertions(+)
|
||||
create mode 100644 cmd/blkmap.c
|
||||
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 3e47c9b34c..316b85fed7 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -796,6 +796,7 @@ F: tools/binman/
|
||||
BLKMAP
|
||||
M: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
S: Maintained
|
||||
+F: cmd/blkmap.c
|
||||
F: drivers/block/blkmap.c
|
||||
F: include/blkmap.h
|
||||
|
||||
diff --git a/cmd/Kconfig b/cmd/Kconfig
|
||||
index 2caa4af71c..3dd3cdc656 100644
|
||||
--- a/cmd/Kconfig
|
||||
+++ b/cmd/Kconfig
|
||||
@@ -1959,6 +1959,25 @@ config CMD_BLOCK_CACHE
|
||||
during development, but also allows the cache to be disabled when
|
||||
it might hurt performance (e.g. when using the ums command).
|
||||
|
||||
+config CMD_BLKMAP
|
||||
+ bool "blkmap - Composable virtual block devices"
|
||||
+ depends on BLKMAP
|
||||
+ default y if BLKMAP
|
||||
+ help
|
||||
+ Create virtual block devices that are backed by various sources,
|
||||
+ e.g. RAM, or parts of an existing block device. Though much more
|
||||
+ rudimentary, it borrows a lot of ideas from Linux's device mapper
|
||||
+ subsystem.
|
||||
+
|
||||
+ Example use-cases:
|
||||
+ - Treat a region of RAM as a block device, i.e. a RAM disk. This let's
|
||||
+ you extract files from filesystem images stored in RAM (perhaps as a
|
||||
+ result of a TFTP transfer).
|
||||
+ - Create a virtual partition on an existing device. This let's you
|
||||
+ access filesystems that aren't stored at an exact partition
|
||||
+ boundary. A common example is a filesystem image embedded in an FIT
|
||||
+ image.
|
||||
+
|
||||
config CMD_BUTTON
|
||||
bool "button"
|
||||
depends on BUTTON
|
||||
diff --git a/cmd/Makefile b/cmd/Makefile
|
||||
index 36d2daf22a..837eee39b1 100644
|
||||
--- a/cmd/Makefile
|
||||
+++ b/cmd/Makefile
|
||||
@@ -27,6 +27,7 @@ obj-$(CONFIG_CMD_BCB) += bcb.o
|
||||
obj-$(CONFIG_CMD_BDI) += bdinfo.o
|
||||
obj-$(CONFIG_CMD_BIND) += bind.o
|
||||
obj-$(CONFIG_CMD_BINOP) += binop.o
|
||||
+obj-$(CONFIG_CMD_BLKMAP) += blkmap.o
|
||||
obj-$(CONFIG_CMD_BLOBLIST) += bloblist.o
|
||||
obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o
|
||||
obj-$(CONFIG_CMD_BMP) += bmp.o
|
||||
diff --git a/cmd/blkmap.c b/cmd/blkmap.c
|
||||
new file mode 100644
|
||||
index 0000000000..b34c013072
|
||||
--- /dev/null
|
||||
+++ b/cmd/blkmap.c
|
||||
@@ -0,0 +1,233 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (c) 2023 Addiva Elektronik
|
||||
+ * Author: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
+ */
|
||||
+
|
||||
+#include <blk.h>
|
||||
+#include <blkmap.h>
|
||||
+#include <common.h>
|
||||
+#include <command.h>
|
||||
+#include <malloc.h>
|
||||
+#include <dm/device.h>
|
||||
+
|
||||
+static int blkmap_curr_dev;
|
||||
+
|
||||
+struct map_ctx {
|
||||
+ struct udevice *dev;
|
||||
+ lbaint_t blknr, blkcnt;
|
||||
+};
|
||||
+
|
||||
+typedef int (*map_parser_fn)(struct map_ctx *ctx, int argc, char *const argv[]);
|
||||
+
|
||||
+struct map_handler {
|
||||
+ const char *name;
|
||||
+ map_parser_fn fn;
|
||||
+};
|
||||
+
|
||||
+int do_blkmap_map_linear(struct map_ctx *ctx, int argc, char *const argv[])
|
||||
+{
|
||||
+ struct blk_desc *lbd;
|
||||
+ int err, ldevnum;
|
||||
+ lbaint_t lblknr;
|
||||
+
|
||||
+ if (argc < 4)
|
||||
+ return CMD_RET_USAGE;
|
||||
+
|
||||
+ ldevnum = dectoul(argv[2], NULL);
|
||||
+ lblknr = dectoul(argv[3], NULL);
|
||||
+
|
||||
+ lbd = blk_get_devnum_by_uclass_idname(argv[1], ldevnum);
|
||||
+ if (!lbd) {
|
||||
+ printf("Found no device matching \"%s %d\"\n",
|
||||
+ argv[1], ldevnum);
|
||||
+ return CMD_RET_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ err = blkmap_map_linear(ctx->dev, ctx->blknr, ctx->blkcnt,
|
||||
+ lbd->bdev, lblknr);
|
||||
+ if (err) {
|
||||
+ printf("Unable to map \"%s %d\" at block 0x" LBAF ": %d\n",
|
||||
+ argv[1], ldevnum, ctx->blknr, err);
|
||||
+
|
||||
+ return CMD_RET_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ printf("Block 0x" LBAF "+0x" LBAF " mapped to block 0x" LBAF " of \"%s %d\"\n",
|
||||
+ ctx->blknr, ctx->blkcnt, lblknr, argv[1], ldevnum);
|
||||
+ return CMD_RET_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+int do_blkmap_map_mem(struct map_ctx *ctx, int argc, char *const argv[])
|
||||
+{
|
||||
+ phys_addr_t addr;
|
||||
+ int err;
|
||||
+
|
||||
+ if (argc < 2)
|
||||
+ return CMD_RET_USAGE;
|
||||
+
|
||||
+ addr = hextoul(argv[1], NULL);
|
||||
+
|
||||
+ err = blkmap_map_pmem(ctx->dev, ctx->blknr, ctx->blkcnt, addr);
|
||||
+ if (err) {
|
||||
+ printf("Unable to map %#llx at block 0x" LBAF ": %d\n",
|
||||
+ (unsigned long long)addr, ctx->blknr, err);
|
||||
+ return CMD_RET_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ printf("Block 0x" LBAF "+0x" LBAF " mapped to %#llx\n",
|
||||
+ ctx->blknr, ctx->blkcnt, (unsigned long long)addr);
|
||||
+ return CMD_RET_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+struct map_handler map_handlers[] = {
|
||||
+ { .name = "linear", .fn = do_blkmap_map_linear },
|
||||
+ { .name = "mem", .fn = do_blkmap_map_mem },
|
||||
+
|
||||
+ { .name = NULL }
|
||||
+};
|
||||
+
|
||||
+static int do_blkmap_map(struct cmd_tbl *cmdtp, int flag,
|
||||
+ int argc, char *const argv[])
|
||||
+{
|
||||
+ struct map_handler *handler;
|
||||
+ struct map_ctx ctx;
|
||||
+
|
||||
+ if (argc < 5)
|
||||
+ return CMD_RET_USAGE;
|
||||
+
|
||||
+ ctx.dev = blkmap_from_label(argv[1]);
|
||||
+ if (!ctx.dev) {
|
||||
+ printf("\"%s\" is not the name of any known blkmap\n", argv[1]);
|
||||
+ return CMD_RET_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ ctx.blknr = hextoul(argv[2], NULL);
|
||||
+ ctx.blkcnt = hextoul(argv[3], NULL);
|
||||
+ argc -= 4;
|
||||
+ argv += 4;
|
||||
+
|
||||
+ for (handler = map_handlers; handler->name; handler++) {
|
||||
+ if (!strcmp(handler->name, argv[0]))
|
||||
+ return handler->fn(&ctx, argc, argv);
|
||||
+ }
|
||||
+
|
||||
+ printf("Unknown map type \"%s\"\n", argv[0]);
|
||||
+ return CMD_RET_USAGE;
|
||||
+}
|
||||
+
|
||||
+static int do_blkmap_create(struct cmd_tbl *cmdtp, int flag,
|
||||
+ int argc, char *const argv[])
|
||||
+{
|
||||
+ const char *label;
|
||||
+ int err;
|
||||
+
|
||||
+ if (argc != 2)
|
||||
+ return CMD_RET_USAGE;
|
||||
+
|
||||
+ label = argv[1];
|
||||
+
|
||||
+ err = blkmap_create(label, NULL);
|
||||
+ if (err) {
|
||||
+ printf("Unable to create \"%s\": %d\n", label, err);
|
||||
+ return CMD_RET_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ printf("Created \"%s\"\n", label);
|
||||
+ return CMD_RET_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static int do_blkmap_destroy(struct cmd_tbl *cmdtp, int flag,
|
||||
+ int argc, char *const argv[])
|
||||
+{
|
||||
+ struct udevice *dev;
|
||||
+ const char *label;
|
||||
+ int err;
|
||||
+
|
||||
+ if (argc != 2)
|
||||
+ return CMD_RET_USAGE;
|
||||
+
|
||||
+ label = argv[1];
|
||||
+
|
||||
+ dev = blkmap_from_label(label);
|
||||
+ if (!dev) {
|
||||
+ printf("\"%s\" is not the name of any known blkmap\n", label);
|
||||
+ return CMD_RET_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ err = blkmap_destroy(dev);
|
||||
+ if (err) {
|
||||
+ printf("Unable to destroy \"%s\": %d\n", label, err);
|
||||
+ return CMD_RET_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ printf("Destroyed \"%s\"\n", label);
|
||||
+ return CMD_RET_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static int do_blkmap_get(struct cmd_tbl *cmdtp, int flag,
|
||||
+ int argc, char *const argv[])
|
||||
+{
|
||||
+ struct udevice *dev;
|
||||
+ const char *label;
|
||||
+ int err;
|
||||
+
|
||||
+ if (argc < 3)
|
||||
+ return CMD_RET_USAGE;
|
||||
+
|
||||
+ label = argv[1];
|
||||
+
|
||||
+ dev = blkmap_from_label(label);
|
||||
+ if (!dev) {
|
||||
+ printf("\"%s\" is not the name of any known blkmap\n", label);
|
||||
+ return CMD_RET_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ if (!strcmp(argv[2], "dev")) {
|
||||
+ if (argc == 3) {
|
||||
+ printf("%d\n", dev_seq(dev));
|
||||
+ } else {
|
||||
+ err = env_set_hex(argv[3], dev_seq(dev));
|
||||
+ if (err)
|
||||
+ return CMD_RET_FAILURE;
|
||||
+ }
|
||||
+ } else {
|
||||
+ return CMD_RET_USAGE;
|
||||
+ }
|
||||
+
|
||||
+ return CMD_RET_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static int do_blkmap_common(struct cmd_tbl *cmdtp, int flag,
|
||||
+ int argc, char *const argv[])
|
||||
+{
|
||||
+ /* The subcommand parsing pops the original argv[0] ("blkmap")
|
||||
+ * which blk_common_cmd expects. Push it back again.
|
||||
+ */
|
||||
+ argc++;
|
||||
+ argv--;
|
||||
+
|
||||
+ return blk_common_cmd(argc, argv, UCLASS_BLKMAP, &blkmap_curr_dev);
|
||||
+}
|
||||
+
|
||||
+U_BOOT_CMD_WITH_SUBCMDS(
|
||||
+ blkmap, "Composeable virtual block devices",
|
||||
+ "info - list configured devices\n"
|
||||
+ "blkmap part - list available partitions on current blkmap device\n"
|
||||
+ "blkmap dev [<dev>] - show or set current blkmap device\n"
|
||||
+ "blkmap read <addr> <blk#> <cnt>\n"
|
||||
+ "blkmap write <addr> <blk#> <cnt>\n"
|
||||
+ "blkmap get <label> dev [<var>] - store device number in variable\n"
|
||||
+ "blkmap create <label> - create device\n"
|
||||
+ "blkmap destroy <label> - destroy device\n"
|
||||
+ "blkmap map <label> <blk#> <cnt> linear <interface> <dev> <blk#> - device mapping\n"
|
||||
+ "blkmap map <label> <blk#> <cnt> mem <addr> - memory mapping\n",
|
||||
+ U_BOOT_SUBCMD_MKENT(info, 2, 1, do_blkmap_common),
|
||||
+ U_BOOT_SUBCMD_MKENT(part, 2, 1, do_blkmap_common),
|
||||
+ U_BOOT_SUBCMD_MKENT(dev, 4, 1, do_blkmap_common),
|
||||
+ U_BOOT_SUBCMD_MKENT(read, 5, 1, do_blkmap_common),
|
||||
+ U_BOOT_SUBCMD_MKENT(write, 5, 1, do_blkmap_common),
|
||||
+ U_BOOT_SUBCMD_MKENT(get, 5, 1, do_blkmap_get),
|
||||
+ U_BOOT_SUBCMD_MKENT(create, 2, 1, do_blkmap_create),
|
||||
+ U_BOOT_SUBCMD_MKENT(destroy, 2, 1, do_blkmap_destroy),
|
||||
+ U_BOOT_SUBCMD_MKENT(map, 32, 1, do_blkmap_map));
|
||||
diff --git a/disk/part.c b/disk/part.c
|
||||
index d449635254..35300df590 100644
|
||||
--- a/disk/part.c
|
||||
+++ b/disk/part.c
|
||||
@@ -140,6 +140,7 @@ void dev_print(struct blk_desc *dev_desc)
|
||||
case UCLASS_NVME:
|
||||
case UCLASS_PVBLOCK:
|
||||
case UCLASS_HOST:
|
||||
+ case UCLASS_BLKMAP:
|
||||
printf ("Vendor: %s Rev: %s Prod: %s\n",
|
||||
dev_desc->vendor,
|
||||
dev_desc->revision,
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
From e9a394da1d75b2b3bea81e53ec2899d240a98861 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Thu, 16 Feb 2023 15:13:33 +0100
|
||||
Subject: [PATCH v2 7/9] test: blkmap: Add test suite
|
||||
|
||||
Verify that:
|
||||
|
||||
- Block maps can be created and destroyed
|
||||
- Mappings aren't allowed to overlap
|
||||
- Multiple mappings can be attached and be read/written from/to
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
MAINTAINERS | 1 +
|
||||
configs/sandbox_defconfig | 1 +
|
||||
test/dm/Makefile | 1 +
|
||||
test/dm/blkmap.c | 201 ++++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 204 insertions(+)
|
||||
create mode 100644 test/dm/blkmap.c
|
||||
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 316b85fed7..bbcb5117fe 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -799,6 +799,7 @@ S: Maintained
|
||||
F: cmd/blkmap.c
|
||||
F: drivers/block/blkmap.c
|
||||
F: include/blkmap.h
|
||||
+F: test/dm/blkmap.c
|
||||
|
||||
BOOTDEVICE
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
|
||||
index 34c342b6f5..06021e4902 100644
|
||||
--- a/configs/sandbox_defconfig
|
||||
+++ b/configs/sandbox_defconfig
|
||||
@@ -145,6 +145,7 @@ CONFIG_ADC=y
|
||||
CONFIG_ADC_SANDBOX=y
|
||||
CONFIG_AXI=y
|
||||
CONFIG_AXI_SANDBOX=y
|
||||
+CONFIG_BLKMAP=y
|
||||
CONFIG_SYS_IDE_MAXBUS=1
|
||||
CONFIG_SYS_ATA_BASE_ADDR=0x100
|
||||
CONFIG_SYS_ATA_STRIDE=4
|
||||
diff --git a/test/dm/Makefile b/test/dm/Makefile
|
||||
index 7a79b6e1a2..e15bdbf04b 100644
|
||||
--- a/test/dm/Makefile
|
||||
+++ b/test/dm/Makefile
|
||||
@@ -29,6 +29,7 @@ obj-$(CONFIG_ADC) += adc.o
|
||||
obj-$(CONFIG_SOUND) += audio.o
|
||||
obj-$(CONFIG_AXI) += axi.o
|
||||
obj-$(CONFIG_BLK) += blk.o
|
||||
+obj-$(CONFIG_BLKMAP) += blkmap.o
|
||||
obj-$(CONFIG_BUTTON) += button.o
|
||||
obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o
|
||||
obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode.o
|
||||
diff --git a/test/dm/blkmap.c b/test/dm/blkmap.c
|
||||
new file mode 100644
|
||||
index 0000000000..7a163d6eae
|
||||
--- /dev/null
|
||||
+++ b/test/dm/blkmap.c
|
||||
@@ -0,0 +1,201 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (c) 2023 Addiva Elektronik
|
||||
+ * Author: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
+ */
|
||||
+
|
||||
+#include <common.h>
|
||||
+#include <blk.h>
|
||||
+#include <blkmap.h>
|
||||
+#include <dm.h>
|
||||
+#include <asm/test.h>
|
||||
+#include <dm/test.h>
|
||||
+#include <test/test.h>
|
||||
+#include <test/ut.h>
|
||||
+
|
||||
+#define BLKSZ 0x200
|
||||
+
|
||||
+struct mapping {
|
||||
+ int src;
|
||||
+ int cnt;
|
||||
+ int dst;
|
||||
+};
|
||||
+
|
||||
+const struct mapping unordered_mapping[] = {
|
||||
+ { 0, 1, 3 },
|
||||
+ { 1, 3, 0 },
|
||||
+ { 4, 2, 6 },
|
||||
+ { 6, 2, 4 },
|
||||
+
|
||||
+ { 0, 0, 0 }
|
||||
+};
|
||||
+
|
||||
+const struct mapping identity_mapping[] = {
|
||||
+ { 0, 8, 0 },
|
||||
+
|
||||
+ { 0, 0, 0 }
|
||||
+};
|
||||
+
|
||||
+static char identity[8 * BLKSZ];
|
||||
+static char unordered[8 * BLKSZ];
|
||||
+static char buffer[8 * BLKSZ];
|
||||
+
|
||||
+static void mkblob(void *base, const struct mapping *m)
|
||||
+{
|
||||
+ int nr;
|
||||
+
|
||||
+ for (; m->cnt; m++) {
|
||||
+ for (nr = 0; nr < m->cnt; nr++) {
|
||||
+ memset(base + (m->dst + nr) * BLKSZ,
|
||||
+ m->src + nr, BLKSZ);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int dm_test_blkmap_read(struct unit_test_state *uts)
|
||||
+{
|
||||
+ struct udevice *dev, *blk;
|
||||
+ const struct mapping *m;
|
||||
+
|
||||
+ ut_assertok(blkmap_create("rdtest", &dev));
|
||||
+ ut_assertok(blk_get_from_parent(dev, &blk));
|
||||
+
|
||||
+ /* Generate an ordered and an unordered pattern in memory */
|
||||
+ mkblob(unordered, unordered_mapping);
|
||||
+ mkblob(identity, identity_mapping);
|
||||
+
|
||||
+ /* Create a blkmap that cancels out the disorder */
|
||||
+ for (m = unordered_mapping; m->cnt; m++) {
|
||||
+ ut_assertok(blkmap_map_mem(dev, m->src, m->cnt,
|
||||
+ unordered + m->dst * BLKSZ));
|
||||
+ }
|
||||
+
|
||||
+ /* Read out the data via the blkmap device to another area,
|
||||
+ * and verify that it matches the ordered pattern.
|
||||
+ */
|
||||
+ ut_asserteq(8, blk_read(blk, 0, 8, buffer));
|
||||
+ ut_assertok(memcmp(buffer, identity, sizeof(buffer)));
|
||||
+
|
||||
+ ut_assertok(blkmap_destroy(dev));
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_blkmap_read, 0);
|
||||
+
|
||||
+static int dm_test_blkmap_write(struct unit_test_state *uts)
|
||||
+{
|
||||
+ struct udevice *dev, *blk;
|
||||
+ const struct mapping *m;
|
||||
+
|
||||
+ ut_assertok(blkmap_create("wrtest", &dev));
|
||||
+ ut_assertok(blk_get_from_parent(dev, &blk));
|
||||
+
|
||||
+ /* Generate an ordered and an unordered pattern in memory */
|
||||
+ mkblob(unordered, unordered_mapping);
|
||||
+ mkblob(identity, identity_mapping);
|
||||
+
|
||||
+ /* Create a blkmap that mimics the disorder */
|
||||
+ for (m = unordered_mapping; m->cnt; m++) {
|
||||
+ ut_assertok(blkmap_map_mem(dev, m->src, m->cnt,
|
||||
+ buffer + m->dst * BLKSZ));
|
||||
+ }
|
||||
+
|
||||
+ /* Write the ordered data via the blkmap device to another
|
||||
+ * area, and verify that the result matches the unordered
|
||||
+ * pattern.
|
||||
+ */
|
||||
+ ut_asserteq(8, blk_write(blk, 0, 8, identity));
|
||||
+ ut_assertok(memcmp(buffer, unordered, sizeof(buffer)));
|
||||
+
|
||||
+ ut_assertok(blkmap_destroy(dev));
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_blkmap_write, 0);
|
||||
+
|
||||
+static int dm_test_blkmap_slicing(struct unit_test_state *uts)
|
||||
+{
|
||||
+ struct udevice *dev;
|
||||
+
|
||||
+ ut_assertok(blkmap_create("slicetest", &dev));
|
||||
+
|
||||
+ ut_assertok(blkmap_map_mem(dev, 8, 8, NULL));
|
||||
+
|
||||
+ /* Can't overlap on the low end */
|
||||
+ ut_asserteq(-EBUSY, blkmap_map_mem(dev, 4, 5, NULL));
|
||||
+ /* Can't be inside */
|
||||
+ ut_asserteq(-EBUSY, blkmap_map_mem(dev, 10, 2, NULL));
|
||||
+ /* Can't overlap on the high end */
|
||||
+ ut_asserteq(-EBUSY, blkmap_map_mem(dev, 15, 4, NULL));
|
||||
+
|
||||
+ /* But we should be able to add slices right before and
|
||||
+ * after
|
||||
+ */
|
||||
+ ut_assertok(blkmap_map_mem(dev, 4, 4, NULL));
|
||||
+ ut_assertok(blkmap_map_mem(dev, 16, 4, NULL));
|
||||
+
|
||||
+ ut_assertok(blkmap_destroy(dev));
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_blkmap_slicing, 0);
|
||||
+
|
||||
+static int dm_test_blkmap_creation(struct unit_test_state *uts)
|
||||
+{
|
||||
+ struct udevice *first, *second;
|
||||
+
|
||||
+ ut_assertok(blkmap_create("first", &first));
|
||||
+
|
||||
+ /* Can't have two "first"s */
|
||||
+ ut_asserteq(-EBUSY, blkmap_create("first", &second));
|
||||
+
|
||||
+ /* But "second" should be fine */
|
||||
+ ut_assertok(blkmap_create("second", &second));
|
||||
+
|
||||
+ /* Once "first" is destroyed, we should be able to create it
|
||||
+ * again
|
||||
+ */
|
||||
+ ut_assertok(blkmap_destroy(first));
|
||||
+ ut_assertok(blkmap_create("first", &first));
|
||||
+
|
||||
+ ut_assertok(blkmap_destroy(first));
|
||||
+ ut_assertok(blkmap_destroy(second));
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_blkmap_creation, 0);
|
||||
+
|
||||
+static int dm_test_cmd_blkmap(struct unit_test_state *uts)
|
||||
+{
|
||||
+ ulong loadaddr = env_get_hex("loadaddr", 0);
|
||||
+ struct udevice *dev;
|
||||
+
|
||||
+ console_record_reset();
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap info", 0));
|
||||
+ ut_assert_console_end();
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap create ramdisk", 0));
|
||||
+ ut_assert_nextline("Created \"ramdisk\"");
|
||||
+ ut_assert_console_end();
|
||||
+
|
||||
+ ut_assertnonnull((dev = blkmap_from_label("ramdisk")));
|
||||
+
|
||||
+ ut_assertok(run_commandf("blkmap map ramdisk 0 800 mem 0x%lx", loadaddr));
|
||||
+ ut_assert_nextline("Block 0x0+0x800 mapped to 0x%lx", loadaddr);
|
||||
+ ut_assert_console_end();
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap info", 0));
|
||||
+ ut_assert_nextline("Device 0: Vendor: U-Boot Rev: 1.0 Prod: blkmap");
|
||||
+ ut_assert_nextline(" Type: Hard Disk");
|
||||
+ ut_assert_nextline(" Capacity: 1.0 MB = 0.0 GB (2048 x 512)");
|
||||
+ ut_assert_console_end();
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap get ramdisk dev devnum", 0));
|
||||
+ ut_asserteq(dev_seq(dev), env_get_hex("devnum", 0xdeadbeef));
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap destroy ramdisk", 0));
|
||||
+ ut_assert_nextline("Destroyed \"ramdisk\"");
|
||||
+ ut_assert_console_end();
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap info", 0));
|
||||
+ ut_assert_console_end();
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_cmd_blkmap, 0);
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
From 53e157184110e66144e805e733e5f0a7a4a031a8 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Thu, 16 Feb 2023 15:14:27 +0100
|
||||
Subject: [PATCH v2 8/9] doc: blkmap: Add introduction and examples
|
||||
|
||||
Explain block maps by going through two common use-cases.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
MAINTAINERS | 1 +
|
||||
doc/usage/blkmap.rst | 111 +++++++++++++++++++++++++++++++++++++++++++
|
||||
doc/usage/index.rst | 1 +
|
||||
3 files changed, 113 insertions(+)
|
||||
create mode 100644 doc/usage/blkmap.rst
|
||||
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index bbcb5117fe..e02dacc20a 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -797,6 +797,7 @@ BLKMAP
|
||||
M: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
S: Maintained
|
||||
F: cmd/blkmap.c
|
||||
+F: doc/usage/blkmap.rst
|
||||
F: drivers/block/blkmap.c
|
||||
F: include/blkmap.h
|
||||
F: test/dm/blkmap.c
|
||||
diff --git a/doc/usage/blkmap.rst b/doc/usage/blkmap.rst
|
||||
new file mode 100644
|
||||
index 0000000000..dbfa8e5aad
|
||||
--- /dev/null
|
||||
+++ b/doc/usage/blkmap.rst
|
||||
@@ -0,0 +1,111 @@
|
||||
+.. SPDX-License-Identifier: GPL-2.0+
|
||||
+..
|
||||
+.. Copyright (c) 2023 Addiva Elektronik
|
||||
+.. Author: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
+
|
||||
+Block Maps (blkmap)
|
||||
+===================
|
||||
+
|
||||
+Block maps are a way of looking at various sources of data through the
|
||||
+lens of a regular block device. It lets you treat devices that are not
|
||||
+block devices, like RAM, as if they were. It also lets you export a
|
||||
+slice of an existing block device, which does not have to correspond
|
||||
+to a partition boundary, as a new block device.
|
||||
+
|
||||
+This is primarily useful because U-Boot's filesystem drivers only
|
||||
+operate on block devices, so a block map lets you access filesystems
|
||||
+wherever they might be located.
|
||||
+
|
||||
+The implementation is loosely modeled on Linux's "Device Mapper"
|
||||
+subsystem, see `kernel documentation`_ for more information.
|
||||
+
|
||||
+.. _kernel documentation: https://docs.kernel.org/admin-guide/device-mapper/index.html
|
||||
+
|
||||
+
|
||||
+Example: Netbooting an Ext4 Image
|
||||
+---------------------------------
|
||||
+
|
||||
+Say that our system is using an Ext4 filesystem as its rootfs, where
|
||||
+the kernel is stored in ``/boot``. This image is then typically stored
|
||||
+in an eMMC partition. In this configuration, we can use something like
|
||||
+``load mmc 0 ${kernel_addr_r} /boot/Image`` to load the kernel image
|
||||
+into the expected location, and then boot the system. No problems.
|
||||
+
|
||||
+Now imagine that during development, or as a recovery mechanism, we
|
||||
+want to boot the same type of image by downloading it over the
|
||||
+network. Getting the image to the target is easy enough:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ dhcp ${ramdisk_addr_r} rootfs.ext4
|
||||
+
|
||||
+But now we are faced with a predicament: how to we extract the kernel
|
||||
+image? Block maps to the rescue!
|
||||
+
|
||||
+We start by creating a new device:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ blkmap create netboot
|
||||
+
|
||||
+Before setting up the mapping, we figure out the size of the
|
||||
+downloaded file, in blocks:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ setexpr fileblks ${filesize} + 0x1ff
|
||||
+ setexpr fileblks ${filesize} / 0x200
|
||||
+
|
||||
+Then we can add a mapping to the start of our device, backed by the
|
||||
+memory at `${loadaddr}`:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ blkmap map netboot 0 ${fileblks} mem ${fileaddr}
|
||||
+
|
||||
+Now we can access the filesystem via the virtual device:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ blkmap get netboot dev devnum
|
||||
+ load blkmap ${devnum} ${kernel_addr_r} /boot/Image
|
||||
+
|
||||
+
|
||||
+Example: Accessing a filesystem inside an FIT image
|
||||
+---------------------------------------------------
|
||||
+
|
||||
+In this example, an FIT image is stored in an eMMC partition. We would
|
||||
+like to read the file ``/etc/version``, stored inside a Squashfs image
|
||||
+in the FIT. Since the Squashfs image is not stored on a partition
|
||||
+boundary, there is no way of accessing it via ``load mmc ...``.
|
||||
+
|
||||
+What we can to instead is to first figure out the offset and size of
|
||||
+the filesystem:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ mmc dev 0
|
||||
+ mmc read ${loadaddr} 0 0x100
|
||||
+
|
||||
+ fdt addr ${loadaddr}
|
||||
+ fdt get value squashaddr /images/ramdisk data-position
|
||||
+ fdt get value squashsize /images/ramdisk data-size
|
||||
+
|
||||
+ setexpr squashblk ${squashaddr} / 0x200
|
||||
+ setexpr squashsize ${squashsize} + 0x1ff
|
||||
+ setexpr squashsize ${squashsize} / 0x200
|
||||
+
|
||||
+Then we can create a block map that maps to that slice of the full
|
||||
+partition:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ blkmap create sq
|
||||
+ blkmap map sq 0 ${squashsize} linear mmc 0 ${squashblk}
|
||||
+
|
||||
+Now we can access the filesystem:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ blkmap get sq dev devnum
|
||||
+ load blkmap ${devnum} ${loadaddr} /etc/version
|
||||
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
|
||||
index cde7dcb14a..2dfcd4b2b2 100644
|
||||
--- a/doc/usage/index.rst
|
||||
+++ b/doc/usage/index.rst
|
||||
@@ -4,6 +4,7 @@ Use U-Boot
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
+ blkmap
|
||||
dfu
|
||||
environment
|
||||
fdt_overlays
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
From 0a0ceadab82a1e76d0d21b14b75510d3bd9228ff Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Thu, 16 Feb 2023 15:15:59 +0100
|
||||
Subject: [PATCH v2 9/9] efi_loader: device_path: support blkmap devices
|
||||
|
||||
Create a distinct EFI device path for each blkmap device.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
include/efi_loader.h | 4 ++++
|
||||
lib/efi_loader/efi_device_path.c | 30 ++++++++++++++++++++++++++++++
|
||||
2 files changed, 34 insertions(+)
|
||||
|
||||
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
||||
index c664d6cdf2..eb3818b457 100644
|
||||
--- a/include/efi_loader.h
|
||||
+++ b/include/efi_loader.h
|
||||
@@ -134,6 +134,10 @@ static inline efi_status_t efi_launch_capsules(void)
|
||||
#define U_BOOT_GUID \
|
||||
EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \
|
||||
0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b)
|
||||
+/* GUID used as root for blkmap devices */
|
||||
+#define U_BOOT_BLKMAP_DEV_GUID \
|
||||
+ EFI_GUID(0x4cad859d, 0xd644, 0x42ff, \
|
||||
+ 0x87, 0x0b, 0xc0, 0x2e, 0xac, 0x05, 0x58, 0x63)
|
||||
/* GUID used as host device on sandbox */
|
||||
#define U_BOOT_HOST_DEV_GUID \
|
||||
EFI_GUID(0xbbe4e671, 0x5773, 0x4ea1, \
|
||||
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
|
||||
index 3b267b713e..4b4c96bc2e 100644
|
||||
--- a/lib/efi_loader/efi_device_path.c
|
||||
+++ b/lib/efi_loader/efi_device_path.c
|
||||
@@ -21,6 +21,9 @@
|
||||
#include <asm-generic/unaligned.h>
|
||||
#include <linux/compat.h> /* U16_MAX */
|
||||
|
||||
+#ifdef CONFIG_BLKMAP
|
||||
+const efi_guid_t efi_guid_blkmap_dev = U_BOOT_BLKMAP_DEV_GUID;
|
||||
+#endif
|
||||
#ifdef CONFIG_SANDBOX
|
||||
const efi_guid_t efi_guid_host_dev = U_BOOT_HOST_DEV_GUID;
|
||||
#endif
|
||||
@@ -573,6 +576,16 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
|
||||
*/
|
||||
return dp_size(dev->parent)
|
||||
+ sizeof(struct efi_device_path_vendor) + 1;
|
||||
+#endif
|
||||
+#ifdef CONFIG_BLKMAP
|
||||
+ case UCLASS_BLKMAP:
|
||||
+ /*
|
||||
+ * blkmap devices will be represented as a vendor
|
||||
+ * device node with an extra byte for the device
|
||||
+ * number.
|
||||
+ */
|
||||
+ return dp_size(dev->parent)
|
||||
+ + sizeof(struct efi_device_path_vendor) + 1;
|
||||
#endif
|
||||
default:
|
||||
return dp_size(dev->parent);
|
||||
@@ -631,6 +644,23 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
|
||||
#endif
|
||||
case UCLASS_BLK:
|
||||
switch (dev->parent->uclass->uc_drv->id) {
|
||||
+#ifdef CONFIG_BLKMAP
|
||||
+ case UCLASS_BLKMAP: {
|
||||
+ struct efi_device_path_vendor *dp;
|
||||
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
|
||||
+
|
||||
+ dp_fill(buf, dev->parent);
|
||||
+ dp = buf;
|
||||
+ ++dp;
|
||||
+ dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
|
||||
+ dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
|
||||
+ dp->dp.length = sizeof(*dp) + 1;
|
||||
+ memcpy(&dp->guid, &efi_guid_blkmap_dev,
|
||||
+ sizeof(efi_guid_t));
|
||||
+ dp->vendor_data[0] = desc->devnum;
|
||||
+ return &dp->vendor_data[1];
|
||||
+ }
|
||||
+#endif
|
||||
#ifdef CONFIG_SANDBOX
|
||||
case UCLASS_HOST: {
|
||||
/* stop traversing parents at this point: */
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,42 +1,14 @@
|
||||
setenv valid_media no
|
||||
echo "Press Ctrl-C NOW to enter boot menu"
|
||||
if sleep "${ixbootdelay}"; then
|
||||
run ixbootorder
|
||||
|
||||
for tgt in "${boot_targets}"; do
|
||||
if test "${tgt}" = "mmc0"; then
|
||||
setenv devtype "mmc"
|
||||
setenv devnum 0
|
||||
mmc dev 0
|
||||
elif test "${tgt}" = "mmc1"; then
|
||||
setenv devtype "mmc"
|
||||
setenv devnum 1
|
||||
mmc dev 1
|
||||
else
|
||||
setenv devtype "${tgt}"
|
||||
setenv devnum 0
|
||||
fi
|
||||
|
||||
if part number ${devtype} ${devnum} aux auxpart; then
|
||||
if load ${devtype} ${devnum}:${auxpart} ${loadaddr} /uboot.env; then
|
||||
env import -b ${loadaddr} ${filesize} BOOT_ORDER DEBUG
|
||||
fi
|
||||
|
||||
test -n "${BOOT_ORDER}" || setenv BOOT_ORDER "primary secondary net"
|
||||
|
||||
if test -n "${DEBUG}"; then
|
||||
setenv bootargs_log "debug"
|
||||
else
|
||||
setenv bootargs_log "loglevel=4"
|
||||
fi
|
||||
|
||||
setenv valid_media yes
|
||||
run ixbootmedia
|
||||
fi
|
||||
done
|
||||
|
||||
if test "${valid_media}" = "no"; then
|
||||
echo "NO BOOTABLE MEDIA FOUND, falling back to netboot"
|
||||
setenv BOOT_ORDER "net"
|
||||
setenv bootargs_log "debug"
|
||||
run ixbootmedia
|
||||
echo "FATAL: Exhausted all available boot sources, rebooting"
|
||||
sleep 1
|
||||
reset
|
||||
fi
|
||||
|
||||
reset
|
||||
bootmenu
|
||||
if test "${dev_mode}" != "yes"; then
|
||||
pause "Console shell access PROHIBITED. Press any key to reset..."
|
||||
reset
|
||||
fi
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
echo "Booting from ${devtype}${devnum} (order: ${BOOT_ORDER})"
|
||||
|
||||
for s in "${BOOT_ORDER}"; do
|
||||
setenv slot "${s}"
|
||||
run ixbootslot
|
||||
done
|
||||
@@ -10,34 +10,42 @@ elif test "${slot}" = "net"; then
|
||||
fi
|
||||
|
||||
if test "${prepared}" = "ok"; then
|
||||
echo "${slot}: Validating..."
|
||||
if iminfo ${ramdisk_addr_r}; then
|
||||
echo "${slot}: Booting..."
|
||||
echo "${slot}: Validating..."
|
||||
|
||||
setenv bootargs_user "rauc.slot=${slot}"
|
||||
if test "${factory_reset}" = "yes"; then
|
||||
setenv bootargs_user "${bootargs_user} finit.cond=factory-reset"
|
||||
fi
|
||||
if test "${dev_mode}" = "yes"; then
|
||||
setenv bootargs_user "${bootargs_user} finit.cond=dev-mode"
|
||||
fi
|
||||
iminfo ${ramdisk_addr_r}
|
||||
imok=$?
|
||||
|
||||
blkmap create boot
|
||||
blkmap get boot dev blkmapnum
|
||||
blkmap map boot 0 ${sqblkcnt} mem ${sqaddr}
|
||||
|
||||
for conf in "${board}-syslinux.conf syslinux.conf"; do
|
||||
if test -e blkmap ${blkmapnum} /boot/syslinux/${conf}; then
|
||||
sysboot blkmap ${blkmapnum} any ${scriptaddr} /boot/syslinux/${conf}
|
||||
fi
|
||||
done
|
||||
|
||||
blkmap destroy boot
|
||||
|
||||
echo "${slot}: ERROR: Boot failed"
|
||||
else
|
||||
echo "${slot}: ERROR: Validation failed"
|
||||
if test ${imok} -eq 0 || test "${dev_mode}" = "yes"; then
|
||||
if test ${imok} -ne 0; then
|
||||
echo "DEVELOPER MODE ACTIVE, BOOTING UNTRUSTED IMAGE"
|
||||
fi
|
||||
|
||||
echo "${slot}: Booting..."
|
||||
|
||||
setenv bootargs_user "rauc.slot=${slot}"
|
||||
if test "${factory_reset}" = "yes"; then
|
||||
setenv bootargs_user "${bootargs_user} finit.cond=factory-reset"
|
||||
fi
|
||||
if test "${dev_mode}" = "yes"; then
|
||||
setenv bootargs_user "${bootargs_user} finit.cond=dev-mode"
|
||||
fi
|
||||
|
||||
blkmap create boot
|
||||
blkmap get boot dev blkmapnum
|
||||
blkmap map boot 0 ${sqblkcnt} mem ${sqaddr}
|
||||
|
||||
for conf in "${board}-syslinux.conf syslinux.conf"; do
|
||||
if test -e blkmap ${blkmapnum} /boot/syslinux/${conf}; then
|
||||
sysboot blkmap ${blkmapnum} any ${scriptaddr} /boot/syslinux/${conf}
|
||||
fi
|
||||
done
|
||||
|
||||
blkmap destroy boot
|
||||
|
||||
echo "${slot}: ERROR: Boot failed"
|
||||
else
|
||||
echo "${slot}: ERROR: Validation failed"
|
||||
fi
|
||||
else
|
||||
echo "${slot}: ERROR: Unable to use slot"
|
||||
echo "${slot}: ERROR: Unable to use slot"
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
if button factory-reset; then
|
||||
echo "Keep button pressed for 10 seconds to engage factory reset"
|
||||
if sleep 10 && button factory-reset; then
|
||||
run ixfactory
|
||||
fi
|
||||
fi
|
||||
@@ -1,13 +0,0 @@
|
||||
setenv dev_mode no
|
||||
setenv factory_reset no
|
||||
|
||||
echo -n "dev-mode: "
|
||||
run ixdevmode
|
||||
echo -n "factory-reset: "
|
||||
run ixfactory
|
||||
|
||||
if test "${dev_mode}" = "yes"; then
|
||||
sleep 1 && run ixboot
|
||||
else
|
||||
run ixboot
|
||||
fi
|
||||
@@ -1,7 +1,4 @@
|
||||
if button factory-reset; then
|
||||
echo "Keep button pressed for 10 seconds to engage reset"
|
||||
if sleep 10 && button factory-reset; then
|
||||
setenv factory_reset yes
|
||||
echo "FACTORY RESET ENGAGED"
|
||||
fi
|
||||
fi
|
||||
setenv factory_reset yes
|
||||
echo "FACTORY RESET ENGAGED"
|
||||
echo "ALL user data will be deleted on system boot."
|
||||
echo "To ABORT, power off device NOW."
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
${devtype} dev ${devnum}
|
||||
${devtype} read ${ramdisk_addr_r} ${devoffs} 0x10
|
||||
|
||||
fdt addr ${ramdisk_addr_r}
|
||||
fdt get value squashaddr /images/ramdisk data-position
|
||||
fdt get value squashsize /images/ramdisk data-size
|
||||
|
||||
setexpr blkcnt ${squashaddr} + ${squashsize}
|
||||
setexpr blkcnt ${blkcnt} + 0x1ff
|
||||
setexpr blkcnt ${blkcnt} / 0x200
|
||||
|
||||
${devtype} read ${ramdisk_addr_r} ${devoffs} ${blkcnt}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
setenv dev_mode no
|
||||
setenv factory_reset no
|
||||
|
||||
echo -n "dev-mode: "
|
||||
run ixbtn-devmode
|
||||
echo -n "factory-reset: "
|
||||
run ixbtn-factory
|
||||
|
||||
setenv valid_media no
|
||||
setenv ixmenu_n 0
|
||||
|
||||
for tgt in "${boot_targets}"; do
|
||||
if test "${tgt}" = "mmc0"; then
|
||||
setenv devtype "mmc"
|
||||
setenv devnum 0
|
||||
mmc dev 0
|
||||
elif test "${tgt}" = "mmc1"; then
|
||||
setenv devtype "mmc"
|
||||
setenv devnum 1
|
||||
mmc dev 1
|
||||
else
|
||||
setenv devtype "${tgt}"
|
||||
setenv devnum 0
|
||||
fi
|
||||
|
||||
if part number ${devtype} ${devnum} aux auxpart; then
|
||||
setenv "boot_${tgt}_primary" "setenv devtype ${devtype}; setenv devnum ${devnum}; setenv slot primary; run ixbootslot"
|
||||
setenv "bootmenu_${ixmenu_n}" "Boot primary ${tgt} partition=run boot_${tgt}_primary"
|
||||
setexpr ixmenu_n ${ixmenu_n} + 1
|
||||
|
||||
setenv "boot_${tgt}_secondary" "setenv devtype ${devtype}; setenv devnum ${devnum}; setenv slot secondary; run ixbootslot"
|
||||
setenv "bootmenu_${ixmenu_n}" "Boot secondary ${tgt} partition=run boot_${tgt}_secondary"
|
||||
setexpr ixmenu_n ${ixmenu_n} + 1
|
||||
|
||||
if load ${devtype} ${devnum}:${auxpart} ${loadaddr} /uboot.env; then
|
||||
env import -b ${loadaddr} ${filesize} BOOT_ORDER DEBUG
|
||||
fi
|
||||
|
||||
if test -n "${DEBUG}"; then
|
||||
setenv bootargs_log "debug"
|
||||
else
|
||||
setenv bootargs_log "loglevel=4"
|
||||
fi
|
||||
|
||||
test -n "${BOOT_ORDER}" || setenv BOOT_ORDER "primary secondary net"
|
||||
echo "Valid boot device found on ${tgt} (order: ${BOOT_ORDER})"
|
||||
|
||||
for slot in "${BOOT_ORDER}"; do
|
||||
if test "${slot}" = "primary"; then
|
||||
setenv ixbootorder "${ixbootorder}run boot_${tgt}_primary; "
|
||||
elif test "${slot}" = "secondary"; then
|
||||
setenv ixbootorder "${ixbootorder}run boot_${tgt}_secondary; "
|
||||
elif test "${slot}" = "net"; then
|
||||
setenv ixbootorder "${ixbootorder}run boot_net; "
|
||||
fi
|
||||
done
|
||||
|
||||
setenv valid_media yes
|
||||
fi
|
||||
done
|
||||
|
||||
setenv "boot_net" "setenv slot net; run ixbootslot"
|
||||
setenv "bootmenu_${ixmenu_n}" "Boot over network=run boot_net"
|
||||
setexpr ixmenu_n ${ixmenu_n} + 1
|
||||
|
||||
setenv "bootmenu_${ixmenu_n}" "Factory reset=run ixfactory; echo; pause; bootmenu"
|
||||
setexpr ixmenu_n ${ixmenu_n} + 1
|
||||
|
||||
if test "${valid_media}" = "no"; then
|
||||
echo "NO BOOTABLE MEDIA FOUND, falling back to netboot"
|
||||
setenv bootargs_log "debug"
|
||||
setenv ixbootorder "run boot_net"
|
||||
fi
|
||||
@@ -1,16 +1,28 @@
|
||||
if dhcp ${ramdisk_addr_r}; then
|
||||
setenv autoload no
|
||||
|
||||
setenv old_fdt_addr ${fdt_addr}
|
||||
if fdt addr ${ramdisk_addr_r}; then
|
||||
fdt get value sqoffs /images/rootfs data-position
|
||||
fdt get value sqsize /images/rootfs data-size
|
||||
fdt addr ${old_fdt_addr}
|
||||
if dhcp; then
|
||||
setenv proto tftp
|
||||
setenv dltool tftpboot
|
||||
|
||||
setexpr sqaddr ${ramdisk_addr_r} + ${sqoffs}
|
||||
setexpr sqblkcnt ${sqsize} / 0x200
|
||||
setexpr sqkbsize ${sqsize} / 0x400
|
||||
if setexpr proto sub "^(http|tftp)://.*" "\\1" "${bootfile}" && setexpr bootfile sub "^(http|tftp)://([^/]+?)/(.*)" "\2:\3"; then
|
||||
if test "${proto}" = "http"; then
|
||||
setenv dltool wget
|
||||
fi
|
||||
fi
|
||||
|
||||
setenv bootargs_root "root=/dev/ram0 ramdisk_size=0x${sqkbsize} initrd=0x${sqaddr},${sqsize}"
|
||||
setenv prepared ok
|
||||
if ${dltool} ${ramdisk_addr_r} "${bootfile}"; then
|
||||
setenv old_fdt_addr ${fdt_addr}
|
||||
if fdt addr ${ramdisk_addr_r}; then
|
||||
fdt get value sqoffs /images/rootfs data-position
|
||||
fdt get value sqsize /images/rootfs data-size
|
||||
fdt addr ${old_fdt_addr}
|
||||
|
||||
setexpr sqaddr ${ramdisk_addr_r} + ${sqoffs}
|
||||
setexpr sqblkcnt ${sqsize} / 0x200
|
||||
setexpr sqkbsize ${sqsize} / 0x400
|
||||
|
||||
setenv bootargs_root "root=/dev/ram0 ramdisk_size=0x${sqkbsize} initrd=0x${sqaddr},${sqsize}"
|
||||
setenv prepared ok
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
if part number mmc 0 aux auxpart; then
|
||||
if load mmc 0:${auxpart} ${loadaddr} /uboot.env; then
|
||||
env import -b ${loadaddr} ${filesize} BOOT_ORDER DEBUG
|
||||
fi
|
||||
fi
|
||||
@@ -1,28 +0,0 @@
|
||||
setenv devtype mmc
|
||||
setenv devnum 0
|
||||
part start ${devtype} ${devnum} ${slot} devoffs
|
||||
|
||||
${devtype} dev ${devnum}
|
||||
${devtype} read ${ramdisk_addr_r} ${devoffs} 0x10
|
||||
|
||||
setenv bootargs_root "root=/dev/dm-0 dm-mod.create=\"rootfs,,0,ro,0"
|
||||
|
||||
setenv old_fdt_addr ${fdt_addr}
|
||||
if fdt addr ${ramdisk_addr_r}; then
|
||||
fdt get value sqoffs /images/rootfs data-position
|
||||
fdt get value sqsize /images/rootfs data-size
|
||||
fdt addr ${old_fdt_addr}
|
||||
|
||||
setexpr sqaddr ${ramdisk_addr_r} + ${sqoffs}
|
||||
setexpr sqblknr ${sqoffs} / 0x200
|
||||
setexpr sqblkcnt ${sqsize} / 0x200
|
||||
setexpr fitblkcnt ${sqblknr} + ${sqblkcnt}
|
||||
|
||||
if ${devtype} read ${ramdisk_addr_r} ${devoffs} ${fitblkcnt}; then
|
||||
setexpr decsqblkcnt fmt %u ${sqblkcnt}
|
||||
setexpr decsqblknr fmt %u ${sqblknr}
|
||||
setenv bootargs_root "${bootargs_root} ${decsqblkcnt} linear PARTLABEL=${slot} ${decsqblknr}\""
|
||||
setenv ramdisk "-"
|
||||
setenv prepared ok
|
||||
fi
|
||||
fi
|
||||
@@ -1,34 +0,0 @@
|
||||
test-dir := $(BR2_EXTERNAL_INFIX_PATH)/test
|
||||
INFIX_TESTS ?= $(test-dir)/case/all.yaml
|
||||
|
||||
test-env = $(test-dir)/env \
|
||||
-f $(BINARIES_DIR)/infix-x86_64.img \
|
||||
-f $(BINARIES_DIR)/infix-x86_64-disk.img \
|
||||
-f $(BINARIES_DIR)/OVMF.fd \
|
||||
-p $(BINARIES_DIR)/infix-x86_64.pkg \
|
||||
$(1) $(2)
|
||||
|
||||
test-env-qeneth = $(call test-env,-q $(test-dir)/virt/quad,$(1))
|
||||
test-env-run = $(call test-env,-C -t $(BINARIES_DIR)/qemu.dot,$(1))
|
||||
|
||||
test test-qeneth:
|
||||
$(call test-env-qeneth,\
|
||||
$(BR2_EXTERNAL_INFIX_PATH)/test/9pm/9pm.py \
|
||||
$(INFIX_TESTS))
|
||||
test-sh test-qeneth-sh:
|
||||
$(call test-env-qeneth,-i /bin/sh)
|
||||
|
||||
test-run: | ~/.infix-test-venv
|
||||
$(call test-env-run,\
|
||||
$(BR2_EXTERNAL_INFIX_PATH)/test/9pm/9pm.py \
|
||||
$(INFIX_TESTS))
|
||||
test-run-sh: | ~/.infix-test-venv
|
||||
$(call test-env-run,/bin/sh)
|
||||
|
||||
test-run-play: | ~/.infix-test-venv
|
||||
$(call test-env-run,$(test-dir)/case/meta/play.py)
|
||||
|
||||
~/.infix-test-venv:
|
||||
$(test-dir)/docker/init-venv.sh $(test-dir)/docker/pip-requirements.txt
|
||||
|
||||
.PHONY: test test-sh test-qeneth test-qeneth-sh test-run test-run-sh test-run-play
|
||||
|
||||
+1
-1
Submodule buildroot updated: 1d96daca15...abf742aab8
@@ -18,15 +18,15 @@ BR2_SYSTEM_BIN_SH_BASH=y
|
||||
BR2_TARGET_GENERIC_GETTY_PORT="@console"
|
||||
BR2_TARGET_GENERIC_GETTY_TERM="xterm"
|
||||
BR2_SYSTEM_DHCP="eth0"
|
||||
BR2_ENABLE_LOCALE_WHITELIST="C en_US en_CA"
|
||||
BR2_GENERATE_LOCALE="en_US en_CA"
|
||||
BR2_ENABLE_LOCALE_WHITELIST="C en_US en_CA C.UTF-8"
|
||||
BR2_GENERATE_LOCALE="en_US en_CA C.UTF-8"
|
||||
BR2_TARGET_TZ_INFO=y
|
||||
BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rootfs"
|
||||
BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh"
|
||||
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
|
||||
BR2_LINUX_KERNEL=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.22"
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.34"
|
||||
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig"
|
||||
BR2_LINUX_KERNEL_DTS_SUPPORT=y
|
||||
@@ -58,12 +58,14 @@ BR2_PACKAGE_PYTHON_GUNICORN=y
|
||||
BR2_PACKAGE_LIBSSH_OPENSSL=y
|
||||
BR2_PACKAGE_LIBSSH2=y
|
||||
BR2_PACKAGE_LIBSSH2_OPENSSL=y
|
||||
BR2_PACKAGE_LIBXCRYPT=y
|
||||
BR2_PACKAGE_LIBOPENSSL_BIN=y
|
||||
BR2_PACKAGE_LIBCURL_CURL=y
|
||||
BR2_PACKAGE_NETOPEER2_CLI=y
|
||||
BR2_PACKAGE_NSS_MDNS=y
|
||||
BR2_PACKAGE_LINUX_PAM=y
|
||||
BR2_PACKAGE_LIBPAM_RADIUS_AUTH=y
|
||||
BR2_PACKAGE_ONIGURUMA=y
|
||||
BR2_PACKAGE_AVAHI=y
|
||||
BR2_PACKAGE_AVAHI_DAEMON=y
|
||||
BR2_PACKAGE_AVAHI_DEFAULT_SERVICES=y
|
||||
BR2_PACKAGE_CHRONY=y
|
||||
@@ -94,6 +96,7 @@ BR2_PACKAGE_SOCAT=y
|
||||
BR2_PACKAGE_TCPDUMP=y
|
||||
BR2_PACKAGE_TRACEROUTE=y
|
||||
BR2_PACKAGE_ULOGD=y
|
||||
BR2_PACKAGE_WHOIS=y
|
||||
BR2_PACKAGE_BASH_COMPLETION=y
|
||||
BR2_PACKAGE_SUDO=y
|
||||
BR2_PACKAGE_TTYD=y
|
||||
@@ -152,9 +155,11 @@ BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_LIBINPUT=y
|
||||
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
|
||||
DISK_IMAGE_BOOT_BIN=y
|
||||
GNS3_APPLIANCE_RAM=512
|
||||
GNS3_APPLIANCE_IFNUM=10
|
||||
TRUSTED_KEYS=y
|
||||
TRUSTED_KEYS_DEVELOPMENT=y
|
||||
GNS3_APPLIANCE_RAM=512
|
||||
GNS3_APPLIANCE_IFNUM=10
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
BR2_aarch64=y
|
||||
BR2_cortex_a72=y
|
||||
BR2_TOOLCHAIN_EXTERNAL=y
|
||||
BR2_TOOLCHAIN_EXTERNAL_BOOTLIN=y
|
||||
BR2_DL_DIR="$(BR2_EXTERNAL_INFIX_PATH)/dl"
|
||||
BR2_CCACHE=y
|
||||
BR2_CCACHE_DIR="$(BR2_EXTERNAL_INFIX_PATH)/.ccache"
|
||||
BR2_ENABLE_DEBUG=y
|
||||
BR2_PACKAGE_OVERRIDE_FILE="$(BR2_EXTERNAL_INFIX_PATH)/local.mk"
|
||||
BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_INFIX_PATH)/patches"
|
||||
BR2_SSP_NONE=y
|
||||
BR2_INIT_NONE=y
|
||||
BR2_SYSTEM_BIN_SH_NONE=y
|
||||
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
|
||||
# BR2_PACKAGE_BUSYBOX is not set
|
||||
# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set
|
||||
# BR2_TARGET_ROOTFS_TAR is not set
|
||||
BR2_TARGET_UBOOT=y
|
||||
BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
|
||||
BR2_TARGET_UBOOT_CUSTOM_VERSION=y
|
||||
BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2023.07.02"
|
||||
BR2_TARGET_UBOOT_BOARD_DEFCONFIG="qemu_arm64"
|
||||
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_INFIX_PATH)/board/common/uboot/extras.config"
|
||||
BR2_TARGET_UBOOT_FORMAT_DTB=y
|
||||
BR2_PACKAGE_HOST_GENIMAGE=y
|
||||
BR2_PACKAGE_HOST_RAUC=y
|
||||
BR2_PACKAGE_HOST_UBOOT_TOOLS=y
|
||||
BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT=y
|
||||
BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
|
||||
TRUSTED_KEYS=y
|
||||
TRUSTED_KEYS_DEVELOPMENT=y
|
||||
DISK_IMAGE_BOOT_BIN=y
|
||||
DISK_IMAGE_BOOT_DATA="${BINARIES_DIR}/flash-image.bin"
|
||||
DISK_IMAGE_BOOT_OFFSET=0x00200000
|
||||
@@ -19,8 +19,8 @@ BR2_SYSTEM_BIN_SH_BASH=y
|
||||
BR2_TARGET_GENERIC_GETTY_PORT="@console"
|
||||
BR2_TARGET_GENERIC_GETTY_TERM="xterm"
|
||||
BR2_SYSTEM_DHCP="eth0"
|
||||
BR2_ENABLE_LOCALE_WHITELIST="C en_US en_CA"
|
||||
BR2_GENERATE_LOCALE="en_US en_CA"
|
||||
BR2_ENABLE_LOCALE_WHITELIST="C en_US en_CA C.UTF-8"
|
||||
BR2_GENERATE_LOCALE="en_US en_CA C.UTF-8"
|
||||
BR2_TARGET_TZ_INFO=y
|
||||
BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rootfs"
|
||||
BR2_ROOTFS_POST_BUILD_SCRIPT="$(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/post-build.sh ${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh"
|
||||
@@ -28,7 +28,7 @@ BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image
|
||||
BR2_ROOTFS_POST_SCRIPT_ARGS="-c $(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/genimage.cfg"
|
||||
BR2_LINUX_KERNEL=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.22"
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.34"
|
||||
BR2_LINUX_KERNEL_PATCH="$(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/rk3328-nanopi-r2s-dts.patch"
|
||||
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/linux_defconfig"
|
||||
@@ -65,16 +65,17 @@ BR2_PACKAGE_UBOOT_TOOLS_FIT_CHECK_SIGN=y
|
||||
BR2_PACKAGE_UBOOT_TOOLS_MKENVIMAGE=y
|
||||
BR2_PACKAGE_PYTHON3=y
|
||||
BR2_PACKAGE_PYTHON_GUNICORN=y
|
||||
BR2_PACKAGE_CA_CERTIFICATES=y
|
||||
BR2_PACKAGE_LIBSSH_OPENSSL=y
|
||||
BR2_PACKAGE_LIBSSH2=y
|
||||
BR2_PACKAGE_LIBSSH2_OPENSSL=y
|
||||
BR2_PACKAGE_LIBXCRYPT=y
|
||||
BR2_PACKAGE_LIBOPENSSL_BIN=y
|
||||
BR2_PACKAGE_LIBCURL_CURL=y
|
||||
BR2_PACKAGE_NETOPEER2_CLI=y
|
||||
BR2_PACKAGE_NSS_MDNS=y
|
||||
BR2_PACKAGE_LINUX_PAM=y
|
||||
BR2_PACKAGE_LIBPAM_RADIUS_AUTH=y
|
||||
BR2_PACKAGE_ONIGURUMA=y
|
||||
BR2_PACKAGE_AVAHI=y
|
||||
BR2_PACKAGE_AVAHI_DAEMON=y
|
||||
BR2_PACKAGE_AVAHI_DEFAULT_SERVICES=y
|
||||
BR2_PACKAGE_CHRONY=y
|
||||
@@ -85,7 +86,6 @@ BR2_PACKAGE_FPING=y
|
||||
BR2_PACKAGE_FRR=y
|
||||
# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set
|
||||
BR2_PACKAGE_IPROUTE2=y
|
||||
BR2_PACKAGE_IPTABLES=y
|
||||
BR2_PACKAGE_IPTABLES_NFTABLES=y
|
||||
BR2_PACKAGE_IPUTILS=y
|
||||
BR2_PACKAGE_LLDPD=y
|
||||
@@ -106,6 +106,7 @@ BR2_PACKAGE_SOCAT=y
|
||||
BR2_PACKAGE_TCPDUMP=y
|
||||
BR2_PACKAGE_TRACEROUTE=y
|
||||
BR2_PACKAGE_ULOGD=y
|
||||
BR2_PACKAGE_WHOIS=y
|
||||
BR2_PACKAGE_BASH_COMPLETION=y
|
||||
BR2_PACKAGE_SUDO=y
|
||||
BR2_PACKAGE_TTYD=y
|
||||
@@ -181,6 +182,8 @@ BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_LIBINPUT=y
|
||||
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
|
||||
# SIGN_ENABLED is not set
|
||||
# GNS3_APPLIANCE is not set
|
||||
|
||||
@@ -17,15 +17,15 @@ BR2_SYSTEM_BIN_SH_BASH=y
|
||||
BR2_TARGET_GENERIC_GETTY_PORT="@console"
|
||||
BR2_TARGET_GENERIC_GETTY_TERM="xterm"
|
||||
BR2_SYSTEM_DHCP="eth0"
|
||||
BR2_ENABLE_LOCALE_WHITELIST="C en_US en_CA"
|
||||
BR2_GENERATE_LOCALE="en_US en_CA"
|
||||
BR2_ENABLE_LOCALE_WHITELIST="C en_US en_CA C.UTF-8"
|
||||
BR2_GENERATE_LOCALE="en_US en_CA C.UTF-8"
|
||||
BR2_TARGET_TZ_INFO=y
|
||||
BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/rootfs"
|
||||
BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh"
|
||||
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
|
||||
BR2_LINUX_KERNEL=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.22"
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.34"
|
||||
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/linux_defconfig"
|
||||
BR2_LINUX_KERNEL_INSTALL_TARGET=y
|
||||
@@ -53,12 +53,14 @@ BR2_PACKAGE_PYTHON_GUNICORN=y
|
||||
BR2_PACKAGE_LIBSSH_OPENSSL=y
|
||||
BR2_PACKAGE_LIBSSH2=y
|
||||
BR2_PACKAGE_LIBSSH2_OPENSSL=y
|
||||
BR2_PACKAGE_LIBXCRYPT=y
|
||||
BR2_PACKAGE_LIBOPENSSL_BIN=y
|
||||
BR2_PACKAGE_LIBCURL_CURL=y
|
||||
BR2_PACKAGE_NETOPEER2_CLI=y
|
||||
BR2_PACKAGE_NSS_MDNS=y
|
||||
BR2_PACKAGE_LINUX_PAM=y
|
||||
BR2_PACKAGE_LIBPAM_RADIUS_AUTH=y
|
||||
BR2_PACKAGE_ONIGURUMA=y
|
||||
BR2_PACKAGE_AVAHI=y
|
||||
BR2_PACKAGE_AVAHI_DAEMON=y
|
||||
BR2_PACKAGE_AVAHI_DEFAULT_SERVICES=y
|
||||
BR2_PACKAGE_CHRONY=y
|
||||
@@ -89,6 +91,7 @@ BR2_PACKAGE_SOCAT=y
|
||||
BR2_PACKAGE_TCPDUMP=y
|
||||
BR2_PACKAGE_TRACEROUTE=y
|
||||
BR2_PACKAGE_ULOGD=y
|
||||
BR2_PACKAGE_WHOIS=y
|
||||
BR2_PACKAGE_BASH_COMPLETION=y
|
||||
BR2_PACKAGE_SUDO=y
|
||||
BR2_PACKAGE_TTYD=y
|
||||
@@ -155,7 +158,9 @@ BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
GNS3_APPLIANCE_RAM=512
|
||||
GNS3_APPLIANCE_IFNUM=10
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
|
||||
TRUSTED_KEYS=y
|
||||
TRUSTED_KEYS_DEVELOPMENT=y
|
||||
GNS3_APPLIANCE_RAM=512
|
||||
GNS3_APPLIANCE_IFNUM=10
|
||||
|
||||
@@ -4,6 +4,107 @@ Change Log
|
||||
All notable changes to the project are documented in this file.
|
||||
|
||||
|
||||
[v24.06.0][] - 2024-06-28
|
||||
-------------------------
|
||||
|
||||
> **Note:** this release contains **breaking changes** in YANG models
|
||||
> that are incompatible with existing configuration files. So, after
|
||||
> upgrade, but before reboot, a factory reset is required!
|
||||
|
||||
### Changes
|
||||
- Upgrade Buildroot to 2024.02.3 (LTS)
|
||||
- Upgrade Linux kernel to 6.6.34 (LTS)
|
||||
- Upgrade bundled curiOS httpd container to v24.05.0
|
||||
- Default web landing page refactored into a Buildroot package to make
|
||||
it possible to overload from customer repos.
|
||||
- Enable DCB support in aarch64 kernel (for EtherType prio override)
|
||||
- Topology mapper improvements, including option for deterministic
|
||||
reproduction of logical to physical mappings
|
||||
- New version of `gencert` tool, for self signed HTTPS certificates.
|
||||
This allows dropping dependency on building a host rust toolchain
|
||||
- Issue #374: add timestamps to dagger .log files
|
||||
- Add small delay in U-Boot to allow stopping boot on reference boards
|
||||
- Document how to provision the bootloader and Infix on a blank board
|
||||
- Use initial hostname from `/etc/os-release` as configuration fallback
|
||||
- Update documentation for use of VETH pairs in containers
|
||||
- Issue #454: create bridges in `factory-config` with IGMP/MLD snooping
|
||||
enabled by default
|
||||
- The following YANG models have been updated to newer draft versions:
|
||||
`ietf-crypto-types`, `ietf-keystore`, `ietf-netconf-server`, `ietf-ssh-common`,
|
||||
`ietf-ssh-server`, `ietf-tcp-client`, `ietf-tcp-common`, `ietf-tcp-server`,
|
||||
`ietf-tcp-server`, `ietf-tcp-server`, `ietf-tcp-server`.
|
||||
In these there are a lot of breaking changes, most likely
|
||||
you will need to redo your configuration from `factory-config`.
|
||||
- The Augeas package has been dropped, so `augtool` is no longer available
|
||||
- VLAN interfaces can now map the incoming PCP value to the
|
||||
kernel-internal priority on ingress, and perform the reverse mapping
|
||||
on egress.
|
||||
- `mv88e6xxx` ports can now use Linux's priority information to select
|
||||
the appropriate egress queue, via the `mqprio` queuing discipline.
|
||||
- Add logging of output from container start/stop action
|
||||
- Clean up stale directories after OCI container archive import
|
||||
- Add support for `show leaf-node` in CLI configure context
|
||||
- Allow non-admin users to use the CLI. NACM rules still apply
|
||||
- Ensure filesystem is sync'ed properly after a CLI `copy` command
|
||||
- Issue #178: add early boot script to migrate configuration files of
|
||||
older version to new syntax. Initial, rudimentary support, for the
|
||||
change in shell types
|
||||
- Issue #308: add `version` field to configuration file using a new
|
||||
model, infix-meta.yang. Used to trigger migration from older formats
|
||||
to newer on future breaking changes
|
||||
- Issue #432: extract YANG documentation at build time. Part of the
|
||||
release tarballs is now `yangdoc.html` for the complete tree of all
|
||||
YANG configuration, operational data, RPCs, and notification nodes
|
||||
- Issue #435: add support for `$factory$` password hash. This allows
|
||||
backing up configuration files with device specific passwords. Upon
|
||||
restore to another device this ensures the replacement's password is
|
||||
used instead of the originals'
|
||||
- Issue #435: add support for hostname format specifiers. The default
|
||||
hostname configuration is now `%h-%m` to encode, `infix-c0-ff-ee`
|
||||
- Issue #435: support for "empty" NETCONF host keys. Primarily used in
|
||||
static factory-config setups. When a configuration is detected with
|
||||
this, the automatically generated, device specific 2048 bit RSA host
|
||||
key pair is used. With this, vendor/product specific factory-config
|
||||
is now fully supported. See `src/confd/README.md`
|
||||
- Issue #447: add support for [yescrypt][], `$y$` hashes. This also
|
||||
adds support for `$0$cleartext` password according to ietf-system.yang
|
||||
- Issue #455: split CLI tutorial into multiple files for easy access
|
||||
from the CLI admin-exec context using the `help` command
|
||||
- Issue #478: add operational support for ietf-system.yang, reading
|
||||
actual hostname and passwords after issue #435
|
||||
- Merge infix-shell-types.yang with infix-system.yang
|
||||
- cli: improved error/warning message on missing or incomplete command
|
||||
|
||||
[yescrypt]: https://en.wikipedia.org/wiki/Yescrypt)
|
||||
|
||||
### Fixes
|
||||
- Fix #424: regression, root user can log in without password
|
||||
- Fix build regressions in `cn9130_crb_boot_defconfig` caused by upgrade
|
||||
to Buildroot v2024.02 and recent multi-key support in RAUC and U-Boot
|
||||
- Fix provisioning script after changes to make GRUB loading more robust
|
||||
- Fix missing `/etc/resolv.conf`, as noticed by `avahi-daemon`, when a
|
||||
user calls `no system` from the CLI
|
||||
- Fix #428: loss of admin account after upgrade to v24.04
|
||||
- Fix #429: failing to load `startup-config` does not trigger the fail
|
||||
secure mode, causing the system to end up in an undefined state
|
||||
- Fix #453: fix inconsistent behavior of custom MAC address (interface
|
||||
`phys-address` for VETH pairs. Allows fixed MAC in containers
|
||||
- Fix #462: increase port column width for CLI `show bridge mdb`
|
||||
- Fix #468: non-admin users can get a POSIX shell as login shell, root
|
||||
cause was buggy Augeas library, replaced with plain C API.
|
||||
- Fix #469: non-admin users added to *any* group get administrator
|
||||
privileges (added to UNIX `wheel` group)
|
||||
- Fix #473: bridge interface with IPv6 SLAAC never get global prefix
|
||||
- Fix #476: Custom command for containers not working
|
||||
- Fix #479: timeout from underlying datastore when disabling containers
|
||||
in configuration. Only disabling (stopping) container now done in the
|
||||
configuration change, removal of container done in the background
|
||||
- Fix locking issue with standard counter groups on `mv88e6xxx`
|
||||
- Add missing LICENSE hash for factory reset tool
|
||||
- Fix timeout handling in container restart command
|
||||
- Fix MDB/ATU synchronization issue from IGMPv3/MLDv2 reports on
|
||||
`mv88e6xxx` systems
|
||||
|
||||
[v24.04.2][] - 2024-05-15
|
||||
-------------------------
|
||||
|
||||
@@ -881,6 +982,7 @@ Supported YANG models in addition to those used by sysrepo and netopeer:
|
||||
|
||||
[buildroot]: https://buildroot.org/
|
||||
[UNRELEASED]: https://github.com/kernelkit/infix/compare/v24.04.0...HEAD
|
||||
[v24.06.0]: https://github.com/kernelkit/infix/compare/v24.04.0...v24.06.0
|
||||
[v24.04.2]: https://github.com/kernelkit/infix/compare/v24.04.1...v24.04.2
|
||||
[v24.04.1]: https://github.com/kernelkit/infix/compare/v24.04.0...v24.04.1
|
||||
[v24.04.0]: https://github.com/kernelkit/infix/compare/v24.02.0...v24.04.0
|
||||
|
||||
+2
-1
@@ -11,8 +11,9 @@ the `help` command.
|
||||
|
||||
- **CLI Topics**
|
||||
- [Introduction to the CLI](cli/introduction.md)
|
||||
- [CLI User's Guide](cli/tutorial.md)
|
||||
- [Configuring using the CLI](cli/configure.md)
|
||||
- [Quick Overview](cli/quick.md)
|
||||
- [Upgrading the Software](cli/upgrade.md)
|
||||
- **Infix User Guide**
|
||||
- [Introduction](introduction.md)
|
||||
- [System Configuration](system.md)
|
||||
|
||||
@@ -1,109 +1,3 @@
|
||||
User Guide
|
||||
==========
|
||||
|
||||
The command line interface (CLI, see-ell-aye) implements a CISCO-like,
|
||||
or Juniper Networks JunOS-like, CLI for UNIX systems.
|
||||
|
||||
New users always get the CLI as the default "shell" when logging in, but
|
||||
the default `admin` user logs in to `bash`. To access the CLI, type:
|
||||
|
||||
cli
|
||||
|
||||
Key commands available in any context are:
|
||||
|
||||
help
|
||||
show
|
||||
|
||||
For each command it also possible to press the `?` key and `TAB` to get
|
||||
more help and suggestions for completion.
|
||||
|
||||
> **Note:** for the sake of brevity, the hostname in the following examples
|
||||
> has been shortened to `host`. The default name is composed from a product
|
||||
> specific string followed by the last three octets of the system base MAC
|
||||
> address, e.g., `switch-12-34-56`. An example of how to change the hostname
|
||||
> is included below.
|
||||
|
||||
|
||||
Admin Exec
|
||||
----------
|
||||
|
||||
The top-level context after logging in and starting the CLI is the
|
||||
admin-exec or "main" context. It is used for querying system status,
|
||||
managing configuration files/profiles and doing advanced debugging.
|
||||
|
||||
Available commands can be seen by pressing `?` at the prompt:
|
||||
|
||||
```
|
||||
admin@host:/>
|
||||
configure Create new candidate-config based on running-config
|
||||
copy Copy configuration, e.g., copy running-config startup-config
|
||||
exit Exit from CLI (log out)
|
||||
factory-reset Restore the system to factory default state
|
||||
follow Monitor a log file, use Ctrl-C to abort
|
||||
help Help system (also try '?' key)
|
||||
logout Alias to exit
|
||||
netcalc IP subnet calculator
|
||||
password Password tools
|
||||
ping Ping a network host or multicast group
|
||||
poweroff Poweroff system (system policy may yield reboot)
|
||||
reboot Reboot system
|
||||
set Set operations, e.g., current date/time
|
||||
shell Enter system shell
|
||||
show Show system status and configuration files
|
||||
tcpdump Capture network traffic
|
||||
upgrade Install a software update bundle
|
||||
```
|
||||
|
||||
To get more help for a given command, type the command, a space, and
|
||||
then tap `?` again. You can also tap the `Tab` key to see available
|
||||
argument completions.
|
||||
|
||||
### Upgrading the Software
|
||||
|
||||
The admin-exec command `upgrade` can be used to install software images, or
|
||||
bundles. A bundle is a signed and self-contained package that carries all the
|
||||
information necessary to determine if it holds a bootloader, a Linux image, or
|
||||
even both.
|
||||
|
||||
To install a new software image to the currently *inactive* partition[^1], we
|
||||
use the `upgrade` command and a URI to a ftp/tftp/sftp or http/https server
|
||||
that hosts the file:
|
||||
|
||||
```
|
||||
admin@host:/> upgrade tftp://192.168.122.1/firmware-x86_64-v23.11.pkg
|
||||
installing
|
||||
0% Installing
|
||||
0% Determining slot states
|
||||
20% Determining slot states done.
|
||||
20% Checking bundle
|
||||
20% Verifying signature
|
||||
40% Verifying signature done.
|
||||
40% Checking bundle done.
|
||||
40% Checking manifest contents
|
||||
60% Checking manifest contents done.
|
||||
60% Determining target install group
|
||||
80% Determining target install group done.
|
||||
80% Updating slots
|
||||
80% Checking slot rootfs.1
|
||||
90% Checking slot rootfs.1 done.
|
||||
90% Copying image to rootfs.1
|
||||
99% Copying image to rootfs.1 done.
|
||||
99% Updating slots done.
|
||||
100% Installing done.
|
||||
Installing `tftp://192.168.122.1/firmware-x86_64-v23.11.pkg` succeeded
|
||||
admin@host:/>
|
||||
```
|
||||
|
||||
The secondary partition (`rootfs.1`) has now been upgraded and will be used as
|
||||
the *active* partition on the next boot. Leaving the primary partition, with
|
||||
the version we are currently running, intact in case of trouble.
|
||||
|
||||
[^1]: It is not possible to upgrade the partition we booted from. Thankfully
|
||||
the underlying "rauc" subsystem keeps track of this. Hence, to upgrade
|
||||
both partitions you must reboot to the new version (to verify it works)
|
||||
and then repeat the same command.
|
||||
|
||||
|
||||
Configure Context
|
||||
-----------------
|
||||
|
||||
@@ -382,7 +276,3 @@ is filtered, except LLDP frames as shown above.
|
||||
> **Note:** the bridge can be named anything, provided the interface
|
||||
> name is not already taken. However, for any name outside the pattern
|
||||
> `br[0-9]+`, you have to set the interface type manually to `bridge`.
|
||||
|
||||
|
||||
|
||||
[1]: https://src.libcode.org/pkun/klish
|
||||
+93
-19
@@ -1,6 +1,7 @@
|
||||
# Introduction
|
||||
|
||||
The command line interface (CLI, see-ell-i) is the traditional way of
|
||||
The command line interface (CLI, see-ell-aye) implements a CISCO-like,
|
||||
or Juniper Networks JunOS-like, CLI. It is the traditional way of
|
||||
interacting with single network equipment like switches and routers.
|
||||
Today more advanced graphical NETCONF-based tools are available that
|
||||
allows for managing entire fleets of installed equipment.
|
||||
@@ -9,34 +10,107 @@ Nevertheless, when it comes to initial deployment and debugging, it
|
||||
is very useful to know how to navigate and use the CLI. This very
|
||||
short guide intends to help you with that.
|
||||
|
||||
|
||||
## About
|
||||
|
||||
New users usually get the CLI as the default "shell" when logging in,
|
||||
but the default `admin` user logs in to `bash`. To access the CLI,
|
||||
type:
|
||||
|
||||
```
|
||||
admin@host-12-34-56:~$ cli
|
||||
|
||||
See the 'help' command for an introduction to the system
|
||||
|
||||
admin@host-12-34-56:/>
|
||||
```
|
||||
|
||||
The prompt (beginning of the line) changes slightly. Key commands
|
||||
available in any context are:
|
||||
|
||||
```
|
||||
admin@host-12-34-56:/> help # Try: Tab or ?
|
||||
...
|
||||
admin@host-12-34-56:/> show # Try: Tab or ?
|
||||
admin@host-12-34-56:/> # Try: Tab or ?
|
||||
```
|
||||
|
||||
> **Tip:** Even on an empty command line you can tap the Tab or ? keys.
|
||||
> See `help keybindings` for more tips!
|
||||
|
||||
|
||||
## Key Concepts
|
||||
|
||||
The two modes in the CLI are the admin-exec and the configure context.
|
||||
|
||||
When logging in to the system, be it from console or SSH, you first have
|
||||
a stopover in a UNIX shell, usually Bash. Type `cli` to enter the CLI
|
||||
and finally land in admin-exec. Here you can inspect system status and
|
||||
do operations to debug networking issues, e.g. ping. You can also enter
|
||||
configure context by typing: `configure`
|
||||
The top-level context after logging in and starting the CLI is the
|
||||
admin-exec or "main" context. It is used for querying system status,
|
||||
managing configuration files/profiles and doing advanced debugging.
|
||||
|
||||
The system has several datastores (or files):
|
||||
Available commands can be seen by pressing `?` at the prompt:
|
||||
|
||||
- `factory-config` consists of a set of default configurations, some
|
||||
static and others generated per-device, e.g., a unique hostname and
|
||||
number of ports/interfaces. This file is generated at boot.
|
||||
- `startup-config` is created from `factory-config` at boot if it does
|
||||
not exist. It is loaded as the system configuration on each boot.
|
||||
- `running-config` is what is actively running on the system. If no
|
||||
changes have been made since the system booted, it is the same as
|
||||
`startup-config`.
|
||||
```
|
||||
admin@host:/>
|
||||
configure Create new candidate-config based on running-config
|
||||
copy Copy file or configuration, e.g., copy running-config startup-config
|
||||
dir List available configuration files
|
||||
exit Exit from CLI (log out)
|
||||
factory-reset Restore the system to factory default state
|
||||
follow Monitor a log file, use Ctrl-C to abort
|
||||
help Help system (try also the '?' key)
|
||||
logout Alias to exit
|
||||
netcalc IP subnet calculator, with subnetting
|
||||
password Password tools
|
||||
ping Ping a network host or multicast group
|
||||
poweroff Poweroff system (system policy may yield reboot)
|
||||
reboot Reboot system
|
||||
remove Remove a configuration file
|
||||
set Set operations, e.g., current date/time
|
||||
show Show system status and configuration files
|
||||
tcpdump Capture network traffic
|
||||
upgrade Install a software update bundle from remote or local file
|
||||
```
|
||||
|
||||
The system has three *main datastores* (or files): *factory*, *startup*,
|
||||
and *running* that can be managed and inspected using the `copy`,
|
||||
`show`, and `configure` commands. The traditional names used in the CLI
|
||||
for these are listed below:
|
||||
|
||||
- `factory-config` the default configuration from factory for the
|
||||
device, i.e., what the system returns to after a `factory-reset`
|
||||
- `startup-config` created from `factory-config` at first boot after
|
||||
factory reset. Loaded as the system configuration on each boot
|
||||
- `running-config` what is actively running on the system. If no
|
||||
changes have been made since boot, it is the same as `startup-config`
|
||||
- `candidate-config` is created from `running-config` when entering the
|
||||
configure context. Any changes made here can be discarded (`abort`,
|
||||
`rollback`) or committed (`commit`, `leave`) to `running-config`.
|
||||
`rollback`) or committed (`commit`, `leave`) to `running-config`
|
||||
|
||||
To save configuration changes made to the `running-config` so the system
|
||||
will use them consecutive reboots, use the `copy` command:
|
||||
Edit the *running* configuration using the `configure` command. This
|
||||
copies *running* to *candidate*, a temporary datastore, where changes
|
||||
are made:
|
||||
|
||||
admin@host-12-34-56:/> copy running-config startup-config
|
||||
```
|
||||
admin@host-12-34-56:/> configure
|
||||
admin@host-12-34-56:/config/> ... # Try: Tab or ?
|
||||
admin@host-12-34-56:/config/> leave
|
||||
```
|
||||
|
||||
The `leave` command activates the changes by issuing a transaction to,
|
||||
essentially, copy the *candidate* back to *running*. Depending on the
|
||||
changes made, this can take a few seconds. If the changes are invalid,
|
||||
i.e., not correct according to the underlying YANG models, a warning is
|
||||
shown and the session remains in configure context. Use the `abort`
|
||||
command to cancel your changes, or investigate further with the `diff`
|
||||
command (see more below).
|
||||
|
||||
To save configuration changes made to the `running-config` to persistent
|
||||
store, so the system will use them for consecutive reboots, use the
|
||||
`copy` command:
|
||||
|
||||
```
|
||||
admin@host-12-34-56:/> copy running-config startup-config
|
||||
```
|
||||
|
||||
In *configure context* the following commands are available:
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
## Usage
|
||||
|
||||
```
|
||||
netcalc <ADDRESS/LEN | NETWORK NETMASK> [split <1-32 | 64-128>]
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
`netcalc` is a network calculator that takes an IP address and a subnet
|
||||
mask, or an IP address and prefix mask in CIDR notation, and then returns
|
||||
information about the subnet. Both IPv4 and IPv6 is supported.
|
||||
|
||||
A subnet can be entered in two ways:
|
||||
|
||||
- `192.168.2.0 255.255.255.0`: traditional IPv4 'address netmask' style
|
||||
- `192.168.2.0/24`: modern prefix length, same also for IPv6
|
||||
|
||||
An optional `split LEN` can be given as argument, the new length value
|
||||
must be bigger than the current prefix length. See example below.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Its most commonly used features are to understand how many addresses an
|
||||
IP subnet has, what the broadcast address is, first and last *usable*
|
||||
address.
|
||||
|
||||
```
|
||||
admin@example:/> netcalc 192.168.2.0/24
|
||||
Address : 192.168.2.0 11000000.10101000.00000010. 00000000
|
||||
Netmask : 255.255.255.0 = 24 11111111.11111111.11111111. 00000000
|
||||
Wildcard : 0.0.0.255 00000000.00000000.00000000. 11111111
|
||||
=>
|
||||
Network : 192.168.2.0/24 11000000.10101000.00000010. 00000000
|
||||
HostMin : 192.168.2.1 11000000.10101000.00000010. 00000001
|
||||
HostMax : 192.168.2.254 11000000.10101000.00000010. 11111110
|
||||
Broadcast: 192.168.2.255 11000000.10101000.00000010. 11111111
|
||||
Hosts/Net: 254 Class C, Private network (RFC1918)
|
||||
```
|
||||
|
||||
Another common use-case is for IP subnetting, i.e., using only as many
|
||||
addresses for an IP subnet as needed. Example, to split the above /24
|
||||
in four:
|
||||
|
||||
```
|
||||
admin@example:/> netcalc 192.168.2.0/24 split 26
|
||||
Address : 192.168.2.0 11000000.10101000.00000010. 00000000
|
||||
Netmask : 255.255.255.0 = 24 11111111.11111111.11111111. 00000000
|
||||
Wildcard : 0.0.0.255 00000000.00000000.00000000. 11111111
|
||||
=>
|
||||
Network : 192.168.2.0/24 11000000.10101000.00000010. 00000000
|
||||
HostMin : 192.168.2.1 11000000.10101000.00000010. 00000001
|
||||
HostMax : 192.168.2.254 11000000.10101000.00000010. 11111110
|
||||
Broadcast: 192.168.2.255 11000000.10101000.00000010. 11111111
|
||||
Hosts/Net: 254 Class C, Private network (RFC1918)
|
||||
|
||||
[Split network/26]
|
||||
Network : 192.168.2.0 - 192.168.2.63 Netmask : 255.255.255.192
|
||||
Network : 192.168.2.64 - 192.168.2.127 Netmask : 255.255.255.192
|
||||
Network : 192.168.2.128 - 192.168.2.191 Netmask : 255.255.255.192
|
||||
Network : 192.168.2.192 - 192.168.2.255 Netmask : 255.255.255.192
|
||||
```
|
||||
+2
-2
@@ -19,9 +19,9 @@ keybindings are really useful to learn!
|
||||
| **Command** | **Description** |
|
||||
|---------------------|--------------------------------------------|
|
||||
| `help introduction` | An introduction to the CLI |
|
||||
| `help keybindings` | Lists keybindings and other helpful tricks |
|
||||
| `help tutorial` | The CLI User Guide |
|
||||
| `help configure` | How to use configure context |
|
||||
| `help text-editor` | Help with the built-in text-editor command |
|
||||
| `help keybindings` | Lists keybindings and other helpful tricks |
|
||||
|
||||
> In `configure` context the `help setting` command shows the YANG
|
||||
> description text for each node and container. To reach the admin
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
## Network Traffic Inspection
|
||||
|
||||
`tcpdump` is useful tool for analyzing and diagnosing network problems.
|
||||
This document presents the limited feature set that exposed is in the
|
||||
CLI. Administrator level users with shell access can use the full
|
||||
feature set, and is not described here.
|
||||
|
||||
The following section is useful for understanding how to use the tool.
|
||||
A section called [Examples](#examples) follows that, which may be what
|
||||
you want to scroll down to.
|
||||
|
||||
|
||||
### Hardware Overview
|
||||
|
||||
Using `tcpdump` effectively requires an understanding of how the
|
||||
underlying hardware works. For a standard PC, or common single-board
|
||||
computers (SBC), the network cards (NICs) are usually connected directly
|
||||
to the CPU.
|
||||
|
||||
.---------.
|
||||
| +-- eth0
|
||||
| CPU |
|
||||
| +-- eth1
|
||||
'---------'
|
||||
|
||||
In this setup it is evident that traffic coming in on either eth0 or
|
||||
eth1 reach the CPU, i.e., running `tcpdump eth0` captures all traffic.
|
||||
|
||||
However, on other types of networking hardware, e.g., dedicated switch
|
||||
core setups depicted below, the flow of network traffic will likely
|
||||
*not* pass through the CPU. This depends of course on how the switch is
|
||||
set up, for instance if routing between all ports is enabled, each flow
|
||||
will reach the CPU, but in a plain switching setup it will not.
|
||||
|
||||
.---------.
|
||||
| |
|
||||
| CPU |
|
||||
| |
|
||||
'----+----'
|
||||
|
|
||||
|
|
||||
.----------+---------.
|
||||
| |
|
||||
---+ +---
|
||||
E1 | SC | E3
|
||||
---+ +---
|
||||
E2 | | E4
|
||||
'--+--+--+--+--+--+--'
|
||||
| | | | | |
|
||||
E5 E6 E7 E8 E9 E10
|
||||
|
||||
So, running `tcpdump e1` in a switching setup, inside the CPU, the only
|
||||
traffic that will be captured is traffic ingressing port E1 destined for
|
||||
the CPU itself. To analyze traffic going through the switch, you need
|
||||
something called *port mirroring*, or *port monitoring*, i.e., setting
|
||||
up the switch core to mirror traffic ingressing and/or egressing a set
|
||||
of ports to another port. On this *monitor port* you can then run your
|
||||
tcpdump, which means you need an external device (laptop).
|
||||
|
||||
> A planned feature is to support mirroring traffic to the CPU port,
|
||||
> which would be an effective way to log and monitor traffic over a
|
||||
> longer period of time. Highly effective for diagnosing intermittent
|
||||
> and other rare network issues.
|
||||
|
||||
If only "proof of life" is required, then sometimes port counters, also
|
||||
called *RMON counters*, can be very useful too. Seeing counters of a
|
||||
particular type increment means traffic is ingressing or egressing.
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
Listen to all traffic on an interface:
|
||||
|
||||
admin@example:/> tcpdump e1
|
||||
|
||||
Listen to only ping traffic:
|
||||
|
||||
admin@example:/> tcpdump e1 expression icmp
|
||||
|
||||
Listen to traffic on a given port:
|
||||
|
||||
admin@example:/> tcpdump e1 expression "port 80"
|
||||
|
||||
Wait for one ping only:
|
||||
|
||||
admin@example:/> tcpdump e1 count 1 expression icmp
|
||||
|
||||
Very verbose output:
|
||||
|
||||
admin@example:/> tcpdump e1 verbose
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
Upgrading the Software
|
||||
----------------------
|
||||
|
||||
The admin-exec command `upgrade` can be used to install software images, or
|
||||
bundles. A bundle is a signed and self-contained package that carries all the
|
||||
information necessary to determine if it holds a bootloader, a Linux image, or
|
||||
even both.
|
||||
|
||||
To install a new software image to the currently *inactive* partition[^1], we
|
||||
use the `upgrade` command and a URI to a ftp/tftp/sftp or http/https server
|
||||
that hosts the file:
|
||||
|
||||
```
|
||||
admin@host:/> upgrade tftp://192.168.122.1/firmware-x86_64-v23.11.pkg
|
||||
installing
|
||||
0% Installing
|
||||
0% Determining slot states
|
||||
20% Determining slot states done.
|
||||
20% Checking bundle
|
||||
20% Verifying signature
|
||||
40% Verifying signature done.
|
||||
40% Checking bundle done.
|
||||
40% Checking manifest contents
|
||||
60% Checking manifest contents done.
|
||||
60% Determining target install group
|
||||
80% Determining target install group done.
|
||||
80% Updating slots
|
||||
80% Checking slot rootfs.1
|
||||
90% Checking slot rootfs.1 done.
|
||||
90% Copying image to rootfs.1
|
||||
99% Copying image to rootfs.1 done.
|
||||
99% Updating slots done.
|
||||
100% Installing done.
|
||||
Installing `tftp://192.168.122.1/firmware-x86_64-v23.11.pkg` succeeded
|
||||
admin@host:/>
|
||||
```
|
||||
|
||||
The secondary partition (`rootfs.1`) has now been upgraded and will be used as
|
||||
the *active* partition on the next boot. Leaving the primary partition, with
|
||||
the version we are currently running, intact in case of trouble.
|
||||
|
||||
[^1]: It is not possible to upgrade the partition we booted from. Thankfully
|
||||
the underlying "rauc" subsystem keeps track of this. Hence, to upgrade
|
||||
both partitions you must reboot to the new version (to verify it works)
|
||||
and then repeat the same command.
|
||||
+60
-19
@@ -390,12 +390,30 @@ network:
|
||||
|
||||
### Container Host Interface
|
||||
|
||||
Another common use-case is to move a network interface into the network
|
||||
namespace of a container. Which the container bridge network type does
|
||||
behind the scenes with one end of the automatically created VETH pair.
|
||||
This works with regular Ethernet interfaces as well, but here we will
|
||||
use a VETH pair as an example along with a regular bridge (where other
|
||||
Ethernet interfaces may live as well).
|
||||
Another common use-case is to move network interfaces into the network
|
||||
namespace of a container[^3]. This of course works with plain Ethernet
|
||||
interfaces as well, but here we will use one end of a VETH pair as an
|
||||
example.
|
||||
|
||||
[^3]: Something which the container bridge network type does behind the
|
||||
scenes with one end of an automatically created VETH pair.
|
||||
|
||||
#### Routed Setup
|
||||
|
||||
In this routed setup we reserve 192.168.0.0/24 for the network between
|
||||
the host and the `ntpd` container.
|
||||
|
||||
_____________
|
||||
| |
|
||||
veth0 .1 | .2 eth0 |
|
||||
\ 192.168.0.0/24 | / |
|
||||
'--------------------' [ntpd] |
|
||||
|_____________|
|
||||
|
||||
Configuration is a straight-forward VETH pair setup where we name the
|
||||
container-end of pair `ntpd`. This is just a convenience for us when
|
||||
reading the configuration later. The *real action* happens on the last
|
||||
line where we declare the `ntpd` end as a container network interface:
|
||||
|
||||
admin@example:/config/> edit interface veth0
|
||||
admin@example:/config/interface/veth0/> set veth peer ntpd
|
||||
@@ -403,23 +421,49 @@ Ethernet interfaces may live as well).
|
||||
admin@example:/config/interface/veth0/> end
|
||||
admin@example:/config/> edit interface ntpd
|
||||
admin@example:/config/interface/ntpd/> set ipv4 address 192.168.0.2 prefix-length 24
|
||||
admin@example:/config/interface/ntpd/> set phys-address 00:c0:ff:ee:00:01
|
||||
admin@example:/config/interface/ntpd/> set container-network
|
||||
|
||||
This is a routed setup, where we reserve 192.168.0.0/24 for the network
|
||||
between the host and the `ntpd` container. A perhaps more common case
|
||||
is to put `veth0` as a port in a bridge with other physical ports. The
|
||||
point of the routed case is that port forwarding from the container in
|
||||
this case is limited to a single interface, not *all interfaces* as is
|
||||
the default in the masquerading container bridge setup.
|
||||
> Notice how you can also set a custom MAC address at the same time.
|
||||
|
||||
When a container has multiple host interfaces it can often be useful to
|
||||
have a default route installed. This can be added from the host with a
|
||||
`0.0.0.0/0` route on one of the interfaces. The following is an example
|
||||
when adding a second VETH pair to the container:
|
||||
Adding the interface to the container is the same as before, but since
|
||||
everything for host interfaces is set up in the interfaces context, we
|
||||
can take a bit of a shortcut.
|
||||
|
||||
admin@example:/config/container/ntpd/> set network ntpd
|
||||
admin@example:/config/container/ntpd/> leave
|
||||
|
||||
The point of the routed case is that port forwarding from the container
|
||||
in this case is limited to a single interface, not *all interfaces* as
|
||||
is the default in the masquerading container bridge setup.
|
||||
|
||||
|
||||
#### Bridged Setup
|
||||
|
||||
A perhaps more common case is to bridge the other end of the VETH pair
|
||||
with other physical ports. In this section we show how to add a new
|
||||
pair to give our container two interfaces:
|
||||
|
||||
_______________
|
||||
| | .1 br0
|
||||
veth0 .1 | .2 eth0 | / \
|
||||
\ 192.168.0.0/24 | / eth1 .2 | veth1b e1
|
||||
'------------------' \ | 192.168.1.0/24 /
|
||||
| [ntpd] '------------------'
|
||||
|_______________|
|
||||
|
||||
We start by adding the second VETH pair:
|
||||
|
||||
admin@example:/config/> edit interface veth1a
|
||||
admin@example:/config/interface/veth1a/> set veth peer veth1b
|
||||
admin@example:/config/interface/veth1a/> set ipv4 address 192.168.1.2 prefix-length 24
|
||||
|
||||
> The LAN bridge (br0) in this example has IP address 192.168.1.1.
|
||||
|
||||
When a container has multiple host interfaces it can often be useful to
|
||||
have a default route installed. This can be added from the host with a
|
||||
`0.0.0.0/0` route on one of the interfaces:
|
||||
|
||||
admin@example:/config/interface/veth1a/> set container-network route 0.0.0.0/0 gateway 192.168.1.1
|
||||
admin@example:/config/interface/veth1a/> show
|
||||
type veth;
|
||||
@@ -439,9 +483,6 @@ Please note, container network routes require the base interface also
|
||||
have a static IP address set. Setting only the route, but no address,
|
||||
means the route is skipped.
|
||||
|
||||
> The LAN bridge (br0) in this example has IP address 192.168.1.1.
|
||||
|
||||
|
||||
### Host Networking
|
||||
|
||||
The third use-case is host networking, this is where a container share
|
||||
|
||||
+41
-5
@@ -97,8 +97,10 @@ To see available defconfigs for supported targets, use:
|
||||
Development
|
||||
-----------
|
||||
|
||||
When changing a package, locally kept sources, or when using [`local.mk`](override-package.md),
|
||||
you only want to rebuild the parts you have modified:
|
||||
Developing with Infix is the same as [developing with Buildroot][4].
|
||||
When working with a package, be it locally kept sources, or when using
|
||||
[`local.mk`](override-package.md), you only want to rebuild the parts
|
||||
you have modified:
|
||||
|
||||
make foo-rebuild
|
||||
|
||||
@@ -106,7 +108,7 @@ or
|
||||
|
||||
make foo-reconfigure
|
||||
|
||||
or, when nothing seems to bite:
|
||||
or, as a last resort when nothing seems to bite:
|
||||
|
||||
make foo-dirclean foo-rebuild
|
||||
|
||||
@@ -119,6 +121,38 @@ This rebuilds (and installs) `foo` and `bar`, the `all` target calls
|
||||
on Buildroot to finalize the target filesystem and generate the images.
|
||||
The final `run` argument is explained below.
|
||||
|
||||
### `confd`
|
||||
|
||||
The Infix `src/confd/` is the engine of the system. Currently it is a
|
||||
plugin for `systemd-plugind` and contains XPath subscriptions to all the
|
||||
supported YANG models.
|
||||
|
||||
There are essentially two ways of adding support for a new YANG model:
|
||||
|
||||
- The [sysrepo way][3], or
|
||||
- The Infix way, using libsrx (the `lydx_*()` functions)
|
||||
|
||||
The former is well documented in sysrepo, and the latter is best taught
|
||||
by example, e.g., `src/confd/src/infix-dhcp.c`. Essentially libsrx is a
|
||||
way of traversing the libyang tree instead of fetching changes by XPath.
|
||||
|
||||
When working with `confd` you likely want to enable full debug mode,
|
||||
this is how you do it:
|
||||
|
||||
1. Open the file `package/confd/confd.conf`
|
||||
2. Uncomment the first line `set DEBUG=1`
|
||||
3. Change the following line to add `-v3` at the end
|
||||
|
||||
[S12345] sysrepo-plugind -f -p /run/confd.pid -n -- Configuration daemon
|
||||
|
||||
to:
|
||||
|
||||
[S12345] sysrepo-plugind -f -p /run/confd.pid -n -v3 -- Configuration daemon
|
||||
|
||||
Now you can rebuild `confd`, just as described above, and restart Infix:
|
||||
|
||||
make confd-rebuild all run
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
@@ -142,8 +176,8 @@ and then use GitHub to create a *Pull Reqeuest*.
|
||||
For this to work as painlessly as possible:
|
||||
|
||||
1. Fork Infix to your own user or organization[^1]
|
||||
2. Fork all the Infix submodules, e.g., `buildroot` to your own user
|
||||
or organization as well
|
||||
2. Fork all the Infix submodules, e.g., `kernelkit/buildroot` to your
|
||||
own user or organization as well
|
||||
3. Clone your fork of Infix to your laptop/workstation
|
||||
|
||||
If you use a GitHub organization you get the added benefit of having
|
||||
@@ -170,3 +204,5 @@ $ git submodule update --init
|
||||
[0]: https://github.com/kernelkit/infix/releases
|
||||
[1]: https://buildroot.org/downloads/manual/manual.html
|
||||
[2]: https://github.com/wkz/qeneth
|
||||
[3]: https://netopeer.liberouter.org/doc/sysrepo/master/html/dev_guide.html
|
||||
[4]: https://buildroot.org/downloads/manual/manual.html#_developer_guide
|
||||
|
||||
+53
-28
@@ -1,50 +1,75 @@
|
||||
Package override
|
||||
Package Override
|
||||
================
|
||||
|
||||
This guide demonstrates how the `local.mk` file is utilized to override
|
||||
a Linux Buildroot package. The example of `tcpdump` serves to illustrate
|
||||
This guide demonstrates how the `local.mk` file is utilized to override
|
||||
a Linux Buildroot package. As an example we use `tcpdump` to illustrate
|
||||
this process.
|
||||
|
||||
In an instance such as `Infix` using tcpdump, the `local.mk` file is modified
|
||||
as shown below:
|
||||
> For a comprehensive guide to utilizing Buildroot during development,
|
||||
> including the `<pkg>_OVERRIDE_SRCDIR` mechanism, shown below, please
|
||||
> see [Using Buildroot during development][1] in the official docs.
|
||||
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
Since the `output/` directory is often wiped for rebuilds, make sure you
|
||||
keep the file `local.mk` in the top directory and only symlink it to your
|
||||
build directory:
|
||||
|
||||
~$ cd infix/
|
||||
~/infix(main)$ touch local.mk
|
||||
~/infix/output(main)$ ln -s ../local.mk .
|
||||
~/infix/output(main)$ cd ..
|
||||
|
||||
|
||||
Override
|
||||
--------
|
||||
|
||||
Now edit the file:
|
||||
|
||||
~/infix(main)$ editor local.mk
|
||||
|
||||
Add an override for `tcpdump`. The file is a Makefile snippet so you
|
||||
can add a lot of things. Comment out lines with the UNIX comment `#`
|
||||
character if needed:
|
||||
|
||||
```
|
||||
TCPDUMP_OVERRIDE_SRCDIR = /path/to/tcpdump/repo
|
||||
```
|
||||
|
||||
and stored in the `output/` folder, alongside the `.config` file:
|
||||
```
|
||||
user@PC:~/infix$ll output/ | grep -e 'local.mk' -e '.config'
|
||||
-rw-r--r-- 1 group user 119936 Nov 10 18:04 .config
|
||||
-rw-r--r-- 1 group user 43 Nov 10 18:25 local.mk
|
||||
```
|
||||
Building
|
||||
--------
|
||||
|
||||
The execution of `make tcpdump-rebuild all` triggers a process where
|
||||
Buildroot synchronizes the tcpdump source code from the specified override directory
|
||||
to `output/build/tcpdump-custom`, followed by the rebuilding of the entire project.
|
||||
The execution of `make tcpdump-rebuild all` triggers a process where
|
||||
Buildroot synchronizes the tcpdump source code from the specified
|
||||
override directory to `output/build/tcpdump-custom`, followed by the
|
||||
rebuilding of the entire project.
|
||||
|
||||
```
|
||||
user@PC:~/infix$ make tcpdump-rebuild all
|
||||
~/infix$(main)$ make tcpdump-rebuild all
|
||||
```
|
||||
|
||||
Buildroot follows a process of downloading and processing tarballs:
|
||||
extraction, configuration, compilation, and installation. The source
|
||||
for each package is extracted to a temporary build directory:
|
||||
|
||||
output/build/<package>-<version> # e.g., tcpdump-4.99.4
|
||||
|
||||
Let's have a look at what we got:
|
||||
|
||||
```
|
||||
user@PC:~/infix$ ll /output/build/ | grep tcpdump
|
||||
~/infix$(main)$ ll /output/build/ | grep tcpdump
|
||||
drwxr-xr-x 7 group user 20480 Nov 10 18:26 tcpdump-4.99.4/
|
||||
drwxr-xr-x 7 group user 12288 Nov 10 18:28 tcpdump-custom/
|
||||
```
|
||||
|
||||
Buildroot follows a process of downloading and processing tarballs
|
||||
(extraction, configuration, compilation, and installation).
|
||||
The source code is stored in a temporary directory:
|
||||
`output/build/<package>-<version>` (i.e. `tcpdump-4.99.4/`),
|
||||
which is removed and recreated with each `make` command. That is why
|
||||
the direct modifications in the `output/build` directory are generally
|
||||
**not recommended**.
|
||||
As long as your local override is in place, Buildroot will use your
|
||||
custom version.
|
||||
|
||||
To manage the development changes more effectively, where the package source code
|
||||
remains untouched, Buildroot incorporates the `<pkg>_OVERRIDE_SRCDIR` feature.
|
||||
> **Remember:** the build directory is ephemeral, so be careful to
|
||||
> change any of the files therein. It can be useful though during
|
||||
> debugging, but just make sure to learn the difference between the
|
||||
> various Buildroot commands to build, clean, reconfigure, etc.
|
||||
|
||||
For a comprehensive understanding of utilizing Buildroot during development,
|
||||
including detailed elaboration on the `<pkg>_OVERRIDE_SRCDIR` feature,
|
||||
refer to section 8.13.6 in [Using Buildroot during development](https://nightly.buildroot.org/).
|
||||
[1]: https://buildroot.org/downloads/manual/manual.html#_using_buildroot_during_development
|
||||
|
||||
@@ -784,6 +784,38 @@ models for details.
|
||||
~$
|
||||
```
|
||||
|
||||
## Examples using RESTCONF
|
||||
|
||||
### Factory Reset
|
||||
|
||||
```
|
||||
~$ curl -kX POST -H "Content-Type: application/yang-data+json" https://example.local/restconf/operations/ietf-factory-default:factory-reset -u admin:admin
|
||||
curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0
|
||||
```
|
||||
|
||||
### System Reboot
|
||||
|
||||
```
|
||||
~$ curl -kX POST -H "Content-Type: application/yang-data+json" https://example.local/restconf/operations/ietf-system:system-restart -u admin:admin
|
||||
```
|
||||
|
||||
### Set Date and Time
|
||||
|
||||
Here's an example of an RPC that takes input/argument:
|
||||
|
||||
```
|
||||
~$ curl -kX POST -H "Content-Type: application/yang-data+json" https://example.local/restconf/operations/ietf-system:set-current-datetime -u admin:admin -d '{"ietf-system:input": {"current-datetime": "2024-04-17T13:48:02-01:00"}}'
|
||||
```
|
||||
|
||||
You can verify that the changes took by a remote SSH command:
|
||||
|
||||
```
|
||||
~$ ssh admin@example.local 'date'
|
||||
Wed Apr 17 14:48:12 UTC 2024
|
||||
~$
|
||||
```
|
||||
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
### <a id="port-test-intro"></a> Port Configuration Example for Production Tests
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
Test System Architecture
|
||||
========================
|
||||
|
||||
Tenets
|
||||
------
|
||||
|
||||
- **Keep overhead to a minimum**. Tests should be fast to both write
|
||||
and run. Ideally, the developer should _want_ to add tests early in
|
||||
the development cycle because they instinctively feel that that is
|
||||
the quickest route to arrive at a correct and robust implementation.
|
||||
|
||||
- **Both physical and virtual hardware matters**. Infix is primarily
|
||||
deployed on physical hardware, so being able to run the test suite
|
||||
on real devices is crucial to guarantee a high quality product. At
|
||||
the same time, there is much value in running the same suite on
|
||||
virtual hardware, as it makes it easy to catch regressions early.
|
||||
It is also much more practical and economical to build large virtual
|
||||
networks than physical ones.
|
||||
|
||||
- **Avoid CLI scipting & scraping**. Reliably interacting with a DUT
|
||||
over a serial line in a robust way is _very_ hard to get right.
|
||||
Given that we have a proper API (RESTCONF), we should leverage that
|
||||
when testing. Front-ends can be tested by other means.
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||

|
||||
|
||||
The test system is made up of several independent components, which
|
||||
are typically used in concert to run a full test suite.
|
||||
|
||||
### Test Cases
|
||||
|
||||
A test case is an executable, receiving the physical topology as a
|
||||
positional argument, which produces [TAP][] compliant output on its
|
||||
`stdout`. I.e., it is executed in the following manner:
|
||||
|
||||
test-case [OPTS] <physical-topology>
|
||||
|
||||
Test cases are typically written in Python, using the
|
||||
[Infamy](#infamy) library. Ultimately though, it can be implemented
|
||||
in any language, as long as it matches the calling convention above.
|
||||
|
||||
### Infamy
|
||||
|
||||
Rather than having each test case come up with its own implementation
|
||||
of how to map topologies, how to push NETCONF data to a device, etc.,
|
||||
we provide a library of functions to take care of all that, dubbed
|
||||
"Infamy". When adding a new test case, ask yourself if any parts of
|
||||
it might belong in Infamy as a generalized component that can be
|
||||
reused by other tests.
|
||||
|
||||
Some of the core functions provided by Infamy are:
|
||||
|
||||
- Mapping a logical topology to a physical one
|
||||
- Finding and attaching to a device over an Ethernet interface, using
|
||||
NETCONF
|
||||
- Pushing/pulling NETCONF data to/from a device
|
||||
- Generating TAP compliant output
|
||||
|
||||
### 9PM
|
||||
|
||||
To run multiple tests, we employ [9PM][]. It let's us define test
|
||||
suites as simple YAML files. Suites can also be hierarchically
|
||||
structured, with a suite being made up of other suites, etc.
|
||||
|
||||
It also validates the TAP output, making sure to catch early exits
|
||||
from a case, and produces a nice summary report.
|
||||
|
||||
### `/test/env`
|
||||
|
||||
A good way to ensure that nobody ever runs the test suite is to make
|
||||
it _really_ hard to do so. `/test/env`'s job is instead to make it
|
||||
very _easy_ to create a reproducible environment in which tests can be
|
||||
executed.
|
||||
|
||||
Several technologies are leveraged to accomplish this:
|
||||
|
||||
- **Containers**: The entire execution is optionally done inside a
|
||||
standardized `docker` container environment. This ensures that the
|
||||
software needed to run the test suite is always available, no matter
|
||||
which distribution the user is running on their machine.
|
||||
|
||||
- **Python Virtual Environments**: To make sure that the expected
|
||||
versions of all Python packages are available, the execution is
|
||||
wrapped inside a `venv`. This is true for containerized executions,
|
||||
where the container comes with a pre-installed environment, but it
|
||||
can also be sourced from the host system when running outside of the
|
||||
container.
|
||||
|
||||
- **Virtual Test Topology**: Using [Qeneth][], the environment can
|
||||
optionally be started with a virtual topology of DUTs to run the
|
||||
tests on.
|
||||
|
||||
> `docker` is the only supported container environment when running
|
||||
> tests in the host's network namespace. When running on a virtual
|
||||
> Qeneth topology, `podman` may also be used by installing the
|
||||
> `podman-docker` package from your host system's distro.
|
||||
|
||||
|
||||
Physical and Logical Topologies
|
||||
-------------------------------
|
||||
|
||||
Imagine that we want to create a test with three DUTs; one acting as a
|
||||
DHCP server, and the other two as DHCP clients - with all three having
|
||||
a management connection to the host PC running the test. In other
|
||||
words, the test requires a _logical_ topology like the one below.
|
||||
|
||||
<img align="right" src="img/testing-log.dot.svg" alt="Example Logical Topology">
|
||||
|
||||
```dot
|
||||
graph "dhcp-client-server" {
|
||||
host [
|
||||
label="host | { <c1> c1 | <srv> srv | <c2> c2 }",
|
||||
kind="controller",
|
||||
];
|
||||
|
||||
server [
|
||||
label="{ <mgmt> mgmt } | server | { <c1> c1 | <c2> c2 }",
|
||||
kind="infix",
|
||||
];
|
||||
client1 [
|
||||
label="{ <mgmt> mgmt } | client1 | { <srv> srv }",
|
||||
kind="infix",
|
||||
];
|
||||
client2 [
|
||||
label="{ <mgmt> mgmt } | client2 | { <srv> srv }",
|
||||
kind="infix",
|
||||
];
|
||||
|
||||
host:srv -- server:mgmt
|
||||
host:c1 -- client1:mgmt
|
||||
host:c2 -- client2:mgmt
|
||||
|
||||
server:c1 -- client1:srv;
|
||||
server:c2 -- client2:srv;
|
||||
}
|
||||
```
|
||||
|
||||
When running in a virtualized environment, one could simply create a
|
||||
setup that matches the test's logical topology. But in scenarios when
|
||||
devices are physical systems, connected by real copper cables, this is
|
||||
not possible (unless you have some wicked L1 relay matrix thingy).
|
||||
|
||||
Instead, the test implementation does not concern itself with the
|
||||
exact nodes used to run the test, only that the _logical_ topology can
|
||||
be _mapped_ to some subset of the _physical_ topology. In
|
||||
mathematical terms, the physical topology must contain a subgraph that
|
||||
is _isomorphic_ to the logical topology.
|
||||
|
||||
Standing on the shoulders of giants (i.e. people with mathematics
|
||||
degrees), we can deploy well-known algorithms to find such subgraphs.
|
||||
Continuing our example, let's say we want to run our DHCP test on the
|
||||
_physical_ topology below.
|
||||
|
||||
<img align="right" src="img/testing-phy.dot.svg" alt="Example Physical Topology">
|
||||
|
||||
```dot
|
||||
graph "quad-ring" {
|
||||
host [
|
||||
label="host | { <d1a> d1a | <d1b> d1b | <d1c> d1c | <d2a> d2a | <d2b> d2b | <d2c> d2c | <d3a> d3a | <d3b> d3b | <d3c> d3c | <d4a> d4a | <d4b> d4b | <d4c> d4c }",
|
||||
kind="controller",
|
||||
];
|
||||
|
||||
dut1 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut1 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
dut2 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut2 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
dut3 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut3 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
dut4 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut4 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
|
||||
host:d1a -- dut1:e1
|
||||
host:d1b -- dut1:e2
|
||||
host:d1c -- dut1:e3
|
||||
|
||||
host:d2a -- dut2:e1
|
||||
host:d2b -- dut2:e2
|
||||
host:d2c -- dut2:e3
|
||||
|
||||
host:d3a -- dut3:e1
|
||||
host:d3b -- dut3:e2
|
||||
host:d3c -- dut3:e3
|
||||
|
||||
host:d4a -- dut4:e1
|
||||
host:d4b -- dut4:e2
|
||||
host:d4c -- dut4:e3
|
||||
|
||||
dut1:e5 -- dut2:e4
|
||||
dut2:e5 -- dut3:e4
|
||||
dut3:e5 -- dut4:e4
|
||||
dut4:e5 -- dut1:e4
|
||||
}
|
||||
```
|
||||
|
||||
Our test (in fact, all tests) receives the physical topology as an
|
||||
input parameter, and then maps the desired logical topology onto it,
|
||||
producing a mapping from logical nodes and ports to their physical
|
||||
counterparts.
|
||||
|
||||
```dot
|
||||
{
|
||||
"client1": "dut1",
|
||||
"client1:mgmt": "dut1:e1",
|
||||
"client1:srv": "dut1:e4",
|
||||
"client2": "dut3",
|
||||
"client2:mgmt": "dut3:e2",
|
||||
"client2:srv": "dut3:e5",
|
||||
"host": "host",
|
||||
"host:c1": "host:d1a",
|
||||
"host:c2": "host:d3b",
|
||||
"host:srv": "host:d4c",
|
||||
"server": "dut4",
|
||||
"server:c1": "dut4:e5",
|
||||
"server:c2": "dut4:e4",
|
||||
"server:mgmt": "dut4:e3"
|
||||
}
|
||||
```
|
||||
|
||||
With this information, the test knows that, in this particular
|
||||
environment, the server should be managed via the port called `d4c` on
|
||||
the node called `host`; that the port connected to the server on
|
||||
`client1` is `e4` on `dut1`, etc. Thereby separating the
|
||||
implementation of the test from any specific physical setup.
|
||||
|
||||
Testcases are not required to use a logical topology; they may choose
|
||||
to accept whatever physical topology its given, and dynamically
|
||||
determine the DUTs to use for testing. As an example, an STP test
|
||||
could accept an arbitrary physical topology, run the STP algorithm on
|
||||
it offline, enable STP on all DUTs, and then verify that the resulting
|
||||
spanning tree matches the expected one.
|
||||
|
||||
[9PM]: https://github.com/rical/9pm
|
||||
[Qeneth]: https://github.com/wkz/qeneth
|
||||
[TAP]: https://testanything.org/
|
||||
+108
-294
@@ -7,287 +7,57 @@ that one or more DUTs are configured over NETCONF; the resulting
|
||||
network is then black-box tested by injecting and inspecting network
|
||||
traffic at various points.
|
||||
|
||||
This document is intended to be a practical guide on how to run,
|
||||
develop and debug tests. There is a separate document describing the
|
||||
[Test System Architecture](test-arch.md).
|
||||
|
||||
TL;DR
|
||||
-----
|
||||
|
||||
Build Infix and run the test suite on a set of virtual Infix nodes.
|
||||
Modes of Testing
|
||||
----------------
|
||||
|
||||
### Virtual Devices
|
||||
|
||||
By default, tests are run on a topology made up of virtual Infix nodes
|
||||
using [Qeneth][]. To run the full regression test suite: build Infix
|
||||
for `x86_64`:
|
||||
|
||||
$ make x86_64_defconfig
|
||||
$ make
|
||||
$ make test
|
||||
|
||||
To run a subset of tests, e.g., only the DHCP client tests:
|
||||
### Physical Devices
|
||||
|
||||
$ make test INFIX_TESTS=case/infix_dhcp/all.yaml
|
||||
To run the tests on a preexisting topology from the host's network
|
||||
namespace, specify the `host` `TEST_MODE`:
|
||||
|
||||
> **Note:** see the below section [Quick Start Guide][] for how to
|
||||
> connect to the test system, debug and develop tests, and more.
|
||||
$ make TEST_MODE=host test
|
||||
|
||||
This typically used when testing on physical hardware. By default the
|
||||
topology will be sourced from `/etc/infamy.dot`, but this can be
|
||||
overwritten by setting the `TOPOLOGY` variable:
|
||||
|
||||
$ make TEST_MODE=host TOPOLOGY=~/my-topology.dot test
|
||||
|
||||
|
||||
Tenets
|
||||
------
|
||||
### `make run` Devices
|
||||
|
||||
- **Keep overhead to a minimum**. Tests should be fast to both write
|
||||
and run. Ideally, the developer should _want_ to add tests early in
|
||||
the development cycle because they instinctively feel that that is
|
||||
the quickest route to arrive at a correct and robust implementation.
|
||||
Some tests only require a single DUT. These can therefore be run
|
||||
against an Infix image started from `make run`. This requires that the
|
||||
instance is configured to use TAP networking.
|
||||
|
||||
- **Both physical and virtual hardware matters**. Infix is primarily
|
||||
deployed on physical hardware, so being able to run the test suite
|
||||
on real devices is crucial to guarantee a high quality product. At
|
||||
the same time, there is much value in running the same suite on
|
||||
virtual hardware, as it makes it easy to catch regressions early.
|
||||
It is also much more practical and economical to build large virtual
|
||||
networks than physical ones.
|
||||
When the instance is running, you can open a separate terminal and run
|
||||
the subset of the test suite that can be mapped to it:
|
||||
|
||||
- **Avoid CLI scipting & scraping**. Reliably interacting with a DUT
|
||||
over a serial line in a robust way is _very_ hard to get right.
|
||||
Given that we have a proper API (RESTCONF), we should leverage that
|
||||
when testing. Front-ends can be tested by other means.
|
||||
|
||||
|
||||
Architectural Overview
|
||||
----------------------
|
||||
|
||||

|
||||
|
||||
The test system is made up of several independent components, which
|
||||
are typically used in concert to run a full test suite.
|
||||
|
||||
### Test Cases
|
||||
|
||||
A test case is an executable, receiving the physical topology as a
|
||||
positional argument, which produces [TAP][] compliant output on its
|
||||
`stdout`. I.e., it is executed in the following manner:
|
||||
|
||||
test-case [OPTS] <physical-topology>
|
||||
|
||||
Test cases are typically written in Python, using the
|
||||
[Infamy](#infamy) library. Ultimately though, it can be implemented
|
||||
in any language, as long as it matches the calling convention above.
|
||||
|
||||
### Infamy
|
||||
|
||||
Rather than having each test case come up with its own implementation
|
||||
of how to map topologies, how to push NETCONF data to a device, etc.,
|
||||
we provide a library of functions to take care of all that, dubbed
|
||||
"Infamy". When adding a new test case, ask yourself if any parts of
|
||||
it might belong in Infamy as a generalized component that can be
|
||||
reused by other tests.
|
||||
|
||||
Some of the core functions provided by Infamy are:
|
||||
|
||||
- Mapping a logical topology to a physical one
|
||||
- Finding and attaching to a device over an Ethernet interface, using
|
||||
NETCONF
|
||||
- Pushing/pulling NETCONF data to/from a device
|
||||
- Generating TAP compliant output
|
||||
|
||||
### 9PM
|
||||
|
||||
To run multiple tests, we employ [9PM][]. It let's us define test
|
||||
suites as simple YAML files. Suites can also be hierarchically
|
||||
structured, with a suite being made up of other suites, etc.
|
||||
|
||||
It also validates the TAP output, making sure to catch early exits
|
||||
from a case, and produces a nice summary report.
|
||||
|
||||
### `/test/env`
|
||||
|
||||
A good way to ensure that nobody ever runs the test suite is to make
|
||||
it _really_ hard to do so. `/test/env`'s job is instead to make it
|
||||
very _easy_ to create a reproducible environment in which tests can be
|
||||
executed.
|
||||
|
||||
Several technologies are leveraged to accomplish this:
|
||||
|
||||
- **Containers**: The entire execution is optionally done inside a
|
||||
standardized container environment, using either `podman` or
|
||||
`docker`. This ensures that the software needed to run the test
|
||||
suite is always available, no matter which distribution the user is
|
||||
running on their machine.
|
||||
|
||||
- **Python Virtual Environments**: To make sure that the expected
|
||||
versions of all Python packages are available, the execution is
|
||||
wrapped inside a `venv`. This is true for containerized executions,
|
||||
where the container comes with a pre-installed environment, but it
|
||||
can also be sourced from the host system when running outside of the
|
||||
container.
|
||||
|
||||
- **Virtual Test Topology**: Using [Qeneth][], the environment can
|
||||
optionally be started with a virtual topology of DUTs to run the
|
||||
tests on.
|
||||
$ make TEST_MODE=run test
|
||||
|
||||
|
||||
Interactive Usage
|
||||
-----------------
|
||||
|
||||
Some tests only require a single DUT. These can therefore be run
|
||||
against an Infix image started from `make run`. When the instance is
|
||||
running, you can open a separate terminal and run `make test-run`, to
|
||||
run the subset of the test suite that can be mapped to it.
|
||||
|
||||
Both `make test` and `make test-run` targets have a respective target
|
||||
with a `-sh` suffix. These can be used to start an interactive session
|
||||
in the reproducible environment, which is usually much easier to work
|
||||
with during a debugging session.
|
||||
|
||||
Inside the reproducible environment, a wrapper for Qeneth is created for
|
||||
the running network's directory. E.g., calling `qeneth status` inside a
|
||||
`make test-sh` environment show the expected status information.
|
||||
|
||||
> **Note:** for more information and help writing a test, see the below
|
||||
> [Quick Start Guide][].
|
||||
|
||||
|
||||
Physical and Logical Topologies
|
||||
-------------------------------
|
||||
|
||||
Imagine that we want to create a test with three DUTs; one acting as a
|
||||
DHCP server, and the other two as DHCP clients - with all three having
|
||||
a management connection to the host PC running the test. In other
|
||||
words, the test requires a _logical_ topology like the one below.
|
||||
|
||||
<img align="right" src="img/testing-log.dot.svg" alt="Example Logical Topology">
|
||||
|
||||
```dot
|
||||
graph "dhcp-client-server" {
|
||||
host [
|
||||
label="host | { <c1> c1 | <srv> srv | <c2> c2 }",
|
||||
kind="controller",
|
||||
];
|
||||
|
||||
server [
|
||||
label="{ <mgmt> mgmt } | server | { <c1> c1 | <c2> c2 }",
|
||||
kind="infix",
|
||||
];
|
||||
client1 [
|
||||
label="{ <mgmt> mgmt } | client1 | { <srv> srv }",
|
||||
kind="infix",
|
||||
];
|
||||
client2 [
|
||||
label="{ <mgmt> mgmt } | client2 | { <srv> srv }",
|
||||
kind="infix",
|
||||
];
|
||||
|
||||
host:srv -- server:mgmt
|
||||
host:c1 -- client1:mgmt
|
||||
host:c2 -- client2:mgmt
|
||||
|
||||
server:c1 -- client1:srv;
|
||||
server:c2 -- client2:srv;
|
||||
}
|
||||
```
|
||||
|
||||
When running in a virtualized environment, one could simply create a
|
||||
setup that matches the test's logical topology. But in scenarios when
|
||||
devices are physical systems, connected by real copper cables, this is
|
||||
not possible (unless you have some wicked L1 relay matrix thingy).
|
||||
|
||||
Instead, the test implementation does not concern itself with the
|
||||
exact nodes used to run the test, only that the _logical_ topology can
|
||||
be _mapped_ to some subset of the _physical_ topology. In
|
||||
mathematical terms, the physical topology must contain a subgraph that
|
||||
is _isomorphic_ to the logical topology.
|
||||
|
||||
Standing on the shoulders of giants (i.e. people with mathematics
|
||||
degrees), we can deploy well-known algorithms to find such subgraphs.
|
||||
Continuing our example, let's say we want to run our DHCP test on the
|
||||
_physical_ topology below.
|
||||
|
||||
<img align="right" src="img/testing-phy.dot.svg" alt="Example Physical Topology">
|
||||
|
||||
```dot
|
||||
graph "quad-ring" {
|
||||
host [
|
||||
label="host | { <d1a> d1a | <d1b> d1b | <d1c> d1c | <d2a> d2a | <d2b> d2b | <d2c> d2c | <d3a> d3a | <d3b> d3b | <d3c> d3c | <d4a> d4a | <d4b> d4b | <d4c> d4c }",
|
||||
kind="controller",
|
||||
];
|
||||
|
||||
dut1 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut1 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
dut2 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut2 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
dut3 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut3 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
dut4 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut4 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
|
||||
host:d1a -- dut1:e1
|
||||
host:d1b -- dut1:e2
|
||||
host:d1c -- dut1:e3
|
||||
|
||||
host:d2a -- dut2:e1
|
||||
host:d2b -- dut2:e2
|
||||
host:d2c -- dut2:e3
|
||||
|
||||
host:d3a -- dut3:e1
|
||||
host:d3b -- dut3:e2
|
||||
host:d3c -- dut3:e3
|
||||
|
||||
host:d4a -- dut4:e1
|
||||
host:d4b -- dut4:e2
|
||||
host:d4c -- dut4:e3
|
||||
|
||||
dut1:e5 -- dut2:e4
|
||||
dut2:e5 -- dut3:e4
|
||||
dut3:e5 -- dut4:e4
|
||||
dut4:e5 -- dut1:e4
|
||||
}
|
||||
```
|
||||
|
||||
Our test (in fact, all tests) receives the physical topology as an
|
||||
input parameter, and then maps the desired logical topology onto it,
|
||||
producing a mapping from logical nodes and ports to their physical
|
||||
counterparts.
|
||||
|
||||
```dot
|
||||
{
|
||||
"client1": "dut1",
|
||||
"client1:mgmt": "dut1:e1",
|
||||
"client1:srv": "dut1:e4",
|
||||
"client2": "dut3",
|
||||
"client2:mgmt": "dut3:e2",
|
||||
"client2:srv": "dut3:e5",
|
||||
"host": "host",
|
||||
"host:c1": "host:d1a",
|
||||
"host:c2": "host:d3b",
|
||||
"host:srv": "host:d4c",
|
||||
"server": "dut4",
|
||||
"server:c1": "dut4:e5",
|
||||
"server:c2": "dut4:e4",
|
||||
"server:mgmt": "dut4:e3"
|
||||
}
|
||||
```
|
||||
|
||||
With this information, the test knows that, in this particular
|
||||
environment, the server should be managed via the port called `d4c` on
|
||||
the node called `host`; that the port connected to the server on
|
||||
`client1` is `e4` on `dut1`, etc. Thereby separating the
|
||||
implementation of the test from any specific physical setup.
|
||||
|
||||
Testcases are not required to use a logical topology; they may choose
|
||||
to accept whatever physical topology its given, and dynamically
|
||||
determine the DUTs to use for testing. As an example, an STP test
|
||||
could accept an arbitrary physical topology, run the STP algorithm on
|
||||
it offline, enable STP on all DUTs, and then verify that the resulting
|
||||
spanning tree matches the expected one.
|
||||
|
||||
|
||||
Quick Start Guide
|
||||
-----------------
|
||||
|
||||
When developing a test, instead of blindly coding in Python and running
|
||||
`make test` over and over, start a test shell:
|
||||
When developing and debugging tests, the overhead of repeatedly
|
||||
setting up and tearing down the test environment can quickly start to
|
||||
weigh you down. In these situation, you can start an interactive test
|
||||
environment:
|
||||
|
||||
$ make test-sh
|
||||
Info: Generating topology
|
||||
@@ -299,13 +69,28 @@ When developing a test, instead of blindly coding in Python and running
|
||||
Info: Launching dut4
|
||||
11:42:52 infamy0:test #
|
||||
|
||||
The example above uses the default mode (`qeneth`), but the `host` and
|
||||
`run` modes also support the `test-sh` target.
|
||||
|
||||
It takes a little while to start up, but then we have a shell prompt
|
||||
inside the container running Infamy. It's a very limited environment,
|
||||
but it has enough to easily run single tests, connect to the virtual
|
||||
devices, and *step* your code. Let's run a test:
|
||||
devices, and *step* your code.
|
||||
|
||||
|
||||
### Running Subsets of Tests
|
||||
|
||||
Each test case is a separate executable, which can be run without
|
||||
arguments:
|
||||
|
||||
11:42:53 infamy0:test # ./case/infix_dhcp/dhcp_basic.py
|
||||
|
||||
To run a suite of tests, e.g., only the DHCP client tests, pass the
|
||||
suite as an argument to [9PM][]:
|
||||
|
||||
11:42:53 infamy0:test # ./9pm/9pm.py case/infix_dhcp/all.yaml
|
||||
|
||||
|
||||
### Connecting to Infamy
|
||||
|
||||
The test system runs in a Docker container, so to get a shell prompt in
|
||||
@@ -313,6 +98,7 @@ The test system runs in a Docker container, so to get a shell prompt in
|
||||
with a helper script for this:
|
||||
|
||||
$ ./test/shell
|
||||
11:42:53 infamy0:test #
|
||||
|
||||
By default it connect to the latest started Infamy instance. If you for
|
||||
some reason run multiple instances of Infamy the `shell` script takes an
|
||||
@@ -320,6 +106,8 @@ optional argument "system", which is the hostname of the container you
|
||||
want to connect to:
|
||||
|
||||
$ ./test/shell infamy2
|
||||
11:42:53 infamy2:test #
|
||||
|
||||
|
||||
### Connecting to a DUT
|
||||
|
||||
@@ -331,7 +119,7 @@ there is another helper script in Infamy for this:
|
||||
$ ./test/console 1
|
||||
Trying 127.0.0.1...
|
||||
Connected to 127.0.0.1.
|
||||
|
||||
|
||||
Infix -- a Network Operating System v23.11.0-226-g0c144da (console)
|
||||
infix-00-00-00 login: admin
|
||||
Password:
|
||||
@@ -339,9 +127,9 @@ there is another helper script in Infamy for this:
|
||||
| . . | Infix -- a Network Operating System
|
||||
|-. v .-| https://kernelkit.github.io
|
||||
'-'---'-'
|
||||
|
||||
|
||||
Run the command 'cli' for interactive OAM
|
||||
|
||||
|
||||
admin@infix-00-00-00:~$
|
||||
|
||||
From here we can observe `dut1` freely while running tests.
|
||||
@@ -369,10 +157,47 @@ You can also connect to the console of a DUT from within a `shell`:
|
||||
> the BusyBox version so you press 'e' + enter instead of 'q' to quit.
|
||||
|
||||
|
||||
### Debug a Test
|
||||
### Attaching to MACVLANs
|
||||
|
||||
First, add a Python `breakpoint()` to your test and run it from your
|
||||
`make test-sh` Infamy instance:
|
||||
To fully isolate the host's interfaces from one another, many tests
|
||||
will stack a MACVLAN on an interface, which is then placed in a
|
||||
separate network namespace.
|
||||
|
||||
It is often useful to attach to those namespaces, so that you can
|
||||
interactively inject traffic into the test setup.
|
||||
|
||||
First, connect to the Infamy instance in question:
|
||||
|
||||
$ ./test/shell
|
||||
11:43:19 infamy0:test #
|
||||
|
||||
Then, attach to the MACVLAN namespace by running the `nsenter` helper
|
||||
script from the test directory, supplying the base interface name as
|
||||
the first argument:
|
||||
|
||||
11:43:19 infamy0:test # ./nsenter d1b
|
||||
11:43:20 infamy0(d1b):test #
|
||||
|
||||
By default, an interactive shell is started, but you can also supply
|
||||
another command:
|
||||
|
||||
11:43:19 infamy0:test # ./nsenter d1b ip -br addr
|
||||
lo UNKNOWN 127.0.0.1/8 ::1/128
|
||||
iface@if7 UP 10.0.0.1/24 fe80::38d0:88ff:fe77:b7cd/64
|
||||
|
||||
You can now freely debug the network activity of your test and the
|
||||
responses from the DUT.
|
||||
|
||||
|
||||
### Using the Python Debugger
|
||||
|
||||
The built in `breakpoint()` function in Python is very useful when you
|
||||
want to run a test case to a certain point at which you might want to
|
||||
interactively inspect either the test's or the device's state.
|
||||
|
||||
Simply insert a call to `breakpoint()` at the point of interest in
|
||||
your test and run it as normal. Once Python executes the call, it will
|
||||
drop you into the Python debugger:
|
||||
|
||||
11:42:58 infamy0:test # ./case/infix_dhcp/dhcp_basic.py
|
||||
# Starting (2024-02-10 11:42:59)
|
||||
@@ -382,32 +207,15 @@ First, add a Python `breakpoint()` to your test and run it from your
|
||||
> /home/jocke/src/infix/test/case/infix_dhcp/dhcp_basic.py(44)<module>()
|
||||
(Pdb)
|
||||
|
||||
You are now in the Python debugger, Pdb.
|
||||
At this point you have full access to the test's state, but it is also
|
||||
an opportunity to inspect the state of the DUTs (e.g. via their
|
||||
console or over SSH).
|
||||
|
||||
### Debug a Test in a MacVLAN
|
||||
It is also possible to run a test under Pdb from the get-go, if you
|
||||
want to setup breakpoints without modifying the source, or simply step
|
||||
through the code:
|
||||
|
||||
Most tests use some sort of network connection to the DUTs. From a test
|
||||
shell you cannot see or debug that connection by default. So you need
|
||||
to employ a little trick.
|
||||
|
||||
Open another terminal, and start a test shell in your Infamy instance:
|
||||
|
||||
$ ./test/shell
|
||||
11:43:19 infamy0:test #
|
||||
|
||||
MacVLAN interfaces created by Infamy run in another network namespace,
|
||||
to enter it we can look for a sleeper process:
|
||||
|
||||
11:43:20 infamy0:test # nsenter -n U -t $(pidof sleep infinity)
|
||||
|
||||
You are now one step further down:
|
||||
|
||||
infamy0:/home/jocke/src/infix/test# ip -br a
|
||||
lo UNKNOWN 127.0.0.1/8 ::1/128
|
||||
iface@if7 UP 10.0.0.1/24 fe80::38d0:88ff:fe77:b7cd/64
|
||||
|
||||
You can now freely debug the network activity of your test and the
|
||||
responses from the DUT.
|
||||
11:42:58 infamy0:test # python -m pdb case/infix_dhcp/dhcp_basic.py
|
||||
|
||||
|
||||
### Deterministic Topology Mappings
|
||||
@@ -448,7 +256,13 @@ the whole suite) with identical topology mappings:
|
||||
|
||||
$ make PYTHONHASHSEED=3773822171 INFIX_TESTS=case/ietf_system/hostname.py test
|
||||
|
||||
### Determinstic use of communication protocol (NETCONF/RESTCONF)
|
||||
|
||||
By default the protocol will be chosen randomly. If you supply a
|
||||
`PYTHONHASHSEED` as described above, you will get the same protocol
|
||||
chosen. If you want to choose the communcation protocol:
|
||||
|
||||
$ make INFAMY_EXTRA_ARGS="--transport=restconf" INFIX_TESTS=case/ietf_system/hostname.py test
|
||||
|
||||
[9PM]: https://github.com/rical/9pm
|
||||
[Qeneth]: https://github.com/wkz/qeneth
|
||||
[TAP]: https://testanything.org/
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
menu "Packages"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/confd/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/curios-httpd/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/execd/Config.in"
|
||||
@@ -21,6 +22,13 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/mcd/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/mdns-alias/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/netbrowse/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/podman/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/python-libyang/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/python-statd/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/python-yangdoc/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/skeleton-init-finit/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/tetris/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/libyang-cpp/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/sysrepo-cpp/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/rousette/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/nghttp2-asio/Config.in"
|
||||
endmenu
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
menu "Host utilities"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/python-libyang/Config.in.host"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/python-yangdoc/Config.in.host"
|
||||
endmenu
|
||||
+35
-1
@@ -1,6 +1,5 @@
|
||||
config BR2_PACKAGE_CONFD
|
||||
bool "confd"
|
||||
select BR2_PACKAGE_AUGEAS
|
||||
select BR2_PACKAGE_JANSSON
|
||||
select BR2_PACKAGE_LIBITE
|
||||
select BR2_PACKAGE_NETOPEER2
|
||||
@@ -12,3 +11,38 @@ config BR2_PACKAGE_CONFD
|
||||
either the on-system CLI or using NETCONF.
|
||||
|
||||
https://github.com/kernelkit/infix
|
||||
|
||||
if BR2_PACKAGE_CONFD
|
||||
|
||||
choice
|
||||
prompt "Default password crypt"
|
||||
default BR2_PACKAGE_CONFD_YESCRYPT
|
||||
help
|
||||
When users set $0$cleartext-password as their password confd
|
||||
salts and encrypts the "cleartext-password" with this selected
|
||||
hash algorithm.
|
||||
|
||||
Infix defaults to yescrypt.
|
||||
|
||||
config BR2_PACKAGE_CONFD_MD5CRYPT
|
||||
bool "md5crypt"
|
||||
|
||||
config BR2_PACKAGE_CONFD_SHA256CRYPT
|
||||
bool "sha256crypt"
|
||||
|
||||
config BR2_PACKAGE_CONFD_SHA512CRYPT
|
||||
bool "sha512crypt"
|
||||
|
||||
config BR2_PACKAGE_CONFD_YESCRYPT
|
||||
bool "yescrypt"
|
||||
|
||||
endchoice
|
||||
|
||||
config BR2_PACKAGE_CONFD_DEFAULT_CRYPT
|
||||
string
|
||||
default "md5crypt" if BR2_PACKAGE_CONFD_MD5CRYPT
|
||||
default "sha256crypt" if BR2_PACKAGE_CONFD_SHA256CRYPT
|
||||
default "sha512crypt" if BR2_PACKAGE_CONFD_SHA512CRYPT
|
||||
default "yescrypt" if BR2_PACKAGE_CONFD_YESCRYPT
|
||||
|
||||
endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#set DEBUG=1
|
||||
|
||||
run name:bootstrap log:prio:user.notice norestart <pid/syslogd> \
|
||||
run name:bootstrap log:prio:user.notice norestart <usr/ixinit-done> \
|
||||
[S] /usr/libexec/confd/bootstrap \
|
||||
-- Bootstrapping YANG datastore
|
||||
|
||||
|
||||
+39
-3
@@ -4,17 +4,19 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
|
||||
CONFD_VERSION = 1.0
|
||||
CONFD_SITE_METHOD = local
|
||||
CONFD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/confd
|
||||
CONFD_LICENSE = BSD-3-Clause
|
||||
CONFD_LICENSE_FILES = LICENSE
|
||||
CONFD_REDISTRIBUTE = NO
|
||||
CONFD_DEPENDENCIES = augeas jansson libite sysrepo libsrx libglib2
|
||||
CONFD_DEPENDENCIES = host-sysrepo sysrepo netopeer2 jansson libite sysrepo libsrx libglib2
|
||||
CONFD_AUTORECONF = YES
|
||||
CONFD_CONF_OPTS += --disable-silent-rules --with-crypt=$(BR2_PACKAGE_CONFD_DEFAULT_CRYPT)
|
||||
CONFD_SYSREPO_SHM_PREFIX = sr_buildroot$(subst /,_,$(CONFIG_DIR))_confd
|
||||
|
||||
define CONFD_CONF_ENV
|
||||
CFLAGS="$(INFIX_CFLAGS)"
|
||||
CFLAGS="$(INFIX_CFLAGS)"
|
||||
endef
|
||||
|
||||
ifeq ($(BR2_PACKAGE_PODMAN),y)
|
||||
@@ -30,6 +32,40 @@ define CONFD_INSTALL_EXTRA
|
||||
mkdir -p $(TARGET_DIR)/etc/avahi/services
|
||||
cp $(CONFD_PKGDIR)/avahi.service $(TARGET_DIR)/etc/avahi/services/netconf.service
|
||||
endef
|
||||
|
||||
COMMON_SYSREPO_ENV = \
|
||||
SYSREPO_SHM_PREFIX=$(CONFD_SYSREPO_SHM_PREFIX) \
|
||||
SYSREPOCTL_EXECUTABLE="$(HOST_DIR)/bin/sysrepoctl" \
|
||||
SYSREPOCFG_EXECUTABLE="$(HOST_DIR)/bin/sysrepocfg" \
|
||||
SEARCH_PATH="$(TARGET_DIR)/usr/share/yang/modules/confd/"
|
||||
|
||||
define CONFD_INSTALL_YANG_MODULES
|
||||
$(COMMON_SYSREPO_ENV) \
|
||||
$(BR2_EXTERNAL_INFIX_PATH)/utils/sysrepo-load-modules.sh $(@D)/yang/confd.inc
|
||||
endef
|
||||
|
||||
ifeq ($(BR2_PACKAGE_PODMAN),y)
|
||||
define CONFD_INSTALL_YANG_MODULES_CONTAINERS
|
||||
$(COMMON_SYSREPO_ENV) \
|
||||
$(BR2_EXTERNAL_INFIX_PATH)/utils/sysrepo-load-modules.sh $(@D)/yang/containers.inc
|
||||
endef
|
||||
endif
|
||||
|
||||
define CONFD_PERMISSIONS
|
||||
/etc/sysrepo/data/ r 660 root wheel - - - - -
|
||||
/etc/sysrepo/data d 770 root wheel - - - - -
|
||||
endef
|
||||
|
||||
define CONFD_CLEANUP
|
||||
rm -f /dev/shm/$(CONFD_SYSREPO_SHM_PREFIX)*
|
||||
endef
|
||||
|
||||
CONFD_PRE_INSTALL_TARGET_HOOKS += CONFD_CLEANUP
|
||||
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_EXTRA
|
||||
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES
|
||||
ifeq ($(BR2_PACKAGE_PODMAN),y)
|
||||
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES_CONTAINERS
|
||||
endif
|
||||
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_CLEANUP
|
||||
|
||||
$(eval $(autotools-package))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Locally computed
|
||||
sha256 ab15fd526bd8dd18a9e77ebc139656bf4d33e97fc7238cd11bf60e2b9b8666c6 COPYING
|
||||
sha256 b47eac9c7a6a25e0e38e8c993b862b88322ddfb226dba59674ee1c37f9ea4749 curios-httpd-oci-arm64-v24.03.0.tar.gz
|
||||
sha256 36bf6b27b54b1bccc68fd6156f6d6bb3b7e7851df90d56c614b1e4e056e170d9 curios-httpd-oci-amd64-v24.03.0.tar.gz
|
||||
sha256 988a523bf4be543cb4ea1d3472ce4720e0b92511546817028b90150a3f054e9f curios-httpd-oci-arm64-v24.05.0.tar.gz
|
||||
sha256 25f94a7c44cdbbceca3f89382b8bea0dcd8d178032c97a9113bb69bbc1770528 curios-httpd-oci-amd64-v24.05.0.tar.gz
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
CURIOS_HTTPD_VERSION = v24.03.0
|
||||
CURIOS_HTTPD_VERSION = v24.05.0
|
||||
CURIOS_HTTPD_SOURCE = curios-httpd-oci-$(GO_GOARCH)-$(CURIOS_HTTPD_VERSION).tar.gz
|
||||
CURIOS_HTTPD_SITE = https://github.com/kernelkit/curiOS/releases/download/$(CURIOS_HTTPD_VERSION)
|
||||
CURIOS_HTTPD_LICENSE = GPL
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
From 13b107b7b15e6d4823627ea4707a12108fd5a1c7 Mon Sep 17 00:00:00 2001
|
||||
From: Joachim Wiberg <troglobit@gmail.com>
|
||||
Date: Fri, 21 Jun 2024 10:24:35 +0200
|
||||
Subject: [PATCH] Fix #407: extend initctl poll timeout
|
||||
|
||||
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
|
||||
---
|
||||
src/client.c | 6 ++++--
|
||||
2 files changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/client.c b/src/client.c
|
||||
index c3fd3aef..a8c06ac4 100644
|
||||
--- a/src/client.c
|
||||
+++ b/src/client.c
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "client.h"
|
||||
#include "log.h"
|
||||
|
||||
+#define REQUEST_TIMEOUT 15000
|
||||
+
|
||||
static int sd = -1;
|
||||
|
||||
int client_connect(void)
|
||||
@@ -85,7 +87,7 @@ int client_request(struct init_request *rq, ssize_t len)
|
||||
|
||||
pfd.fd = sd;
|
||||
pfd.events = POLLOUT;
|
||||
- if (poll(&pfd, 1, 2000) <= 0) {
|
||||
+ if (poll(&pfd, 1, REQUEST_TIMEOUT) <= 0) {
|
||||
warn("Timed out waiting for Finit, errno %d", errno);
|
||||
return -1;
|
||||
}
|
||||
@@ -107,7 +109,7 @@ int client_request(struct init_request *rq, ssize_t len)
|
||||
|
||||
pfd.fd = sd;
|
||||
pfd.events = POLLIN | POLLERR | POLLHUP;
|
||||
- if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
||||
+ if ((rc = poll(&pfd, 1, REQUEST_TIMEOUT)) <= 0) {
|
||||
if (rc) {
|
||||
if (errno == EINTR) /* shutdown/reboot */
|
||||
return -1;
|
||||
@@ -0,0 +1,64 @@
|
||||
From ab62b5282b0461b14464a4a5de49f3b1fa0604fe Mon Sep 17 00:00:00 2001
|
||||
From: Joachim Wiberg <troglobit@gmail.com>
|
||||
Date: Sat, 25 May 2024 19:33:21 +0200
|
||||
Subject: [PATCH 12/12] runparts: add -b (batch) mode for syslog output
|
||||
Organization: Addiva Elektronik
|
||||
|
||||
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
|
||||
---
|
||||
src/runparts.c | 24 ++++++++++++++++++------
|
||||
1 file changed, 18 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/runparts.c b/src/runparts.c
|
||||
index 5af2c2d..c4225ce 100644
|
||||
--- a/src/runparts.c
|
||||
+++ b/src/runparts.c
|
||||
@@ -26,18 +26,27 @@
|
||||
#else
|
||||
#include <sys/prctl.h>
|
||||
|
||||
+const char *active_msg = NULL;
|
||||
+int interactive = 1;
|
||||
int debug;
|
||||
|
||||
static void print_desc(const char *prefix, const char *msg)
|
||||
{
|
||||
- fprintf(stderr, "\e[1m[\e[0m\e[1;33m ⋯ \e[0m\e[1m]\e[0m %s %s", prefix, msg);
|
||||
+ if (interactive)
|
||||
+ fprintf(stderr, "\e[1m[\e[0m\e[1;33m ⋯ \e[0m\e[1m]\e[0m %s %s", prefix, msg);
|
||||
+ else
|
||||
+ fprintf(stderr, "%s %s ...\n", prefix, msg);
|
||||
+ active_msg = msg;
|
||||
}
|
||||
static void print_result(int rc)
|
||||
{
|
||||
- if (rc)
|
||||
- fputs("\r\e[1m[\e[0m\e[1;31mFAIL\e[0m\e[1m]\e[0m\n", stderr);
|
||||
- else
|
||||
- fputs("\r\e[1m[\e[0m\e[1;32m OK \e[0m\e[1m]\e[0m\n", stderr);
|
||||
+ if (interactive) {
|
||||
+ if (rc)
|
||||
+ fputs("\r\e[1m[\e[0m\e[1;31mFAIL\e[0m\e[1m]\e[0m\n", stderr);
|
||||
+ else
|
||||
+ fputs("\r\e[1m[\e[0m\e[1;32m OK \e[0m\e[1m]\e[0m\n", stderr);
|
||||
+ } else
|
||||
+ fprintf(stderr, "[%s] %s\n", rc ? "FAIL" : " OK ", active_msg ?: "");
|
||||
}
|
||||
|
||||
void sig_unblock(void)
|
||||
@@ -193,8 +202,11 @@ int main(int argc, char *argv[])
|
||||
int rc, c, progress = 0, sysv = 0;
|
||||
char *dir;
|
||||
|
||||
- while ((c = getopt(argc, argv, "dh?ps")) != EOF) {
|
||||
+ while ((c = getopt(argc, argv, "bdh?ps")) != EOF) {
|
||||
switch(c) {
|
||||
+ case 'b': /* batch mode */
|
||||
+ interactive = 0;
|
||||
+ break;
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -10,7 +10,7 @@ GENCERT_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/gencert
|
||||
GENCERT_LICENSE = ISC
|
||||
GENCERT_LICENSE_FILES = LICENSE
|
||||
GENCERT_REDISTRIBUTE = NO
|
||||
GENCERT_DEPENDENCIES = openssl
|
||||
GENCERT_DEPENDENCIES = host-pkgconf libopenssl
|
||||
GENCERT_AUTORECONF = YES
|
||||
|
||||
define GENCERT_CONF_ENV
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Locally calculated
|
||||
sha256 9d9d33b873917ca5d0bdcc47a36d2fd385971ab0c045d1472fcadf95ee5bcf5b LICENCE
|
||||
sha256 e18a45b35ade84201d9d59918e0743c0d9b5451cfe89ec1f7f0f6de2dc343a42 klish-plugin-sysrepo-364f7c7b9c61f2cfd51dfd8d94a8c67449ee439f-br1.tar.gz
|
||||
sha256 e8de6e69d930fcab14b45a0a6e9a2c1b63539d64d65f490d9ba071a676179d0d klish-plugin-sysrepo-bc543fb84294ac791f2ee34573dd11be8c2714cc-br1.tar.gz
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
KLISH_PLUGIN_SYSREPO_VERSION = 364f7c7b9c61f2cfd51dfd8d94a8c67449ee439f
|
||||
KLISH_PLUGIN_SYSREPO_VERSION = bc543fb84294ac791f2ee34573dd11be8c2714cc
|
||||
KLISH_PLUGIN_SYSREPO_SITE = https://github.com/kernelkit/klish-plugin-sysrepo.git
|
||||
#KLISH_PLUGIN_SYSREPO_VERSION = cdd3eb51a7f7ee0ed5bd925fa636061d3b1b85fb
|
||||
#KLISH_PLUGIN_SYSREPO_SITE = https://src.libcode.org/pkun/klish-plugin-sysrepo.git
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Locally calculated
|
||||
sha256 9d9d33b873917ca5d0bdcc47a36d2fd385971ab0c045d1472fcadf95ee5bcf5b LICENCE
|
||||
sha256 edb7b9a53d57d87756a99fa25c4af3d6219bed9a863541e672580a2d1f6e7052 klish-b898fdd9a128adaad3a5c92d8dd7baac2085df1b-br1.tar.gz
|
||||
sha256 eca394cd4b0e1d5da583e3dd7f7c7b71350f53c10fe5f208b5d00e34a77ea111 klish-1af2393234d0d73d6cc3bbf2dc028174298f3fec-br1.tar.gz
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
KLISH_VERSION = b898fdd9a128adaad3a5c92d8dd7baac2085df1b
|
||||
KLISH_VERSION = 1af2393234d0d73d6cc3bbf2dc028174298f3fec
|
||||
KLISH_SITE = https://github.com/kernelkit/klish.git
|
||||
#KLISH_VERSION = tags/3.0.0
|
||||
#KLISH_SITE = https://src.libcode.org/pkun/klish.git
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
config BR2_PACKAGE_LIBYANG_CPP
|
||||
bool "libyang-cpp"
|
||||
depends on BR2_USE_MMU
|
||||
select BR2_PACKAGE_LIBYANG
|
||||
help
|
||||
Libyang CPP bindings
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user