Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ dmicmp_v4_send_echo_request(&dst, my_identifier, 1, NULL, 0, DMARP_DEFAULT_TIMEO
It's its own Application-type DMOD module (`ping`), released alongside
`dmicmp` itself in every tagged release.

## Running as a service

dmicmp answers pings as soon as it's loaded, but being a Library-type
module it has no `main()` to spawn on its own - something still needs to
load it. **[configs/](configs/)** has a
[dmsystem](https://github.com/choco-technologies/dmsystem)/`libsystemd`
unit (`icmp.ini`) plus the two `dmell` scripts it runs
(`icmp-start.dme`/`icmp-stop.dme`, each a one-line `module load`/`module
unload dmicmp`) so ping response can be enabled at boot and toggled off
again. See [docs/service.md](docs/service.md) for the full setup and why
there's no `service stop icmp`.

## API

| Function | Description |
Expand All @@ -105,12 +117,17 @@ See the `docs/` directory:

- **[dmicmp.md](docs/dmicmp.md)** - Design overview and rationale
- **[api-reference.md](docs/api-reference.md)** - Complete API documentation
- **[service.md](docs/service.md)** - Running ICMP echo response as a `dmsystem` service

View documentation using `dmf-man dmicmp`.
## Project Structure

```
dmicmp/
├── configs/ # dmsystem unit + dmell scripts to load/unload dmicmp as a service
│ ├── icmp.ini
│ ├── icmp-start.dme
│ └── icmp-stop.dme
├── docs/ # Documentation (markdown format)
├── include/ # Public headers
│ └── dmicmp.h
Expand Down
11 changes: 11 additions & 0 deletions configs/icmp-start.dme
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/dmell
#
# icmp-start.dme - loads the dmicmp module, which registers itself with dmip
# as the ICMPv4/ICMPv6 protocol handler from its own dmod_init() (see
# ../src/dmicmp.c) - once loaded, this device starts answering ICMP Echo
# Requests (ping) automatically, with no further setup needed. Run standalone
# (e.g. `dmell icmp-start.dme`) or as icmp.ini's exec, to load it at boot -
# see ../docs/service.md.

module load dmicmp
exit $?
10 changes: 10 additions & 0 deletions configs/icmp-stop.dme
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/dmell
#
# icmp-stop.dme - unloads the dmicmp module (dmod_deinit() unregisters it
# from dmip, see ../src/dmicmp.c), so this device stops answering ICMP Echo
# Requests (ping) until icmp-start.dme is run again. Not wired into icmp.ini
# as an "ExecStop" - dmsystem's libsystemd has no such key yet (see
# ../docs/service.md) - so run this one directly, e.g. `dmell icmp-stop.dme`.

module unload dmicmp
exit $?
19 changes: 19 additions & 0 deletions configs/icmp.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# icmp.ini - dmsystem unit that loads the dmicmp module at boot, so this
# device starts answering ICMP Echo Requests (ping) with no manual step.
# Drop it into libsystemd's units directory - see dmsystem's configuration
# docs (https://github.com/choco-technologies/dmsystem/blob/main/app/libsystemd/docs/configuration.md)
# - and adjust the path in "args" below to wherever this dmicmp release was
# installed (${destination}/dmicmp/configs/icmp-start.dme, if installed via
# dmicmp.dmr's own "configs" entry). See ../docs/service.md for the full
# rationale.
description=Answer ICMP Echo Requests (ping) by loading the dmicmp module
exec=dmell
args=/opt/dmicmp/configs/icmp-start.dme
type=oneshot

# type=oneshot: icmp-start.dme only needs to run once - dmicmp stays loaded
# and answering pings on its own once dmod_init() has run (see
# ../src/dmicmp.c), so there is no long-running process for this unit to
# keep alive. "service stop icmp" has nothing left to kill once this has run
# to completion - libsystemd has no ExecStop-style key yet - so to stop
# answering pings, run icmp-stop.dme directly instead (see ../docs/service.md).
5 changes: 5 additions & 0 deletions dmicmp.dmr
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ docs=./docs => ${destination}/${module}/docs [origin=${repo_dir}/docs]
# README file
readme=./README.md => ${destination}/${module}/README.md [origin=${repo_dir}/README.md]

# === Configuration Files ===
# icmp.ini dmsystem unit + icmp-start.dme/icmp-stop.dme dmell scripts that
# load/unload dmicmp to turn ICMP echo (ping) response on/off - see docs/service.md
configs=./configs => ${destination}/${module}/configs [origin=${repo_dir}/configs]

# === Header Files ===
# Include directory with all headers (public header + generated <module>_defs.h)
inc=./include => ${destination}/${module}/include [origin=${repo_dir}/include] [origin=${build_dir}/${module}_defs.h]
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Welcome to the dmicmp module documentation.

- **[dmicmp.md](dmicmp.md)** - Design overview and rationale
- **[api-reference.md](api-reference.md)** - Complete API documentation
- **[service.md](service.md)** - Running ICMP echo response as a `dmsystem` service

## Quick Reference

Expand Down
78 changes: 78 additions & 0 deletions docs/service.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# ICMP echo response as a dmsystem service

## Why this exists

dmicmp needs no setup from other modules to do its core job - it registers
itself with [dmip](https://github.com/choco-technologies/dmip) automatically
in `dmod_init()` (see `src/dmicmp.c`), and from that point on answers ICMP
Echo Requests (ping) with no further calls needed. The catch is exactly that:
`dmod_init()` only runs once something *loads* dmicmp - nothing does that on
its own at boot. `configs/` gives
[dmsystem](https://github.com/choco-technologies/dmsystem)'s `libsystemd` a
way to do it automatically.

## Why a `.dme` script instead of `exec=dmicmp` directly

dmicmp is a **Library**-type DMOD module (see `CMakeLists.txt`), not an
Application - it has no `main()`, so nothing can spawn it as a process the
way `libsystemd` starts a unit (`Dmod_RunModuleDetached`, see dmsystem's
[`app/libsystemd/docs/configuration.md`](https://github.com/choco-technologies/dmsystem/blob/main/app/libsystemd/docs/configuration.md)).
What actually needs to happen is "load this module into the running DMOD
system", which is a different operation - the one
[`dmell`](https://github.com/choco-technologies/dmell) exposes as its own
`module load`/`module unload` built-in. `configs/icmp-start.dme` and
`configs/icmp-stop.dme` are two-line wrappers over exactly that, so a
`libsystemd` unit (whose `exec` must be something it can spawn) can drive
them the same way it drives any other unit.

## Files

| File | Does |
|------|------|
| [`configs/icmp-start.dme`](../configs/icmp-start.dme) | `module load dmicmp` - starts answering pings. |
| [`configs/icmp-stop.dme`](../configs/icmp-stop.dme) | `module unload dmicmp` - stops answering pings. |
| [`configs/icmp.ini`](../configs/icmp.ini) | The dmsystem unit itself: `exec=dmell`, `args=<path to icmp-start.dme>`, `type=oneshot`. |

## Why `type=oneshot`, and why there is no "stop"

`icmp-start.dme` only needs to run once: unlike a `type=simple` unit (a
server expected to keep running until explicitly stopped), dmicmp stays
loaded - and answering pings - entirely on its own once `dmod_init()` has
run, independent of the script or process that triggered it. `type=oneshot`
tells `libsystemd` this exit is expected, not a crash (see dmsystem's
configuration docs, "Service type").

This does mean `service stop icmp` has nothing to act on: `libsystemd` stops
a unit by killing its tracked process
(`libsystemd_stop_service_internal()`), and a oneshot unit's process is
already gone by the time it would run. `libsystemd` also has no `ExecStop`-
style key yet - a unit file has no way to name a separate command to run on
stop. So turning ping response back off is a deliberate separate step, not
something `service stop icmp` does: run `icmp-stop.dme` directly.

```bash
dmell /opt/dmicmp/configs/icmp-stop.dme
```

Whether dmicmp is currently answering pings or not is therefore controlled
entirely by which of the two scripts was last run - `module load`/`module
unload` are idempotent-safe either way (loading an already-loaded module or
unloading an already-unloaded one just fails harmlessly and is logged, it
does not crash the shell).

## Enabling at boot

Install dmicmp with its `.dmr` (see the root [README.md](../README.md)), then
drop `icmp.ini` into `libsystemd`'s units directory and point its `args` at
wherever `icmp-start.dme` was installed:

```bash
cp /opt/dmicmp/configs/icmp.ini /etc/dmsystem/units/icmp.ini
# args= in icmp.ini must match the actual install path, e.g.:
# args=/opt/dmicmp/configs/icmp-start.dme
dmod_loader systemd.dmf --args "/etc/dmsystem/units"
```

See also dmsystem's [configuration.md](https://github.com/choco-technologies/dmsystem/blob/main/app/libsystemd/docs/configuration.md#dependency-ordering)
if you want dmicmp brought up only `after`/once a particular network
interface unit (`after=`/`requires=` in `icmp.ini`) is already running.
Loading