├── .github └── workflows │ ├── main.yml │ └── release.yml ├── .gitignore ├── .goreleaser.yml ├── .markdownlint.json ├── .vscode ├── ltex.dictionary.en-US.txt ├── ltex.disabledRules.en-US.txt ├── ltex.hiddenFalsePositives.en-US.txt └── settings.json ├── LICENSE ├── Makefile ├── README.md ├── __init__.py ├── animate.py ├── animation ├── README.md ├── geostationary.toml ├── iridium.toml ├── kuiper.toml ├── oneweb.toml └── starlink.toml ├── builder ├── Dockerfile ├── build-script.sh ├── ceinit ├── fcinit.c ├── inittab ├── interfaces ├── prepare.sh └── run-user-script ├── celestial-make ├── celestial.go ├── celestial.py ├── celestial ├── __init__.py ├── animation.py ├── config.py ├── dot_test.py ├── fw_test.py ├── host.py ├── proto_util.py ├── satgen_connstellation.py ├── serializer.py ├── sgp4_solver.py ├── shell.py ├── types.py └── zip_serializer.py ├── compile.Dockerfile ├── config.toml ├── docs ├── .gitignore ├── 404.html ├── Gemfile ├── Gemfile.lock ├── README.md ├── _config.yml ├── assets │ ├── actual_line.png │ ├── celestial-constellation.gif │ ├── diff_ecdf.png │ ├── expected_line.png │ ├── reachable_actual.png │ ├── reachable_expected.png │ └── results_scatter.png ├── compilation.md ├── configuration.md ├── contributing.md ├── index.md ├── kernel.md ├── limitations.md ├── nestedvirtualization.md ├── output.md ├── quickstart.md ├── runtime │ ├── dns.md │ ├── http.md │ ├── index.md │ ├── networking.md │ └── time.md └── setup.md ├── go.mod ├── go.sum ├── kernel ├── .gitignore ├── Dockerfile ├── Makefile ├── compile.sh ├── config-5.12 ├── config-5.15 └── config.sh ├── pkg ├── dns │ └── dns.go ├── ebpfem │ ├── ebpf │ │ ├── headers │ │ │ ├── helpers.h │ │ │ └── maps.h │ │ └── net.c │ ├── ebpfem.go │ ├── ebpfem_test.go │ ├── edt_x86_bpfel.go │ ├── edt_x86_bpfel.o │ ├── types.go │ └── util.go ├── info │ ├── api.go │ └── info.go ├── netem │ ├── ipnet.go │ ├── ipset.go │ ├── netem.go │ ├── tc.go │ └── tc_test.go ├── orchestrator │ ├── info.go │ ├── network.go │ ├── network_test.go │ ├── orchestrator.go │ ├── types.go │ └── virt.go ├── peer │ └── peer.go ├── server │ └── server.go └── virt │ ├── host.go │ ├── link.go │ ├── machine.go │ ├── net.go │ ├── net_test.go │ ├── peer.go │ ├── types.go │ ├── virt.go │ ├── virt_test.go │ └── vm.go ├── proto └── celestial │ ├── __init__.py │ ├── celestial.pb.go │ ├── celestial.proto │ ├── celestial_grpc.pb.go │ ├── celestial_pb2.py │ ├── celestial_pb2.pyi │ ├── celestial_pb2_grpc.py │ └── celestial_pb2_grpc.pyi ├── quick-start ├── .gitignore ├── README.md ├── check_validator.py ├── graphs │ ├── actual_line.png │ ├── diff_ecdf.png │ ├── expected_line.png │ ├── reachable_actual.png │ ├── reachable_expected.png │ └── results_scatter.png ├── quickstart.toml ├── requirements.txt ├── tofu │ └── gcloud.tf └── validator │ ├── server.sh │ ├── validator-base.sh │ ├── validator.py │ └── validator.sh ├── requirements-animation.txt ├── requirements.txt ├── satgen.Dockerfile ├── satgen.py ├── setup.cfg └── test ├── integration ├── .gitignore ├── .terraform.lock.hcl ├── celestial_test.go ├── dependencies.sh ├── fileslist.txt ├── google.auto.tfvars ├── infrastructure.tf ├── integration.sh ├── make_key.sh └── rootfs │ ├── .gitignore │ ├── Makefile │ ├── ssh-base.sh │ └── ssh.sh ├── microvm ├── .gitignore ├── .terraform.lock.hcl ├── dependencies.sh ├── fileslist.txt ├── google.auto.tfvars ├── infrastructure.tf ├── make_key.sh ├── microvm.sh ├── rootfs │ ├── .gitignore │ ├── Makefile │ ├── ssh-base.sh │ └── ssh.sh └── run_microvm.sh └── system ├── .gitignore ├── .terraform.lock.hcl ├── Makefile ├── analyze.py ├── app ├── .gitignore ├── validator-base.sh ├── validator.py └── validator.sh ├── build.sh ├── cleanresults.py ├── config.toml ├── dependencies.sh ├── fileslist.txt ├── getresults.sh ├── google.auto.tfvars ├── infrastructure.tf ├── output ├── ecdf-inv.png ├── ecdf.png ├── heatmap-inv.png ├── heatmap.png └── lineplot.png ├── prepare.sh ├── results.csv └── test.sh /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | name: Code Quality 19 | 20 | # Controls when the action will run. 21 | on: 22 | # Triggers the workflow on push or pull request events but only for the main branch 23 | push: 24 | branches: [main] 25 | pull_request: 26 | branches: [main] 27 | 28 | # Allows you to run this workflow manually from the Actions tab 29 | workflow_dispatch: 30 | 31 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 32 | jobs: 33 | python: 34 | runs-on: ubuntu-latest 35 | 36 | steps: 37 | - uses: actions/checkout@v4 38 | - name: mypy-check 39 | uses: jpetrucciani/mypy-check@master 40 | with: 41 | requirements: "types-toml numpy types-requests mypy-protobuf" 42 | path: "*.py" 43 | mypy_flags: "--config setup.cfg" 44 | 45 | go: 46 | name: go 47 | runs-on: ubuntu-latest 48 | steps: 49 | - uses: actions/checkout@v4 50 | - uses: actions/setup-go@v5 51 | with: 52 | go-version: '1.22' 53 | cache: false 54 | - name: golangci-lint 55 | uses: golangci/golangci-lint-action@v4 56 | with: 57 | version: latest 58 | args: --out-format=colored-line-number 59 | 60 | markdown: 61 | runs-on: ubuntu-latest 62 | steps: 63 | - uses: actions/checkout@v4 64 | - name: markdownlint-cli 65 | uses: nosborn/github-action-markdown-cli@v3.3.0 66 | with: 67 | files: README.md 68 | config_file: " .markdownlint.json" 69 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | name: goreleaser 19 | 20 | on: 21 | push: 22 | tags: 23 | - "*" 24 | 25 | jobs: 26 | goreleaser: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | with: 32 | fetch-depth: 0 33 | - uses: actions/setup-go@v5 34 | with: 35 | go-version: '1.22' 36 | cache: false 37 | - name: Run GoReleaser 38 | uses: goreleaser/goreleaser-action@v5 39 | with: 40 | version: latest 41 | args: release --clean 42 | env: 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | builds: 19 | - id: "celestial.bin" 20 | main: ./celestial.go 21 | binary: celestial.bin 22 | goos: 23 | - linux 24 | goarch: 25 | - amd64 26 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD013": { 3 | "tables": false 4 | }, 5 | "MD033": false 6 | } -------------------------------------------------------------------------------- /.vscode/ltex.dictionary.en-US.txt: -------------------------------------------------------------------------------- 1 | eBPF 2 | gRPC 3 | microVMs 4 | toolchain 5 | microVM 6 | kbit 7 | OpenTofu 8 | ECDF 9 | -------------------------------------------------------------------------------- /.vscode/ltex.disabledRules.en-US.txt: -------------------------------------------------------------------------------- 1 | UNIT_SPACE 2 | -------------------------------------------------------------------------------- /.vscode/ltex.hiddenFalsePositives.en-US.txt: -------------------------------------------------------------------------------- 1 | {"rule":"COMMA_PARENTHESIS_WHITESPACE","sentence":"^\\Q{: .text-yellow-300 } Disclaimer: Using Google Cloud Platform (or any other cloud service) can incur costs.\\E$"} 2 | {"rule":"COMMA_PARENTHESIS_WHITESPACE","sentence":"^\\Q{: .text-red-200 } Warning: We will be starting a few cloud machines in this tutorial!\\E$"} 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ltex.enabled": [ 3 | "markdown" 4 | ], 5 | "go.toolsEnvVars": { 6 | "GOOS": "linux", 7 | "GOARCH": "amd64" 8 | }, 9 | "mypy.runUsingActiveInterpreter": true 10 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | # For normal use, we recommend running Make commands with the celestial-make 19 | # Docker container, as that has all the right depencies installed. Especially 20 | # cumbersome are gRPC and protobuf, which make breaking changes without a 21 | # proper versioning scheme. Simply replace `make` with `./celestial-make`. 22 | 23 | ARCH=amd64 24 | OS=linux 25 | 26 | PROJECT_NAME := "celestial" 27 | PKG := "github.com/OpenFogStack/$(PROJECT_NAME)" 28 | GO_FILES := $(shell find . -name '*.go' | grep -v _test.go) 29 | 30 | .PHONY: build proto ebpf containers celestial-make satgen-docker rootfsbuilder 31 | 32 | build: celestial.bin 33 | 34 | containers: celestial-make satgen-docker rootfsbuilder 35 | 36 | proto: proto/celestial/celestial.pb.go proto/celestial/celestial_grpc.pb.go proto/celestial/celestial_pb2.py proto/celestial/celestial_pb2.pyi proto/celestial/celestial_pb2_grpc.py proto/celestial/celestial_pb2_grpc.pyi 37 | proto/celestial/celestial.pb.go proto/celestial/celestial_grpc.pb.go proto/celestial/celestial_pb2.py proto/celestial/celestial_pb2.pyi proto/celestial/celestial_pb2_grpc.py proto/celestial/celestial_pb2_grpc.pyi: proto/celestial/celestial.proto proto/celestial/__init__.py ## build proto files 38 | @protoc -I proto/celestial/ celestial.proto --go_out=proto/celestial --go_opt=paths=source_relative --go-grpc_out=proto/celestial --go-grpc_opt=require_unimplemented_servers=false,paths=source_relative 39 | @python3 -m grpc_tools.protoc -I proto/celestial/ --python_out=proto/celestial --grpc_python_out=proto/celestial --mypy_out=proto/celestial celestial.proto --mypy_grpc_out=proto/celestial 40 | 41 | ebpf: pkg/ebpfem/edt_x86_bpfel.go pkg/ebpfem/edt_x86_bpfel.o ## build ebpf files 42 | pkg/ebpfem/edt_x86_bpfel.go pkg/ebpfem/edt_x86_bpfel.o: pkg/ebpfem/ebpfem.go pkg/ebpfem/ebpf/net.c pkg/ebpfem/ebpf/headers/helpers.h pkg/ebpfem/ebpf/headers/maps.h ## build ebpf files 43 | ## apt-get install -y clang gcc-multilib libbpf-dev llvm 44 | @go generate ./pkg/ebpfem 45 | 46 | celestial.bin: go.mod go.sum celestial.go ${GO_FILES} ## build go binary 47 | GOOS=${OS} GOARCH=${ARCH} go build -o celestial.bin . 48 | 49 | celestial-make: compile.Dockerfile ## build the compile container 50 | @docker build --platform ${OS}/${ARCH} -f $< -t $@ . 51 | 52 | satgen-docker: satgen.Dockerfile satgen.py requirements.txt celestial/*.py ## build the satgen container 53 | @docker build -f $< -t $@ . 54 | 55 | rootfsbuilder: builder/build-script.sh builder/Dockerfile builder/fcinit.c builder/inittab builder/interfaces builder/run-user-script builder/prepare.sh builder/ceinit ## build the rootfs builder container 56 | @docker build --platform=linux/amd64 -t $@:latest builder/ 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Celestial 🛰 2 | 3 | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6640549.svg)](https://doi.org/10.5281/zenodo.6640549) 4 | 5 | Celestial is an emulator for the LEO edge. 6 | It supports satellite servers as well as ground stations. 7 | Each node is booted as a microVM. 8 | Celestial scales across as many hosts as you want. 9 | 10 | At any given time, only a subset of given satellite servers are booted, 11 | dependent on your configured bounding box. 12 | 13 | Celestial... 14 | 15 | - ...creates Firecracker microVMs with your custom kernel and filesystem 16 | - ...modifies network connections for a realistic network condition 17 | - ...let's you define a bounding box on earth, so you only need to emulate 18 | satellites that you're actually interested in 19 | - ...creates/suspends microVMs as they move in to/out of your bounding box 20 | - ...has APIs for your satellites to retrieve some meta-information 21 | 22 | Check out [`celestial-videoconferencing-evaluation`](https://github.com/OpenFogStack/celestial-videoconferencing-evaluation) 23 | for an example application on Celestial! 24 | Also check out the [`celestial-buoy-evaluation`](https://github.com/OpenFogStack/celestial-buoy-evaluation) 25 | and the [`celestial-twissandra-evaluation`](https://github.com/OpenFogStack/celestial-twissandra-evaluation). 26 | Even more examples can be found in [the `examples` directory](./examples). 27 | 28 | **A word of caution**: you can technically run the server-side software on any 29 | computer you want, but it requires root access to fiddle with your network settings. 30 | Therefore, we _highly_ encourage you to only run it on dedicated servers. 31 | It's doing its best to clean up everything, but it has to make changes to a lot 32 | of networking settings, so we can't guarantee that it doesn't destroy any of your 33 | other stuff. 34 | 35 | ## Research 36 | 37 | If you use this software in a publication, please cite it as: 38 | 39 | ### Text 40 | 41 | T. Pfandzelter and D. Bermbach, **Celestial: Virtual Software System Testbeds 42 | for the LEO Edge**, 23rd ACM/IFIP International Middleware Conference 43 | (Middleware '22), Quebec City, Canada, 2022, doi: 10.1145/3528535.3531517. 44 | 45 | ### BibTeX 46 | 47 | ```bibtex 48 | @inproceedings{pfandzelter2022celestial, 49 | title = "Celestial: Virtual Software System Testbeds for the LEO Edge", 50 | booktitle = "23rd ACM/IFIP International Middleware Conference (Middleware '22)", 51 | author = "Pfandzelter, Tobias and Bermbach, David", 52 | year = 2022 53 | } 54 | ``` 55 | 56 | A full list of our [publications](https://www.tu.berlin/en/mcc/research/publications/) 57 | and [prototypes](https://www.tu.berlin/en/mcc/research/prototypes/) 58 | is available on our group website. 59 | 60 | ## License 61 | 62 | The code in this repository is licensed under the terms of the [GPLv3](./LICENSE) 63 | license. 64 | 65 | ## Documentation 66 | 67 | The complete documentation can be found at [`openfogstack.github.io/celestial`](https://openfogstack.github.io/celestial) 68 | or in the `docs` directory. 69 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | -------------------------------------------------------------------------------- /animate.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | """ 19 | If you want to animate a constellation instead of running a full emulation, 20 | you can use this file. It takes a Celestial configuration file and starts a 21 | VTK-based animation of the constellation. You can use the animation to 22 | visualize the constellation and its satellites. 23 | 24 | Note that this will not generate a .zip file that can be used for emulation. 25 | 26 | Prequisites 27 | ----------- 28 | 29 | Make sure you have all the necessary dependencies installed. You can install 30 | them using pip in a virtual environment: 31 | 32 | python3 -m venv .venv 33 | source .venv/bin/activate 34 | pip install -r requirements.txt 35 | pip install -r requirements-animation.txt 36 | 37 | Usage 38 | ----- 39 | 40 | python3 animate.py [config.toml] 41 | 42 | Note that the animation will start in a new window and may require re-sizing. 43 | To stop the animation, send a SIGTERM or SIGINT to the original process. 44 | Closing the animation window will not stop the animation process properly 45 | (a weird behavior of VTK). 46 | """ 47 | 48 | import time 49 | import toml 50 | import sys 51 | import multiprocessing as mp 52 | 53 | import celestial.config 54 | import celestial.animation 55 | 56 | if __name__ == "__main__": 57 | if len(sys.argv) > 3 or len(sys.argv) < 2: 58 | exit("Usage: python3 animate.py [config.toml]") 59 | 60 | # read toml 61 | try: 62 | text_config = toml.load(sys.argv[1]) 63 | except Exception as e: 64 | exit(str(e)) 65 | 66 | output_file = None 67 | if len(sys.argv) == 3: 68 | output_file = sys.argv[2] 69 | 70 | # read the configuration 71 | config: celestial.config.Config = celestial.config.Config(text_config) 72 | 73 | animation_conn, animation_constellation_conn = mp.Pipe() 74 | 75 | animation = mp.Process( 76 | target=celestial.animation.Animation, 77 | kwargs={ 78 | "animation_conn": animation_conn, 79 | }, 80 | ) 81 | 82 | animation.start() 83 | 84 | # init the constellation 85 | constellation = celestial.animation.AnimationConstellation( 86 | config, animation_constellation_conn 87 | ) 88 | 89 | # run the simulation 90 | i = 0 + config.offset 91 | start_time = time.perf_counter() 92 | 93 | while i < config.duration + config.offset: 94 | print(f"step {i}") 95 | constellation.step(i) 96 | i += config.resolution 97 | 98 | while time.perf_counter() - start_time < i - config.offset: 99 | time.sleep(0.001) 100 | 101 | animation.join() 102 | 103 | print("Done!") 104 | -------------------------------------------------------------------------------- /animation/README.md: -------------------------------------------------------------------------------- 1 | # Animation Only 2 | 3 | If you would like to animate a satellite constellation, use the `animate.py` 4 | program in the root of the repository: 5 | 6 | ```sh 7 | python3 animate.py ./path/to/configuration.toml 8 | ``` 9 | 10 | ![Constellation Animation](../docs/assets/celestial-constellation.gif) 11 | 12 | In the [`animation`](./animation) directory, you can find multiple example 13 | configuration files. 14 | 15 | `starlink.toml` has all parameters for the complete Starlink constellation, so 16 | use that to animate that constellation: 17 | 18 | ```sh 19 | # in /celestial root directory 20 | python3 animate.py ./animation/starlink.toml 21 | ``` 22 | 23 | `geostationary.toml` has a single geostationary satellite in orbit 24 | around earth. 25 | -------------------------------------------------------------------------------- /animation/geostationary.toml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | bbox = [-90.0, -180.0, 90.0, 180.0] 19 | resolution = 1 20 | duration = 86400 21 | 22 | [network_params] 23 | bandwidth_kbits = 10_000_000 24 | min_elevation = 25 25 | ground_station_connection_type = "all" 26 | 27 | [compute_params] 28 | vcpu_count = 1 29 | mem_size_mib = 512 30 | disk_size_mib = 10 31 | kernel = "x.bin" 32 | rootfs = "x.img" 33 | 34 | [[shell]] 35 | planes = 1 36 | sats = 1 37 | altitude_km = 35000 38 | inclination = 0.0 39 | arc_of_ascending_nodes = 360.0 40 | eccentricity = 0.0 41 | 42 | [[ground_station]] 43 | name = "TUBerlin" 44 | lat = 52.51499 45 | long = 13.32674 46 | -------------------------------------------------------------------------------- /animation/iridium.toml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | bbox = [-90.0, -180.0, 90.0, 180.0] 19 | resolution = 1 20 | duration = 86400 21 | 22 | [network_params] 23 | bandwidth_kbits = 10_000_000 24 | min_elevation = 25 25 | ground_station_connection_type = "all" 26 | 27 | [compute_params] 28 | vcpu_count = 1 29 | mem_size_mib = 512 30 | disk_size_mib = 10 31 | kernel = "x.bin" 32 | rootfs = "x.img" 33 | 34 | [[shell]] 35 | planes = 6 36 | sats = 11 37 | altitude_km = 780 38 | inclination = 90.0 39 | arc_of_ascending_nodes = 180.0 40 | eccentricity = 0.0 41 | 42 | [[ground_station]] 43 | name = "TUBerlin" 44 | lat = 52.51499 45 | long = 13.32674 46 | -------------------------------------------------------------------------------- /animation/kuiper.toml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | bbox = [-90.0, -180.0, 90.0, 180.0] 19 | resolution = 1 20 | duration = 86400 21 | 22 | [network_params] 23 | bandwidth_kbits = 10_000_000 24 | min_elevation = 40 25 | ground_station_connection_type = "all" 26 | 27 | [compute_params] 28 | vcpu_count = 1 29 | mem_size_mib = 512 30 | disk_size_mib = 10 31 | kernel = "x.bin" 32 | rootfs = "x.img" 33 | 34 | [[shell]] 35 | planes = 34 36 | sats = 34 37 | altitude_km = 630 38 | inclination = 51.9 39 | arc_of_ascending_nodes = 360.0 40 | eccentricity = 0.0 41 | 42 | [[shell]] 43 | planes = 36 44 | sats = 36 45 | altitude_km = 610 46 | inclination = 42.0 47 | arc_of_ascending_nodes = 360.0 48 | eccentricity = 0.0 49 | 50 | [[shell]] 51 | planes = 28 52 | sats = 28 53 | altitude_km = 590 54 | inclination = 33.0 55 | arc_of_ascending_nodes = 360.0 56 | eccentricity = 0.0 57 | 58 | [[ground_station]] 59 | name = "TUBerlin" 60 | lat = 52.51499 61 | long = 13.32674 62 | -------------------------------------------------------------------------------- /animation/oneweb.toml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | bbox = [-90.0, -180.0, 90.0, 180.0] 19 | resolution = 1 20 | duration = 86400 21 | 22 | [network_params] 23 | bandwidth_kbits = 10_000_000 24 | min_elevation = 40 25 | ground_station_connection_type = "all" 26 | 27 | [compute_params] 28 | vcpu_count = 1 29 | mem_size_mib = 512 30 | disk_size_mib = 10 31 | kernel = "x.bin" 32 | rootfs = "x.img" 33 | 34 | [[shell]] 35 | planes = 36 36 | sats = 49 37 | altitude_km = 1200 38 | inclination = 87.9 39 | arc_of_ascending_nodes = 360.0 40 | eccentricity = 0.0 41 | 42 | [[shell]] 43 | planes = 32 44 | sats = 72 45 | altitude_km = 1200 46 | inclination = 40.0 47 | arc_of_ascending_nodes = 360.0 48 | eccentricity = 0.0 49 | 50 | [[shell]] 51 | planes = 32 52 | sats = 72 53 | altitude_km = 1200 54 | inclination = 55.0 55 | arc_of_ascending_nodes = 360.0 56 | eccentricity = 0.0 57 | 58 | [[ground_station]] 59 | name = "TUBerlin" 60 | lat = 52.51499 61 | long = 13.32674 62 | -------------------------------------------------------------------------------- /animation/starlink.toml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | bbox = [-90.0, -180.0, 90.0, 180.0] 19 | resolution = 1 20 | duration = 86400 21 | 22 | [network_params] 23 | bandwidth_kbits = 10_000_000 24 | min_elevation = 40 25 | ground_station_connection_type = "all" 26 | 27 | [compute_params] 28 | vcpu_count = 1 29 | mem_size_mib = 512 30 | disk_size_mib = 10 31 | kernel = "x.bin" 32 | rootfs = "x.img" 33 | 34 | # https://en.wikipedia.org/wiki/Starlink 35 | # Last accessed: 2024-01-24 36 | 37 | # Group 1 38 | [[shell]] 39 | planes = 72 40 | sats = 22 41 | altitude_km = 550 42 | inclination = 53.0 43 | arc_of_ascending_nodes = 360.0 44 | eccentricity = 0.0 45 | 46 | # Group 2 47 | [[shell]] 48 | planes = 36 49 | sats = 20 50 | altitude_km = 570 51 | inclination = 70.0 52 | arc_of_ascending_nodes = 360.0 53 | eccentricity = 0.0 54 | 55 | # Group 3 56 | [[shell]] 57 | planes = 6 58 | sats = 58 59 | altitude_km = 560 60 | inclination = 97.6 61 | arc_of_ascending_nodes = 360.0 62 | eccentricity = 0.0 63 | 64 | # Group 4 65 | [[shell]] 66 | planes = 72 67 | sats = 22 68 | altitude_km = 540 69 | inclination = 53.2 70 | arc_of_ascending_nodes = 360.0 71 | eccentricity = 0.0 72 | 73 | # Group 4 74 | [[shell]] 75 | planes = 4 76 | sats = 43 77 | altitude_km = 560 78 | inclination = 97.6 79 | arc_of_ascending_nodes = 360.0 80 | eccentricity = 0.0 81 | 82 | # Group 5 (v2) 83 | [[shell]] 84 | planes = 28 85 | sats = 120 86 | altitude_km = 530 87 | inclination = 43.0 88 | arc_of_ascending_nodes = 360.0 89 | eccentricity = 0.0 90 | 91 | # Group 6 (v2) 92 | [[shell]] 93 | planes = 28 94 | sats = 120 95 | altitude_km = 559 96 | inclination = 43.0 97 | arc_of_ascending_nodes = 360.0 98 | eccentricity = 0.0 99 | 100 | # Group 7 (v2) 101 | [[shell]] 102 | planes = 28 103 | sats = 120 104 | altitude_km = 525 105 | inclination = 53.0 106 | arc_of_ascending_nodes = 360.0 107 | eccentricity = 0.0 108 | 109 | [[shell]] 110 | planes = 28 111 | sats = 120 112 | altitude_km = 535 113 | inclination = 33.0 114 | arc_of_ascending_nodes = 360.0 115 | eccentricity = 0.0 116 | 117 | [[ground_station]] 118 | name = "TUBerlin" 119 | lat = 52.51499 120 | long = 13.32674 121 | -------------------------------------------------------------------------------- /builder/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | FROM debian:sid 19 | 20 | ARG ALPINE_VERSION_MAJOR="3" 21 | ARG ALPINE_VERSION_MINOR="18" 22 | ARG ALPINE_VERSION_PATCH="0" 23 | ARG ALPINE_ARCH="x86_64" 24 | 25 | ARG ALPINE_VERSION="${ALPINE_VERSION_MAJOR}.${ALPINE_VERSION_MINOR}.${ALPINE_VERSION_PATCH}" 26 | 27 | RUN apt update && \ 28 | apt install -y \ 29 | wget \ 30 | squashfs-tools \ 31 | gcc && \ 32 | rm -rf /var/lib/apt/lists/* 33 | 34 | RUN mkdir minirootfs 35 | RUN wget http://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION_MAJOR}.${ALPINE_VERSION_MINOR}/releases/${ALPINE_ARCH}/alpine-minirootfs-${ALPINE_VERSION}-${ALPINE_ARCH}.tar.gz && \ 36 | cd minirootfs && \ 37 | tar xzf ../alpine-minirootfs-${ALPINE_VERSION}-${ALPINE_ARCH}.tar.gz && \ 38 | cd .. && \ 39 | rm alpine-minirootfs-${ALPINE_VERSION}-${ALPINE_ARCH}.tar.gz && \ 40 | mkdir -p ./rootfs && \ 41 | cp -r minirootfs/* ./rootfs/ && \ 42 | rm -rf minirootfs 43 | 44 | # install dependencies in minirootfs 45 | RUN cp /etc/resolv.conf ./rootfs/etc/resolv.conf && \ 46 | chroot ./rootfs/ apk -X "http://dl-5.alpinelinux.org/alpine/v${ALPINE_VERSION_MAJOR}.${ALPINE_VERSION_MINOR}/main" -U --allow-untrusted --root / --initdb add \ 47 | openrc \ 48 | ca-certificates \ 49 | alpine-base \ 50 | util-linux \ 51 | iptables \ 52 | iproute2 \ 53 | strace \ 54 | attr \ 55 | grep \ 56 | chrony 57 | 58 | COPY fcinit.c fcinit.c 59 | RUN gcc -static -O3 -o ./rootfs/sbin/fcinit fcinit.c && \ 60 | rm fcinit.c 61 | 62 | COPY inittab ./rootfs/etc/inittab 63 | COPY interfaces ./rootfs/etc/network/interfaces 64 | COPY run-user-script ./rootfs/sbin/run-user-script 65 | COPY prepare.sh ./rootfs/prepare.sh 66 | COPY ceinit ./rootfs/sbin/ceinit 67 | 68 | COPY build-script.sh /build-script.sh 69 | 70 | ENTRYPOINT ["/bin/sh", "/build-script.sh"] 71 | -------------------------------------------------------------------------------- /builder/build-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | # $1 = filename for your rootfs 21 | 22 | set -ex 23 | 24 | # mount /dev/random and /dev/urandom (needed for some operations, such as git) 25 | mkdir -p ./rootfs/dev 26 | touch ./rootfs/dev/random 27 | mount --rbind /dev/random ./rootfs/dev/random 28 | mount --make-rslave ./rootfs/dev/random 29 | touch ./rootfs/dev/urandom 30 | mount --rbind /dev/urandom ./rootfs/dev/urandom 31 | mount --make-rslave ./rootfs/dev/urandom 32 | 33 | # # copy the necessary files 34 | cp /app.sh ./rootfs/app.sh 35 | 36 | if [ -d "/files" ]; then 37 | cp -rv /files/* ./rootfs/ 38 | fi 39 | 40 | chroot ./rootfs/ /bin/sh /prepare.sh 41 | rm ./rootfs/prepare.sh 42 | 43 | if [ -f "/base.sh" ]; then 44 | cp /base.sh ./rootfs/base.sh 45 | chroot ./rootfs/ /bin/sh base.sh 46 | rm ./rootfs/base.sh 47 | fi 48 | 49 | # these are the mount points we need to create 50 | mkdir -p ./rootfs/overlay/root \ 51 | ./rootfs/overlay/work \ 52 | ./rootfs/mnt \ 53 | ./rootfs/rom 54 | 55 | # now delete the nameserver config again 56 | rm ./rootfs/etc/resolv.conf 57 | ln -s /proc/net/pnp ./rootfs/etc/resolv.conf 58 | # and unmount the devices 59 | umount ./rootfs/dev/random 60 | rm ./rootfs/dev/random 61 | umount ./rootfs/dev/urandom 62 | rm ./rootfs/dev/urandom 63 | 64 | mksquashfs ./rootfs rootfs.img -noappend 65 | 66 | mv rootfs.img /opt/code/"$1" 67 | -------------------------------------------------------------------------------- /builder/ceinit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | # see https://github.com/firecracker-microvm/firecracker/discussions/3061 20 | # in addition to the base file system, here we mount our overlay 21 | # overlay_root is a kernel parameter 22 | # check that $overlay_root is set and /dev/$overlay_root exists 23 | # if not, give an error 24 | 25 | if [ -z "$overlay_root" ] || 26 | [ ! -e "/dev/$overlay_root" ] && [ ! -d "/dev/$overlay_root" ]; then 27 | echo "FATAL: Overlay root given as $overlay_root but /dev/$overlay_root does not exist" 28 | echo "Known devices:" 29 | ls /dev 30 | exit 1 31 | fi 32 | 33 | echo "Initializing overlay root /dev/$overlay_root" 34 | 35 | /bin/mount -t ext4 "/dev/$overlay_root" /overlay 36 | mkdir -p /overlay/root /overlay/work 37 | 38 | /bin/mount \ 39 | -o noatime,lowerdir=/,upperdir=/overlay/root,workdir=/overlay/work \ 40 | -t overlay "overlayfs:/overlay/root" /mnt 41 | 42 | pivot_root /mnt /mnt/rom 43 | 44 | ./sbin/fcinit 45 | 46 | exec /sbin/init 47 | -------------------------------------------------------------------------------- /builder/fcinit.c: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // Init wrapper for boot timing. It points at /sbin/init. 3 | 4 | #include 5 | 6 | #define MAGIC_VALUE_SIGNAL_GUEST_BOOT_COMPLETE 123 7 | 8 | #include 9 | 10 | #define MAGIC_IOPORT_SIGNAL_GUEST_BOOT_COMPLETE 0x03f0 11 | 12 | static __inline void boot_done(void) 13 | { 14 | iopl(3); 15 | outb_p(MAGIC_VALUE_SIGNAL_GUEST_BOOT_COMPLETE, MAGIC_IOPORT_SIGNAL_GUEST_BOOT_COMPLETE); 16 | } 17 | 18 | int main(int argc, char* const argv[]) 19 | { 20 | boot_done(); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /builder/inittab: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | ::sysinit:/sbin/openrc sysinit 19 | ::sysinit:/sbin/openrc boot 20 | ::wait:/sbin/openrc default 21 | 22 | # Set up a couple of getty's 23 | # tty1::respawn:/sbin/getty 38400 tty1 24 | # tty2::respawn:/sbin/getty 38400 tty2 25 | # tty3::respawn:/sbin/getty 38400 tty3 26 | # tty4::respawn:/sbin/getty 38400 tty4 27 | # tty5::respawn:/sbin/getty 38400 tty5 28 | # tty6::respawn:/sbin/getty 38400 tty6 29 | 30 | # Put a getty on the serial port 31 | ttyS0::wait:-/bin/ash /sbin/run-user-script /start.sh 32 | 33 | # Stuff to do for the 3-finger salute 34 | ::ctrlaltdel:/sbin/reboot 35 | 36 | # Stuff to do before rebooting 37 | ::shutdown:/sbin/openrc shutdown 38 | -------------------------------------------------------------------------------- /builder/interfaces: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | auto eth0 19 | iface eth0 inet manual 20 | -------------------------------------------------------------------------------- /builder/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | # link rc services 20 | ln -sf /etc/init.d/devfs /etc/runlevels/boot/devfs 21 | ln -sf /etc/init.d/procfs /etc/runlevels/boot/procfs 22 | ln -sf /etc/init.d/sysfs /etc/runlevels/boot/sysfs 23 | 24 | ln -sf networking /etc/init.d/net.eth0 25 | ln -sf /etc/init.d/networking /etc/runlevels/default/networking 26 | ln -sf /etc/init.d/net.eth0 /etc/runlevels/default/net.eth0 27 | 28 | # disable modules 29 | echo rc_want="!modules">> /etc/rc.conf 30 | # disable fsck 31 | echo rc_need="!fsck">> /etc/rc.conf 32 | 33 | passwd root -d root 34 | exit 35 | -------------------------------------------------------------------------------- /builder/run-user-script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | # if /dev/ptp0 is available, we can use it as a time source 20 | if [ -e /dev/ptp0 ]; then 21 | # setup chrony to use PTP as the time source 22 | echo "refclock PHC /dev/ptp0 poll -2 dpoll -2 offset 0 trust prefer" > /etc/chrony/chrony.conf 23 | echo "Using PTP clock /dev/ptp0 as time source" 24 | else 25 | echo "NOT using PTP clock /dev/ptp0 as time source" 26 | fi 27 | 28 | # start chronyd 29 | rc-service chronyd start 30 | 31 | # clock synchronization 32 | chronyc makestep 33 | sleep 1 34 | chronyc makestep 35 | # chronyc tracking 36 | 37 | # network setup 38 | IP=$(/sbin/ip route | awk '/default/ { print $3 }') 39 | echo "$IP info.celestial" >> /etc/hosts 40 | 41 | echo "Celestial: Starting user script..." 42 | 43 | /bin/sh app.sh 44 | 45 | echo "Celestial: User script finished, shutting down..." 46 | reboot -f # reboot actually shuts down the microVM in Firecracker 47 | -------------------------------------------------------------------------------- /celestial-make: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | make celestial-make 21 | docker run --platform=linux/amd64 --rm -v "$(pwd)":/celestial celestial-make $@ 22 | -------------------------------------------------------------------------------- /celestial/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | import os 19 | import sys 20 | 21 | currentdir = os.path.dirname(os.path.realpath(__file__)) 22 | sys.path.append(currentdir) 23 | -------------------------------------------------------------------------------- /celestial/dot_test.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | import numpy as np 19 | import numba 20 | import time 21 | 22 | 23 | @numba.njit # type: ignore 24 | def dot_product_manual(matrix_3x3: np.ndarray, vector_3x1: np.ndarray) -> np.ndarray: # type: ignore 25 | result = np.zeros((3,), dtype=np.int64) 26 | 27 | for i in range(3): 28 | for j in range(3): 29 | result[i] += matrix_3x3[i, j] * vector_3x1[j] 30 | 31 | return result # type: ignore 32 | 33 | 34 | def dot_product(matrix_3x3: np.ndarray, vector_3x1: np.ndarray) -> np.ndarray: # type: ignore 35 | result = np.dot(matrix_3x3, vector_3x1) 36 | return result # type: ignore 37 | 38 | 39 | if __name__ == "__main__": 40 | # Example usage 41 | matrix_3x3 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) 42 | vector_3x1 = np.array([2, 3, 4]) 43 | 44 | # Explicitly type the input arguments 45 | matrix_3x3 = matrix_3x3.astype(np.int64) 46 | vector_3x1 = vector_3x1.astype(np.int64) 47 | 48 | t1 = time.perf_counter() 49 | result = dot_product(matrix_3x3, vector_3x1) 50 | t2 = time.perf_counter() 51 | print(result) 52 | 53 | # Example usage 54 | matrix_3x3 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) 55 | vector_3x1 = np.array([2, 3, 4]) 56 | 57 | t3 = time.perf_counter() 58 | result_manual = dot_product_manual(matrix_3x3, vector_3x1) 59 | t4 = time.perf_counter() 60 | print(result_manual) 61 | 62 | print(f"dot_product took {t2 - t1} seconds") 63 | print(f"dot_product_manual took {t4 - t3} seconds") 64 | -------------------------------------------------------------------------------- /celestial/host.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | """Adapter for communication with the Celestial hosts over gRPC""" 19 | 20 | import typing 21 | import grpc 22 | import time 23 | import logging 24 | 25 | import proto.celestial.celestial_pb2 26 | import proto.celestial.celestial_pb2_grpc 27 | 28 | 29 | class Host: 30 | """ 31 | Communication link for a Celestial host. 32 | """ 33 | 34 | def __init__(self, num: int, addr: str): 35 | """ 36 | Initialize host communication. 37 | 38 | :param num: The host number. 39 | :param addr: The address of the host. 40 | """ 41 | self.num = num 42 | self.addr = addr 43 | 44 | c = grpc.insecure_channel(self.addr) 45 | self.stub = proto.celestial.celestial_pb2_grpc.CelestialStub(c) 46 | 47 | self.public_key = "" 48 | 49 | def register(self) -> proto.celestial.celestial_pb2.RegisterResponse: 50 | """ 51 | Send a `register` request to the host. 52 | 53 | :return: The response from the host. 54 | """ 55 | try: 56 | request = proto.celestial.celestial_pb2.RegisterRequest(host=self.num) 57 | 58 | response: proto.celestial.celestial_pb2.RegisterResponse = ( 59 | self.stub.Register(request) 60 | ) 61 | 62 | except Exception as e: 63 | logging.error(f"Error registering host {self.num}: {e}") 64 | exit(1) 65 | 66 | # others currently not used 67 | self.peer_public_key = response.peer_public_key 68 | 69 | self.peer_listen_addr = ( 70 | self.addr.split(":")[0] + ":" + response.peer_listen_addr.split(":")[1] 71 | ) 72 | 73 | logging.debug(f"host {self.num} registered") 74 | logging.debug(f"memory: {response.available_ram}") 75 | logging.debug(f"cpu: {response.available_cpus}") 76 | 77 | return response 78 | 79 | def init( 80 | self, 81 | init_request: proto.celestial.celestial_pb2.InitRequest, 82 | ) -> None: 83 | """ 84 | Send an `init` request to the host. 85 | 86 | :param hosts: A list of all hosts in the constellation. 87 | :param machines: A dictionary mapping host numbers to a list of machine ID and machine configuration tuples. 88 | """ 89 | 90 | self.stub.Init(init_request) 91 | 92 | return 93 | 94 | def stop(self) -> None: 95 | """ 96 | Send a `stop` request to the host. 97 | """ 98 | self.stub.Stop(proto.celestial.celestial_pb2.Empty()) 99 | 100 | def update( 101 | self, 102 | update_requests: typing.Iterator[ 103 | proto.celestial.celestial_pb2.StateUpdateRequest 104 | ], 105 | ) -> None: 106 | """ 107 | Send a `update` request to the host. 108 | 109 | :param machine_diff: An iterator of machine ID and machine state tuples. 110 | :param link_diff: An iterator of link tuples. 111 | """ 112 | 113 | t1 = time.perf_counter() 114 | self.stub.Update(update_requests) 115 | t2 = time.perf_counter() 116 | logging.debug(f"update transmission took {t2-t1} seconds") 117 | 118 | return 119 | -------------------------------------------------------------------------------- /celestial/serializer.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | """A protocol for serializers and deserializers""" 19 | 20 | import typing 21 | import celestial.types 22 | 23 | 24 | class Serializer(typing.Protocol): 25 | """ 26 | A serializer takes constellation updates and serializes it into a format 27 | that can be used for emulation. 28 | """ 29 | 30 | def init_machine( 31 | self, 32 | machine: celestial.types.MachineID_dtype, 33 | config: celestial.config.MachineConfig, 34 | ) -> None: 35 | """ 36 | Serialize a machine initialization. 37 | 38 | :param machine: The machine ID of the machine. 39 | :param config: The configuration of the machine. 40 | """ 41 | ... 42 | 43 | def diff_link( 44 | self, 45 | t: celestial.types.timestamp_s, 46 | source: celestial.types.MachineID_dtype, 47 | target: celestial.types.MachineID_dtype, 48 | link: celestial.types.Link_dtype, 49 | ) -> None: 50 | """ 51 | Serialize a link update. 52 | 53 | :param t: The timestamp of the update. 54 | :param source: The source machine of the link. 55 | :param target: The target machine of the link. 56 | :param link: The link. 57 | """ 58 | ... 59 | 60 | def diff_machine( 61 | self, 62 | t: celestial.types.timestamp_s, 63 | machine: celestial.types.MachineID_dtype, 64 | s: celestial.types.VMState, 65 | ) -> None: 66 | """ 67 | Serialize a machine state update. 68 | 69 | :param t: The timestamp of the update. 70 | :param machine: The machine ID of the machine. 71 | :param s: The state of the machine. 72 | """ 73 | ... 74 | 75 | def persist(self) -> None: 76 | """ 77 | Persist the serialized state. Called at the end of the simulation. 78 | """ 79 | ... 80 | 81 | 82 | class Deserializer(typing.Protocol): 83 | """ 84 | Deserializes a serialized state into a constellation update. 85 | """ 86 | 87 | def config(self) -> celestial.config.Config: 88 | """ 89 | Get the configuration of the simulation. 90 | 91 | :return: The configuration of the simulation. 92 | """ 93 | ... 94 | 95 | def init_machine( 96 | self, 97 | ) -> typing.List[ 98 | typing.Tuple[celestial.types.MachineID_dtype, celestial.config.MachineConfig] 99 | ]: 100 | """ 101 | Deserialize the initial machine states. 102 | 103 | :return: A list of machine ID and machine configuration tuples. 104 | """ 105 | ... 106 | 107 | def diff_links( 108 | self, t: celestial.types.timestamp_s 109 | ) -> typing.List[ 110 | typing.Tuple[ 111 | celestial.types.MachineID_dtype, 112 | celestial.types.MachineID_dtype, 113 | celestial.types.Link_dtype, 114 | ] 115 | ]: 116 | """ 117 | Deserialize the link updates. 118 | 119 | :param t: The timestamp of the update. 120 | :return: A list of link updates. 121 | """ 122 | ... 123 | 124 | def diff_machines( 125 | self, t: celestial.types.timestamp_s 126 | ) -> typing.List[ 127 | typing.Tuple[celestial.types.MachineID_dtype, celestial.types.VMState] 128 | ]: 129 | """ 130 | Deserialize the machine state updates. 131 | 132 | :param t: The timestamp of the update. 133 | :return: A list of machine state updates. 134 | """ 135 | ... 136 | -------------------------------------------------------------------------------- /compile.Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | 19 | FROM debian:bookworm@sha256:b16cef8cbcb20935c0f052e37fc3d38dc92bfec0bcfb894c328547f81e932d67 20 | 21 | ARG OS=linux 22 | ARG ARCH=x86_64 23 | ARG GO_ARCH=amd64 24 | ARG LIBPROTOC_VERSION=25.1 25 | ARG GO_VERSION=1.22.1 26 | ARG PROTOC_GEN_GO_VERSION=1.31.0 27 | ARG PROTOC_GEN_GO_GRPC_VERSION=1.3 28 | 29 | RUN apt-get update && apt-get install -y \ 30 | --no-install-recommends \ 31 | --no-install-suggests \ 32 | ca-certificates \ 33 | wget \ 34 | make \ 35 | clang \ 36 | gcc-multilib \ 37 | libbpf-dev \ 38 | llvm \ 39 | build-essential \ 40 | unzip \ 41 | python3 \ 42 | git \ 43 | python3-pip \ 44 | python3-venv && \ 45 | apt-get clean && rm -rf /var/lib/apt/lists/* 46 | 47 | RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v${LIBPROTOC_VERSION}/protoc-${LIBPROTOC_VERSION}-${OS}-${ARCH}.zip && \ 48 | unzip protoc-${LIBPROTOC_VERSION}-${OS}-${ARCH}.zip -d protoc-${LIBPROTOC_VERSION} && \ 49 | mv protoc-${LIBPROTOC_VERSION} /usr/local/protoc && \ 50 | rm protoc-${LIBPROTOC_VERSION}-${OS}-${ARCH}.zip && \ 51 | chmod +x /usr/local/protoc/bin/* && \ 52 | ln -s /usr/local/protoc/bin/protoc /usr/local/bin/protoc 53 | 54 | RUN wget https://go.dev/dl/go${GO_VERSION}.${OS}-${GO_ARCH}.tar.gz && \ 55 | rm -rf /usr/local/go && \ 56 | tar -C /usr/local -xzf go${GO_VERSION}.${OS}-${GO_ARCH}.tar.gz && \ 57 | echo 'export PATH="$PATH:/usr/local/go/bin"' >> /etc/profile && \ 58 | echo 'export PATH="$PATH:/root/go/bin"' >> /etc/profile && \ 59 | echo 'export GOPATH=/root/go' >> /etc/profile && \ 60 | echo 'export GOBIN="/root/go/bin"' >> /etc/profile && \ 61 | rm -rf go${GO_VERSION}.${OS}-${GO_ARCH}.tar.gz 62 | 63 | ENV PATH $PATH:/usr/local/go/bin 64 | ENV PATH $PATH:/root/go/bin 65 | ENV GOPATH /root/go 66 | ENV GOBIN /root/go/bin 67 | 68 | RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v${PROTOC_GEN_GO_VERSION} && \ 69 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v${PROTOC_GEN_GO_GRPC_VERSION} 70 | 71 | RUN python3 -m venv /venv 72 | ENV PATH="/venv/bin:$PATH" 73 | COPY requirements.txt requirements.txt 74 | RUN python3 -m pip install -r requirements.txt -U 75 | 76 | WORKDIR /celestial 77 | 78 | ENTRYPOINT [ "make" ] -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | .jekyll-cache 4 | .jekyll-metadata 5 | vendor 6 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404.html 3 | layout: default 4 | --- 5 | 6 | 19 | 20 |
21 |

404

22 | 23 |

Page not found :(

24 |

The requested page could not be found.

25 |
26 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | # Hello! This is where you manage which Jekyll version is used to run. 3 | # When you want to use a different version, change it below, save the 4 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 5 | # 6 | # bundle exec jekyll serve 7 | # 8 | # This will help ensure the proper Jekyll version is running. 9 | # Happy Jekylling! 10 | # gem "jekyll", "~> 4.2.2" 11 | # This is the default theme for new Jekyll sites. You may change this to anything you like. 12 | #gem "minima", "~> 2.5" 13 | gem "just-the-docs" 14 | 15 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and 16 | # uncomment the line below. To upgrade, run `bundle update github-pages`. 17 | gem "github-pages", "~> 228", group: :jekyll_plugins 18 | 19 | # somehow I need this 20 | gem "webrick" 21 | 22 | # Performance-booster for watching directories on Windows 23 | gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] 24 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Celestial Docs 2 | 3 | These docs are made for GitHub pages using Jekyll and the `just-the-docs` theme. 4 | You need Ruby < v3.3.0 for this to work ([thanks, GitHub!](https://github.com/github/pages-gem/issues/899#issuecomment-1880156387)). 5 | 6 | GitHub recommends `bundler`: 7 | 8 | ```sh 9 | gem install bundler 10 | bundle install 11 | bundle exec jekyll serve 12 | ``` 13 | 14 | You should now be able to view documentation locally at `http://localhost:4000`. 15 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Jekyll! 2 | # 3 | # This config file is meant for settings that affect your whole blog, values 4 | # which you are expected to set up once and rarely edit after that. If you find 5 | # yourself editing this file very often, consider using Jekyll's data files 6 | # feature for the data you need to update frequently. 7 | # 8 | # For technical reasons, this file is *NOT* reloaded automatically when you use 9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process. 10 | # 11 | # If you need help with YAML syntax, here are some quick references for you: 12 | # https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml 13 | # https://learnxinyminutes.com/docs/yaml/ 14 | # 15 | # Site settings 16 | # These are used to personalize your new site. If you look in the HTML files, 17 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. 18 | # You can create any custom variable you would like, and they will be accessible 19 | # in the templates via {{ site.myvariable }}. 20 | 21 | title: Celestial 🛰 22 | description: >- # this means to ignore newlines until "baseurl:" 23 | Celestial is an emulator for the LEO edge. It supports satellite servers as well as ground stations. Each node is booted as a microVM. Celestial scales across as many hosts as you want. 24 | baseurl: "/celestial" # the subpath of your site, e.g. /blog 25 | url: "https://openfogstack.github.io" # the base hostname & protocol for your site, e.g. http://example.com 26 | 27 | # Build settings 28 | remote_theme: just-the-docs/just-the-docs 29 | 30 | aux_links: 31 | "Celestial on GitHub": 32 | - "//github.com/OpenFogStack/celestial" 33 | 34 | footer_content: "Copyright © 2024 Tobias Pfandzelter, The OpenFogStack Team. Licensed under the terms of the GPLv3 license." 35 | 36 | gh_edit_link: true # show or hide edit this page link 37 | gh_edit_link_text: "Edit this page on GitHub" 38 | gh_edit_repository: "https://github.com/OpenFogStack/celestial" # the github URL for your repo 39 | gh_edit_branch: "main" # the branch that your docs is served from 40 | gh_edit_source: docs # the source that your files originate from 41 | gh_edit_view_mode: "tree" # "tree" or "edit" if you want the user to jump into the editor immediately 42 | 43 | # Exclude from processing. 44 | # The following items will not be processed, by default. 45 | # Any item listed under the `exclude:` key here will be automatically added to 46 | # the internal "default list". 47 | # 48 | # Excluded items can be processed by explicitly listing the directories or 49 | # their entries' file path in the `include:` list. 50 | # 51 | # exclude: 52 | # - .sass-cache/ 53 | # - .jekyll-cache/ 54 | # - gemfiles/ 55 | # - Gemfile 56 | # - Gemfile.lock 57 | # - node_modules/ 58 | # - vendor/bundle/ 59 | # - vendor/cache/ 60 | # - vendor/gems/ 61 | # - vendor/ruby/ 62 | -------------------------------------------------------------------------------- /docs/assets/actual_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/actual_line.png -------------------------------------------------------------------------------- /docs/assets/celestial-constellation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/celestial-constellation.gif -------------------------------------------------------------------------------- /docs/assets/diff_ecdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/diff_ecdf.png -------------------------------------------------------------------------------- /docs/assets/expected_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/expected_line.png -------------------------------------------------------------------------------- /docs/assets/reachable_actual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/reachable_actual.png -------------------------------------------------------------------------------- /docs/assets/reachable_expected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/reachable_expected.png -------------------------------------------------------------------------------- /docs/assets/results_scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/results_scatter.png -------------------------------------------------------------------------------- /docs/compilation.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Compilation 4 | nav_order: 4 5 | --- 6 | 7 | ## Compilation 8 | 9 | Compiling the project requires generating protocol buffer files, generating some 10 | Go code for eBPF, and compiling Go code into a static binary. 11 | 12 | We recommend using Docker to compile the project. 13 | 14 | ### Using Docker 15 | 16 | #### Building the Compile Container 17 | 18 | Run `make celestial-make` to build a container that has all the dependencies 19 | needed to compile the project. 20 | 21 | #### Protocol Buffer 22 | 23 | You can use the pre-compiled gRPC/protocol buffer files or compile your own: 24 | 25 | ```sh 26 | # compile all protofiles for python and go 27 | docker run --platform linux/amd64 --rm -v $(pwd):/celestial celestial-make proto 28 | ``` 29 | 30 | #### Go Server 31 | 32 | Compile the host server with: 33 | 34 | ```sh 35 | docker run --platfrom linux/amd64 --rm -v $(pwd):/celestial celestial-make celestial.bin 36 | ``` 37 | 38 | ### Manually 39 | 40 | To manually compile and generate code, install the dependencies found in [`compile.Dockerfile`](https://github.com/OpenFogStack/celestial/blob/compile.Dockerfile). 41 | Then run `make` to compile. 42 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Contributing 4 | nav_order: 2 5 | --- 6 | 7 | ## Contributing 8 | 9 | Feel free to contribute to this project in any way you see fit. 10 | Please note that all contributions must adhere to the terms of the GPLv3 license. 11 | 12 | If you want to contribute code, please open a pull request on this GitHub repository. 13 | Please make sure that your code passes the quality checks. 14 | You can use [`act`](https://github.com/nektos/act) to run GitHub actions locally. 15 | 16 | Most importantly, please check that `mypy` type checking completes without errors. 17 | You can also use the tests in the [`test/`](https://github.com/OpenFogStack/celestial/blob/test) 18 | directory to confirm that there are no regressions. 19 | 20 | We include some tests for host-side code in the [`pkg/`](https://github.com/OpenFogStack/celestial/blob/pkg) 21 | directory as well that can be run with `go test`. 22 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | title: About 4 | nav_order: 1 5 | --- 6 | 7 | ## About 8 | 9 | Celestial is an emulator for the LEO edge. 10 | It supports satellite servers as well as ground stations. 11 | Each node is booted as a microVM. 12 | Celestial scales across as many hosts as you want. 13 | 14 | At any given time, only a subset of given satellite servers are booted, 15 | dependent on your configured bounding box. 16 | 17 | Celestial... 18 | 19 | - ...creates Firecracker microVMs with your custom kernel and filesystem 20 | - ...modifies network connections for a realistic network condition 21 | - ...lets you define a bounding box on earth, so you only need to emulate 22 | satellites that you're actually interested in 23 | - ...creates/suspends microVMs as they move in to/out of your bounding box 24 | - ...has APIs for your satellites to retrieve some meta-information 25 | 26 | Check out [`celestial-videoconferencing-evaluation`](https://github.com/OpenFogStack/celestial-videoconferencing-evaluation) 27 | for an example application on Celestial! 28 | Also check out the [`celestial-buoy-evaluation`](https://github.com/OpenFogStack/celestial-buoy-evaluation) 29 | and the [`celestial-twissandra-evaluation`](https://github.com/OpenFogStack/celestial-twissandra-evaluation). 30 | 31 | **A word of caution**: you can technically run the server-side software on any 32 | computer you want, but it requires root access to fiddle with your network settings. 33 | Therefore, we _highly_ encourage you to only run it on dedicated servers. 34 | It's doing its best to clean up everything, but it has to make changes to a lot 35 | of networking settings, so we can't guarantee that it doesn't destroy any of your 36 | other stuff. 37 | 38 | ### Research 39 | 40 | If you use this software in a publication, please cite it as: 41 | 42 |
43 | T. Pfandzelter and D. Bermbach, **Celestial: Virtual Software System Testbeds 44 | for the LEO Edge**, 23rd ACM/IFIP International Middleware Conference 45 | (Middleware '22), Quebec City, Canada, 2022, doi: 10.1145/3528535.3531517. 46 |
47 | ```bibtex 48 | @inproceedings{pfandzelter2022celestial, 49 | author = "Pfandzelter, Tobias and Bermbach, David", 50 | title = "Celestial: Virtual Software System Testbeds for the LEO Edge", 51 | booktitle = "Proceedings of the 23rd ACM/IFIP International Middleware Conference", 52 | pages = "69--81", 53 | month = nov, 54 | year = 2022, 55 | publisher = "Association for Computing Machinery", 56 | address = "New York, NY, USA", 57 | series = "Middleware '22", 58 | location = "Quebec, QC, Canada", 59 | url = "https://doi.org/10.1145/3528535.3531517", 60 | doi = "10.1145/3528535.3531517" 61 | } 62 | ``` 63 | 64 | A full list of our [publications](https://www.tu.berlin/en/mcc/research/publications/) 65 | and [prototypes](https://www.tu.berlin/en/mcc/research/prototypes/) 66 | is available on our group website. 67 | 68 | ### License 69 | 70 | The code in this repository is licensed under the terms of the [GPLv3](./LICENSE) 71 | license. 72 | 73 | ### Documentation 74 | 75 | The complete documentation can be found at [`openfogstack.github.io/celestial`](https://openfogstack.github.io/celestial) 76 | or in the `docs` directory. 77 | -------------------------------------------------------------------------------- /docs/kernel.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Guest Kernel 4 | nav_order: 8 5 | --- 6 | 7 | 8 | ## Building a Kernel 9 | 10 | Compiling your own Linux is not actually that hard. 11 | You will want to do this if the `hello-world` kernel provided by Firecracker lacks 12 | options you need or if you want to use a newer kernel version. 13 | This documentation is adapted from the [Firecracker developer guide](https://github.com/firecracker-microvm/firecracker/blob/main/docs/rootfs-and-kernel-setup.md). 14 | We recommend using the `v5.12` kernel configuration we provide in the [`./kernel`](https://github.com/OpenFogStack/celestial/blob/kernel/config-5.12) 15 | directory. 16 | 17 | You need three things: 18 | 19 | 1. Kernel sources 20 | 2. A tool chain 21 | 3. A configuration file 22 | 23 | You can get the kernel sources by cloning the Linux repository: 24 | 25 | ```sh 26 | # warning! this is about 3.5GB in size so sit back and wait 27 | git clone https://github.com/torvalds/linux.git linux.git 28 | cd linux.git 29 | 30 | # then checkout the version you want, e.g. v4.19 31 | git checkout v4.19 32 | ``` 33 | 34 | You also need a few things for your tool chain. 35 | The details depend on your distribution, here are the packages needed on Ubuntu 18.04: 36 | 37 | ```sh 38 | sudo apt-get install build-essential linux-source bc kmod cpio flex \ 39 | libncurses5-dev libelf-dev libssl-dev bison -y 40 | ``` 41 | 42 | Finally, your config file is used to configure your kernel. 43 | We recommend our [`./kernel/config-5.12`](https://github.com/OpenFogStack/celestial/blob/kernel/config-5.12) 44 | for the `v5.12` configuration. 45 | You should name your config file `.config` and place it in the `linux.git` folder. 46 | 47 | You can modify this configuration with the `menuconfig` tool: 48 | 49 | ```sh 50 | make menuconfig 51 | ``` 52 | 53 | Save your configuration and build your kernel with: 54 | 55 | ```sh 56 | make vmlinux 57 | ``` 58 | 59 | Pro-tip: use `make vmlinux -j [NO_THREADS]` to multi-thread your compilation. 60 | 61 | This takes a few minutes. 62 | There you go, now you have your `vmlinux` file that you can use as a kernel. 63 | 64 | If you want to use Docker within your microVM, you need to build a kernel that has 65 | support for everything Docker requires. 66 | Check out [this repository](https://github.com/njapke/docker-in-firecracker) for 67 | information on how to do that. 68 | -------------------------------------------------------------------------------- /docs/nestedvirtualization.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Nested Virtualization 4 | nav_order: 9 5 | --- 6 | 7 | ## A Word On Virtualization Capabilities 8 | 9 | To use Firecracker on cloud VMs, those must support what is called _nested virtualization_. 10 | Not all cloud VMs support this, e.g., on AWS EC2 you must use `metal` instances. 11 | 12 | You can read more about this setup [here](https://github.com/firecracker-microvm/firecracker/blob/main/docs/dev-machine-setup.md). 13 | 14 | ### Example: Creating an Ubuntu 22.04 Image in Google Cloud 15 | 16 | This uses the `gcloud` shell: 17 | 18 | ```sh 19 | # set configuration 20 | # use Frankfurt as a region 21 | $ FC_REGION=europe-west3 22 | $ FC_ZONE=europe-west3-c 23 | 24 | $ gcloud config set compute/region ${FC_REGION} 25 | Updated property [compute/region]. 26 | 27 | $ gcloud config set compute/zone ${FC_ZONE} 28 | Updated property [compute/zone]. 29 | 30 | # set a name for the image 31 | $ FC_VDISK=disk-ubnt 32 | $ FC_IMAGE=ubnt-nested-kvm 33 | 34 | # create disk 35 | $ gcloud compute disks create ${FC_VDISK} \ 36 | --image-project ubuntu-os-cloud --image-family ubuntu-2204-lts 37 | Created [https://www.googleapis.com/compute/v1/projects/[PROJECT-ID]/zones/europe-west3-c/disks/disk-ubnt]. 38 | NAME ZONE SIZE_GB TYPE STATUS 39 | disk-ubnt europe-west3-c 10 pd-standard READY 40 | 41 | # create image from disk with associated nested virtualization option 42 | $ gcloud compute images create ${FC_IMAGE} --source-disk ${FC_VDISK} \ 43 | --source-disk-zone ${FC_ZONE} \ 44 | --licenses "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx" 45 | Created [https://www.googleapis.com/compute/v1/projects/[PROJECT-ID]/global/images/ubnt-nested-kvm]. 46 | NAME PROJECT FAMILY DEPRECATED STATUS 47 | ubnt-nested-kvm [PROJECT-ID] READY 48 | ``` 49 | 50 | Once you have done that, start a VM with that image. 51 | Enter it with `ssh` and enable access to `/dev/kvm`, then check that it's working: 52 | 53 | ```sh 54 | $ sudo setfacl -m u:${USER}:rw /dev/kvm 55 | $ [ -r /dev/kvm ] && [ -w /dev/kvm ] && echo "OK" || echo "FAIL" 56 | OK 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/output.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Output 4 | nav_order: 10 5 | --- 6 | 7 | ## Output 8 | 9 | There are different ways to retrieve experiment results from Celestial. 10 | You can also use your own cloud storage or logging database if your host has Internet 11 | access. 12 | 13 | ### `stderr` and `stdout` 14 | 15 | If your machines have terminal devices available (not using the `8250.nr_uarts=0` 16 | boot parameter), your software can write to `stdout` and `stderr`. 17 | The streams of those devices will be forwarded to text files on your host. 18 | You can see the outputs of your machines in the `/celestial/out` folder. 19 | For each machine, there is a `.out` and a `.err` file, that capture `stdout` and 20 | `stderr`, respectively. 21 | 22 | Note that this is not recommended for performance-critical applications as writing 23 | a lot of data to your host disk in this way can be slow. 24 | 25 | ### Retrieving Files from microVM Disks 26 | 27 | If your software manipulates files on your microVM file system, you also have the 28 | option to retrieve those files later. 29 | Celestial creates an overlay file system for each microVM as 30 | `ce[SHELL]-[ID].ext4` for satellites or `ce[NAME].ext4` for ground stations. 31 | Note that if you use multiple hosts, the file system will only be created on the 32 | host that hosts that particular machine. 33 | 34 | You can mount this file system to copy files (either directly on the host or by 35 | downloading a copy of the file system). 36 | For example, to copy a file named `output.csv` from the file system of satellite 37 | 840 in shell 1, do: 38 | 39 | ```sh 40 | # create a temporary mounting point 41 | sudo mkdir -p ./tmp-dir 42 | 43 | # mount the filesystem 44 | sudo mount /celestial/ce1-840.ext4 ./tmp-dir -o loop 45 | 46 | # copy the relevant file to your directory 47 | sudo cp ./tmp-dir/output.csv sat1-840-output.csv 48 | 49 | # unmount the filesystem 50 | sudo umount ./tmp-dir 51 | 52 | # remove the mounting point 53 | sudo rmdir ./tmp-dir 54 | ``` 55 | 56 | We recommend only mounting the file system after its microVM has been shut down to 57 | avert any file system corruption. 58 | Also keep in mind that you must unmount the file system if you want to run Celestial 59 | again as Celestial will try to overwrite this file system with a fresh copy. 60 | -------------------------------------------------------------------------------- /docs/runtime/dns.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: DNS API 4 | nav_order: 4 5 | parent: Runtime 6 | --- 7 | 8 | ## DNS API 9 | 10 | In addition to finding information about itself, a machine can also find the network 11 | address of another machine by querying the provided DNS service. 12 | This service is available at the machine's gateway on port 53 using `systemd-resolved` 13 | on the host. 14 | This is set as the default DNS server in Celestial. 15 | It supports only `A` requests for the custom `.celestial` TLD. 16 | 17 | Records are in the form `[ID].[SHELL].celestial` for satellites and `[NAME].gst.celestial` 18 | for ground stations. 19 | Note that all addresses are resolved if the machine is known, regardless of whether 20 | that machine is active or can be accessed. 21 | 22 | When using our builder, you can also use the hostname `info.celestial` as the address 23 | of the info server, alas the gateway IP for a microVM. 24 | -------------------------------------------------------------------------------- /docs/runtime/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Runtime 4 | nav_order: 11 5 | has_children: True 6 | --- 7 | 8 | Celestial offers multiple advanced runtime features that your applications can 9 | leverage. 10 | These are available within your microVMs. 11 | -------------------------------------------------------------------------------- /docs/runtime/networking.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Networking 4 | nav_order: 1 5 | parent: Runtime 6 | --- 7 | 8 | ## Networking 9 | 10 | In Celestial, all machines are equipped with a virtual network adapter that is 11 | available within the microVM as `eth0`. 12 | Each machine is placed in a dedicated subnet. 13 | Machines that can communicate with each other (these are machines where a network 14 | path exists between their corresponding satellites or ground stations) can find 15 | each other using the DNS service described below. 16 | 17 | All networks are subnets of the `10.0.0.0/8` network. 18 | Networks are calculated as follows: 19 | 20 | 1. Byte is always `10` (0x0A) 21 | 1. Byte is the shell identifier, `0` for ground stations and starting at `1` for 22 | satellite shells 23 | 1. Byte is the satellite's identifier in the shell, shifted right by 6 bits (e.g. 24 | `12` or `0x0C` for satellite `831`) 25 | 1. Byte is the satellite's identifier in the shell, shifted left by 2 bits (e.g. 26 | `252` or `0xFC` for satellite `831`) 27 | 28 | Within this network, the network + 1 is the gateway IP and network + 2 is the microVMs 29 | IP. 30 | The network has a `/30` network mask, hence only those two are available. 31 | 32 | eBPF programs and `tc` are used to modify network latency between microVMs. 33 | WireGuard is used to link machines on different hosts. 34 | -------------------------------------------------------------------------------- /docs/runtime/time.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Time API 4 | nav_order: 2 5 | parent: Runtime 6 | --- 7 | 8 | ## Time 9 | 10 | Since the user provides kernel and root filesystem, all time and clock control is 11 | in their hands. 12 | 13 | If you're running experiments on Celestial you might be interested in an accurate 14 | wall clock in your VMs, e.g. to measure network delays. 15 | There are two ways to configure clock synchronization in your VMs: NTP and PTP. 16 | You can read a bit more about that in [the Firecracker documentation](https://github.com/firecracker-microvm/firecracker/blob/main/FAQ.md#my-guest-wall-clock-is-drifting-how-can-i-fix-it). 17 | 18 | By default, root file systems built with the builder toolchain are set up for PTP. 19 | 20 | ### PTP 21 | 22 | The downside of NTP is that all your machines synchronize with an external time-server. 23 | If you run hundreds of machines, that's quite a bit of network traffic. 24 | 25 | PTP synchronizes your machines with the host's time using cheap para-virtualized 26 | KVM calls. 27 | It's a lot more accurate as well (on one machine - if you run Celestial across 28 | multiple serves, make sure to synchronize those too, and expect some inaccuracies!). 29 | 30 | The downside here is that both hour host and guest must support it. 31 | 32 | On a host side, we have seen that it works with Amazon Linux 2 and 33 | Ubuntu 22.04 LTS, but we weren't able to get it to work with Debian. 34 | There is probably a way to find out if your host supports it, but maybe you just 35 | need to try it out. 36 | For Ubuntu 22.04 LTS, it worked for Amazon Web Services and Google Cloud, but not 37 | on our local machine. 38 | The reason was that the host clock source was `kvm-clock` (nested virtualization) 39 | and not `tsc`. 40 | If starting a microVM gives you the log message `NOT using /dev/ptp0`, `tsc` is 41 | not set as a clock source on your host. 42 | Celestial will try to set this, but it may not work. 43 | 44 | ```sh 45 | # reading current clock source says kvm-clock 46 | $ cat /sys/devices/system/clocksource/clocksource0/current_clocksource 47 | kvm-clock 48 | 49 | # tsc is available 50 | $ cat /sys/devices/system/clocksource/clocksource0/available_clocksource 51 | kvm-clock tsc acpi_pm 52 | 53 | # set tsc as a clock source 54 | $ echo tsc > /sys/devices/system/clocksource/clocksource0/current_clocksource 55 | ``` 56 | 57 | Note that this will change after a reboot. 58 | Making this persist requires changing you kernel parameters. 59 | 60 | On a client side, you need to configure a time synchronization service and have 61 | PTP support enabled in your kernel with these lines in your kernel config: 62 | 63 | ```config 64 | CONFIG_PTP_1588_CLOCK=y 65 | CONFIG_PTP_1588_CLOCK_KVM=y 66 | ``` 67 | 68 | These configuration flags are set accordingly in our [default Linux guest kernel](./kernel.html). 69 | 70 | Once you boot, you should see a `/dev/ptp0` device (if you don't your host probably 71 | doesn't support it). 72 | 73 | You then need to configure that device for your time keeping service, e.g. in `chrony`: 74 | 75 | ```sh 76 | echo "refclock PHC /dev/ptp0 poll 3 dpoll -2 offset 0" > /etc/chrony/chrony.conf 77 | ``` 78 | 79 | You should then restart the `chrony` daemon: 80 | 81 | ```sh 82 | service chronyd restart 83 | ``` 84 | 85 | To force time synchronization in the guest, use: 86 | 87 | ```sh 88 | $ chronyc -a makestep 89 | 200 OK 90 | 91 | $ chronyc tracking 92 | Reference ID : 50484330 (PHC0) 93 | Stratum : 1 94 | Ref time (UTC) : Mon May 10 11:58:30 2021 95 | System time : 0.000000122 seconds fast of NTP time 96 | Last offset : -0.000005912 seconds 97 | RMS offset : 0.000003069 seconds 98 | Frequency : 83.203 ppm slow 99 | Residual freq : -0.177 ppm 100 | Skew : 0.502 ppm 101 | Root delay : 0.000000001 seconds 102 | Root dispersion : 0.000010668 seconds 103 | Update interval : 7.9 seconds 104 | Leap status : Normal 105 | ``` 106 | 107 | This happens before your application script runs in guest root file systems built 108 | with our builder toolchain. 109 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | // 2 | // This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | // Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | // 5 | // This program is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, version 3. 8 | // 9 | // This program is distributed in the hope that it will be useful, but 10 | // WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | // General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | 18 | module github.com/OpenFogStack/celestial 19 | 20 | go 1.21.0 21 | 22 | toolchain go1.22.1 23 | 24 | require ( 25 | github.com/cilium/ebpf v0.15.0 26 | github.com/firecracker-microvm/firecracker-go-sdk v1.0.0 27 | github.com/go-ping/ping v1.1.0 28 | github.com/gorilla/mux v1.8.1 29 | github.com/miekg/dns v1.1.57 30 | github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 31 | github.com/pkg/errors v0.9.1 32 | github.com/sirupsen/logrus v1.9.3 33 | github.com/vishvananda/netlink v1.2.1-beta.2 34 | golang.org/x/sys v0.15.0 35 | golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 36 | google.golang.org/grpc v1.59.0 37 | google.golang.org/protobuf v1.31.0 38 | ) 39 | 40 | require ( 41 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect 42 | github.com/containerd/fifo v1.1.0 // indirect 43 | github.com/containernetworking/cni v1.1.2 // indirect 44 | github.com/containernetworking/plugins v1.3.0 // indirect 45 | github.com/go-logr/logr v1.2.4 // indirect 46 | github.com/go-logr/stdr v1.2.2 // indirect 47 | github.com/go-openapi/analysis v0.21.4 // indirect 48 | github.com/go-openapi/errors v0.20.4 // indirect 49 | github.com/go-openapi/jsonpointer v0.20.0 // indirect 50 | github.com/go-openapi/jsonreference v0.20.2 // indirect 51 | github.com/go-openapi/loads v0.21.2 // indirect 52 | github.com/go-openapi/runtime v0.26.0 // indirect 53 | github.com/go-openapi/spec v0.20.9 // indirect 54 | github.com/go-openapi/strfmt v0.21.7 // indirect 55 | github.com/go-openapi/swag v0.22.4 // indirect 56 | github.com/go-openapi/validate v0.22.1 // indirect 57 | github.com/golang/protobuf v1.5.3 // indirect 58 | github.com/google/uuid v1.3.1 // indirect 59 | github.com/hashicorp/errwrap v1.1.0 // indirect 60 | github.com/hashicorp/go-multierror v1.1.1 // indirect 61 | github.com/josharian/intern v1.0.0 // indirect 62 | github.com/mailru/easyjson v0.7.7 // indirect 63 | github.com/mitchellh/mapstructure v1.5.0 // indirect 64 | github.com/oklog/ulid v1.3.1 // indirect 65 | github.com/opentracing/opentracing-go v1.2.0 // indirect 66 | github.com/vishvananda/netns v0.0.4 // indirect 67 | go.mongodb.org/mongo-driver v1.12.1 // indirect 68 | go.opentelemetry.io/otel v1.19.0 // indirect 69 | go.opentelemetry.io/otel/metric v1.19.0 // indirect 70 | go.opentelemetry.io/otel/trace v1.19.0 // indirect 71 | golang.org/x/crypto v0.14.0 // indirect 72 | golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect 73 | golang.org/x/mod v0.13.0 // indirect 74 | golang.org/x/net v0.17.0 // indirect 75 | golang.org/x/sync v0.4.0 // indirect 76 | golang.org/x/text v0.13.0 // indirect 77 | golang.org/x/tools v0.14.0 // indirect 78 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect 79 | gopkg.in/yaml.v2 v2.4.0 // indirect 80 | gopkg.in/yaml.v3 v3.0.1 // indirect 81 | ) 82 | -------------------------------------------------------------------------------- /kernel/.gitignore: -------------------------------------------------------------------------------- 1 | vmlinux-*.bin -------------------------------------------------------------------------------- /kernel/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | FROM ubuntu:18.04 19 | 20 | RUN apt-get update && \ 21 | apt-get install -y \ 22 | git \ 23 | make \ 24 | build-essential \ 25 | linux-source \ 26 | bc \ 27 | kmod \ 28 | cpio \ 29 | flex \ 30 | libncurses5-dev \ 31 | libelf-dev \ 32 | libssl-dev \ 33 | bison -y && \ 34 | rm -rf /var/lib/apt/lists/* 35 | 36 | ARG KERNEL_VERSION="5.12.0" 37 | 38 | RUN git clone https://github.com/torvalds/linux.git /linux.git --branch v${KERNEL_VERSION} --depth 1 39 | WORKDIR /linux.git 40 | -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | PWD=$(shell pwd) 19 | 20 | .PHONY: all container-% 21 | 22 | all: container-% 23 | 24 | container-%: Dockerfile 25 | @docker build --platform=linux/amd64 --build-arg KERNEL_VERSION=$* -t kernelbuilder:v$* . 26 | 27 | config-%: container-% 28 | @docker run --platform=linux/amd64 -it --rm -v ${PWD}:/input kernelbuilder:v$* /input/config.sh /input $* 29 | 30 | vmlinux-%.bin: container-% config-% 31 | @docker run --platform=linux/amd64 -it --rm -v ${PWD}:/input kernelbuilder:v$* /input/compile.sh /input $* $@ 32 | -------------------------------------------------------------------------------- /kernel/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | INPUT="$1" 6 | KERNEL_VERSION="$2" 7 | OUTPUT="$3" 8 | 9 | # check that $INPUT/config-$KERNEL_VERSION exists 10 | # if not, give an error 11 | if [ ! -f "${INPUT}/config-${KERNEL_VERSION}" ]; then 12 | echo "FATAL: config-${KERNEL_VERSION} does not exist in ${INPUT}" 13 | exit 1 14 | fi 15 | 16 | pushd /linux.git 17 | 18 | # then checkout the version you want, e.g. v4.19 19 | git checkout "v${KERNEL_VERSION}" 20 | 21 | cp "${INPUT}/config-${KERNEL_VERSION}" .config 22 | 23 | make vmlinux -j 24 | 25 | cp vmlinux "${OUTPUT}/vmlinux-${KERNEL-VERSION}.bin" 26 | -------------------------------------------------------------------------------- /kernel/config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | set -ex 20 | 21 | INPUT="$1" 22 | KERNEL_VERSION="$2" 23 | 24 | # check that $INPUT/config-$KERNEL_VERSION exists 25 | # if yes, do not overwrite 26 | if [ -f "${INPUT}/config-${KERNEL_VERSION}" ]; then 27 | echo "config-${KERNEL_VERSION} exists in ${INPUT}, skipping..." 28 | exit 0 29 | fi 30 | 31 | pushd /linux.git 32 | 33 | # then checkout the version you want, e.g. v4.19 34 | git checkout "v${KERNEL_VERSION}" 35 | 36 | make defconfig 37 | 38 | # enable CONFIG_RANDOM_TRUST_CPU 39 | sed -i 's/# CONFIG_RANDOM_TRUST_CPU is not set/CONFIG_RANDOM_TRUST_CPU=y/' .config 40 | 41 | cp .config "${INPUT}/config-${KERNEL_VERSION}" 42 | -------------------------------------------------------------------------------- /pkg/ebpfem/ebpf/headers/helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Soeren Becker, Nils Japke, Tobias Pfandzelter, The 4 | * OpenFogStack Team. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, version 3. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | **/ 18 | 19 | // Source: https://github.com/srnbckr/ebpf-network-emulation/blob/main/cmd/headers/helpers.h 20 | 21 | // hdr_cursor is used to keep track of the current position in data parsing 22 | struct hdr_cursor 23 | { 24 | void *pos; 25 | }; 26 | 27 | // parse_ethhdr parses the ethernet header of a packet, and performs necessary bounds checks. 28 | // returns the next protocol 29 | static __always_inline int parse_ethhdr(struct hdr_cursor *nh, 30 | void *data_end, 31 | struct ethhdr **ethhdr) 32 | { 33 | struct ethhdr *eth = nh->pos; 34 | int hdrsize = sizeof(*eth); 35 | 36 | /* Byte-count bounds check; check if current pointer + size of header 37 | * is after data_end. 38 | */ 39 | if (nh->pos + hdrsize > data_end) 40 | return TC_ACT_SHOT; 41 | 42 | nh->pos += hdrsize; 43 | *ethhdr = eth; 44 | 45 | return eth->h_proto; /* network-byte-order */ 46 | } 47 | 48 | // parse_iphdr parses the IP header of a packet, and performs necessary bounds checks (more complicated due to variable length of IPv4). 49 | // returns the next protocol 50 | static __always_inline int parse_iphdr(struct hdr_cursor *nh, 51 | void *data_end, 52 | struct iphdr **iphdr) 53 | { 54 | struct iphdr *iph = nh->pos; 55 | int hdrsize; 56 | 57 | // ignore compare-distinct-pointer-types warning 58 | #pragma GCC diagnostic push 59 | #pragma GCC diagnostic ignored "-Wcompare-distinct-pointer-types" 60 | if (iph + 1 > data_end) 61 | #pragma GCC diagnostic pop 62 | return TC_ACT_SHOT; 63 | 64 | hdrsize = iph->ihl * 4; 65 | /* Sanity check packet field is valid */ 66 | if (hdrsize < sizeof(*iph)) 67 | return TC_ACT_SHOT; 68 | 69 | /* Variable-length IPv4 header, need to use byte-based arithmetic */ 70 | if (nh->pos + hdrsize > data_end) 71 | return TC_ACT_SHOT; 72 | 73 | nh->pos += hdrsize; 74 | *iphdr = iph; 75 | 76 | return iph->protocol; 77 | } 78 | -------------------------------------------------------------------------------- /pkg/ebpfem/ebpf/headers/maps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Soeren Becker, Nils Japke, Tobias Pfandzelter, The 4 | * OpenFogStack Team. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, version 3. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | **/ 18 | 19 | // Adapted from: https://github.com/srnbckr/ebpf-network-emulation/blob/main/cmd/headers/maps.h 20 | struct handle_kbps_delay 21 | { 22 | __u32 throttle_rate_kbps; 23 | __u32 delay_us; 24 | } HANDLE_KBPS_DELAY; 25 | 26 | struct 27 | { 28 | __uint(type, BPF_MAP_TYPE_HASH); 29 | __type(key, __u32); 30 | __type(value, HANDLE_KBPS_DELAY); 31 | __uint(max_entries, 65535); 32 | } IP_HANDLE_KBPS_DELAY SEC(".maps"); 33 | -------------------------------------------------------------------------------- /pkg/ebpfem/ebpfem_test.go: -------------------------------------------------------------------------------- 1 | //go:build linux && amd64 2 | // +build linux,amd64 3 | 4 | /* 5 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 6 | * Copyright (c) 2024 Soeren Becker, Nils Japke, Tobias Pfandzelter, The 7 | * OpenFogStack Team. 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, version 3. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | **/ 21 | 22 | package ebpfem 23 | 24 | import ( 25 | "fmt" 26 | "net" 27 | "os/exec" 28 | "testing" 29 | 30 | "github.com/pkg/errors" 31 | log "github.com/sirupsen/logrus" 32 | 33 | "github.com/OpenFogStack/celestial/pkg/orchestrator" 34 | ) 35 | 36 | const ( 37 | HOST_IF = "ens4" 38 | ) 39 | 40 | func TestMain(m *testing.M) { 41 | log.SetLevel(log.DebugLevel) 42 | 43 | m.Run() 44 | } 45 | 46 | func TestBasic(t *testing.T) { 47 | id := orchestrator.MachineID{ 48 | Group: 1, 49 | Id: 1, 50 | } 51 | 52 | gateway := net.IPNet{ 53 | IP: net.IPv4(10, 1, 0, 1), 54 | Mask: net.IPv4Mask(255, 255, 255, 252), 55 | } 56 | 57 | tap := "test-1-1" 58 | 59 | e := New() 60 | 61 | // remove old network device (if it exists) 62 | // ip link del [TAP_NAME] 63 | 64 | cmd := exec.Command("ip", "link", "del", tap) 65 | 66 | if _, err := cmd.CombinedOutput(); err != nil { 67 | // ignore 68 | log.Debugf("could not delete tap %s: %s", tap, err) 69 | } 70 | 71 | // iptables -D FORWARD -i [TAP_NAME] -o [HOSTINTERFACE] -j ACCEPT 72 | 73 | cmd = exec.Command("iptables", "-D", "FORWARD", "-i", tap, "-o", HOST_IF, "-j", "ACCEPT") 74 | 75 | if _, err := cmd.CombinedOutput(); err != nil { 76 | // ignore 77 | log.Debugf("could not delete iptables rule: %s", err) 78 | } 79 | 80 | // create a tap device 81 | 82 | // ip tuntap add [TAP_NAME] mode tap 83 | 84 | cmd = exec.Command("ip", "tuntap", "add", tap, "mode", "tap") 85 | 86 | if out, err := cmd.CombinedOutput(); err != nil { 87 | t.Fatalf("%#v: output: %s", cmd.Args, out) 88 | 89 | } 90 | 91 | // set up proxy ARP 92 | // sysctl -w net.ipv4.conf.[TAP_NAME].proxy_arp=1 93 | cmd = exec.Command("sysctl", "-w", fmt.Sprintf("net.ipv4.conf.%s.proxy_arp=1", tap)) 94 | 95 | if out, err := cmd.CombinedOutput(); err != nil { 96 | t.Fatalf("%#v: output: %s", cmd.Args, out) 97 | 98 | } 99 | 100 | // disable ipv6 101 | // sysctl -w net.ipv6.conf.[TAP_NAME].disable_ipv6=1 102 | cmd = exec.Command("sysctl", "-w", fmt.Sprintf("net.ipv6.conf.%s.disable_ipv6=1", tap)) 103 | 104 | if out, err := cmd.CombinedOutput(); err != nil { 105 | t.Fatalf("%#v: output: %s", cmd.Args, out) 106 | 107 | } 108 | 109 | // ip addr add [IP_ADDRESS] dev [TAP_NAME] 110 | 111 | cmd = exec.Command("ip", "addr", "add", gateway.String(), "dev", tap) 112 | 113 | if out, err := cmd.CombinedOutput(); err != nil { 114 | t.Fatalf("%#v: output: %s", cmd.Args, out) 115 | } 116 | 117 | // ip link set [TAP_NAME] up 118 | 119 | cmd = exec.Command("ip", "link", "set", tap, "up") 120 | 121 | if out, err := cmd.CombinedOutput(); err != nil { 122 | t.Fatalf("%#v: output: %s", cmd.Args, out) 123 | 124 | } 125 | 126 | // iptables -A FORWARD -i [TAP_NAME] -o [HOSTINTERFACE] -j ACCEPT 127 | 128 | cmd = exec.Command("iptables", "-A", "FORWARD", "-i", tap, "-o", HOST_IF, "-j", "ACCEPT") 129 | 130 | if out, err := cmd.CombinedOutput(); err != nil { 131 | t.Fatalf("%#v: output: %s", cmd.Args, out) 132 | 133 | } 134 | 135 | log.Tracef("created tap %s", tap) 136 | log.Debug("starting ebpf stuff") 137 | 138 | // create a new machine with ebpfem 139 | err := e.Register(id, tap) 140 | 141 | if err != nil { 142 | t.Fatalf("error registering machine: %s", errors.WithStack(err)) 143 | } 144 | 145 | // try to block a link 146 | target := net.IPNet{ 147 | IP: net.IPv4(10, 1, 0, 4), 148 | Mask: net.IPv4Mask(255, 255, 255, 252), 149 | } 150 | 151 | err = e.SetBandwidth(id, target, 100) 152 | 153 | if err != nil { 154 | t.Fatalf("error setting bandwidth: %s", errors.WithStack(err)) 155 | } 156 | 157 | err = e.SetLatency(id, target, 100) 158 | 159 | if err != nil { 160 | t.Fatalf("error setting latency: %s", errors.WithStack(err)) 161 | } 162 | 163 | err = e.BlockLink(id, target) 164 | 165 | if err != nil { 166 | t.Fatalf("error blocking link: %s", errors.WithStack(err)) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /pkg/ebpfem/edt_x86_bpfel.go: -------------------------------------------------------------------------------- 1 | // Code generated by bpf2go; DO NOT EDIT. 2 | //go:build 386 || amd64 3 | 4 | package ebpfem 5 | 6 | import ( 7 | "bytes" 8 | _ "embed" 9 | "fmt" 10 | "io" 11 | 12 | "github.com/cilium/ebpf" 13 | ) 14 | 15 | type edtHandleKbpsDelay struct { 16 | ThrottleRateKbps uint32 17 | DelayUs uint32 18 | } 19 | 20 | // loadEdt returns the embedded CollectionSpec for edt. 21 | func loadEdt() (*ebpf.CollectionSpec, error) { 22 | reader := bytes.NewReader(_EdtBytes) 23 | spec, err := ebpf.LoadCollectionSpecFromReader(reader) 24 | if err != nil { 25 | return nil, fmt.Errorf("can't load edt: %w", err) 26 | } 27 | 28 | return spec, err 29 | } 30 | 31 | // loadEdtObjects loads edt and converts it into a struct. 32 | // 33 | // The following types are suitable as obj argument: 34 | // 35 | // *edtObjects 36 | // *edtPrograms 37 | // *edtMaps 38 | // 39 | // See ebpf.CollectionSpec.LoadAndAssign documentation for details. 40 | func loadEdtObjects(obj interface{}, opts *ebpf.CollectionOptions) error { 41 | spec, err := loadEdt() 42 | if err != nil { 43 | return err 44 | } 45 | 46 | return spec.LoadAndAssign(obj, opts) 47 | } 48 | 49 | // edtSpecs contains maps and programs before they are loaded into the kernel. 50 | // 51 | // It can be passed ebpf.CollectionSpec.Assign. 52 | type edtSpecs struct { 53 | edtProgramSpecs 54 | edtMapSpecs 55 | } 56 | 57 | // edtSpecs contains programs before they are loaded into the kernel. 58 | // 59 | // It can be passed ebpf.CollectionSpec.Assign. 60 | type edtProgramSpecs struct { 61 | TcMain *ebpf.ProgramSpec `ebpf:"tc_main"` 62 | } 63 | 64 | // edtMapSpecs contains maps before they are loaded into the kernel. 65 | // 66 | // It can be passed ebpf.CollectionSpec.Assign. 67 | type edtMapSpecs struct { 68 | IP_HANDLE_KBPS_DELAY *ebpf.MapSpec `ebpf:"IP_HANDLE_KBPS_DELAY"` 69 | FlowMap *ebpf.MapSpec `ebpf:"flow_map"` 70 | } 71 | 72 | // edtObjects contains all objects after they have been loaded into the kernel. 73 | // 74 | // It can be passed to loadEdtObjects or ebpf.CollectionSpec.LoadAndAssign. 75 | type edtObjects struct { 76 | edtPrograms 77 | edtMaps 78 | } 79 | 80 | func (o *edtObjects) Close() error { 81 | return _EdtClose( 82 | &o.edtPrograms, 83 | &o.edtMaps, 84 | ) 85 | } 86 | 87 | // edtMaps contains all maps after they have been loaded into the kernel. 88 | // 89 | // It can be passed to loadEdtObjects or ebpf.CollectionSpec.LoadAndAssign. 90 | type edtMaps struct { 91 | IP_HANDLE_KBPS_DELAY *ebpf.Map `ebpf:"IP_HANDLE_KBPS_DELAY"` 92 | FlowMap *ebpf.Map `ebpf:"flow_map"` 93 | } 94 | 95 | func (m *edtMaps) Close() error { 96 | return _EdtClose( 97 | m.IP_HANDLE_KBPS_DELAY, 98 | m.FlowMap, 99 | ) 100 | } 101 | 102 | // edtPrograms contains all programs after they have been loaded into the kernel. 103 | // 104 | // It can be passed to loadEdtObjects or ebpf.CollectionSpec.LoadAndAssign. 105 | type edtPrograms struct { 106 | TcMain *ebpf.Program `ebpf:"tc_main"` 107 | } 108 | 109 | func (p *edtPrograms) Close() error { 110 | return _EdtClose( 111 | p.TcMain, 112 | ) 113 | } 114 | 115 | func _EdtClose(closers ...io.Closer) error { 116 | for _, closer := range closers { 117 | if err := closer.Close(); err != nil { 118 | return err 119 | } 120 | } 121 | return nil 122 | } 123 | 124 | // Do not access this directly. 125 | // 126 | //go:embed edt_x86_bpfel.o 127 | var _EdtBytes []byte 128 | -------------------------------------------------------------------------------- /pkg/ebpfem/edt_x86_bpfel.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/pkg/ebpfem/edt_x86_bpfel.o -------------------------------------------------------------------------------- /pkg/ebpfem/types.go: -------------------------------------------------------------------------------- 1 | //go:build linux && amd64 2 | // +build linux,amd64 3 | 4 | /* 5 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 6 | * Copyright (c) 2024 Soeren Becker, Nils Japke, Tobias Pfandzelter, The 7 | * OpenFogStack Team. 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, version 3. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | **/ 21 | 22 | package ebpfem 23 | 24 | import ( 25 | "sync" 26 | 27 | "github.com/OpenFogStack/celestial/pkg/orchestrator" 28 | ) 29 | 30 | const ( 31 | DEFAULT_LATENCY_US = 0 32 | DEFAULT_BANDWIDTH_KBPS = 1_000_000 33 | 34 | BLOCKED_LATENCY_US = 1_000_000_000 35 | BLOCKED_BANDWIDTH_KBPS = 0 36 | ) 37 | 38 | type handleKbpsDelay struct { 39 | throttleRateKbps uint32 40 | delayUs uint32 41 | } 42 | 43 | type vm struct { 44 | netIf string 45 | 46 | // ebpf specific 47 | objs *edtObjects 48 | hbd map[string]*handleKbpsDelay 49 | 50 | sync.Mutex 51 | } 52 | 53 | type EBPFem struct { 54 | vms map[orchestrator.MachineID]*vm 55 | sync.RWMutex 56 | } 57 | -------------------------------------------------------------------------------- /pkg/info/api.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | package info 19 | 20 | type Identifier struct { 21 | Shell uint8 `json:"shell"` 22 | ID uint32 `json:"id"` 23 | Name string `json:"name,omitempty"` 24 | } 25 | 26 | // Node is returned by `/self`, `/gst/{name}` and `/shell/{group}/{id}`. 27 | type Node struct { 28 | Type string `json:"type"` 29 | Active bool `json:"active"` 30 | Identifier Identifier `json:"identifier"` 31 | } 32 | 33 | // Shell is returned by `/shell/{group}`. 34 | type Shell struct { 35 | Sats []Node `json:"sats"` 36 | } 37 | 38 | // Constellation is returned by `/info`. 39 | type Constellation struct { 40 | Shells []Shell `json:"shells"` 41 | Groundstations []Node `json:"groundstations"` 42 | } 43 | 44 | type Segment struct { 45 | Source Identifier `json:"source"` 46 | Target Identifier `json:"target"` 47 | DelayUs uint32 `json:"delay_us,omitempty"` 48 | BandwidthKbps uint64 `json:"bandwidth_kbps,omitempty"` 49 | } 50 | 51 | // Path is returned by `/path/{source_group}/{source_id}/{target_group}/{target_id}`. 52 | type Path struct { 53 | Source Identifier `json:"source"` 54 | Target Identifier `json:"target"` 55 | DelayUs uint32 `json:"delay_us,omitempty"` 56 | BandwidthKbps uint64 `json:"bandwidth_kbits,omitempty"` 57 | Blocked bool `json:"blocked,omitempty"` 58 | Segments []Segment `json:"segments"` 59 | } 60 | -------------------------------------------------------------------------------- /pkg/netem/ipnet.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | package netem 19 | 20 | import "net" 21 | 22 | type ipnet struct { 23 | ipA byte 24 | ipB byte 25 | ipC byte 26 | ipD byte 27 | maskA byte 28 | maskB byte 29 | maskC byte 30 | maskD byte 31 | } 32 | 33 | func (i ipnet) String() string { 34 | n := i.ipnet() 35 | return n.String() 36 | } 37 | 38 | func (i ipnet) ip() net.IP { 39 | return net.IPv4(i.ipA, i.ipB, i.ipC, i.ipD) 40 | } 41 | 42 | func (i ipnet) mask() net.IPMask { 43 | return net.IPv4Mask(i.maskA, i.maskB, i.maskC, i.maskD) 44 | } 45 | 46 | func (i ipnet) ipnet() net.IPNet { 47 | return net.IPNet{ 48 | IP: i.ip(), 49 | Mask: i.mask(), 50 | } 51 | } 52 | 53 | func fromIPNet(n net.IPNet) ipnet { 54 | ip := n.IP.To4() 55 | mask := n.Mask 56 | 57 | return ipnet{ 58 | ipA: ip[0], 59 | ipB: ip[1], 60 | ipC: ip[2], 61 | ipD: ip[3], 62 | maskA: mask[0], 63 | maskB: mask[1], 64 | maskC: mask[2], 65 | maskD: mask[3], 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pkg/netem/tc_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | package netem 19 | 20 | import ( 21 | "net" 22 | "testing" 23 | ) 24 | 25 | func Test_getBaseNet(t *testing.T) { 26 | type args struct { 27 | ipNet net.IPNet 28 | } 29 | tests := []struct { 30 | name string 31 | args args 32 | want *net.IPNet 33 | }{ 34 | { 35 | name: "test1", 36 | args: args{ 37 | ipNet: net.IPNet{ 38 | IP: net.IPv4(10, 1, 0, 0), 39 | Mask: net.IPv4Mask(255, 255, 255, 0), 40 | }, 41 | }, 42 | want: &net.IPNet{ 43 | IP: net.IPv4(10, 1, 0, 0), 44 | Mask: net.IPv4Mask(255, 255, 255, 0), 45 | }, 46 | }, 47 | { 48 | name: "test2", 49 | args: args{ 50 | ipNet: net.IPNet{ 51 | IP: net.IPv4(10, 1, 0, 1), 52 | Mask: net.IPv4Mask(255, 255, 255, 0), 53 | }, 54 | }, 55 | want: &net.IPNet{ 56 | IP: net.IPv4(10, 1, 0, 0), 57 | Mask: net.IPv4Mask(255, 255, 255, 0), 58 | }, 59 | }, 60 | { 61 | name: "test3", 62 | args: args{ 63 | ipNet: net.IPNet{ 64 | IP: net.IPv4(10, 1, 0, 2), 65 | Mask: net.IPv4Mask(255, 255, 255, 0), 66 | }, 67 | }, 68 | want: &net.IPNet{ 69 | IP: net.IPv4(10, 1, 0, 0), 70 | Mask: net.IPv4Mask(255, 255, 255, 0), 71 | }, 72 | }, 73 | { 74 | name: "test4", 75 | args: args{ 76 | ipNet: net.IPNet{ 77 | IP: net.IPv4(10, 1, 0, 3), 78 | Mask: net.IPv4Mask(255, 255, 255, 0), 79 | }, 80 | }, 81 | want: &net.IPNet{ 82 | IP: net.IPv4(10, 1, 0, 0), 83 | Mask: net.IPv4Mask(255, 255, 255, 0), 84 | }, 85 | }, 86 | { 87 | name: "test5", 88 | args: args{ 89 | ipNet: net.IPNet{ 90 | IP: net.IPv4(10, 1, 0, 4), 91 | Mask: net.IPv4Mask(255, 255, 255, 252), 92 | }, 93 | }, 94 | want: &net.IPNet{ 95 | IP: net.IPv4(10, 1, 0, 4), 96 | Mask: net.IPv4Mask(255, 255, 255, 252), 97 | }, 98 | }, 99 | } 100 | for _, tt := range tests { 101 | t.Run(tt.name, func(t *testing.T) { 102 | if got := getBaseNet(tt.args.ipNet); got.String() != tt.want.String() { 103 | t.Errorf("getBaseNet() = %v, want %v", got, tt.want) 104 | } 105 | }) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /pkg/orchestrator/network.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | package orchestrator 19 | 20 | import ( 21 | "fmt" 22 | "sort" 23 | "strings" 24 | 25 | "github.com/pkg/errors" 26 | log "github.com/sirupsen/logrus" 27 | ) 28 | 29 | func (n NetworkState) String() string { 30 | s := make([]string, 0) 31 | 32 | for i := range n { 33 | for j := range n[i] { 34 | s = append(s, fmt.Sprintf("%s -> %s : %s", i.String(), j.String(), n[i][j].String())) 35 | } 36 | } 37 | 38 | // sort 39 | sort.Strings(s) 40 | 41 | return strings.Join(s, "\n") 42 | } 43 | 44 | func (l Link) String() string { 45 | if l.Blocked { 46 | return "blocked" 47 | } 48 | 49 | return fmt.Sprintf("%dus %dkbps (next: %s)", l.LatencyUs, l.BandwidthKbps, l.Next.String()) 50 | } 51 | 52 | func path(a, b MachineID, n NetworkState) (PathInfo, error) { 53 | if a == b { 54 | return PathInfo{}, errors.Errorf("cannot give path from %s to itself", a) 55 | } 56 | 57 | log.Tracef("path from %s to %s", a.String(), b.String()) 58 | 59 | p := PathInfo{ 60 | Source: a, 61 | Target: b, 62 | } 63 | 64 | if n[a][b].Blocked { 65 | log.Tracef("path from %s to %s is blocked", a.String(), b.String()) 66 | p.Blocked = true 67 | return p, nil 68 | } 69 | 70 | p.LatencyUs = n[a][b].LatencyUs 71 | p.BandwidthKbps = n[a][b].BandwidthKbps 72 | p.Segments = make([]SegmentInfo, 0) 73 | 74 | for a != b { 75 | hop := n[a][b] 76 | log.Tracef("next hop from %s to %s: %s", a.String(), b.String(), hop.String()) 77 | 78 | if _, ok := n[a][hop.Next]; !ok { 79 | return PathInfo{}, errors.Errorf("could not find next hop %s for %s", hop.Next.String(), a.String()) 80 | } 81 | 82 | s := SegmentInfo{ 83 | Source: a, 84 | Target: hop.Next, 85 | LatencyUs: n[a][hop.Next].LatencyUs, 86 | BandwidthKbps: n[a][hop.Next].BandwidthKbps, 87 | } 88 | 89 | p.Segments = append(p.Segments, s) 90 | 91 | a = hop.Next 92 | } 93 | 94 | return p, nil 95 | } 96 | -------------------------------------------------------------------------------- /pkg/orchestrator/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | package orchestrator 19 | 20 | import "fmt" 21 | 22 | type MachineState uint8 23 | 24 | const ( 25 | STOPPED MachineState = iota 26 | ACTIVE 27 | ) 28 | 29 | type Link struct { 30 | // Blocked is true if the link is blocked 31 | Blocked bool 32 | // Latency in microseconds 33 | LatencyUs uint32 34 | // Bandwidth in kilobytes per second 35 | BandwidthKbps uint64 36 | 37 | // used for path reconstruction 38 | Next MachineID 39 | } 40 | 41 | type MachineID struct { 42 | // is 0 for ground stations 43 | Group uint8 44 | Id uint32 45 | } 46 | 47 | func (m MachineID) String() string { 48 | return fmt.Sprintf("%d.%d", m.Group, m.Id) 49 | } 50 | 51 | type Host uint8 52 | 53 | type NetworkState map[MachineID]map[MachineID]*Link 54 | 55 | type MachinesState map[MachineID]MachineState 56 | 57 | type State struct { 58 | NetworkState 59 | MachinesState 60 | } 61 | 62 | type ISL struct { 63 | // Latency in microseconds 64 | Latency uint32 65 | // Bandwidth in bytes per second 66 | Bandwidth uint64 67 | } 68 | 69 | type machine struct { 70 | name string 71 | Host Host 72 | config MachineConfig 73 | } 74 | 75 | type MachineConfig struct { 76 | VCPUCount uint8 77 | // RAM in bytes 78 | RAM uint64 79 | // DiskSize in bytes 80 | DiskSize uint64 81 | // DiskImage is the path to the disk image 82 | DiskImage string 83 | // Kernel is the path to the kernel 84 | Kernel string 85 | // BootParams are the additional boot parameters 86 | BootParams []string 87 | } 88 | -------------------------------------------------------------------------------- /pkg/orchestrator/virt.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | package orchestrator 19 | 20 | import "net" 21 | 22 | type VirtualizationBackend interface { 23 | RegisterMachine(machine MachineID, name string, host Host, config MachineConfig) error 24 | BlockLink(source MachineID, target MachineID) error 25 | UnblockLink(source MachineID, target MachineID) error 26 | SetLatency(source MachineID, target MachineID, latency uint32) error 27 | SetBandwidth(source MachineID, target MachineID, bandwidth uint64) error 28 | StopMachine(machine MachineID) error 29 | StartMachine(machine MachineID) error 30 | GetIPAddress(id MachineID) (net.IPNet, error) 31 | ResolveIPAddress(ip net.IP) (MachineID, error) 32 | Stop() error 33 | } 34 | -------------------------------------------------------------------------------- /pkg/virt/link.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | package virt 19 | 20 | import ( 21 | "net" 22 | 23 | "github.com/OpenFogStack/celestial/pkg/orchestrator" 24 | ) 25 | 26 | func (v *Virt) getNetwork(id orchestrator.MachineID) (net.IPNet, error) { 27 | n, err := getNet(id) 28 | if err != nil { 29 | return net.IPNet{}, err 30 | } 31 | 32 | return n.ip, nil 33 | } 34 | 35 | func (v *Virt) setbandwidth(source orchestrator.MachineID, target orchestrator.MachineID, bandwidth uint64) error { 36 | n, err := v.getNetwork(target) 37 | if err != nil { 38 | return err 39 | } 40 | return v.neb.SetBandwidth(source, n, bandwidth) 41 | } 42 | 43 | func (v *Virt) setlatency(source orchestrator.MachineID, target orchestrator.MachineID, latency uint32) error { 44 | n, err := v.getNetwork(target) 45 | if err != nil { 46 | return err 47 | } 48 | return v.neb.SetLatency(source, n, latency) 49 | } 50 | 51 | func (v *Virt) unblocklink(source orchestrator.MachineID, target orchestrator.MachineID) error { 52 | n, err := v.getNetwork(target) 53 | if err != nil { 54 | return err 55 | } 56 | return v.neb.UnblockLink(source, n) 57 | } 58 | func (v *Virt) blocklink(source orchestrator.MachineID, target orchestrator.MachineID) error { 59 | n, err := v.getNetwork(target) 60 | if err != nil { 61 | return err 62 | } 63 | return v.neb.BlockLink(source, n) 64 | } 65 | -------------------------------------------------------------------------------- /pkg/virt/peer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | package virt 19 | 20 | import "github.com/OpenFogStack/celestial/pkg/orchestrator" 21 | 22 | func (v *Virt) route(m *machine, host orchestrator.Host) error { 23 | return v.pb.Route(m.network.network, host) 24 | } 25 | -------------------------------------------------------------------------------- /pkg/virt/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | package virt 19 | 20 | import ( 21 | "net" 22 | "sync" 23 | 24 | "github.com/firecracker-microvm/firecracker-go-sdk" 25 | 26 | "github.com/OpenFogStack/celestial/pkg/orchestrator" 27 | ) 28 | 29 | type state uint8 30 | 31 | const ( 32 | REGISTERED state = iota 33 | STARTED 34 | STOPPED 35 | KILLED 36 | ) 37 | 38 | const HOST_INTERFACE = "ens4" 39 | const GUESTINTERFACE = "eth0" 40 | const ROOTPATH = "/celestial" 41 | const OUTPUTPATH = "/celestial/out" 42 | 43 | var ( 44 | IPTABLES_BIN string 45 | IP_BIN string 46 | SYSCTL_BIN string 47 | DD_BIN string 48 | MKFS_BIN string 49 | ) 50 | 51 | type network struct { 52 | ip net.IPNet 53 | gateway net.IPNet 54 | network net.IPNet 55 | mac net.HardwareAddr 56 | tap string 57 | } 58 | 59 | type machine struct { 60 | name string 61 | 62 | state state 63 | 64 | vcpucount uint8 65 | ram uint64 66 | disksize uint64 67 | diskimage string 68 | kernel string 69 | bootparams []string 70 | 71 | network network 72 | 73 | vm *firecracker.Machine 74 | } 75 | 76 | // Virt provides virtualization functionality using firecracker. 77 | type Virt struct { 78 | hostInterface string 79 | initDelay uint64 // ignored 80 | pb PeeringBackend 81 | neb NetworkEmulationBackend 82 | 83 | machines map[orchestrator.MachineID]*machine 84 | sync.RWMutex 85 | } 86 | 87 | // PeeringBackend is the interface for the peering backend. 88 | type PeeringBackend interface { 89 | GetHostID() (uint8, error) 90 | Route(network net.IPNet, host orchestrator.Host) error 91 | Stop() error 92 | } 93 | 94 | // NetworkEmulationBackend is the interface for the network emulation backend. 95 | type NetworkEmulationBackend interface { 96 | Register(id orchestrator.MachineID, tap string) error 97 | SetBandwidth(source orchestrator.MachineID, target net.IPNet, bandwidth uint64) error 98 | SetLatency(source orchestrator.MachineID, target net.IPNet, latency uint32) error 99 | UnblockLink(source orchestrator.MachineID, target net.IPNet) error 100 | BlockLink(source orchestrator.MachineID, target net.IPNet) error 101 | Stop() error 102 | } 103 | -------------------------------------------------------------------------------- /pkg/virt/vm.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | package virt 19 | 20 | import ( 21 | "context" 22 | 23 | "github.com/pkg/errors" 24 | log "github.com/sirupsen/logrus" 25 | 26 | "github.com/OpenFogStack/celestial/pkg/orchestrator" 27 | ) 28 | 29 | func (v *Virt) transition(id orchestrator.MachineID, state state) error { 30 | v.RLock() 31 | m := v.machines[id] 32 | v.RUnlock() 33 | 34 | if m.state == state { 35 | return nil 36 | } 37 | 38 | switch state { 39 | case STOPPED: 40 | switch m.state { 41 | case STARTED: 42 | err := suspendMachine(m) 43 | if err != nil { 44 | return err 45 | } 46 | m.state = STOPPED 47 | return nil 48 | case REGISTERED: 49 | // not started yet, so nothing to do 50 | // but keep it as registered only, so that it can be started if it ever transitions to STARTED 51 | return nil 52 | default: 53 | log.Tracef("cannot transition %s from %d to %d", id, m.state, state) 54 | } 55 | case STARTED: 56 | switch m.state { 57 | case REGISTERED: 58 | err := startMachine(m) 59 | if err != nil { 60 | return err 61 | } 62 | m.state = STARTED 63 | return nil 64 | 65 | case STOPPED: 66 | err := resumeMachine(m) 67 | if err != nil { 68 | return err 69 | } 70 | m.state = STARTED 71 | return nil 72 | default: 73 | log.Tracef("cannot transition %s from %d to %d", id, m.state, state) 74 | } 75 | case REGISTERED: 76 | return errors.Errorf("cannot transition to REGISTERED") 77 | case KILLED: 78 | switch m.state { 79 | case STARTED: 80 | err := killMachine(m) 81 | if err != nil { 82 | return err 83 | } 84 | return nil 85 | case STOPPED: 86 | err := killMachine(m) 87 | if err != nil { 88 | return err 89 | } 90 | return nil 91 | default: 92 | log.Tracef("cannot transition %s from %d to %d", id, m.state, state) 93 | } 94 | } 95 | return nil 96 | } 97 | 98 | func (v *Virt) register(id orchestrator.MachineID, m *machine, config orchestrator.MachineConfig) error { 99 | 100 | m.state = REGISTERED 101 | m.vcpucount = config.VCPUCount 102 | m.ram = config.RAM 103 | m.disksize = config.DiskSize 104 | m.diskimage = config.DiskImage 105 | m.kernel = config.Kernel 106 | m.bootparams = config.BootParams 107 | 108 | // create the network 109 | 110 | err := m.createNetwork() 111 | 112 | if err != nil { 113 | return err 114 | } 115 | 116 | err = v.neb.Register(id, m.network.tap) 117 | 118 | if err != nil { 119 | return err 120 | } 121 | 122 | return nil 123 | } 124 | 125 | func killMachine(m *machine) error { 126 | log.Trace("Killing machine ", m.name) 127 | 128 | err := m.vm.StopVMM() 129 | 130 | if err != nil { 131 | return err 132 | } 133 | 134 | log.Trace("Killed machine ", m.name) 135 | 136 | return nil 137 | } 138 | 139 | func suspendMachine(m *machine) error { 140 | log.Trace("Suspending machine ", m.name) 141 | return m.vm.PauseVM(context.Background()) 142 | } 143 | 144 | func resumeMachine(m *machine) error { 145 | log.Trace("Resuming machine ", m.name) 146 | return m.vm.ResumeVM(context.Background()) 147 | } 148 | 149 | func startMachine(m *machine) error { 150 | log.Trace("Starting machine ", m.name) 151 | // perform init tasks 152 | err := m.initialize() 153 | 154 | if err != nil { 155 | return err 156 | } 157 | 158 | return m.vm.Start(context.Background()) 159 | } 160 | -------------------------------------------------------------------------------- /proto/celestial/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | import os 19 | import sys 20 | 21 | currentdir = os.path.dirname(os.path.realpath(__file__)) 22 | sys.path.append(currentdir) 23 | -------------------------------------------------------------------------------- /proto/celestial/celestial.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | **/ 17 | 18 | syntax = "proto3"; 19 | 20 | package openfogstack.celestial.celestial; 21 | option go_package = "./;celestial"; 22 | 23 | service Celestial { 24 | rpc Register(RegisterRequest) returns (RegisterResponse); 25 | rpc Init(InitRequest) returns (Empty); 26 | rpc Update(stream StateUpdateRequest) returns (Empty); 27 | rpc Stop(Empty) returns (Empty); 28 | } 29 | 30 | enum VMState { 31 | VM_STATE_STOPPED = 0; 32 | VM_STATE_ACTIVE = 1; 33 | } 34 | 35 | message MachineID { 36 | uint32 group = 1; 37 | uint32 id = 2; 38 | } 39 | 40 | message Empty {} 41 | 42 | message RegisterRequest { 43 | uint32 host = 1; 44 | } 45 | 46 | message RegisterResponse { 47 | uint32 available_cpus = 1; 48 | uint64 available_ram = 2; 49 | string peer_public_key = 3; 50 | string peer_listen_addr = 4; 51 | } 52 | 53 | message InitRequest { 54 | message Host { 55 | uint32 id = 1; 56 | string peer_public_key = 2; 57 | string peer_listen_addr = 3; 58 | } 59 | 60 | repeated Host hosts = 1; 61 | message Machine { 62 | message MachineConfig { 63 | // should also be 8 bit but protobuf doesn't support uint8... 64 | uint32 vcpu_count = 1; 65 | uint64 ram = 2; 66 | uint64 disk_size = 3; 67 | string root_image = 4; 68 | string kernel = 5; 69 | repeated string boot_parameters = 6; 70 | } 71 | 72 | MachineID id = 1; 73 | optional string name = 2; 74 | // should actually be 8 bit but protobuf doesn't support uint8... 75 | uint32 host = 3; 76 | MachineConfig config = 4; 77 | } 78 | 79 | repeated Machine machines = 2; 80 | } 81 | 82 | message StateUpdateRequest { 83 | message MachineDiff { 84 | VMState active = 1; 85 | MachineID id = 2; 86 | } 87 | message NetworkDiff { 88 | bool blocked = 1; 89 | MachineID source = 2; 90 | MachineID target = 3; 91 | uint32 latency_us = 4; 92 | uint64 bandwidth_kbps = 5; 93 | // used for path reconstruction 94 | MachineID next = 6; 95 | MachineID prev = 7; 96 | } 97 | 98 | repeated MachineDiff machine_diffs = 1; 99 | repeated NetworkDiff network_diffs = 2; 100 | } 101 | -------------------------------------------------------------------------------- /proto/celestial/celestial_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | 5 | This file is part of Celestial (https://github.com/OpenFogStack/celestial). 6 | Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, version 3. 11 | 12 | This program is distributed in the hope that it will be useful, but 13 | WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | """ 20 | import abc 21 | import celestial_pb2 22 | import collections.abc 23 | import grpc 24 | import grpc.aio 25 | import typing 26 | 27 | _T = typing.TypeVar('_T') 28 | 29 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): 30 | ... 31 | 32 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore 33 | ... 34 | 35 | class CelestialStub: 36 | def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ... 37 | Register: grpc.UnaryUnaryMultiCallable[ 38 | celestial_pb2.RegisterRequest, 39 | celestial_pb2.RegisterResponse, 40 | ] 41 | Init: grpc.UnaryUnaryMultiCallable[ 42 | celestial_pb2.InitRequest, 43 | celestial_pb2.Empty, 44 | ] 45 | Update: grpc.StreamUnaryMultiCallable[ 46 | celestial_pb2.StateUpdateRequest, 47 | celestial_pb2.Empty, 48 | ] 49 | Stop: grpc.UnaryUnaryMultiCallable[ 50 | celestial_pb2.Empty, 51 | celestial_pb2.Empty, 52 | ] 53 | 54 | class CelestialAsyncStub: 55 | Register: grpc.aio.UnaryUnaryMultiCallable[ 56 | celestial_pb2.RegisterRequest, 57 | celestial_pb2.RegisterResponse, 58 | ] 59 | Init: grpc.aio.UnaryUnaryMultiCallable[ 60 | celestial_pb2.InitRequest, 61 | celestial_pb2.Empty, 62 | ] 63 | Update: grpc.aio.StreamUnaryMultiCallable[ 64 | celestial_pb2.StateUpdateRequest, 65 | celestial_pb2.Empty, 66 | ] 67 | Stop: grpc.aio.UnaryUnaryMultiCallable[ 68 | celestial_pb2.Empty, 69 | celestial_pb2.Empty, 70 | ] 71 | 72 | class CelestialServicer(metaclass=abc.ABCMeta): 73 | @abc.abstractmethod 74 | def Register( 75 | self, 76 | request: celestial_pb2.RegisterRequest, 77 | context: _ServicerContext, 78 | ) -> typing.Union[celestial_pb2.RegisterResponse, collections.abc.Awaitable[celestial_pb2.RegisterResponse]]: ... 79 | @abc.abstractmethod 80 | def Init( 81 | self, 82 | request: celestial_pb2.InitRequest, 83 | context: _ServicerContext, 84 | ) -> typing.Union[celestial_pb2.Empty, collections.abc.Awaitable[celestial_pb2.Empty]]: ... 85 | @abc.abstractmethod 86 | def Update( 87 | self, 88 | request_iterator: _MaybeAsyncIterator[celestial_pb2.StateUpdateRequest], 89 | context: _ServicerContext, 90 | ) -> typing.Union[celestial_pb2.Empty, collections.abc.Awaitable[celestial_pb2.Empty]]: ... 91 | @abc.abstractmethod 92 | def Stop( 93 | self, 94 | request: celestial_pb2.Empty, 95 | context: _ServicerContext, 96 | ) -> typing.Union[celestial_pb2.Empty, collections.abc.Awaitable[celestial_pb2.Empty]]: ... 97 | 98 | def add_CelestialServicer_to_server(servicer: CelestialServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... 99 | -------------------------------------------------------------------------------- /quick-start/.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | *.img 3 | *.bin 4 | *.ext4 5 | -------------------------------------------------------------------------------- /quick-start/README.md: -------------------------------------------------------------------------------- 1 | # Quick Start 2 | 3 | This directory contains a quick start example to help you get into Celestial. 4 | Please refer to our [quick start guide](https://openfogstack.github.io/celestial/quickstart) 5 | to get started. 6 | -------------------------------------------------------------------------------- /quick-start/check_validator.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | import pandas as pd 5 | import matplotlib.pyplot as plt 6 | import seaborn as sns 7 | 8 | GRAPHS_DIR = "./graphs" 9 | NUM_HOSTS = 2 10 | 11 | sns.set(rc={"figure.figsize": (9, 3)}, style="whitegrid") 12 | 13 | 14 | def save_fig(ax: plt.Axes, name: str, file_type: str = "png") -> None: 15 | fig = ax.get_figure() 16 | fig.tight_layout() 17 | file_name = name + "." + file_type 18 | os.makedirs(GRAPHS_DIR, exist_ok=True) 19 | fig.savefig(os.path.join(GRAPHS_DIR, file_name), bbox_inches="tight") 20 | fig.clear() 21 | 22 | 23 | if __name__ == "__main__": 24 | # usage: python3 check_validator.py [results.csv] 25 | if not len(sys.argv) == 2: 26 | exit("Usage: python3 check_validator.py [results.csv]") 27 | 28 | results_file = sys.argv[1] 29 | 30 | # read the data file 31 | validate = pd.read_csv(results_file) 32 | 33 | # convert the "0.0" times to "1e7", i.e., "infinity" 34 | # validate["actual"] = validate["actual"].apply(lambda x: 1e7 if x == 0.0 else x) 35 | 36 | # normalize the start time to 0 37 | start_time = validate["t"].min() 38 | validate["t"] = validate["t"] - start_time 39 | 40 | # we check with the database service before and after the ping 41 | # so our expected value is the average of the two 42 | # BUT the database only gives us one-way latency, while the ping 43 | # service gives us two-way latency 44 | # so we need to double the expected latency as well 45 | validate["expected"] = ( 46 | (validate["expected_before"] + validate["expected_after"]) / 2 47 | ) * 2 48 | 49 | # unless the value is 1e7, in which case the expected value becomes 2e7 50 | validate["expected"] = validate["expected"].apply( 51 | (lambda x: 1e7 if x == 2e7 else x) 52 | ) 53 | 54 | # the difference is the expected value minus the actual measurement 55 | validate["diff"] = abs((validate["expected"]) - validate["actual"]) 56 | 57 | # satellites are distributed across our hosts by modulo 58 | validate["host"] = validate["sat"] % NUM_HOSTS 59 | 60 | # let's give our differences a few limits 61 | # less than three ms difference is still acceptable, anything above 100 is 62 | # considered a problem 63 | # note that 1e7 is a lot above any measurement 64 | validate["OK"] = validate["diff"].apply( 65 | (lambda x: "OK" if abs(x) < 3 else "MEH" if abs(x) < 100 else "NOT OK") 66 | ) 67 | 68 | # let's plot the results and check if there are any problems 69 | results_scatter = sns.scatterplot( 70 | data=validate, x="t", y="diff", hue="OK", style="host" 71 | ) 72 | 73 | save_fig(results_scatter, "results_scatter") 74 | 75 | # let's see the differences we have observed 76 | # 60% are great at 0ms 77 | # 90% are ok below 4ms 78 | diff_ecdf = sns.ecdfplot(data=validate[validate["OK"] != "NOT OK"], x="diff") 79 | save_fig(diff_ecdf, "diff_ecdf") 80 | 81 | # first plot the _expected_ values 82 | expected_line = sns.lineplot(data=validate, x="t", y="expected", hue="sat") 83 | expected_line.set_yscale("log") 84 | save_fig(expected_line, "expected_line") 85 | 86 | # then plot the actual measurements 87 | actual_line = sns.lineplot(data=validate, x="t", y="actual", hue="sat") 88 | actual_line.set_yscale("log") 89 | save_fig(actual_line, "actual_line") 90 | 91 | # let's see only the ones that are not unreachable next 92 | validate_reachable = validate[ 93 | (validate["expected"] < 1e7) & (validate["actual"] < 1e7) 94 | ] 95 | 96 | # first plot the _expected_ values 97 | reachable_expected = sns.lineplot( 98 | data=validate_reachable, x="t", y="expected", hue="sat" 99 | ) 100 | reachable_expected.set_yscale("log") 101 | save_fig(reachable_expected, "reachable_expected") 102 | 103 | # then plot the actual measurements 104 | reachable_actual = sns.lineplot( 105 | data=validate_reachable, x="t", y="actual", hue="sat" 106 | ) 107 | reachable_actual.set_yscale("log") 108 | save_fig(reachable_actual, "reachable_actual") 109 | -------------------------------------------------------------------------------- /quick-start/graphs/actual_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/actual_line.png -------------------------------------------------------------------------------- /quick-start/graphs/diff_ecdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/diff_ecdf.png -------------------------------------------------------------------------------- /quick-start/graphs/expected_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/expected_line.png -------------------------------------------------------------------------------- /quick-start/graphs/reachable_actual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/reachable_actual.png -------------------------------------------------------------------------------- /quick-start/graphs/reachable_expected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/reachable_expected.png -------------------------------------------------------------------------------- /quick-start/graphs/results_scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/results_scatter.png -------------------------------------------------------------------------------- /quick-start/quickstart.toml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | # This is a simple configuration file for Celestial that is used in our 19 | # quick-start guide. 20 | 21 | # Our bounding box determines which satellites will be emulated. We only 22 | # want satellites that are roughly above Europe. 23 | bbox = [35.000000, -15.000000, 65.000000, 35.000000] 24 | 25 | # We want an update to the topology every five second. 26 | resolution = 5 27 | 28 | # Our entire experiment should run for 15 minutes. 29 | duration = 900 30 | 31 | # These are the network parameters. We want a bandwidth of 10 Mbit/s, a 32 | # mininum elevation for radio links of about 25 degrees (common for Starlink), 33 | # and our ground station should connect to all satellites in reach (instead of 34 | # only the closest one). 35 | [network_params] 36 | bandwidth_kbits = 10_000_000 37 | min_elevation = 25 38 | ground_station_connection_type = "all" 39 | 40 | # This configures the compute parameters for our satellites. We want 1 vCPU, 41 | # 256 MiB of RAM, 1 GiB of disk space, and we want to boot the v5.12 kernel 42 | # we downloaded with the server.img root file system. We will override some 43 | # of these parameters for our ground station below. 44 | [compute_params] 45 | vcpu_count = 1 46 | mem_size_mib = 256 47 | disk_size_mib = 1 48 | kernel = "vmlinux-5.12.bin" 49 | rootfs = "server.img" 50 | 51 | # This is the satellite constellation configuration. We follow an older 52 | # Starlink configuration with 72 planes and 22 satellites per plane. The 53 | # satellites are at an altitude of 550 km, have an inclination of 53 degrees, 54 | # and their ascending nodes are evenly distributed over 360 degrees (Walker 55 | # Delta). The eccentricity is 0, so the orbits are circular. 56 | [[shell]] 57 | planes = 72 58 | sats = 22 59 | altitude_km = 550 60 | inclination = 53.0 61 | arc_of_ascending_nodes = 360.0 62 | eccentricity = 0.0 63 | 64 | # This is our validator ground station located in Berlin. 65 | [[ground_station]] 66 | name = "validator" 67 | lat = 52.51492067 68 | long = 13.32666938 69 | 70 | # We change some of the compute parameters for our ground station. We want 71 | # 4 vCPUs, 4 GiB of RAM, 10 GiB of disk space, and we want to boot with the 72 | # validator.img root file system. 73 | [ground_station.compute_params] 74 | vcpu_count = 4 75 | mem_size_mib = 4096 76 | disk_size_mib = 10 77 | rootfs = "validator.img" 78 | -------------------------------------------------------------------------------- /quick-start/requirements.txt: -------------------------------------------------------------------------------- 1 | pandas==2.1.0 2 | seaborn==0.13.1 3 | -------------------------------------------------------------------------------- /quick-start/tofu/gcloud.tf: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | terraform { 19 | backend "local" {} 20 | } 21 | 22 | provider "google" { 23 | project = var.gcp_project 24 | region = var.gcp_region 25 | } 26 | 27 | variable "gcp_project" { 28 | # default = YOUR_GCP_PROJECT_ID 29 | } 30 | 31 | variable "gcp_region" { 32 | default = "europe-west3" 33 | } 34 | 35 | variable "gcp_zone" { 36 | default = "c" 37 | } 38 | 39 | variable "coordinator_type" { 40 | default = "n2-standard-8" 41 | } 42 | 43 | variable "host_type" { 44 | default = "n2-standard-32" 45 | } 46 | 47 | variable "host_count" { 48 | default = 2 49 | } 50 | 51 | output "host_ip" { 52 | value = google_compute_instance.celestial-test-host.*.network_interface.0.access_config.0.nat_ip 53 | } 54 | 55 | # the zone variable must be within the region 56 | # hence this weird setup 57 | locals { 58 | zone = "${var.gcp_region}-${var.gcp_zone}" 59 | } 60 | 61 | # we use a version of Ubuntu 22.04 LTS 62 | # this data item gives us the latest available image 63 | data "google_compute_image" "ubuntu2204image" { 64 | family = "ubuntu-2204-lts" 65 | project = "ubuntu-os-cloud" 66 | } 67 | 68 | # we want our instances to be able to talk to each other directly 69 | # hence we add them all to a dedicated network 70 | resource "google_compute_network" "celestial-test-network" { 71 | name = "celestial-test-network" 72 | description = "This network connects Celestial hosts." 73 | auto_create_subnetworks = true 74 | } 75 | 76 | # we also need to enable ingress to our machines 77 | resource "google_compute_firewall" "celestial-test-net-firewall-external" { 78 | name = "celestial-test-net-firewall-external" 79 | description = "This firewall allows external connections to our instance for ssh." 80 | network = google_compute_network.celestial-test-network.id 81 | direction = "INGRESS" 82 | source_ranges = ["0.0.0.0/0"] 83 | 84 | allow { 85 | protocol = "tcp" 86 | ports = ["22", "1969"] 87 | } 88 | } 89 | 90 | # and enable ingress between the machines 91 | resource "google_compute_firewall" "celestial-test-net-firewall-internal" { 92 | name = "celestial-test-net-firewall-internal" 93 | description = "This firewall allows internal connections between our instances." 94 | network = google_compute_network.celestial-test-network.id 95 | direction = "INGRESS" 96 | source_ranges = formatlist("%s/32", google_compute_instance.celestial-test-host.*.network_interface.0.access_config.0.nat_ip) 97 | 98 | allow { 99 | protocol = "udp" 100 | ports = ["1970"] 101 | } 102 | allow { 103 | protocol = "icmp" 104 | } 105 | } 106 | 107 | 108 | # we need to create an image for our hosts 109 | # this needs a custom license to use nested virtualization 110 | resource "google_compute_image" "celestial-test-host-image" { 111 | name = "celestial-test-host-image" 112 | source_image = data.google_compute_image.ubuntu2204image.self_link 113 | licenses = ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-2204-lts", "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"] 114 | } 115 | 116 | # the host instance runs Ubuntu 22.04 117 | resource "google_compute_instance" "celestial-test-host" { 118 | name = "celestial-test-host-${count.index}" 119 | count = var.host_count 120 | machine_type = var.host_type 121 | zone = local.zone 122 | 123 | boot_disk { 124 | initialize_params { 125 | image = google_compute_image.celestial-test-host-image.self_link 126 | } 127 | } 128 | 129 | # adapter for internal network 130 | network_interface { 131 | network = google_compute_network.celestial-test-network.id 132 | # get an external IP address 133 | access_config {} 134 | } 135 | 136 | service_account { 137 | scopes = ["cloud-platform"] 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /quick-start/validator/server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | # The app script runs when a microVM boots. 21 | # This server just needs to answer to pings, so to prevent it from shutting 22 | # down, we just run an infinite loop. 23 | while true; do 24 | echo "$(date): satellite server running!" 25 | sleep 300 26 | done 27 | -------------------------------------------------------------------------------- /quick-start/validator/validator-base.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | # Our base script installs all the necessary dependencies for the validation 21 | # script. This is actually only Python 3 and a few Python 3 packages. 22 | 23 | # Add git, curl, and python3 to the root filesystem. 24 | # git and curl are needed for pip. 25 | apk add git curl python3 py3-pip 26 | 27 | # Add the python3 dependencies: request and ping3 28 | python3 -m pip install ping3 requests 29 | -------------------------------------------------------------------------------- /quick-start/validator/validator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | # Our application script runs as soon as the microVM boots. Here, we mostly 21 | # need to start our validator.py script. This script requires one input: 22 | # the address of the HTTP info server. Using our builder, this is set as the 23 | # hostname "info.celestial". 24 | 25 | # Now we can start our validator script! 26 | python3 validator.py info.celestial 27 | -------------------------------------------------------------------------------- /requirements-animation.txt: -------------------------------------------------------------------------------- 1 | vtk==9.3.0 -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cerberus==1.3.5 2 | grpcio==1.59.0 3 | grpcio-tools==1.59.0 4 | llvmlite==0.41.1 5 | mypy==1.9.0 6 | mypy-protobuf==3.5.0 7 | numba==0.58.1 8 | numpy==1.26.1 9 | protobuf==4.24.4 10 | seaborn==0.13.1 11 | sgp4==2.23 12 | toml @ git+https://github.com/uiri/toml@5706d31 13 | tqdm==4.66.1 14 | types-requests==2.31.0.20240106 15 | types-toml==0.10.8.7 16 | -------------------------------------------------------------------------------- /satgen.Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | FROM python:3.11-slim 19 | 20 | RUN apt update && apt install -y \ 21 | --no-install-recommends \ 22 | --no-install-suggests \ 23 | git && \ 24 | apt clean && rm -rf /var/lib/apt/lists/* 25 | 26 | COPY requirements.txt . 27 | RUN pip install -r requirements.txt 28 | 29 | COPY satgen.py . 30 | COPY celestial/*.py celestial/ 31 | 32 | ENTRYPOINT ["python", "satgen.py"] -------------------------------------------------------------------------------- /satgen.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | """ 19 | Satgen generates satellite trajectories and network configurationfs for a 20 | Celestial emulation run. It takes a TOML configuration file as an input 21 | and generates a custom .zip format file as an output that contains changes 22 | in network topologies at each time step. 23 | 24 | To use satgen.py, you will need a full Celestial configuration file. Satgen 25 | will check that the configuration file matches its expectations and will 26 | exit with an error if it does not. 27 | 28 | Prerequisites 29 | ------------- 30 | 31 | Make sure you have all the necessary dependencies installed. You can install 32 | them using pip in a virtual environment: 33 | 34 | python3 -m venv .venv 35 | source .venv/bin/activate 36 | pip install -r requirements.txt 37 | 38 | 39 | 40 | Usage 41 | ----- 42 | 43 | python3 satgen.py [config.toml] [output-file (optional)] 44 | 45 | The output will be in the specified path or in a generated file based on a hash 46 | of the configuration file if no output path is specified. 47 | """ 48 | 49 | import sys 50 | 51 | import toml 52 | import tqdm 53 | 54 | import celestial.config 55 | import celestial.zip_serializer 56 | import celestial.satgen_connstellation 57 | 58 | if __name__ == "__main__": 59 | if len(sys.argv) > 3 or len(sys.argv) < 2: 60 | exit("Usage: python3 celestial.py [config.toml] [output-file (optional)]") 61 | 62 | # read toml 63 | try: 64 | text_config = toml.load(sys.argv[1]) 65 | except Exception as e: 66 | exit(str(e)) 67 | 68 | output_file = None 69 | if len(sys.argv) == 3: 70 | output_file = sys.argv[2] 71 | 72 | # read the configuration 73 | config: celestial.config.Config = celestial.config.Config(text_config) 74 | 75 | # prepare serializer 76 | # serializer = celestial.json_serializer.JSONSerializer(config) 77 | serializer = celestial.zip_serializer.ZipSerializer(config, output_file) 78 | 79 | # init the constellation 80 | constellation = celestial.satgen_connstellation.SatgenConstellation( 81 | config, serializer 82 | ) 83 | 84 | # run the simulation 85 | i = 0 + config.offset 86 | pbar = tqdm.tqdm(total=int(config.duration / config.resolution)) 87 | while i < config.duration + config.offset: 88 | # import cProfile 89 | 90 | # cProfile.run("constellation.step(i)", sort="cumtime") 91 | constellation.step(i) 92 | i += config.resolution 93 | pbar.update(1) 94 | 95 | # serialize the state 96 | serializer.persist() 97 | 98 | print(f"Output written to {serializer.filename}") 99 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [mypy] 2 | python_version = 3.11 3 | warn_unused_configs = True 4 | disallow_any_generics = True 5 | disallow_untyped_calls = True 6 | disallow_untyped_defs = True 7 | disallow_incomplete_defs = True 8 | check_untyped_defs = True 9 | warn_return_any = True 10 | strict_equality = True 11 | ignore_missing_imports = True 12 | show_column_numbers = True 13 | plugins = numpy.typing.mypy_plugin 14 | -------------------------------------------------------------------------------- /test/integration/.gitignore: -------------------------------------------------------------------------------- 1 | id_ed25519 2 | id_ed25519.pub 3 | rootfs.id_rsa 4 | rootfs.ext4 5 | -------------------------------------------------------------------------------- /test/integration/.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "tofu init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.opentofu.org/hashicorp/google" { 5 | version = "5.11.0" 6 | hashes = [ 7 | "h1:SZvItcManUwdLWQIxHWVgiW0BXbide6kqQAL7XgRTV8=", 8 | "zh:1a92a4e747b7ab14fdfa471a8b58155e3f509a18d4b5c155ca2cfb925a687f65", 9 | "zh:274ce607e702a28d1b2c8307341d2e0b95c85329b8ff743d05ea504811ccdd86", 10 | "zh:5f071bccac9325b771dce2bf83d44ab93159b2d175ebc4543323383da15e6dd3", 11 | "zh:6f6693b4097edf6644301724de54889d2d0f1f79c0d7d429e2957e5a88a9b31d", 12 | "zh:6f82dc7d012d587407bf2a0537bc0591c0de00ee4a31256ea3a8c562730ea88e", 13 | "zh:7f4783582548678630ffa583d27c561f2966d7c6bc0dd6ce7b96bf815396a4c3", 14 | "zh:844111efd3e6bd23fb9651cc889fe47cdc107d2c0606bc7293ca5e8694165d88", 15 | "zh:9e91d192d1a588cf1ee7c346547cff29134d39a378147b79637c23f0aaa350e8", 16 | "zh:b64b046a78e5ed3b26735bb32e53c8437fb416d278e44cf2a836ab415d30a81e", 17 | "zh:b9271c241890c5daaf0852ca533c58a649206f676e7aa115be88dd17a3365c04", 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /test/integration/dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | set -ex 20 | 21 | sudo apt-get update 22 | 23 | sudo apt-get install \ 24 | --no-install-recommends \ 25 | --no-install-suggests \ 26 | -y g++ gcc make cmake build-essential 27 | 28 | # install go 29 | curl -fsSL -o go1.22.1.linux-amd64.tar.gz \ 30 | https://go.dev/dl/go1.22.1.linux-amd64.tar.gz 31 | sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.22.1.linux-amd64.tar.gz 32 | export PATH=$PATH:/usr/local/go/bin 33 | echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc 34 | 35 | # we need the /celestial folder available on the hosts 36 | sudo mkdir -p /celestial 37 | 38 | # we also need wireguard and ipset as dependencies 39 | sudo apt-get install \ 40 | --no-install-recommends \ 41 | --no-install-suggests \ 42 | -y wireguard ipset 43 | 44 | # and we need firecracker on the machine 45 | # download the current release 46 | curl -fsSL -o firecracker-v1.6.0-x86_64.tgz \ 47 | https://github.com/firecracker-microvm/firecracker/releases/download/v1.6.0/firecracker-v1.6.0-x86_64.tgz 48 | tar -xvf firecracker-v1.6.0-x86_64.tgz 49 | # and add the firecracker and jailer binaries 50 | sudo mv release-v1.6.0-x86_64/firecracker-v1.6.0-x86_64 /usr/local/bin/firecracker 51 | sudo mv release-v1.6.0-x86_64/seccompiler-bin-v1.6.0-x86_64 /usr/local/bin/jailer 52 | 53 | sudo mv vmlinux-5.12.bin /celestial/vmlinux.bin 54 | 55 | # sometimes it can also be helpful to increase process and file handler 56 | # limits on your host machines: 57 | cat << END > ./limits.conf 58 | * soft nofile 64000 59 | * hard nofile 64000 60 | root soft nofile 64000 61 | root hard nofile 64000 62 | * soft nproc 64000 63 | * hard nproc 64000 64 | root soft nproc 64000 65 | root hard nproc 64000 66 | END 67 | 68 | sudo mv ./limits.conf /etc/security/limits.conf 69 | 70 | go mod download 71 | -------------------------------------------------------------------------------- /test/integration/fileslist.txt: -------------------------------------------------------------------------------- 1 | test/integration/dependencies.sh 2 | test/integration/id_ed25519 3 | test/integration/rootfs/ssh.img 4 | proto 5 | pkg 6 | celestial.go 7 | go.mod 8 | go.sum 9 | kernel/vmlinux-5.12.bin 10 | test/integration/celestial_test.go 11 | -------------------------------------------------------------------------------- /test/integration/google.auto.tfvars: -------------------------------------------------------------------------------- 1 | gcp_project = "celestial-306310" 2 | -------------------------------------------------------------------------------- /test/integration/infrastructure.tf: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | provider "google" { 19 | project = var.gcp_project 20 | region = var.gcp_region 21 | } 22 | 23 | variable "gcp_project" { 24 | # default = YOUR_GCP_PROJECT_ID 25 | } 26 | 27 | variable "gcp_region" { 28 | default = "europe-west3" 29 | } 30 | 31 | variable "gcp_zone" { 32 | default = "a" 33 | } 34 | 35 | variable "host_type" { 36 | default = "n2-standard-2" 37 | } 38 | 39 | output "zone" { 40 | value = local.zone 41 | } 42 | 43 | output "host_name" { 44 | value = format("%s.%s.%s", google_compute_instance.celestial-test-host.name, local.zone, var.gcp_project) 45 | } 46 | 47 | output "host_id" { 48 | value = google_compute_instance.celestial-test-host.name 49 | } 50 | 51 | output "project" { 52 | value = var.gcp_project 53 | } 54 | 55 | # the zone variable must be within the region 56 | # hence this weird setup 57 | locals { 58 | zone = "${var.gcp_region}-${var.gcp_zone}" 59 | } 60 | 61 | # we use a version of Ubuntu 22.04 LTS 62 | # this data item gives us the latest available image 63 | data "google_compute_image" "ubuntu2204image" { 64 | family = "ubuntu-2204-lts" 65 | project = "ubuntu-os-cloud" 66 | } 67 | 68 | # we want our instances to be able to talk to each other directly 69 | # hence we add them all to a dedicated network 70 | resource "google_compute_network" "celestial-test-network" { 71 | name = "celestial-test-network" 72 | description = "This network connects Celestial hosts." 73 | auto_create_subnetworks = true 74 | } 75 | 76 | # we also need to enable ingress to our machines 77 | resource "google_compute_firewall" "celestial-test-net-firewall-external" { 78 | name = "celestial-test-net-firewall-external" 79 | description = "This firewall allows external connections to our instance for ssh." 80 | network = google_compute_network.celestial-test-network.id 81 | direction = "INGRESS" 82 | source_ranges = ["0.0.0.0/0"] 83 | 84 | allow { 85 | protocol = "tcp" 86 | ports = ["22"] 87 | } 88 | } 89 | 90 | # reserve a static external IP address 91 | resource "google_compute_address" "celestial-test-host-ip" { 92 | name = "celestial-test-host-ip" 93 | } 94 | 95 | # we need to create an image for our hosts 96 | # this needs a custom license to use nested virtualization 97 | resource "google_compute_image" "celestial-test-host-image" { 98 | name = "celestial-test-host-image" 99 | # source_disk = google_compute_disk.celestial-host-disk.self_link 100 | source_image = data.google_compute_image.ubuntu2204image.self_link 101 | licenses = ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-2204-lts", "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"] 102 | } 103 | 104 | # the host instance runs Ubuntu 22.04 105 | resource "google_compute_instance" "celestial-test-host" { 106 | name = "celestial-test-host" 107 | machine_type = var.host_type 108 | zone = local.zone 109 | 110 | boot_disk { 111 | initialize_params { 112 | image = google_compute_image.celestial-test-host-image.self_link 113 | } 114 | } 115 | 116 | # adapter for internal network 117 | network_interface { 118 | network = google_compute_network.celestial-test-network.id 119 | 120 | # use the static IP address 121 | access_config { 122 | nat_ip = google_compute_address.celestial-test-host-ip.address 123 | } 124 | } 125 | 126 | service_account { 127 | scopes = ["cloud-platform"] 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /test/integration/integration.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | # the -no-reboot flag is used to prevent the instance from rebooting 20 | REBOOT=1 21 | 22 | # the other argument is the host: ip address or gcloud 23 | TEST_HOST="" 24 | 25 | for i in "$@" 26 | do 27 | case $i in 28 | -no-reboot) 29 | REBOOT=0 30 | shift # past argument=value 31 | ;; 32 | -host=*) 33 | TEST_HOST="${i#*=}" 34 | shift # past argument=value 35 | ;; 36 | *) 37 | # unknown option 38 | ;; 39 | esac 40 | done 41 | 42 | # check that the host is set 43 | if [ -z "$TEST_HOST" ]; then 44 | echo "No host set!" 45 | echo "Please set the host with -host=... or use -host=gcloud to use terraform" 46 | exit 1 47 | fi 48 | 49 | set -xe 50 | 51 | DIVIDER="==============================" 52 | ROOT="../.." 53 | 54 | pushd "$ROOT" 55 | make rootfsbuilder 56 | popd 57 | 58 | pushd rootfs 59 | make 60 | popd 61 | 62 | echo "$DIVIDER" 63 | echo "Running preparation..." 64 | echo "$DIVIDER" 65 | 66 | ./make_key.sh 67 | 68 | # make the infrastructure if we use gcloud 69 | if [ "$TEST_HOST" == "gcloud" ]; then 70 | tofu init 71 | tofu apply -auto-approve 72 | 73 | 74 | GCP_ZONE="$(tofu output -json | jq -r '.zone.value')" 75 | GCP_PROJECT="$(tofu output -json | jq -r '.project.value')" 76 | GCR_INSTANCE_FULL="$(tofu output -json | jq -r '.host_name.value')" 77 | GCP_INSTANCE="$(tofu output -json | jq -r '.host_id.value')" 78 | 79 | gcloud config set project "$GCP_PROJECT" 80 | SSH_ADDRESS="$GCR_INSTANCE_FULL" 81 | else 82 | SSH_ADDRESS="$TEST_HOST" 83 | fi 84 | 85 | if [ "$REBOOT" -eq 1 ]; then 86 | if [ "$TEST_HOST" == "gcloud" ]; then 87 | # restart the machines 88 | gcloud compute instances stop --zone="$GCP_ZONE" "$GCP_INSTANCE" 89 | sleep 1 90 | gcloud compute instances start --zone="$GCP_ZONE" "$GCP_INSTANCE" 91 | 92 | gcloud compute config-ssh 93 | else 94 | # at least reboot the machine 95 | ssh "$SSH_ADDRESS" sudo reboot now || true 96 | fi 97 | fi 98 | 99 | until ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$SSH_ADDRESS" echo 100 | do 101 | echo "host instance not ready yet" 102 | sleep 5 103 | if [ "$TEST_HOST" == "gcloud" ]; then 104 | # make sure we have the right config 105 | gcloud compute config-ssh 106 | fi 107 | done 108 | 109 | ssh "$SSH_ADDRESS" sudo apt-get update 110 | ssh "$SSH_ADDRESS" sudo apt-get install \ 111 | --no-install-recommends \ 112 | --no-install-suggests \ 113 | -y rsync 114 | 115 | # copy the necessary files 116 | while read -r f; do 117 | # check if the file or directory exists 118 | if [ ! -e "$ROOT/$f" ]; then 119 | echo "File or directory $f does not exist!" 120 | exit 1 121 | fi 122 | 123 | rsync -avz "$ROOT/$f" "$SSH_ADDRESS": 124 | done . 17 | # 18 | 19 | KEYFILE="id_ed25519" 20 | 21 | # check if file exists 22 | if [ -f "$KEYFILE" ]; then 23 | echo "File $KEYFILE exists..." 24 | exit 0 25 | fi 26 | 27 | ssh-keygen -t ed25519 -f "$KEYFILE" -N "" 28 | mv "$KEYFILE.pub" ./rootfs/ 29 | -------------------------------------------------------------------------------- /test/integration/rootfs/.gitignore: -------------------------------------------------------------------------------- 1 | *.ext4 2 | *.img 3 | -------------------------------------------------------------------------------- /test/integration/rootfs/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | .PHONY: all 19 | 20 | all: ssh.img 21 | 22 | ssh.img: ssh.sh ssh-base.sh id_ed25519.pub 23 | @docker run -it --platform=linux/amd64 --rm -v $(PWD)/ssh.sh:/app.sh -v $(PWD)/id_ed25519.pub:/files/id_ed25519.pub -v $(PWD)/ssh-base.sh:/base.sh -v $(PWD):/opt/code --privileged rootfsbuilder $@ 24 | 25 | id_ed25519.pub: 26 | cd .. ; ./make_key.sh 27 | -------------------------------------------------------------------------------- /test/integration/rootfs/ssh-base.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | # the base script install all the necessary dependencies during root 21 | # filesystem compilation 22 | # configure ssh 23 | 24 | apk -U --allow-untrusted --root / add openssh 25 | 26 | ln -sf sshd /etc/init.d/sshd.eth0 27 | ln -sf /etc/init.d/sshd.eth0 /etc/runlevels/default/sshd.eth0 28 | 29 | mkdir -m 0600 -p /root/.ssh/ 30 | ssh-keygen -f /root/.ssh/id_rsa -N "" 31 | ssh-keygen -A 32 | cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys 33 | 34 | cat >> /etc/conf.d/sshd << EOF 35 | sshd_disable_keygen="yes" 36 | rc_need="net.eth0" 37 | EOF 38 | 39 | sed -E -i /etc/ssh/sshd_config \ 40 | -e "/^[# ]*PermitRootLogin .+$/d" \ 41 | -e "/^[# ]*PermitEmptyPasswords .+$/d" \ 42 | -e "/^[# ]*PubkeyAuthentication .+$/d" 43 | 44 | echo " 45 | PermitRootLogin yes 46 | PermitEmptyPasswords yes 47 | PubkeyAuthentication yes 48 | " | tee -a /etc/ssh/sshd_config >/dev/null 49 | 50 | cat id_ed25519.pub >> /root/.ssh/authorized_keys 51 | 52 | # add iperf3 53 | apk -U --allow-untrusted --root / add iperf3 -------------------------------------------------------------------------------- /test/integration/rootfs/ssh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | while true; do 21 | echo "$(date): satellite server running" 22 | sleep 60 23 | done 24 | -------------------------------------------------------------------------------- /test/microvm/.gitignore: -------------------------------------------------------------------------------- 1 | id_ed25519 2 | id_ed25519.pub 3 | rootfs.id_rsa 4 | rootfs.ext4 5 | -------------------------------------------------------------------------------- /test/microvm/.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "tofu init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.opentofu.org/hashicorp/google" { 5 | version = "5.11.0" 6 | hashes = [ 7 | "h1:SZvItcManUwdLWQIxHWVgiW0BXbide6kqQAL7XgRTV8=", 8 | "zh:1a92a4e747b7ab14fdfa471a8b58155e3f509a18d4b5c155ca2cfb925a687f65", 9 | "zh:274ce607e702a28d1b2c8307341d2e0b95c85329b8ff743d05ea504811ccdd86", 10 | "zh:5f071bccac9325b771dce2bf83d44ab93159b2d175ebc4543323383da15e6dd3", 11 | "zh:6f6693b4097edf6644301724de54889d2d0f1f79c0d7d429e2957e5a88a9b31d", 12 | "zh:6f82dc7d012d587407bf2a0537bc0591c0de00ee4a31256ea3a8c562730ea88e", 13 | "zh:7f4783582548678630ffa583d27c561f2966d7c6bc0dd6ce7b96bf815396a4c3", 14 | "zh:844111efd3e6bd23fb9651cc889fe47cdc107d2c0606bc7293ca5e8694165d88", 15 | "zh:9e91d192d1a588cf1ee7c346547cff29134d39a378147b79637c23f0aaa350e8", 16 | "zh:b64b046a78e5ed3b26735bb32e53c8437fb416d278e44cf2a836ab415d30a81e", 17 | "zh:b9271c241890c5daaf0852ca533c58a649206f676e7aa115be88dd17a3365c04", 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /test/microvm/dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | set -ex 20 | 21 | sudo apt-get update 22 | 23 | sudo apt-get install \ 24 | --no-install-recommends \ 25 | --no-install-suggests \ 26 | -y g++ gcc make cmake build-essential 27 | 28 | # and we need firecracker on the machine 29 | # download the current release 30 | curl -fsSL -o firecracker-v1.6.0-x86_64.tgz \ 31 | https://github.com/firecracker-microvm/firecracker/releases/download/v1.6.0/firecracker-v1.6.0-x86_64.tgz 32 | tar -xvf firecracker-v1.6.0-x86_64.tgz 33 | # and add the firecracker and jailer binaries 34 | sudo mv release-v1.6.0-x86_64/firecracker-v1.6.0-x86_64 /usr/local/bin/firecracker 35 | sudo mv release-v1.6.0-x86_64/seccompiler-bin-v1.6.0-x86_64 /usr/local/bin/jailer 36 | 37 | -------------------------------------------------------------------------------- /test/microvm/fileslist.txt: -------------------------------------------------------------------------------- 1 | test/microvm/dependencies.sh 2 | test/microvm/run_microvm.sh 3 | test/microvm/id_ed25519 4 | test/microvm/rootfs/ssh.img 5 | test/microvm/vmlinux.bin 6 | -------------------------------------------------------------------------------- /test/microvm/google.auto.tfvars: -------------------------------------------------------------------------------- 1 | gcp_project = "celestial-306310" 2 | -------------------------------------------------------------------------------- /test/microvm/infrastructure.tf: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | provider "google" { 19 | project = var.gcp_project 20 | region = var.gcp_region 21 | } 22 | 23 | variable "gcp_project" { 24 | # default = YOUR_GCP_PROJECT_ID 25 | } 26 | 27 | variable "gcp_region" { 28 | default = "europe-west3" 29 | } 30 | 31 | variable "gcp_zone" { 32 | default = "a" 33 | } 34 | 35 | variable "host_type" { 36 | default = "n2-standard-2" 37 | } 38 | 39 | output "zone" { 40 | value = local.zone 41 | } 42 | 43 | output "host_name" { 44 | value = format("%s.%s.%s", google_compute_instance.celestial-test-host.name, local.zone, var.gcp_project) 45 | } 46 | 47 | output "host_id" { 48 | value = google_compute_instance.celestial-test-host.name 49 | } 50 | 51 | output "project" { 52 | value = var.gcp_project 53 | } 54 | 55 | # the zone variable must be within the region 56 | # hence this weird setup 57 | locals { 58 | zone = "${var.gcp_region}-${var.gcp_zone}" 59 | } 60 | 61 | # we use a version of Ubuntu 22.04 LTS 62 | # this data item gives us the latest available image 63 | data "google_compute_image" "ubuntu2204image" { 64 | family = "ubuntu-2204-lts" 65 | project = "ubuntu-os-cloud" 66 | } 67 | 68 | # we want our instances to be able to talk to each other directly 69 | # hence we add them all to a dedicated network 70 | resource "google_compute_network" "celestial-test-network" { 71 | name = "celestial-test-network" 72 | description = "This network connects Celestial hosts." 73 | auto_create_subnetworks = true 74 | } 75 | 76 | # we also need to enable ingress to our machines 77 | resource "google_compute_firewall" "celestial-test-net-firewall-external" { 78 | name = "celestial-test-net-firewall-external" 79 | description = "This firewall allows external connections to our instance for ssh." 80 | network = google_compute_network.celestial-test-network.id 81 | direction = "INGRESS" 82 | source_ranges = ["0.0.0.0/0"] 83 | 84 | allow { 85 | protocol = "tcp" 86 | ports = ["22"] 87 | } 88 | } 89 | 90 | # reserve a static external IP address 91 | resource "google_compute_address" "celestial-test-host-ip" { 92 | name = "celestial-test-host-ip" 93 | } 94 | 95 | # we need to create an image for our hosts 96 | # this needs a custom license to use nested virtualization 97 | resource "google_compute_image" "celestial-test-host-image" { 98 | name = "celestial-test-host-image" 99 | # source_disk = google_compute_disk.celestial-host-disk.self_link 100 | source_image = data.google_compute_image.ubuntu2204image.self_link 101 | licenses = ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-2204-lts", "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"] 102 | } 103 | 104 | # the host instance runs Ubuntu 22.04 105 | resource "google_compute_instance" "celestial-test-host" { 106 | name = "celestial-test-host" 107 | machine_type = var.host_type 108 | zone = local.zone 109 | 110 | boot_disk { 111 | initialize_params { 112 | image = google_compute_image.celestial-test-host-image.self_link 113 | } 114 | } 115 | 116 | # adapter for internal network 117 | network_interface { 118 | network = google_compute_network.celestial-test-network.id 119 | 120 | # use the static IP address 121 | access_config { 122 | nat_ip = google_compute_address.celestial-test-host-ip.address 123 | } 124 | } 125 | 126 | service_account { 127 | scopes = ["cloud-platform"] 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /test/microvm/make_key.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | KEYFILE="id_ed25519" 20 | 21 | # check if file exists 22 | if [ -f "$KEYFILE" ]; then 23 | echo "File $KEYFILE exists..." 24 | exit 0 25 | fi 26 | 27 | ssh-keygen -t ed25519 -f "$KEYFILE" -N "" 28 | mv "$KEYFILE.pub" ./rootfs/ 29 | -------------------------------------------------------------------------------- /test/microvm/microvm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | # the -no-reboot flag is used to prevent the instance from rebooting 20 | REBOOT=1 21 | 22 | # the other argument is the host: ip address or gcloud 23 | TEST_HOST="" 24 | 25 | for i in "$@" 26 | do 27 | case $i in 28 | -no-reboot) 29 | REBOOT=0 30 | shift # past argument=value 31 | ;; 32 | -host=*) 33 | TEST_HOST="${i#*=}" 34 | shift # past argument=value 35 | ;; 36 | *) 37 | # unknown option 38 | ;; 39 | esac 40 | done 41 | 42 | # check that the host is set 43 | if [ -z "$TEST_HOST" ]; then 44 | echo "No host set!" 45 | echo "Please set the host with -host=... or use -host=gcloud to use terraform" 46 | exit 1 47 | fi 48 | 49 | set -xe 50 | 51 | DIVIDER="==============================" 52 | ROOT="../.." 53 | 54 | pushd "$ROOT" 55 | make rootfsbuilder 56 | popd 57 | 58 | pushd rootfs 59 | make -B 60 | popd 61 | 62 | echo "$DIVIDER" 63 | echo "Running preparation..." 64 | echo "$DIVIDER" 65 | 66 | ./make_key.sh 67 | 68 | # make the infrastructure if we use gcloud 69 | if [ "$TEST_HOST" == "gcloud" ]; then 70 | tofu init 71 | tofu apply -auto-approve 72 | 73 | GCP_ZONE="$(tofu output -json | jq -r '.zone.value')" 74 | GCP_PROJECT="$(tofu output -json | jq -r '.project.value')" 75 | GCR_INSTANCE_FULL="$(tofu output -json | jq -r '.host_name.value')" 76 | GCP_INSTANCE="$(tofu output -json | jq -r '.host_id.value')" 77 | 78 | gcloud config set project "$GCP_PROJECT" 79 | SSH_ADDRESS="$GCR_INSTANCE_FULL" 80 | else 81 | SSH_ADDRESS="$TEST_HOST" 82 | fi 83 | 84 | if [ "$REBOOT" -eq 1 ]; then 85 | if [ "$TEST_HOST" == "gcloud" ]; then 86 | # restart the machines 87 | gcloud compute instances stop --zone="$GCP_ZONE" "$GCP_INSTANCE" 88 | sleep 1 89 | gcloud compute instances start --zone="$GCP_ZONE" "$GCP_INSTANCE" 90 | 91 | gcloud compute config-ssh 92 | else 93 | # at least reboot the machine 94 | ssh "$SSH_ADDRESS" sudo reboot now || true 95 | fi 96 | fi 97 | 98 | until ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$SSH_ADDRESS" echo 99 | do 100 | echo "host instance not ready yet" 101 | sleep 5 102 | if [ "$TEST_HOST" == "gcloud" ]; then 103 | # make sure we have the right config 104 | gcloud compute config-ssh 105 | fi 106 | done 107 | 108 | ssh "$SSH_ADDRESS" sudo apt-get update 109 | ssh "$SSH_ADDRESS" sudo apt-get install \ 110 | --no-install-recommends \ 111 | --no-install-suggests \ 112 | -y rsync 113 | 114 | # copy the necessary files 115 | while read -r f; do 116 | # check if the file or directory exists 117 | if [ ! -e "$ROOT/$f" ]; then 118 | echo "File or directory $f does not exist!" 119 | exit 1 120 | fi 121 | 122 | rsync -avz "$ROOT/$f" "$SSH_ADDRESS": 123 | done . 16 | # 17 | 18 | .PHONY: all 19 | 20 | all: ssh.img 21 | 22 | ssh.img: ssh.sh ssh-base.sh id_ed25519.pub 23 | @docker run -it --platform=linux/amd64 --rm -v $(PWD)/ssh.sh:/app.sh -v $(PWD)/id_ed25519.pub:/files/id_ed25519.pub -v $(PWD)/ssh-base.sh:/base.sh -v $(PWD):/opt/code --privileged rootfsbuilder $@ 24 | 25 | id_ed25519.pub: 26 | cd .. ; ./make_key.sh 27 | -------------------------------------------------------------------------------- /test/microvm/rootfs/ssh-base.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | # the base script install all the necessary dependencies during root 21 | # filesystem compilation 22 | # configure ssh 23 | 24 | apk -U --allow-untrusted --root / add openssh 25 | 26 | ln -sf sshd /etc/init.d/sshd.eth0 27 | ln -sf /etc/init.d/sshd.eth0 /etc/runlevels/default/sshd.eth0 28 | 29 | mkdir -m 0600 -p /root/.ssh/ 30 | ssh-keygen -f /root/.ssh/id_rsa -N "" 31 | ssh-keygen -A 32 | cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys 33 | 34 | cat >> /etc/conf.d/sshd << EOF 35 | sshd_disable_keygen="yes" 36 | rc_need="net.eth0" 37 | EOF 38 | 39 | sed -E -i /etc/ssh/sshd_config \ 40 | -e "/^[# ]*PermitRootLogin .+$/d" \ 41 | -e "/^[# ]*PermitEmptyPasswords .+$/d" \ 42 | -e "/^[# ]*PubkeyAuthentication .+$/d" 43 | 44 | echo " 45 | PermitRootLogin yes 46 | PermitEmptyPasswords yes 47 | PubkeyAuthentication yes 48 | " | tee -a /etc/ssh/sshd_config >/dev/null 49 | 50 | cat id_ed25519.pub >> /root/.ssh/authorized_keys 51 | -------------------------------------------------------------------------------- /test/microvm/rootfs/ssh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | while true; do 21 | echo "$(date): satellite server running" 22 | sleep 10 23 | done 24 | -------------------------------------------------------------------------------- /test/system/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | output/results.csv 3 | host.log 4 | coordinator.log -------------------------------------------------------------------------------- /test/system/.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "tofu init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.opentofu.org/hashicorp/google" { 5 | version = "5.11.0" 6 | hashes = [ 7 | "h1:SZvItcManUwdLWQIxHWVgiW0BXbide6kqQAL7XgRTV8=", 8 | "zh:1a92a4e747b7ab14fdfa471a8b58155e3f509a18d4b5c155ca2cfb925a687f65", 9 | "zh:274ce607e702a28d1b2c8307341d2e0b95c85329b8ff743d05ea504811ccdd86", 10 | "zh:5f071bccac9325b771dce2bf83d44ab93159b2d175ebc4543323383da15e6dd3", 11 | "zh:6f6693b4097edf6644301724de54889d2d0f1f79c0d7d429e2957e5a88a9b31d", 12 | "zh:6f82dc7d012d587407bf2a0537bc0591c0de00ee4a31256ea3a8c562730ea88e", 13 | "zh:7f4783582548678630ffa583d27c561f2966d7c6bc0dd6ce7b96bf815396a4c3", 14 | "zh:844111efd3e6bd23fb9651cc889fe47cdc107d2c0606bc7293ca5e8694165d88", 15 | "zh:9e91d192d1a588cf1ee7c346547cff29134d39a378147b79637c23f0aaa350e8", 16 | "zh:b64b046a78e5ed3b26735bb32e53c8437fb416d278e44cf2a836ab415d30a81e", 17 | "zh:b9271c241890c5daaf0852ca533c58a649206f676e7aa115be88dd17a3365c04", 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /test/system/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | .PHONY: all 19 | 20 | all: app/validator.img satgen.zip 21 | 22 | app/validator.img: app/validator.sh app/validator-base.sh app/validator.py 23 | @docker run --platform=linux/amd64 --rm -v $(PWD)/app/validator.py:/files/validator.py -v $(PWD)/app/validator.sh:/app.sh -v $(PWD)/app/validator-base.sh:/base.sh -v $(PWD):/opt/code --privileged rootfsbuilder $@ 24 | 25 | satgen.zip: config.toml 26 | cd ../.. && source .venv/bin/activate && python3 satgen.py test/system/$< test/system/$@ && deactivate 27 | -------------------------------------------------------------------------------- /test/system/app/.gitignore: -------------------------------------------------------------------------------- 1 | *.ext4 2 | *.img 3 | -------------------------------------------------------------------------------- /test/system/app/validator-base.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | # add git, curl, and python3 to the root filesystem. 21 | # our program is based on python3, hence we need to install python3. 22 | # git and curl are needed for pip. 23 | # note that the root filesystem here is based on alpine, hence uses the "apk" 24 | # package manager. 25 | apk add git curl python3 py3-pip 26 | 27 | # add the python3 dependencies: request and ping3 28 | python3 -m pip install ping3 requests 29 | -------------------------------------------------------------------------------- /test/system/app/validator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 3. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | # check what chrony is doing 21 | # now it should report the correct timesource 22 | chronyc tracking 23 | 24 | # ready to start the application! 25 | # everything that is sent to stdout will be sent to our file 26 | echo "STARTING VALIDATOR" 27 | 28 | # the validation script should know where it can find the HTTP server 29 | # (at our gateway) 30 | python3 validator.py info.celestial 31 | 32 | while true; do 33 | echo "$(date): satellite server running" 34 | sleep 60 35 | done 36 | -------------------------------------------------------------------------------- /test/system/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | set -xe 20 | 21 | ROOT="../.." 22 | 23 | pushd "$ROOT" || exit 24 | 25 | make build rootfsbuilder -B 26 | 27 | popd || exit 28 | 29 | make 30 | -------------------------------------------------------------------------------- /test/system/cleanresults.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | import os 20 | import sys 21 | 22 | if __name__ == "__main__": 23 | # expect two input arguments 24 | # 1. raw results directory 25 | # 2. clean results file 26 | 27 | if not len(sys.argv) == 3: 28 | exit("Usage: python3 cleanresults.py [raw results] [clean results]") 29 | 30 | raw = sys.argv[1] 31 | clean = sys.argv[2] 32 | 33 | read_lines = 0 34 | written_lines = 0 35 | 36 | with open(clean, "w") as out_file: 37 | out_file.write( 38 | "a_shell,a_sat,t,b_shell,b_sat,expected_before,expected_after,actual\n" 39 | ) 40 | 41 | # read all files in out directory 42 | for filename in os.listdir(raw): 43 | # split by underscore 44 | parts = filename.split("-") 45 | 46 | # check if gst or sat 47 | 48 | if len(parts) != 2: 49 | raise Exception("invalid filename") 50 | 51 | # first part is a_shell 52 | a_shell = parts[0] 53 | 54 | a_sat = parts[1].split(".")[0] 55 | 56 | with open(os.path.join(raw, filename), "r") as in_file: 57 | # read all lines 58 | # decide for each line if it is a data line 59 | while True: 60 | line = in_file.readline() 61 | 62 | if not line: 63 | break 64 | 65 | read_lines += 1 66 | 67 | if "," not in line: 68 | continue 69 | 70 | line = line.strip() 71 | 72 | # split line by comma 73 | parts = line.split(",") 74 | 75 | # second and third parts should be a number 76 | try: 77 | int(parts[1]) 78 | int(parts[2]) 79 | except Exception: 80 | if parts[1] != "gst": 81 | continue 82 | 83 | # write the line! 84 | out_file.write(f"{a_shell},{a_sat},{line}\n") 85 | written_lines += 1 86 | 87 | print(f"read {read_lines} lines, wrote {written_lines} lines") 88 | -------------------------------------------------------------------------------- /test/system/config.toml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, version 3. 8 | # 9 | # This program is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | bbox = [0.0, -60.0, 90.0, 60.0] 18 | resolution = 10 19 | duration = 900 20 | 21 | [network_params] 22 | bandwidth_kbits = 10_000_000 23 | min_elevation = 25 24 | ground_station_connection_type = "all" 25 | 26 | [compute_params] 27 | vcpu_count = 1 28 | mem_size_mib = 512 29 | disk_size_mib = 10 30 | kernel = "vmlinux.bin" 31 | rootfs = "validator.img" 32 | 33 | [[shell]] 34 | planes = 72 35 | sats = 22 36 | altitude_km = 900 37 | inclination = 53.0 38 | arc_of_ascending_nodes = 360.0 39 | eccentricity = 0.0 40 | 41 | [[shell]] 42 | planes = 6 43 | sats = 10 44 | altitude_km = 1000 45 | inclination = 90.0 46 | arc_of_ascending_nodes = 180.0 47 | eccentricity = 0.0 48 | 49 | [[ground_station]] 50 | name = "Berlin" 51 | lat = 52.514182 52 | long = 13.328285 53 | 54 | [ground_station.compute_params] 55 | vcpu_count = 2 56 | mem_size_mib = 2048 57 | disk_size_mib = 100 58 | rootfs = "validator.img" 59 | 60 | [[ground_station]] 61 | name = "NewYork" 62 | lat = 40.76140 63 | long = -73.97165 64 | 65 | [ground_station.compute_params] 66 | vcpu_count = 2 67 | mem_size_mib = 2048 68 | disk_size_mib = 100 69 | rootfs = "validator.img" 70 | -------------------------------------------------------------------------------- /test/system/dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | set -ex 20 | 21 | sudo apt-get update 22 | 23 | # for celestial coordinator: python + python-pip + python dependencies 24 | sudo apt-get install \ 25 | --no-install-recommends \ 26 | --no-install-suggests \ 27 | -y python3 python3-pip python3-dev g++ gcc make cmake build-essential 28 | 29 | python3 -m pip install pip -U 30 | python3 -m pip install -r requirements.txt -U 31 | 32 | # for host 33 | # we need the /celestial folder available on the hosts 34 | sudo mkdir -p /celestial 35 | 36 | # we also need wireguard and ipset as dependencies 37 | sudo apt-get install \ 38 | --no-install-recommends \ 39 | --no-install-suggests \ 40 | -y wireguard ipset 41 | 42 | # and we need firecracker on the machine 43 | # download the current release 44 | curl -fsSL -o firecracker-v1.6.0-x86_64.tgz \ 45 | https://github.com/firecracker-microvm/firecracker/releases/download/v1.6.0/firecracker-v1.6.0-x86_64.tgz 46 | tar -xvf firecracker-v1.6.0-x86_64.tgz 47 | # and add the firecracker and jailer binaries 48 | sudo mv release-v1.6.0-x86_64/firecracker-v1.6.0-x86_64 /usr/local/bin/firecracker 49 | sudo mv release-v1.6.0-x86_64/seccompiler-bin-v1.6.0-x86_64 /usr/local/bin/jailer 50 | 51 | sudo mv vmlinux-5.12.bin /celestial/vmlinux.bin 52 | 53 | # sometimes it can also be helpful to increase process and file handler 54 | # limits on your host machines: 55 | cat << END > ./limits.conf 56 | * soft nofile 64000 57 | * hard nofile 64000 58 | root soft nofile 64000 59 | root hard nofile 64000 60 | * soft nproc 64000 61 | * hard nproc 64000 62 | root soft nproc 64000 63 | root hard nproc 64000 64 | END 65 | 66 | sudo mv ./limits.conf /etc/security/limits.conf 67 | -------------------------------------------------------------------------------- /test/system/fileslist.txt: -------------------------------------------------------------------------------- 1 | test/system/dependencies.sh 2 | test/system/satgen.zip 3 | test/system/app/validator.img 4 | test/system/config.toml 5 | kernel/vmlinux-5.12.bin 6 | requirements.txt 7 | celestial 8 | proto 9 | celestial.py 10 | __init__.py 11 | celestial.bin 12 | -------------------------------------------------------------------------------- /test/system/getresults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial). 4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | set -xe 20 | 21 | if [ $# -ne 1 ]; then 22 | echo "Usage: $0 " 23 | exit 1 24 | fi 25 | 26 | NUM_HOSTS="$1" 27 | 28 | RESULTS_DIR="out" 29 | RESULTS_CLEAN="results.csv" 30 | 31 | TEST_HOST_NAMES=() 32 | for ((i=0;i. 17 | # 18 | 19 | set -xe 20 | 21 | # check that one argument is set 22 | if [ $# -ne 1 ]; then 23 | echo "Usage: $0 " 24 | exit 1 25 | fi 26 | 27 | # check that the argument is a number 28 | if ! [ "$1" -eq "$1" ] 2>/dev/null; then 29 | echo "Argument must be a number" 30 | exit 1 31 | fi 32 | 33 | # check that the argument is greater than 0 34 | if [ "$1" -lt 1 ]; then 35 | echo "Argument must be greater than 0" 36 | exit 1 37 | fi 38 | 39 | HOSTS="$1" 40 | 41 | ROOT="../.." 42 | 43 | # create cloud infrastructure 44 | tofu init 45 | 46 | tofu apply -auto-approve --var "hosts=$HOSTS" 47 | 48 | GCP_ZONE="$(tofu output -json | jq -r '.zone.value')" 49 | GCP_PROJECT="$(tofu output -json | jq -r '.project.value')" 50 | 51 | TEST_HOST_IDS=() 52 | for ((i=0;i "${HOST_LOGS[$i]}" 40 | done 41 | echo -n "" > "$COORD_LOG" 42 | 43 | echo "Running tests..." 44 | 45 | echo "$DIVIDER" 46 | echo "Running build.sh..." 47 | echo "$DIVIDER" 48 | ./build.sh 49 | 50 | echo "$DIVIDER" 51 | echo "Running prepare.sh..." 52 | echo "$DIVIDER" 53 | ./prepare.sh "$NUM_HOSTS" 54 | 55 | gcloud compute config-ssh 56 | INSTANCE_NAMES=() 57 | for ((i=0;i> ${HOST_LOGS[$i]} 2>&1 & 88 | done 89 | 90 | echo -n "Waiting for celestial to start." 91 | for _ in {1..10} ; do 92 | echo -n "." 93 | sleep 1 94 | done 95 | 96 | echo "$DIVIDER" 97 | echo "Running celestial coordinator on host 0..." 98 | echo "$DIVIDER" 99 | command="PYTHONUNBUFFERED=1 python3 celestial.py satgen.zip " 100 | for ((i=0;i> $COORD_LOG 2>&1 & 104 | 105 | # run for 10 minutes 106 | echo "Running for 10 minutes... (Start time: $(date))" 107 | sleep 600 108 | 109 | echo "$DIVIDER" 110 | echo "Killing celestial coordinator..." 111 | echo "$DIVIDER" 112 | # necessary to get SIGTERM to work 113 | ssh "${INSTANCE_NAMES[0]}" "sudo killall python3" 114 | 115 | # get the results 116 | echo "$DIVIDER" 117 | echo "Getting results..." 118 | echo "$DIVIDER" 119 | ./getresults.sh "$NUM_HOSTS" 120 | 121 | echo "$DIVIDER" 122 | echo "Analyzing results..." 123 | echo "$DIVIDER" 124 | mkdir -p output 125 | python3 analyze.py 126 | 127 | echo "$DIVIDER" 128 | echo "Done!" 129 | echo "$DIVIDER" 130 | 131 | # destroy the infrastructure 132 | echo "Destroying infrastructure..." 133 | echo "Run the following command to destroy the infrastructure:" 134 | echo "tofu destroy -auto-approve --var 'hosts=$NUM_HOSTS'" 135 | # tofu destroy -auto-approve 136 | --------------------------------------------------------------------------------