conlink 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/push.yml +3 -3
- package/Dockerfile +1 -1
- package/README.md +200 -12
- package/examples/test10-compose.yaml +14 -3
- package/examples/test7-compose.yaml +6 -1
- package/examples/test9-compose.yaml +8 -3
- package/link-add.sh +19 -14
- package/link-forward.sh +2 -1
- package/link-mirred.sh +8 -29
- package/mdc +38 -25
- package/net2dot.cljs +3 -3
- package/package.json +3 -2
- package/schema.yaml +12 -5
- package/scripts/copy.sh +3 -2
- package/scripts/wait.sh +1 -1
- package/src/conlink/core.cljs +107 -53
- package/src/conlink/util.cljs +1 -1
- package/test/test1.yaml +26 -0
- package/test/test10.yaml +46 -0
- package/test/test2.yaml +37 -0
- package/test/test4.yaml +80 -0
- package/test/test7.yaml +34 -0
- package/test/test9.yaml +110 -0
- package/run-tests.sh +0 -219
|
@@ -11,7 +11,7 @@ jobs:
|
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
steps:
|
|
13
13
|
- name: Checkout
|
|
14
|
-
uses: actions/checkout@
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
15
|
|
|
16
16
|
- name: npm install
|
|
17
17
|
run: npm install
|
|
@@ -19,6 +19,6 @@ jobs:
|
|
|
19
19
|
- name: compose build of conlink
|
|
20
20
|
run: docker compose -f examples/test1-compose.yaml build
|
|
21
21
|
|
|
22
|
-
- name: "
|
|
22
|
+
- name: "dctest test/test*.yaml"
|
|
23
23
|
timeout-minutes: 5
|
|
24
|
-
run: time
|
|
24
|
+
run: time node_modules/.bin/dctest --verbose-commands conlink-test $(ls -v test/test*.yaml)
|
package/Dockerfile
CHANGED
|
@@ -24,7 +24,7 @@ FROM node:16-slim as run
|
|
|
24
24
|
RUN apt-get -y update
|
|
25
25
|
# Runtime deps and utilities
|
|
26
26
|
RUN apt-get -y install libpcap-dev tcpdump iproute2 iputils-ping curl \
|
|
27
|
-
iptables bridge-utils ethtool \
|
|
27
|
+
iptables bridge-utils ethtool jq \
|
|
28
28
|
openvswitch-switch openvswitch-testcontroller
|
|
29
29
|
|
|
30
30
|
COPY --from=build /app/ /app/
|
package/README.md
CHANGED
|
@@ -1,9 +1,46 @@
|
|
|
1
1
|
# conlink: Declarative Low-Level Networking for Containers
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
Create (layer 2 and layer 3) networking between containers using
|
|
5
4
|
a declarative configuration.
|
|
6
5
|
|
|
6
|
+
Conlink also includes scripts that make docker compose a much more
|
|
7
|
+
powerful development and testing environment (refer to
|
|
8
|
+
[Compose scripts](#compose-scripts-mdc-waitsh-and-copysh) for
|
|
9
|
+
details):
|
|
10
|
+
|
|
11
|
+
* [mdc](#mdc): modular management of multiple compose configurations
|
|
12
|
+
* [wait.sh](#waitsh): wait for network and file conditions before continuing
|
|
13
|
+
* [copy.sh](#copysh): recursively copy files with variable templating
|
|
14
|
+
|
|
15
|
+
## Why conlink?
|
|
16
|
+
|
|
17
|
+
There are a number of limitations of docker-compose networking that
|
|
18
|
+
conlink addresses:
|
|
19
|
+
|
|
20
|
+
* Operates at layer 3 of the network stack (i.e. IP).
|
|
21
|
+
* Has a fixed model of container interface naming: first interface is
|
|
22
|
+
`eth0`, second is `eth1`, etc.
|
|
23
|
+
* For containers with multiple interfaces, the mapping between docker
|
|
24
|
+
compose networks and container interface is not controllable
|
|
25
|
+
(https://github.com/docker/compose/issues/4645#issuecomment-701351876,
|
|
26
|
+
https://github.com/docker/compose/issues/8561#issuecomment-1872510968)
|
|
27
|
+
* If a container uses the scale property, then IPs cannot be
|
|
28
|
+
assigned and user assigned MAC addresses will be the same for every
|
|
29
|
+
instance of that service.
|
|
30
|
+
* Docker bridge networking interferes with switch and bridge protocol
|
|
31
|
+
traffic (BPDU, STP, LLDP, etc). Conlink supports the "patch" link
|
|
32
|
+
mode that allows this type of traffic to pass correctly.
|
|
33
|
+
|
|
34
|
+
Conlink has the following features:
|
|
35
|
+
|
|
36
|
+
- Declarative network configuration (links, bridges, patches, etc)
|
|
37
|
+
- Event driven (container restarts and scale changes)
|
|
38
|
+
- Low-level control of network interfaces/links: MTU, routes, port
|
|
39
|
+
forwarding, netem properties, etc
|
|
40
|
+
- Automatic IP and MAC address incrementing for scaled containers
|
|
41
|
+
- Central network container for easy monitoring and debug
|
|
42
|
+
- Composable configuration from multiple sources/locations
|
|
43
|
+
|
|
7
44
|
## Prerequisites
|
|
8
45
|
|
|
9
46
|
General:
|
|
@@ -74,12 +111,12 @@ same bridge (broadcast domain).
|
|
|
74
111
|
Network configuration can either be loaded directly from configuration
|
|
75
112
|
files using the `--network-config` option or it can be loaded from
|
|
76
113
|
`x-network` properties contained in docker-compose files using the
|
|
77
|
-
`--compose-file
|
|
78
|
-
network configuration will be merged into a final network
|
|
79
|
-
configuration.
|
|
114
|
+
`--compose-file` option. Multiple of each option may be specified and
|
|
115
|
+
all the network configuration will be merged into a final network
|
|
116
|
+
configuration. Both options also support colon separated lists.
|
|
80
117
|
|
|
81
|
-
The network configuration can have
|
|
82
|
-
`tunnels`, and `commands`.
|
|
118
|
+
The network configuration can have four top level keys: `links`,
|
|
119
|
+
`bridges`, `tunnels`, and `commands`.
|
|
83
120
|
|
|
84
121
|
### Links
|
|
85
122
|
|
|
@@ -103,12 +140,12 @@ The following table describes the link properties:
|
|
|
103
140
|
| ip | * | CIDR | | IP CIDR 7 |
|
|
104
141
|
| mac | 3 | MAC | | MAC addr 7 |
|
|
105
142
|
| mtu | * | number 4 | 65535 | intf MTU |
|
|
106
|
-
| route | * |
|
|
143
|
+
| route | * | strings 8 | | ip route add args |
|
|
107
144
|
| nat | * | IP | | DNAT/SNAT to IP |
|
|
108
|
-
| netem | * |
|
|
145
|
+
| netem | * | strings 8 | | tc qdisc NetEm options |
|
|
109
146
|
| mode | 5 | string | | virt intf mode |
|
|
110
147
|
| vlanid | vlan | number | | VLAN ID |
|
|
111
|
-
| forward | veth |
|
|
148
|
+
| forward | veth | strings 6 8 | | forward conlink ports 7 |
|
|
112
149
|
|
|
113
150
|
- 1 - veth, dummy, vlan, ipvlan, macvlan, ipvtap, macvtap
|
|
114
151
|
- 2 - defaults to outer compose service
|
|
@@ -117,6 +154,7 @@ The following table describes the link properties:
|
|
|
117
154
|
- 5 - macvlan, macvtap, ipvlan, ipvtap
|
|
118
155
|
- 6 - string syntax: `conlink_port:container_port/proto`
|
|
119
156
|
- 7 - offset by scale/replica index
|
|
157
|
+
- 8 - either a single string or an array of strings
|
|
120
158
|
|
|
121
159
|
Each link has a 'type' key that defaults to "veth" and each link
|
|
122
160
|
definition must also have either a `service` key or a `container` key.
|
|
@@ -531,13 +569,15 @@ validate connectivity using ping:
|
|
|
531
569
|
```
|
|
532
570
|
export BRIDGE_MODE="linux" # "ovs", "patch", "auto"
|
|
533
571
|
docker-compose -f examples/test9-compose.yaml up --build --force-recreate
|
|
534
|
-
docker-compose -f examples/test9-compose.yaml exec
|
|
572
|
+
docker-compose -f examples/test9-compose.yaml exec node1 ping 10.0.1.2
|
|
535
573
|
```
|
|
536
574
|
|
|
537
|
-
### test10: port forwarding
|
|
575
|
+
### test10: port forwarding and routing
|
|
538
576
|
|
|
539
577
|
This example demonstrates port forwarding from the conlink container
|
|
540
|
-
to two containers running simple web servers.
|
|
578
|
+
to two containers running simple web servers. It also demonstrates the
|
|
579
|
+
use of a router container and multiple route rules in the other
|
|
580
|
+
containers.
|
|
541
581
|
|
|
542
582
|
Start the test10 compose configuration:
|
|
543
583
|
|
|
@@ -581,6 +621,154 @@ curl 0.0.0.0:80
|
|
|
581
621
|
curl 0.0.0.0:81
|
|
582
622
|
```
|
|
583
623
|
|
|
624
|
+
Start a two tcpdump processes in the conlink container to watch
|
|
625
|
+
routed ICMP traffic and then ping between containers across the router
|
|
626
|
+
container:
|
|
627
|
+
|
|
628
|
+
```
|
|
629
|
+
docker compose -f examples/test10-compose.yaml exec network tcpdump -nli router_1-es1 icmp
|
|
630
|
+
docker compose -f examples/test10-compose.yaml exec network tcpdump -nli router_1-es2 icmp
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
```
|
|
634
|
+
docker-compose -f examples/test10-compose.yaml exec node1 ping 10.2.0.1
|
|
635
|
+
docker-compose -f examples/test10-compose.yaml exec node1 ping 10.2.0.2
|
|
636
|
+
docker-compose -f examples/test10-compose.yaml exec node2 ping 10.1.0.1
|
|
637
|
+
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
## Compose scripts: mdc, wait.sh, and copy.sh
|
|
641
|
+
|
|
642
|
+
### mdc
|
|
643
|
+
|
|
644
|
+
The `mdc` command adds flexibility and power to the builtin overlay
|
|
645
|
+
capability of docker compose. Docker compose can specify multiple
|
|
646
|
+
compose files that will be combined into a single configuration.
|
|
647
|
+
Compose files that are specified later will overlay or override
|
|
648
|
+
earlier compose files. For example, if compose files A and B are
|
|
649
|
+
loaded by docker compose, then the `image` property of a service in
|
|
650
|
+
file B will take precedence (or override) the `image` property for the
|
|
651
|
+
same service in file A. Some properties such as `volumes` and
|
|
652
|
+
`environment` will have the sub-properties merged or appended to.
|
|
653
|
+
|
|
654
|
+
There are several ways that `mdc` adds to the composition capabilities
|
|
655
|
+
of docker compose:
|
|
656
|
+
1. **Mode/module dependency resolution**. The modes or modules that
|
|
657
|
+
are combined by `mdc` are defined as directories that contain
|
|
658
|
+
mode/module specific content. A `deps` file in a mode/module
|
|
659
|
+
directory is used to specify dependencies on other modes/modules.
|
|
660
|
+
The syntax and resolution algorithm is defined by the
|
|
661
|
+
[resolve-deps](https://github.com/Viasat/resolve-deps) project.
|
|
662
|
+
2. **Environment variable file combining/overlaying**. Each `.env`
|
|
663
|
+
file that appears in a mode/module directory will be appended into
|
|
664
|
+
a single `.env` file at the top-level where the `mdc` command is
|
|
665
|
+
invoked. Later environment variables will override earlier ones
|
|
666
|
+
with the same name. Variable interpolation and some shell-style
|
|
667
|
+
variable expansion can be used to combine/append environment
|
|
668
|
+
variables. For example if FOO and BAR are defined in an earlier
|
|
669
|
+
mode/module, then BAZ could be defined like this:
|
|
670
|
+
`BAZ="${FOO:-${BAR}-SUFF"` which will set BAZ to FOO if FOO is set,
|
|
671
|
+
otherwise, it will set BAZ to BAR with a "-SUFF" suffix.
|
|
672
|
+
3. **Directory hierarchy combining/overlaying**. If the mode/module
|
|
673
|
+
directory has subdirectories that themselves contain a "files/"
|
|
674
|
+
sub-directory, then the mode subdirectories will be recursively
|
|
675
|
+
copied into the top-level ".files/" directory. For example,
|
|
676
|
+
consider if the following files exists under the modes "foo" and
|
|
677
|
+
"bar" (with a dependency of "bar" on "foo"):
|
|
678
|
+
`foo/svc1/files/etc/conf1`, `foo/svc2/files/etc/conf2`, and
|
|
679
|
+
`bar/svc1/files/etc/conf1`. When `mdc` is run this will result in
|
|
680
|
+
the following two files: `.files/svc1/etc/conf1` and
|
|
681
|
+
`.files/svc2/etc/conf2`. The content of `conf1` will come from the
|
|
682
|
+
"bar" mode because it is resolved second. The use of the `copy.sh`
|
|
683
|
+
script (described below) simplifies recursive file copying and also
|
|
684
|
+
provides variable templating of copied files.
|
|
685
|
+
4. **Set environment variables based on the selected modes/modules**.
|
|
686
|
+
When `mdc` is run it will set the following special environment
|
|
687
|
+
variables in the top-level `.env` file:
|
|
688
|
+
* `COMPOSE_FILE`: A colon separated and dependency ordered list of
|
|
689
|
+
compose file paths from each resolved mode/module directory.
|
|
690
|
+
* `COMPOSE_DIR`: The directory where the top-level `.env` is
|
|
691
|
+
created.
|
|
692
|
+
* `COMPOSE_PRPOFILES`: A comma separated list of each resolved
|
|
693
|
+
mode/module with a `MODE_` prefix on the name. These are docker
|
|
694
|
+
compose profiles that can be used to enable services in one
|
|
695
|
+
mode/module compose file when a different mode/module is
|
|
696
|
+
selected/resolved by `mdc`. For example, if a compose file in
|
|
697
|
+
"bar" has a service that should only be enabled when the "foo"
|
|
698
|
+
mode/module is also requested/resolved, then the service can be
|
|
699
|
+
tagged with the `MODE_foo` profile.
|
|
700
|
+
* `MDC_MODE_DIRS`: A comma separated list of mode/module
|
|
701
|
+
directories. This can be used by other external tools that have
|
|
702
|
+
specific mode/module behavior.
|
|
703
|
+
|
|
704
|
+
Conlink network configuration can be specified in `x-network`
|
|
705
|
+
properties within compose files. This can be a problem with the
|
|
706
|
+
builtin overlay functionality of docker compose because `x-` prefixed
|
|
707
|
+
properties are simply overriden as a whole without any special merging
|
|
708
|
+
behavior. To work around this limitation, conlink has the ability to
|
|
709
|
+
directly merge `x-network` configuration from multiple compose files
|
|
710
|
+
by passing the `COMPOSE_FILE` variable to the conlink `--compose-file`
|
|
711
|
+
parameter (which supports a colon sperated list of compose files).
|
|
712
|
+
|
|
713
|
+
### wait.sh
|
|
714
|
+
|
|
715
|
+
The dynamic event driven nature of conlink mean that interfaces may
|
|
716
|
+
appear after the container service code starts running (unlike plain
|
|
717
|
+
docker container networking). For this reason, the `wait.sh` script is
|
|
718
|
+
provided to simplify waiting for interfaces to appear (and other
|
|
719
|
+
network conditions). Here is a compose file snippit that will wait for
|
|
720
|
+
`eth0` to appear and for `eni1` to both appear and have an IP address
|
|
721
|
+
assigned before running the startup command (after the `--`):
|
|
722
|
+
|
|
723
|
+
```
|
|
724
|
+
services:
|
|
725
|
+
svc1:
|
|
726
|
+
volumes:
|
|
727
|
+
- ./conlink/scripts:/scripts:ro
|
|
728
|
+
command: /scripts/wait.sh -i eth0 -I eni1 -- /start-cmd.sh arg1 arg2
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
In addition to waiting for interfaces and address assignment,
|
|
732
|
+
`wait.sh` can also wait for a file to appear (`-f FILE`), a remote TCP
|
|
733
|
+
port to become accessible (`-t HOST:PORT`), or run a command until it
|
|
734
|
+
completes successfully (`-c COMMAND`).
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
### copy.sh
|
|
738
|
+
|
|
739
|
+
One of the features of the `mdc` command is to collect directory
|
|
740
|
+
hierarchies from mode/module directories into a single `.files/`
|
|
741
|
+
directory at the top-level. The intended use of the merged directory
|
|
742
|
+
hierarchy is to be merged into file-systems of running containers.
|
|
743
|
+
However, simple volume mounts will replace entire directory
|
|
744
|
+
hierarchies (and hide all prior files under the mount point). The
|
|
745
|
+
`copy.sh` script is provided for easily merging/overlaying one
|
|
746
|
+
directory hierarchy onto another one. In addition, the `-T` option
|
|
747
|
+
will also replace special `{{VAR}}` tokens in the files being copied
|
|
748
|
+
with the value of the matching environment variable.
|
|
749
|
+
|
|
750
|
+
Here is a compose file snippit that shows the use of `copy.sh` to
|
|
751
|
+
recursively copy/overlay the directory tree in `./.files/svc2` onto
|
|
752
|
+
the container root file-system. In addition, due to the use of the
|
|
753
|
+
`-T` option, the script will replace any occurence of the string
|
|
754
|
+
`{{FOO}}` with the value of the `FOO` environment variable within any
|
|
755
|
+
of the files that are copied:
|
|
756
|
+
|
|
757
|
+
```
|
|
758
|
+
services:
|
|
759
|
+
svc2:
|
|
760
|
+
environment:
|
|
761
|
+
- FOO=123
|
|
762
|
+
volumes:
|
|
763
|
+
- ./.files/svc2:/files:ro
|
|
764
|
+
command: /scripts/copy.sh -T /files / -- /start-cmd.sh arg1 arg2
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
Note that instances of `copy.sh` and `wait.sh` can be easily chained
|
|
768
|
+
together like this:
|
|
769
|
+
```
|
|
770
|
+
/scripts/copy.sh -T /files / -- /scripts/wait.sh -i eth0 -- cmd args
|
|
771
|
+
```
|
|
584
772
|
|
|
585
773
|
## GraphViz network configuration rendering
|
|
586
774
|
|
|
@@ -7,7 +7,8 @@ services:
|
|
|
7
7
|
command: "python3 -m http.server -d /var 80"
|
|
8
8
|
x-network:
|
|
9
9
|
links:
|
|
10
|
-
- {bridge:
|
|
10
|
+
- {bridge: s1, ip: "10.1.0.1/24",
|
|
11
|
+
route: ["10.0.0.0/8 via 10.1.0.100"],
|
|
11
12
|
forward: ["1080:80/tcp", "1180:80/tcp"]}
|
|
12
13
|
|
|
13
14
|
node2:
|
|
@@ -17,8 +18,18 @@ services:
|
|
|
17
18
|
command: "python3 -m http.server -d /usr 80"
|
|
18
19
|
x-network:
|
|
19
20
|
links:
|
|
20
|
-
- {bridge:
|
|
21
|
-
|
|
21
|
+
- {bridge: s2, ip: "10.2.0.1/24",
|
|
22
|
+
route: "10.0.0.0/8 via 10.2.0.100",
|
|
23
|
+
forward: "80:80/tcp"}
|
|
24
|
+
|
|
25
|
+
router:
|
|
26
|
+
image: python:3-alpine
|
|
27
|
+
network_mode: none
|
|
28
|
+
command: sleep Infinity
|
|
29
|
+
x-network:
|
|
30
|
+
links:
|
|
31
|
+
- {bridge: s1, ip: "10.1.0.100/24", dev: es1}
|
|
32
|
+
- {bridge: s2, ip: "10.2.0.100/24", dev: es2}
|
|
22
33
|
|
|
23
34
|
network:
|
|
24
35
|
build: {context: ../}
|
|
@@ -28,7 +28,12 @@ services:
|
|
|
28
28
|
ip: 10.0.1.1/16
|
|
29
29
|
mac: 00:0a:0b:0c:0d:01
|
|
30
30
|
mtu: 4111
|
|
31
|
-
netem: "delay 40ms
|
|
31
|
+
netem: "rate 10mbit delay 40ms"
|
|
32
32
|
- bridge: s2
|
|
33
33
|
ip: 100.0.1.1/16
|
|
34
34
|
dev: eth1
|
|
35
|
+
|
|
36
|
+
x-network:
|
|
37
|
+
links:
|
|
38
|
+
# The delay setting is overridden by the one in the service
|
|
39
|
+
- {service: node, bridge: s1, netem: "delay 200ms"}
|
|
@@ -19,14 +19,19 @@ services:
|
|
|
19
19
|
- BRIDGE_MODE
|
|
20
20
|
command: /app/build/conlink.js --default-bridge-mode linux --compose-file /test/test9-compose.yaml
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
node1:
|
|
23
|
+
image: alpine
|
|
24
|
+
network_mode: none
|
|
25
|
+
command: sleep Infinity
|
|
26
|
+
|
|
27
|
+
node2:
|
|
23
28
|
image: alpine
|
|
24
29
|
network_mode: none
|
|
25
|
-
scale: 2
|
|
26
30
|
command: sleep Infinity
|
|
27
31
|
|
|
28
32
|
x-network:
|
|
29
33
|
links:
|
|
30
|
-
- {bridge: s1, service:
|
|
34
|
+
- {bridge: s1, service: node1, ip: 10.0.1.1/24}
|
|
35
|
+
- {bridge: s1, service: node2, ip: 10.0.1.2/24}
|
|
31
36
|
bridges:
|
|
32
37
|
- {bridge: s1, mode: "${BRIDGE_MODE:-auto}"}
|
package/link-add.sh
CHANGED
|
@@ -32,9 +32,8 @@ usage () {
|
|
|
32
32
|
echo >&2 " --mac MAC0 - MAC address for INTF0"
|
|
33
33
|
echo >&2 " --mac0 MAC0 - MAC address for INTF0"
|
|
34
34
|
echo >&2 " --mac1 MAC1 - MAC address for INTF1"
|
|
35
|
-
echo >&2 " --route
|
|
36
|
-
echo >&2 " --
|
|
37
|
-
echo >&2 " --route1 'ROUTE' - route to add to INTF1"
|
|
35
|
+
echo >&2 " --route|--route0 'ROUTE' - route to add to INTF0 (can repeat)"
|
|
36
|
+
echo >&2 " --route1 'ROUTE' - route to add to INTF1 (can repeat)"
|
|
38
37
|
echo >&2 " --mtu MTU - MTU for both interfaces"
|
|
39
38
|
echo >&2 ""
|
|
40
39
|
echo >&2 " --mode MODE - Mode settings for *vlan TYPEs"
|
|
@@ -43,7 +42,7 @@ usage () {
|
|
|
43
42
|
echo >&2 " --remote REMOTE - Remote address for geneve/vxlan types"
|
|
44
43
|
echo >&2 " --vni VNI - Virtual Network Identifier for geneve/vxlan types"
|
|
45
44
|
echo >&2 ""
|
|
46
|
-
echo >&2 " --netem NETEM - tc qdisc netem OPTIONS (man 8 netem)"
|
|
45
|
+
echo >&2 " --netem NETEM - tc qdisc netem OPTIONS (man 8 netem) (can repeat)"
|
|
47
46
|
echo >&2 " --nat TARGET - Stateless NAT traffic to/from TARGET"
|
|
48
47
|
echo >&2 " (in primary/PID0 netns)"
|
|
49
48
|
echo >&2 ""
|
|
@@ -54,17 +53,21 @@ info() { echo "link-add [${LOG_ID}] ${*}"; }
|
|
|
54
53
|
warn() { >&2 echo "link-add [${LOG_ID}] ${*}"; }
|
|
55
54
|
die() { warn "ERROR: ${*}"; exit 1; }
|
|
56
55
|
|
|
57
|
-
# Set MAC, IP,
|
|
56
|
+
# Set MAC, IP, ROUTES, MTU, and up state for interface in netns
|
|
58
57
|
setup_if() {
|
|
59
|
-
local IF=$1 NS=$2 MAC=$3 IP=$4
|
|
58
|
+
local IF=$1 NS=$2 MAC=$3 IP=$4 MTU=$5 ROUTES=$6 routes=
|
|
59
|
+
echo >&2 "ROUTES: ${ROUTES}"
|
|
60
|
+
while read rt; do
|
|
61
|
+
[ "${rt}" ] && routes="${routes}\nroute add ${rt} dev ${IF}"
|
|
62
|
+
done < <(echo -e "${ROUTES}")
|
|
60
63
|
|
|
61
|
-
info "Setting ${IP:+IP ${IP}, }${MAC:+MAC ${MAC}, }${MTU:+MTU ${MTU}, }${
|
|
64
|
+
info "Setting ${IP:+IP ${IP}, }${MAC:+MAC ${MAC}, }${MTU:+MTU ${MTU}, }${ROUTES:+ROUTES '${ROUTES//$'\n'/,}', }up state"
|
|
62
65
|
ip -netns ${NS} --force -b - <<EOF
|
|
63
66
|
${IP:+addr add ${IP} dev ${IF}}
|
|
64
67
|
${MAC:+link set dev ${IF} address ${MAC}}
|
|
65
68
|
${MTU:+link set dev ${IF} mtu ${MTU}}
|
|
66
69
|
link set dev ${IF} up
|
|
67
|
-
$
|
|
70
|
+
$(echo -e "${routes}")
|
|
68
71
|
EOF
|
|
69
72
|
}
|
|
70
73
|
|
|
@@ -78,7 +81,7 @@ IPTABLES() {
|
|
|
78
81
|
# Parse arguments
|
|
79
82
|
VERBOSE=${VERBOSE:-}
|
|
80
83
|
PID1=${PID1:-<SELF>} IF1=${IF1:-eth0}
|
|
81
|
-
IP0= IP1= MAC0= MAC1=
|
|
84
|
+
IP0= IP1= MAC0= MAC1= ROUTES0= ROUTES1= MTU=
|
|
82
85
|
MODE= VLANID= REMOTE= VNI= NETEM= NAT=
|
|
83
86
|
positional=
|
|
84
87
|
while [ "${*}" ]; do
|
|
@@ -91,8 +94,8 @@ while [ "${*}" ]; do
|
|
|
91
94
|
--ip1) IP1="${OPTARG}"; shift ;;
|
|
92
95
|
--mac|--mac0) MAC0="${OPTARG}"; shift ;;
|
|
93
96
|
--mac1) MAC1="${OPTARG}"; shift ;;
|
|
94
|
-
--route|--route0)
|
|
95
|
-
--route1)
|
|
97
|
+
--route|--route0) ROUTES0="${ROUTES0}\n${OPTARG}"; shift ;;
|
|
98
|
+
--route1) ROUTES1="${ROUTES1}\n${OPTARG}"; shift ;;
|
|
96
99
|
--mtu) MTU="${OPTARG}"; shift ;;
|
|
97
100
|
|
|
98
101
|
--mode) MODE="${OPTARG}"; shift ;;
|
|
@@ -101,13 +104,15 @@ while [ "${*}" ]; do
|
|
|
101
104
|
--remote) REMOTE="${OPTARG}"; shift ;;
|
|
102
105
|
--vni) VNI="${OPTARG}"; shift ;;
|
|
103
106
|
|
|
104
|
-
--netem) NETEM="${OPTARG}"; shift ;;
|
|
107
|
+
--netem) NETEM="${NETEM} ${OPTARG}"; shift ;;
|
|
105
108
|
--nat) NAT="${OPTARG}"; shift ;;
|
|
106
109
|
-h|--help) usage ;;
|
|
107
110
|
*) positional="${positional} $1" ;;
|
|
108
111
|
esac
|
|
109
112
|
shift
|
|
110
113
|
done
|
|
114
|
+
ROUTES0="${ROUTES0#\\n}"
|
|
115
|
+
ROUTES1="${ROUTES1#\\n}"
|
|
111
116
|
set -- ${positional}
|
|
112
117
|
TYPE=$1 PID0=$2 IF0=$3
|
|
113
118
|
|
|
@@ -181,9 +186,9 @@ geneve|vxlan)
|
|
|
181
186
|
;;
|
|
182
187
|
esac
|
|
183
188
|
|
|
184
|
-
setup_if ${IF0} ${NS0} "${MAC0}" "${IP0}" "${
|
|
189
|
+
setup_if ${IF0} ${NS0} "${MAC0}" "${IP0}" "${MTU}" "${ROUTES0}"
|
|
185
190
|
[ "${TYPE}" = "veth" ] && \
|
|
186
|
-
setup_if ${IF1} ${NS1} "${MAC1}" "${IP1}" "${
|
|
191
|
+
setup_if ${IF1} ${NS1} "${MAC1}" "${IP1}" "${MTU}" "${ROUTES1}"
|
|
187
192
|
|
|
188
193
|
if [ "${NETEM}" ]; then
|
|
189
194
|
info "Setting tc qdisc netem: ${NETEM}"
|
package/link-forward.sh
CHANGED
|
@@ -37,7 +37,8 @@ LOG_ID="${spec}"
|
|
|
37
37
|
info "${action^} forwarding ${intf_a} -> ${intf_b}"
|
|
38
38
|
|
|
39
39
|
IPTABLES PREROUTING -t nat -i ${intf_a} -p ${proto} --dport ${port_a} -j DNAT --to-destination ${ip}:${port_b}
|
|
40
|
-
IPTABLES
|
|
40
|
+
IPTABLES PREROUTING -t nat -i ${intf_a} -p ${proto} --dport ${port_a} -j MARK --set-mark 1
|
|
41
|
+
IPTABLES POSTROUTING -t nat -o ${intf_b} -m mark --mark 1 -j MASQUERADE
|
|
41
42
|
|
|
42
43
|
case "${action}" in
|
|
43
44
|
add) ip route replace ${ip} dev ${intf_b} ;;
|
package/link-mirred.sh
CHANGED
|
@@ -34,41 +34,20 @@ die() { warn "ERROR: ${*}"; exit 1; }
|
|
|
34
34
|
add_ingress() {
|
|
35
35
|
local IF=$1 res=
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
info "${IF0} already has ingress qdisc"
|
|
41
|
-
;;
|
|
42
|
-
""|*"qdisc noqueue"*)
|
|
43
|
-
info "Adding ingress qdisc to ${IF}"
|
|
44
|
-
tc qdisc add dev "${IF}" ingress \
|
|
45
|
-
|| die "Could not add ingress qdisc to ${IF}"
|
|
46
|
-
;;
|
|
47
|
-
*)
|
|
48
|
-
die "${IF} has invalid ingress qdisc or could not be queried"
|
|
49
|
-
;;
|
|
50
|
-
esac
|
|
37
|
+
info "Adding ingress qdisc to ${IF}"
|
|
38
|
+
tc qdisc replace dev "${IF}" ingress \
|
|
39
|
+
|| die "Could not add ingress qdisc to ${IF}"
|
|
51
40
|
}
|
|
52
41
|
|
|
53
42
|
# Idempotently add mirred filter redirect rule to an interface
|
|
54
43
|
add_mirred() {
|
|
55
44
|
local IF0=$1 IF1=$2 res=
|
|
56
45
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"")
|
|
63
|
-
info "Adding filter redirect action from ${IF0} to ${IF1}"
|
|
64
|
-
tc filter add dev ${IF0} parent ffff: protocol all u32 match u8 0 0 action \
|
|
65
|
-
mirred egress redirect dev ${IF1} \
|
|
66
|
-
|| die "Could not add filter redirect action from ${IF0} to ${IF1}"
|
|
67
|
-
;;
|
|
68
|
-
*)
|
|
69
|
-
die "${IF0} has invalid filter redirect action or could not be queried"
|
|
70
|
-
;;
|
|
71
|
-
esac
|
|
46
|
+
info "Adding filter redirect action from ${IF0} to ${IF1}"
|
|
47
|
+
tc filter del dev ${IF0} root
|
|
48
|
+
tc filter replace dev ${IF0} parent ffff: protocol all u32 match u8 0 0 action \
|
|
49
|
+
mirred egress redirect dev ${IF1} \
|
|
50
|
+
|| die "Could not add filter redirect action from ${IF0} to ${IF1}"
|
|
72
51
|
}
|
|
73
52
|
|
|
74
53
|
# Parse arguments
|
package/mdc
CHANGED
|
@@ -17,21 +17,18 @@ LS=$(which ls)
|
|
|
17
17
|
RESOLVE_DEPS="${RESOLVE_DEPS-./node_modules/@lonocloud/resolve-deps/resolve-deps.py}"
|
|
18
18
|
DOCKER_COMPOSE="${DOCKER_COMPOSE:-docker-compose}"
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
which ${RESOLVE_DEPS} >/dev/null 2>/dev/null \
|
|
21
|
+
|| die "Missing ${RESOLVE_DEPS}. Perhaps 'npm install'?"
|
|
22
|
+
|
|
23
|
+
# Resolve mode directory paths
|
|
24
|
+
|
|
21
25
|
MODE_SPEC="${1}"; shift
|
|
22
|
-
|
|
23
|
-
MODES="$(${RESOLVE_DEPS} "${MODES_DIR}" ${MODE_SPEC})"
|
|
24
|
-
else
|
|
25
|
-
MODES="${MODE_SPEC//,/ }"
|
|
26
|
-
fi
|
|
26
|
+
RESOLVED_MODES="$(${RESOLVE_DEPS} --path "${MODES_DIR}" --format=paths ${MODE_SPEC})"
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
# Create base (empty) compose file to anchor mode relative paths
|
|
29
|
+
# to the same root directory. Create files dir.
|
|
30
30
|
|
|
31
|
-
declare -A FINISHED
|
|
32
31
|
COMPOSE_FILE=./.compose-empty.yaml
|
|
33
|
-
COMPOSE_PROFILES=
|
|
34
|
-
MDC_MODE_DIRS=
|
|
35
32
|
cat /dev/null > ${ENV_FILE}-mdc-tmp
|
|
36
33
|
echo -e "version: '2.4'\nservices: {}" > ./.compose-empty.yaml
|
|
37
34
|
|
|
@@ -42,19 +39,25 @@ esac
|
|
|
42
39
|
[ -d "${MDC_FILES_DIR}" ] && rm -r${VERBOSE:+v} ${MDC_FILES_DIR}/
|
|
43
40
|
mkdir -p "${MDC_FILES_DIR}"
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
# Incorporate modes' compose config, env, and files
|
|
43
|
+
|
|
44
|
+
declare -A FINISHED
|
|
45
|
+
COMPOSE_PROFILES=
|
|
46
|
+
MDC_MODE_NAMES=
|
|
47
|
+
MDC_MODE_DIRS=
|
|
48
|
+
for resolved in ${RESOLVED_MODES}; do
|
|
49
|
+
mode=${resolved%=*}
|
|
50
|
+
path=${resolved#*=}
|
|
51
|
+
|
|
46
52
|
# Only process each mode once
|
|
47
53
|
[ "${FINISHED[${mode}]}" ] && continue
|
|
48
54
|
FINISHED["${mode}"]=1
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
die "No mode dir found for ${mode}"
|
|
53
|
-
|
|
54
|
-
MDC_MODE_DIRS="${MDC_MODE_DIRS},${MODES_DIR}/${mode}"
|
|
56
|
+
MDC_MODE_NAMES="${MDC_MODE_NAMES} ${mode}"
|
|
57
|
+
MDC_MODE_DIRS="${MDC_MODE_DIRS},${path}"
|
|
55
58
|
|
|
56
59
|
# mode can refer to a compose file in multiple ways
|
|
57
|
-
cfiles="${
|
|
60
|
+
cfiles="${path}/compose.yaml ${path}/compose.yml ${path}/docker-compose.yaml ${path}/docker-compose.yml"
|
|
58
61
|
for cfile in ${cfiles}; do
|
|
59
62
|
if [ -e "${cfile}" ]; then
|
|
60
63
|
COMPOSE_FILE="${COMPOSE_FILE}:${cfile}"
|
|
@@ -66,27 +69,35 @@ for mode in ${MODES}; do
|
|
|
66
69
|
COMPOSE_PROFILES="${COMPOSE_PROFILES},MODE_${mode}"
|
|
67
70
|
|
|
68
71
|
# if there is a mode specific env file then include it
|
|
69
|
-
efiles="${
|
|
72
|
+
efiles="${path}/env ${path}/.env"
|
|
70
73
|
for efile in ${efiles}; do
|
|
71
74
|
if [ -e "${efile}" ]; then
|
|
72
|
-
echo "### mdc begin mode ${mode}" >> ${ENV_FILE}-mdc-tmp
|
|
75
|
+
echo "### mdc begin mode ${mode} (${efile})" >> ${ENV_FILE}-mdc-tmp
|
|
73
76
|
vecho "cat ${efile} >> ${ENV_FILE}-mdc-tmp"
|
|
74
77
|
cat ${efile} >> ${ENV_FILE}-mdc-tmp
|
|
75
|
-
echo
|
|
78
|
+
echo >> ${ENV_FILE}-mdc-tmp
|
|
79
|
+
echo "### mdc end mode ${mode} (${efile})" >> ${ENV_FILE}-mdc-tmp
|
|
76
80
|
fi
|
|
77
81
|
done
|
|
78
82
|
|
|
79
83
|
# if there are mode specific files then copy them to MDC_FILES_DIR
|
|
80
|
-
if [ -d "${
|
|
81
|
-
for vfd in $(cd ${
|
|
84
|
+
if [ -d "${path}" ]; then
|
|
85
|
+
for vfd in $(cd ${path} && $LS -d */files 2>/dev/null || true); do
|
|
82
86
|
dest=${MDC_FILES_DIR}/${vfd%/files}
|
|
83
87
|
mkdir -p ${dest}
|
|
84
|
-
vecho cp -a ${
|
|
85
|
-
cp -a ${
|
|
88
|
+
vecho cp -a ${path}/${vfd}/* ${dest}
|
|
89
|
+
cp -a ${path}/${vfd}/* ${dest}
|
|
86
90
|
done
|
|
87
91
|
fi
|
|
88
92
|
done
|
|
89
93
|
|
|
94
|
+
vecho
|
|
95
|
+
|
|
96
|
+
# Summarize and set env
|
|
97
|
+
|
|
98
|
+
echo >&2 "MODES: ${MDC_MODE_NAMES}"
|
|
99
|
+
vecho "ENV_FILE: ${ENV_FILE}"
|
|
100
|
+
|
|
90
101
|
COMPOSE_FILE="${COMPOSE_FILE#:}"
|
|
91
102
|
vecho "COMPOSE_FILE: ${COMPOSE_FILE}"
|
|
92
103
|
echo "COMPOSE_FILE=${COMPOSE_FILE}" >> ${ENV_FILE}-mdc-tmp
|
|
@@ -100,6 +111,8 @@ MDC_MODE_DIRS="${MDC_MODE_DIRS#,}"
|
|
|
100
111
|
vecho "MDC_MODE_DIRS: ${MDC_MODE_DIRS}"
|
|
101
112
|
echo "MDC_MODE_DIRS=\"${MDC_MODE_DIRS}\"" >> ${ENV_FILE}-mdc-tmp
|
|
102
113
|
|
|
114
|
+
vecho
|
|
115
|
+
|
|
103
116
|
vecho mv ${ENV_FILE}-mdc-tmp ${ENV_FILE}
|
|
104
117
|
mv ${ENV_FILE}-mdc-tmp ${ENV_FILE}
|
|
105
118
|
|
package/net2dot.cljs
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
(S/replace #"[*]" "_STAR_")
|
|
30
30
|
(S/replace #"[$]" "_DOLLAR_")
|
|
31
31
|
(S/replace #"[{]" "_LCURLY_")
|
|
32
|
-
(S/replace #"[}]" "
|
|
32
|
+
(S/replace #"[}]" "_RCURLY_")
|
|
33
33
|
(S/replace #"[ ]" "_SPACE_")))
|
|
34
34
|
|
|
35
35
|
(defn node-props [label props]
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
#(->> (subgraph conlink (str "cluster_bridge_" %2)
|
|
62
62
|
%2 BRIDGE-PROPS)
|
|
63
63
|
(assoc %1 %2))
|
|
64
|
-
{} (keep :bridge (:links network-config)))
|
|
64
|
+
{} (map :bridge (keep :bridge (:links network-config))))
|
|
65
65
|
services (reduce
|
|
66
66
|
#(->> (subgraph host (str "cluster_service_" (dot-id %2))
|
|
67
67
|
(str "service '" (name %2) "'") SVC-PROPS)
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"-" (name dev)))
|
|
86
86
|
out-id (str "out-" outer-dev)
|
|
87
87
|
out-parent (condp = (keyword base)
|
|
88
|
-
:conlink (get bridges bridge)
|
|
88
|
+
:conlink (get bridges (:bridge bridge))
|
|
89
89
|
:host host)
|
|
90
90
|
{:keys [type vlanid]} link
|
|
91
91
|
[elabel iprops] (if (= "host" base)
|