conlink 2.0.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.
Files changed (59) hide show
  1. package/.dockerignore +5 -0
  2. package/Dockerfile +34 -0
  3. package/LICENSE +373 -0
  4. package/README.md +485 -0
  5. package/TODO +34 -0
  6. package/conlink +11 -0
  7. package/conlink-start.sh +172 -0
  8. package/examples/dot.js +36 -0
  9. package/examples/index.html +11 -0
  10. package/examples/net2dot.yaml +21 -0
  11. package/examples/test1-compose.yaml +60 -0
  12. package/examples/test2-compose.yaml +31 -0
  13. package/examples/test2-network.yaml +5 -0
  14. package/examples/test3-network.yaml +5 -0
  15. package/examples/test4-multiple/all-compose.yaml +5 -0
  16. package/examples/test4-multiple/base-compose.yaml +25 -0
  17. package/examples/test4-multiple/node1-compose.yaml +17 -0
  18. package/examples/test4-multiple/nodes2-compose.yaml +20 -0
  19. package/examples/test4-multiple/web-network.yaml +2 -0
  20. package/examples/test5-geneve-compose.yaml +31 -0
  21. package/examples/test6-cfn.yaml +184 -0
  22. package/examples/test7-compose.yaml +31 -0
  23. package/examples/test8-compose.yaml +35 -0
  24. package/host-build.yaml +1 -0
  25. package/inspect.json +210 -0
  26. package/link-add.sh +197 -0
  27. package/link-del.sh +60 -0
  28. package/net2dot +11 -0
  29. package/notes.txt +82 -0
  30. package/old/Dockerfile.bak +26 -0
  31. package/old/add-link.sh +82 -0
  32. package/old/conlink +12 -0
  33. package/old/conlink.cljs +131 -0
  34. package/old/dot_gitignore +1 -0
  35. package/old/examples/test2-compose.yaml +32 -0
  36. package/old/examples/test2-network.yaml +42 -0
  37. package/old/move-link.sh +108 -0
  38. package/old/net2dot.py +122 -0
  39. package/old/notes-old.txt +97 -0
  40. package/old/package.json +16 -0
  41. package/old/schema.yaml +138 -0
  42. package/old/schema.yaml.bak +76 -0
  43. package/old/test2b-compose.yaml +18 -0
  44. package/old/veth-link.sh +96 -0
  45. package/package.json +15 -0
  46. package/schema-ish.yaml +29 -0
  47. package/schema.yaml +71 -0
  48. package/shadow-cljs.edn +33 -0
  49. package/src/conlink/addrs.cljc +63 -0
  50. package/src/conlink/core.cljs +772 -0
  51. package/src/conlink/net2dot.cljs +158 -0
  52. package/src/conlink/util.cljs +140 -0
  53. package/tests/invalid-schema-1.yaml +6 -0
  54. package/tests/invalid-schema-2.yaml +6 -0
  55. package/tests/invalid-schema-3.yaml +17 -0
  56. package/tests/invalid-schema-4.yaml +14 -0
  57. package/tests/invalid-schema-5.yaml +12 -0
  58. package/tests/invalid-schema-6.yaml +12 -0
  59. package/tmp/conlink/.env +1 -0
package/inspect.json ADDED
@@ -0,0 +1,210 @@
1
+ [
2
+ {
3
+ "Id": "43e63a3c948443f55198f4de29fd96805fdb306398ff64d89f1103c355e28357",
4
+ "Created": "2023-10-11T15:55:04.428835024Z",
5
+ "Path": "sh",
6
+ "Args": [
7
+ "-c",
8
+ "while ! ip link show eth0 up; do sleep 1; done; sleep 864000"
9
+ ],
10
+ "State": {
11
+ "Status": "running",
12
+ "Running": true,
13
+ "Paused": false,
14
+ "Restarting": false,
15
+ "OOMKilled": false,
16
+ "Dead": false,
17
+ "Pid": 10216,
18
+ "ExitCode": 0,
19
+ "Error": "",
20
+ "StartedAt": "2023-10-11T15:55:04.576997181Z",
21
+ "FinishedAt": "0001-01-01T00:00:00Z"
22
+ },
23
+ "Image": "sha256:8ca4688f4f356596b5ae539337c9941abc78eda10021d35cbc52659c74d9b443",
24
+ "ResolvConfPath": "/var/lib/docker/containers/43e63a3c948443f55198f4de29fd96805fdb306398ff64d89f1103c355e28357/resolv.conf",
25
+ "HostnamePath": "/var/lib/docker/containers/43e63a3c948443f55198f4de29fd96805fdb306398ff64d89f1103c355e28357/hostname",
26
+ "HostsPath": "/var/lib/docker/containers/43e63a3c948443f55198f4de29fd96805fdb306398ff64d89f1103c355e28357/hosts",
27
+ "LogPath": "/var/lib/docker/containers/43e63a3c948443f55198f4de29fd96805fdb306398ff64d89f1103c355e28357/43e63a3c948443f55198f4de29fd96805fdb306398ff64d89f1103c355e28357-json.log",
28
+ "Name": "/examples_node2_1",
29
+ "RestartCount": 0,
30
+ "Driver": "overlay2",
31
+ "Platform": "linux",
32
+ "MountLabel": "",
33
+ "ProcessLabel": "",
34
+ "AppArmorProfile": "docker-default",
35
+ "ExecIDs": null,
36
+ "HostConfig": {
37
+ "Binds": [],
38
+ "ContainerIDFile": "",
39
+ "LogConfig": {
40
+ "Type": "json-file",
41
+ "Config": {}
42
+ },
43
+ "NetworkMode": "none",
44
+ "PortBindings": {},
45
+ "RestartPolicy": {
46
+ "Name": "",
47
+ "MaximumRetryCount": 0
48
+ },
49
+ "AutoRemove": false,
50
+ "VolumeDriver": "",
51
+ "VolumesFrom": [],
52
+ "ConsoleSize": [
53
+ 0,
54
+ 0
55
+ ],
56
+ "CapAdd": [
57
+ "NET_ADMIN"
58
+ ],
59
+ "CapDrop": null,
60
+ "CgroupnsMode": "host",
61
+ "Dns": null,
62
+ "DnsOptions": null,
63
+ "DnsSearch": null,
64
+ "ExtraHosts": null,
65
+ "GroupAdd": null,
66
+ "IpcMode": "private",
67
+ "Cgroup": "",
68
+ "Links": null,
69
+ "OomScoreAdj": 0,
70
+ "PidMode": "",
71
+ "Privileged": false,
72
+ "PublishAllPorts": false,
73
+ "ReadonlyRootfs": false,
74
+ "SecurityOpt": null,
75
+ "UTSMode": "",
76
+ "UsernsMode": "",
77
+ "ShmSize": 67108864,
78
+ "Runtime": "runc",
79
+ "Isolation": "",
80
+ "CpuShares": 0,
81
+ "Memory": 0,
82
+ "NanoCpus": 0,
83
+ "CgroupParent": "",
84
+ "BlkioWeight": 0,
85
+ "BlkioWeightDevice": null,
86
+ "BlkioDeviceReadBps": null,
87
+ "BlkioDeviceWriteBps": null,
88
+ "BlkioDeviceReadIOps": null,
89
+ "BlkioDeviceWriteIOps": null,
90
+ "CpuPeriod": 0,
91
+ "CpuQuota": 0,
92
+ "CpuRealtimePeriod": 0,
93
+ "CpuRealtimeRuntime": 0,
94
+ "CpusetCpus": "",
95
+ "CpusetMems": "",
96
+ "Devices": null,
97
+ "DeviceCgroupRules": null,
98
+ "DeviceRequests": null,
99
+ "MemoryReservation": 0,
100
+ "MemorySwap": 0,
101
+ "MemorySwappiness": null,
102
+ "OomKillDisable": false,
103
+ "PidsLimit": null,
104
+ "Ulimits": null,
105
+ "CpuCount": 0,
106
+ "CpuPercent": 0,
107
+ "IOMaximumIOps": 0,
108
+ "IOMaximumBandwidth": 0,
109
+ "MaskedPaths": [
110
+ "/proc/asound",
111
+ "/proc/acpi",
112
+ "/proc/kcore",
113
+ "/proc/keys",
114
+ "/proc/latency_stats",
115
+ "/proc/timer_list",
116
+ "/proc/timer_stats",
117
+ "/proc/sched_debug",
118
+ "/proc/scsi",
119
+ "/sys/firmware"
120
+ ],
121
+ "ReadonlyPaths": [
122
+ "/proc/bus",
123
+ "/proc/fs",
124
+ "/proc/irq",
125
+ "/proc/sys",
126
+ "/proc/sysrq-trigger"
127
+ ]
128
+ },
129
+ "GraphDriver": {
130
+ "Data": {
131
+ "LowerDir": "/var/lib/docker/overlay2/f45757baf87c92f0934409fa9617bd4027e1e4472711312b1d8145ca59cdf0f3-init/diff:/var/lib/docker/overlay2/0ee1adfcd9b69bb9354db86819da1c06904d5c664f8d9e0aded8c158a24654df/diff",
132
+ "MergedDir": "/var/lib/docker/overlay2/f45757baf87c92f0934409fa9617bd4027e1e4472711312b1d8145ca59cdf0f3/merged",
133
+ "UpperDir": "/var/lib/docker/overlay2/f45757baf87c92f0934409fa9617bd4027e1e4472711312b1d8145ca59cdf0f3/diff",
134
+ "WorkDir": "/var/lib/docker/overlay2/f45757baf87c92f0934409fa9617bd4027e1e4472711312b1d8145ca59cdf0f3/work"
135
+ },
136
+ "Name": "overlay2"
137
+ },
138
+ "Mounts": [],
139
+ "Config": {
140
+ "Hostname": "43e63a3c9484",
141
+ "Domainname": "",
142
+ "User": "",
143
+ "AttachStdin": false,
144
+ "AttachStdout": false,
145
+ "AttachStderr": false,
146
+ "Tty": false,
147
+ "OpenStdin": false,
148
+ "StdinOnce": false,
149
+ "Env": [
150
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
151
+ ],
152
+ "Cmd": [
153
+ "sh",
154
+ "-c",
155
+ "while ! ip link show eth0 up; do sleep 1; done; sleep 864000"
156
+ ],
157
+ "Image": "alpine",
158
+ "Volumes": null,
159
+ "WorkingDir": "",
160
+ "Entrypoint": null,
161
+ "OnBuild": null,
162
+ "Labels": {
163
+ "com.docker.compose.config-hash": "be458eaf2e2aba67235023be9f8342d88ce0e0f7979749d6496423229a954bd3",
164
+ "com.docker.compose.container-number": "1",
165
+ "com.docker.compose.oneoff": "False",
166
+ "com.docker.compose.project": "examples",
167
+ "com.docker.compose.project.config_files": "examples/test2-compose.yaml",
168
+ "com.docker.compose.project.working_dir": "/home/jmartin/work/viasat/repos/conlink.cljs/examples",
169
+ "com.docker.compose.service": "node2",
170
+ "com.docker.compose.version": "1.29.2"
171
+ }
172
+ },
173
+ "NetworkSettings": {
174
+ "Bridge": "",
175
+ "SandboxID": "963251cd8230a51e9c658653a3fdeedfe10e9f16c03aed802b69d5a6c86f6d19",
176
+ "HairpinMode": false,
177
+ "LinkLocalIPv6Address": "",
178
+ "LinkLocalIPv6PrefixLen": 0,
179
+ "Ports": {},
180
+ "SandboxKey": "/var/run/docker/netns/963251cd8230",
181
+ "SecondaryIPAddresses": null,
182
+ "SecondaryIPv6Addresses": null,
183
+ "EndpointID": "",
184
+ "Gateway": "",
185
+ "GlobalIPv6Address": "",
186
+ "GlobalIPv6PrefixLen": 0,
187
+ "IPAddress": "",
188
+ "IPPrefixLen": 0,
189
+ "IPv6Gateway": "",
190
+ "MacAddress": "",
191
+ "Networks": {
192
+ "none": {
193
+ "IPAMConfig": null,
194
+ "Links": null,
195
+ "Aliases": null,
196
+ "NetworkID": "c7b50bdae4d8c2baa2dfbfcf81a783cddcfd66df84c6ce3f3506985434a161c8",
197
+ "EndpointID": "376d2c90a9e33a6e0fd62dc3f67c6f784d717594b54ebbb7e9d4d372ee0cf115",
198
+ "Gateway": "",
199
+ "IPAddress": "",
200
+ "IPPrefixLen": 0,
201
+ "IPv6Gateway": "",
202
+ "GlobalIPv6Address": "",
203
+ "GlobalIPv6PrefixLen": 0,
204
+ "MacAddress": "",
205
+ "DriverOpts": null
206
+ }
207
+ }
208
+ }
209
+ }
210
+ ]
package/link-add.sh ADDED
@@ -0,0 +1,197 @@
1
+ #!/bin/bash
2
+
3
+ # Copyright (c) 2023, Viasat, Inc
4
+ # Licensed under MPL 2.0
5
+
6
+ set -e
7
+
8
+ usage () {
9
+ echo >&2 "${0} [OPTIONS] TYPE PID0 INTF0"
10
+ echo >&2 ""
11
+ echo >&2 "Create link TYPE interface INTF0 in netns PID0."
12
+ echo >&2 ""
13
+ echo >&2 "Positional arguments:"
14
+ echo >&2 " TYPE is the link/interface type"
15
+ echo >&2 " INTF0 is the primary interface name"
16
+ echo >&2 " PID0 is the primary netns process ID"
17
+ echo >&2 ""
18
+ echo >&2 "The INTF1/PID1 parameters have type specific meaning:"
19
+ echo >&2 " - veth: the peer interface in PID1 netns"
20
+ echo >&2 " - *vlan/*vtap: the parent interface in PID1 netns"
21
+ echo >&2 " - geneve/vxlan: not applicable"
22
+ echo >&2 ""
23
+ echo >&2 "OPTIONS:"
24
+ echo >&2 " --verbose - Verbose output (set -x)"
25
+ echo >&2 " --pid1 PID1 - Secondary netns process ID"
26
+ echo >&2 " (default: <SELF>)"
27
+ echo >&2 " --intf1 INTF1 - Secondary interface name"
28
+ echo >&2 " (default: eth0)"
29
+ echo >&2 " --ip IP0 - IP (CIDR) address for INTF0"
30
+ echo >&2 " --ip0 IP0 - IP (CIDR) address for INTF0"
31
+ echo >&2 " --ip1 IP1 - IP (CIDR) address for INTF1"
32
+ echo >&2 " --mac MAC0 - MAC address for INTF0"
33
+ echo >&2 " --mac0 MAC0 - MAC address for INTF0"
34
+ echo >&2 " --mac1 MAC1 - MAC address for INTF1"
35
+ echo >&2 " --route 'ROUTE' - route to add to INTF0"
36
+ echo >&2 " --route|--route0 'ROUTE' - route to add to INTF0"
37
+ echo >&2 " --route1 'ROUTE' - route to add to INTF1"
38
+ echo >&2 " --mtu MTU - MTU for both interfaces"
39
+ echo >&2 ""
40
+ echo >&2 " --mode MODE - Mode settings for *vlan TYPEs"
41
+ echo >&2 " --vlanid VLANID - VLAN ID for vlan TYPE"
42
+ echo >&2 ""
43
+ echo >&2 " --remote REMOTE - Remote address for geneve/vxlan types"
44
+ echo >&2 " --vni VNI - Virtual Network Identifier for geneve/vxlan types"
45
+ echo >&2 ""
46
+ echo >&2 " --netem NETEM - tc qdisc netem OPTIONS (man 8 netem)"
47
+ echo >&2 " --nat TARGET - Stateless NAT traffic to/from TARGET"
48
+ exit 2
49
+ }
50
+
51
+ info() { echo "link-add [${LOG_ID}] ${*}"; }
52
+ warn() { >&2 echo "link-add [${LOG_ID}] ${*}"; }
53
+ die() { warn "ERROR: ${*}"; exit 1; }
54
+
55
+ # Set MAC, IP, ROUTE, MTU, and up state for interface in netns
56
+ setup_if() {
57
+ local IF=$1 NS=$2 MAC=$3 IP=$4 ROUTE=$5 MTU=$6
58
+
59
+ info "Setting ${IP:+IP ${IP}, }${MAC:+MAC ${MAC}, }${MTU:+MTU ${MTU}, }${ROUTE:+ROUTE '${ROUTE}', }up state"
60
+ ip -netns ${NS} --force -b - <<EOF
61
+ ${IP:+addr add ${IP} dev ${IF}}
62
+ ${MAC:+link set dev ${IF} address ${MAC}}
63
+ ${MTU:+link set dev ${IF} mtu ${MTU}}
64
+ link set dev ${IF} up
65
+ ${ROUTE:+route add ${ROUTE} dev ${IF}}
66
+ EOF
67
+ }
68
+
69
+ IPTABLES() {
70
+ local ns=${1}; shift
71
+ ip netns exec ${ns} iptables -D "${@}" 2>/dev/null || true
72
+ ip netns exec ${ns} iptables -I "${@}"
73
+ }
74
+
75
+
76
+ # Parse arguments
77
+ VERBOSE=${VERBOSE:-}
78
+ PID1=${PID1:-<SELF>} IF1=${IF1:-eth0}
79
+ IP0= IP1= MAC0= MAC1= ROUTE0= ROUTE1= MTU=
80
+ MODE= VLANID= REMOTE= VNI= NETEM= NAT=
81
+ positional=
82
+ while [ "${*}" ]; do
83
+ param=$1; OPTARG=$2
84
+ case ${param} in
85
+ --verbose) VERBOSE=1 ;;
86
+ --pid1) PID1="${OPTARG}"; shift ;;
87
+ --intf1) IF1="${OPTARG}"; shift ;;
88
+ --ip|--ip0) IP0="${OPTARG}"; shift ;;
89
+ --ip1) IP1="${OPTARG}"; shift ;;
90
+ --mac|--mac0) MAC0="${OPTARG}"; shift ;;
91
+ --mac1) MAC1="${OPTARG}"; shift ;;
92
+ --route|--route0) ROUTE0="${OPTARG}"; shift ;;
93
+ --route1) ROUTE1="${OPTARG}"; shift ;;
94
+ --mtu) MTU="${OPTARG}"; shift ;;
95
+
96
+ --mode) MODE="${OPTARG}"; shift ;;
97
+ --vlanid) VLANID="${OPTARG}"; shift ;;
98
+
99
+ --remote) REMOTE="${OPTARG}"; shift ;;
100
+ --vni) VNI="${OPTARG}"; shift ;;
101
+
102
+ --netem) NETEM="${OPTARG}"; shift ;;
103
+ --nat) NAT="${OPTARG}"; shift ;;
104
+ -h|--help) usage ;;
105
+ *) positional="${positional} $1" ;;
106
+ esac
107
+ shift
108
+ done
109
+ set -- ${positional}
110
+ TYPE=$1 PID0=$2 IF0=$3
111
+
112
+ [ "${VERBOSE}" ] && set -x || true
113
+
114
+ # Sanity check arguments
115
+ [ "${TYPE}" -a "${PID0}" -a "${IF0}" ] || usage
116
+ [ "${NAT}" -a -z "${IP0}" ] && die "--nat requires --ip0"
117
+
118
+ LOG_ID="${TYPE} ${PID0}:${IF0}"
119
+ case "${TYPE}" in
120
+ veth)
121
+ LOG_ID="${LOG_ID} <-> ${PID1}:${IF1}"
122
+ ;;
123
+ *vlan|*vtap)
124
+ LOG_ID="${LOG_ID} <<< ${PID1}:${IF1}"
125
+ [ "${IF1}" ] || die "--intf1 required for ${TYPE} link"
126
+ [ "${REMOTE}" -o "${VNI}" ] && die "--remote/--vlanid incompatible with ${TYPE} link"
127
+ ;;
128
+ geneve|vxlan)
129
+ LOG_ID="${LOG_ID} <<->> ${REMOTE}(${VNI})"
130
+ [ "${REMOTE}" -a "${VNI}" ] || die "--remote and --vni required for ${TYPE} link"
131
+ [ "${MODE}" -o "${VLANID}" ] && die "--mode/--vlanid incompatible with ${TYPE} link"
132
+ ;;
133
+ *)
134
+ [ "${PID1}" != "<SELF>" ] && die "--pid1 not supported for ${TYPE} link"
135
+ ;;
136
+ esac
137
+
138
+ [ "${PID1}" = "<SELF>" ] && PID1=$$
139
+ NS0=ns${PID0} NS1=ns${PID1}
140
+
141
+ # Sanity checks
142
+ [ ! -d /proc/$PID0 ] && die "PID0 $PID0 is no longer running!"
143
+ [ ! -d /proc/$PID1 ] && die "PID1 $PID1 is no longer running!"
144
+
145
+ ### Do the work
146
+
147
+ info "Creating ${TYPE} link"
148
+
149
+ info "Creating ip netns to pid mappings"
150
+ export PATH=$PATH:/usr/sbin # to find iptables
151
+ mkdir -p /var/run/netns
152
+ ln -sf /proc/${PID0}/ns/net /var/run/netns/${NS0}
153
+ ln -sf /proc/${PID1}/ns/net /var/run/netns/${NS1}
154
+
155
+ case "${TYPE}" in
156
+ veth)
157
+ info "Creating ${TYPE} pair interfaces"
158
+ echo ip link add ${IF0} netns ${NS0} type veth peer ${IF1} netns ${NS1}
159
+ ip link add ${IF0} netns ${NS0} type veth peer ${IF1} netns ${NS1}
160
+ ;;
161
+ *vlan|*vtap)
162
+ info "Creating ${TYPE} interface"
163
+ SIF0=if0-${RANDOM}
164
+ ip -netns ${NS1} link add name ${SIF0} link ${IF1} type ${TYPE} \
165
+ ${MODE:+mode ${MODE}} ${VLANID:+id ${VLANID}}
166
+ info "Moving ${TYPE} interface"
167
+ ip -netns ${NS1} link set ${SIF0} netns ${NS0}
168
+ info "Renaming ${TYPE} interface"
169
+ ip -netns ${NS0} link set ${SIF0} name ${IF0}
170
+ ;;
171
+ geneve|vxlan)
172
+ info "Creating ${TYPE} tunnel interface"
173
+ ip -netns ${NS1} link add name ${IF0} type ${TYPE} \
174
+ remote ${REMOTE} id ${VNI}
175
+ ;;
176
+ *)
177
+ info "Creating ${TYPE} interface"
178
+ ip -netns ${NS0} link add ${IF0} type ${TYPE}
179
+ ;;
180
+ esac
181
+
182
+ setup_if ${IF0} ${NS0} "${MAC0}" "${IP0}" "${ROUTE0}" "${MTU}"
183
+ [ "${TYPE}" = "veth" ] && \
184
+ setup_if ${IF1} ${NS1} "${MAC1}" "${IP1}" "${ROUTE1}" "${MTU}"
185
+
186
+ if [ "${NETEM}" ]; then
187
+ info "Setting tc qdisc netem: ${NETEM}"
188
+ tc -netns ${NS0} qdisc add dev ${IF0} root netem ${NETEM}
189
+ fi
190
+
191
+ if [ "${NAT}" ]; then
192
+ info "Adding NAT rule to ${NAT}"
193
+ IPTABLES ${NS0} PREROUTING -t nat -i ${IF0} -j DNAT --to-destination ${NAT}
194
+ IPTABLES ${NS0} POSTROUTING -t nat -o ${IF0} -j SNAT --to-source ${IP0%/*}
195
+ fi
196
+
197
+ info "Created ${TYPE} link"
package/link-del.sh ADDED
@@ -0,0 +1,60 @@
1
+ #!/bin/bash
2
+
3
+ # Copyright (c) 2023, Viasat, Inc
4
+ # Licensed under MPL 2.0
5
+
6
+ set -e
7
+
8
+ usage () {
9
+ echo >&2 "${0} [OPTIONS] PID INTF"
10
+ echo >&2 ""
11
+ echo >&2 " INTF is the name of the interface in PID netns"
12
+ echo >&2 " PID is the process ID of the container"
13
+ echo >&2 ""
14
+ echo >&2 " Where OPTIONS are:"
15
+ echo >&2 " --verbose - Verbose output (set -x)"
16
+ exit 2
17
+ }
18
+
19
+ VERBOSE=${VERBOSE:-}
20
+
21
+ info() { echo "del-link [${PID}:${IF}] ${*}"; }
22
+ warn() { >&2 echo "del-link [${PID}:${IF}] ${*}"; }
23
+ die() { warn "ERROR: ${*}"; exit 1; }
24
+
25
+ # Parse arguments
26
+ positional=
27
+ while [ "${*}" ]; do
28
+ param=$1; OPTARG=$2
29
+ case ${param} in
30
+ --verbose) VERBOSE=1 ;;
31
+ -h|--help) usage ;;
32
+ *) positional="${positional} $1" ;;
33
+ esac
34
+ shift
35
+ done
36
+ set -- ${positional}
37
+ PID=$1 IF=$2
38
+
39
+ NS=ns${PID}
40
+
41
+ [ "${VERBOSE}" ] && set -x || true
42
+
43
+ # Check arguments
44
+ [ "${IF}" -a "${PID}" ] || usage
45
+
46
+ # Sanity checks
47
+ [ ! -d /proc/$PID ] && die "PID $PID is no longer running!"
48
+
49
+ ### Do the work
50
+
51
+ info "Deleting link"
52
+
53
+ info "Creating ip netns to pid mapping"
54
+ mkdir -p /var/run/netns
55
+ ln -sf /proc/${PID}/ns/net /var/run/netns/ns${PID}
56
+
57
+ info "Deleting interface"
58
+ ip -netns ${NS} link del ${IF}
59
+
60
+ info "Deleted link"
package/net2dot ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+
3
+ TOP_DIR=$(dirname $(readlink -f "${0}"))
4
+ SCRIPT_NAME=$(basename "${0}")
5
+ NBB=${TOP_DIR}/node_modules/.bin/nbb
6
+
7
+ die() { echo >&2 "${*}"; exit 1; }
8
+
9
+ [ -e "${NBB}" ] || die "Missing ${NBB}. Maybe run 'npm install' in ${TOP_DIR}?"
10
+
11
+ exec ${NBB} -cp "${TOP_DIR}/src" -m conlink.net2dot/main "${@}"
package/notes.txt ADDED
@@ -0,0 +1,82 @@
1
+ - Also see schema-ish.yaml
2
+ links:
3
+ - type: TYPE # Default: 'veth'
4
+ # Others: '*vlan/*vtap', 'dummy', 'tunnel', etc
5
+
6
+ container: FOO # full container name
7
+ # OR
8
+ service: FOO # compose service name
9
+
10
+ bridge: BRIDGE # name of OVS or linux bridge
11
+
12
+ base: BASE # 'conlink', 'host', or 'local'
13
+ # 'conlink' is default for 'type: veth'
14
+ # 'host' is default for 'type: *vlan/*vtap'
15
+
16
+ dev: DEV # internal container device/interface name
17
+ outer-dev: DEV # conlink or host (*vlan) device/interface name
18
+
19
+ # --- optional general ---
20
+
21
+ ip(s): IP # starting address, can include net slash to limit max
22
+ mac: MAC
23
+ mtu: MTU
24
+ route(s): ROUTE # `ip route add ROUTE`, maybe add "dev INTF" automatically
25
+ tc(s): TC # tc/qdisc commands/settings
26
+ flow(s): FLOW # `ovs-ofctl add-flow DOMAIN FLOW`. With var templating.
27
+ command(s): CMD # arbitrary shell cmd. After all links setup for this container
28
+
29
+ # --- optional for 'type: *vlan/*vtap' ---
30
+
31
+ mode: MODE # 'bridge', etc
32
+ vlanid: VLANID # VLAN #
33
+ nat: NAT # nat target
34
+
35
+
36
+ - type maps to 'ip link' type with default of 'veth'
37
+ - when type is 'veth', then base default is 'conlink'
38
+ - when type is 'veth' and base is 'conlink', then bridge is required.
39
+
40
+ - conlink veth link: {type: veth [DEFAULT], base: conlink [DEFAULT], bridge: BRIDGE, dev: DEV}
41
+
42
+
43
+
44
+ Dependencies in python version:
45
+ - argparse
46
+ - shlex (parsing commands)
47
+ - compose_interpolation import TemplateWithDefaults
48
+ - cerberus import Validator
49
+ - options: joi, ajv, json-schema, and z-schema.
50
+ - docker
51
+ - psutil (pid_exists)
52
+ - json
53
+ - yaml
54
+ - mininet
55
+
56
+
57
+ - [deprecated idea] conlink sub-commands:
58
+ conlink spit
59
+ - output override docker-compose file with conlink service
60
+ - figure out volume mounts to get to other compose file(s)
61
+ conlink dc up ...
62
+ - generate override docker-compose file with conlink service
63
+ - run the compose command with override file
64
+ conlink start
65
+ - start inside compose
66
+ conlink run
67
+ - start outside compose
68
+
69
+
70
+ tc:
71
+ tc-htb:
72
+ - replace cbq, control outbound bandwidth
73
+ tc qdisc ... dev dev ( parent classid | root) [ handle major: ] htb [ default minor-id ]
74
+ tc class ... dev dev parent major:[minor] [ classid major:minor ] htb rate rate [ ceil rate ] burst bytes [ cburst bytes ] [ prio priority ]
75
+
76
+ tc-cbq:
77
+ tc qdisc ... dev dev ( parent classid | root) [ handle major: ] cbq [ allot bytes ] avpkt bytes bandwidth rate [ cell bytes ] [ ewma log ] [ mpu bytes ]
78
+ tc class ... dev dev parent major:[minor] [ classid major:minor ] cbq allot bytes [ bandwidth rate ] [ rate rate ] prio pri‐ority [ weight weight ] [ minburst packets ] [ maxburst packets ] [ ewma log ] [ cell bytes ] avpkt bytes [ mpu bytes ] [ bounded isolated ] [ split handle & defmap defmap ] [ estimator interval timeconstant ]
79
+
80
+ tc-netem:
81
+ tc qdisc ... dev DEVICE ] add netem OPTIONS
82
+
@@ -0,0 +1,26 @@
1
+ FROM node:16 as base
2
+
3
+ RUN apt-get -y update #1
4
+
5
+
6
+ #############################################################
7
+ FROM node:16-slim as conlink
8
+
9
+ RUN apt-get -y update #1
10
+
11
+ # network/debug
12
+ RUN apt-get -y install util-linux iproute2 bridge-utils tzdata \
13
+ iptables ethtool tcpdump socat iputils-ping strace socat \
14
+ curl wget iperf3 dnsmasq jq psutils telnet
15
+
16
+ # runtime deps
17
+ RUN apt-get -y install net-tools cgroup-tools \
18
+ openvswitch-switch openvswitch-testcontroller kmod
19
+
20
+ ADD package.json /app/
21
+ RUN cd /app && npm install
22
+
23
+ ADD conlink conlink.cljs /app/
24
+ ADD src/ /app/src/
25
+ RUN ln -sf /app/conlink /sbin/
26
+
@@ -0,0 +1,82 @@
1
+ #!/bin/bash
2
+
3
+ # Copyright (c) 2023, Viasat, Inc
4
+ # Licensed under MPL 2.0
5
+
6
+ set -e
7
+
8
+ usage () {
9
+ echo >&2 "${0} [OPTIONS] TYPE INTF PID [-- SET ARGS]"
10
+ echo >&2 ""
11
+ echo >&2 " TYPE: interface type"
12
+ echo >&2 " INTF: the interface name to create in PID"
13
+ echo >&2 " PID: the process ID of the first namespace"
14
+ echo >&2 ""
15
+ echo >&2 " OPTIONS are:"
16
+ echo >&2 " --verbose - Verbose output (set -x)"
17
+ echo >&2 " --ip IP - IP address for INTF"
18
+ echo >&2 " --mac MAC - MAC address for INTF"
19
+ echo >&2 " --route 'ROUTE' - route to add to INTF"
20
+ echo >&2 " --mtu MTU - MTU for INTF"
21
+ echo >&2 ""
22
+ echo >&2 "The interface is created in PID ns, then the IP, MAC,"
23
+ echo >&2 "and MTU are set, and finally the following command"
24
+ echo >&2 "is executed:"
25
+ echo >&2 " ip link set INTF up SET_ARGS"
26
+ exit 2
27
+ }
28
+
29
+ VERBOSE=${VERBOSE:-}
30
+ IP= MAC= ROUTE= MTU= SET_ARGS=
31
+
32
+ info() { echo "add-link [${TYPE} - ${PID}/${IF}] ${*}"; }
33
+ warn() { >&2 echo "add-link [${TYPE} - ${PID}/${IF}] ${*}"; }
34
+ die() { warn "ERROR: ${*}"; exit 1; }
35
+
36
+ # Parse arguments
37
+ positional=
38
+ while [ "${*}" ]; do
39
+ param=$1; OPTARG=$2
40
+ case ${param} in
41
+ --verbose) VERBOSE=1 ;;
42
+ --ip) IP="${OPTARG}"; shift ;;
43
+ --mac) MAC="${OPTARG}"; shift ;;
44
+ --route) ROUTE="${OPTARG}"; shift ;;
45
+ --mtu) MTU="${OPTARG}"; shift ;;
46
+ -h|--help) usage ;;
47
+ --) SET_ARGS="$*"; break ;;
48
+ *) positional="${positional} $1" ;;
49
+ esac
50
+ shift
51
+ done
52
+ set -- ${positional}
53
+
54
+ TYPE=$1 IF=$2 PID=$3 NS=ns${PID}
55
+
56
+ [ "${VERBOSE}" ] && set -x || true
57
+
58
+ # Check arguments
59
+ [ "${TYPE}" -a "${IF}" -a "${PID}" ] || usage
60
+
61
+ # Sanity checks
62
+ [ ! -d /proc/$PID ] && die "PID $PID is no longer running!"
63
+
64
+ export PATH=$PATH:/usr/sbin
65
+ mkdir -p /var/run/netns
66
+ ln -sf /proc/${PID}/ns/net /var/run/netns/${NS}
67
+
68
+ info "Creating ${TYPE} link ${IF} in ${NS}"
69
+ ip link add ${IF} netns ns${PID} type ${TYPE}
70
+
71
+ ip -netns ${NS} --force -b - <<EOF
72
+ ${IP:+addr add ${IP} dev ${IF}}
73
+ ${MAC:+link set dev ${IF} address ${MAC}}
74
+ ${MTU:+link set dev ${IF} mtu ${MTU}}
75
+ link set dev ${IF} up
76
+ ${ROUTE:+route add ${ROUTE} dev ${IF}}
77
+ ${SET_ARGS:+link set dev ${IF} ${SET_ARGS}}
78
+ EOF
79
+
80
+ info "Created ${TYPE} link ${IF} in ${NS}"
81
+
82
+ # /test/add-link.sh --verbose dummy if0 2500144 --ip 192.168.88.32/24 -- arp on
package/old/conlink ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+
3
+ TOP_DIR=$(dirname $(readlink -f "${0}"))
4
+ SCRIPT_NAME=$(basename "${0}")
5
+ NBB=${TOP_DIR}/node_modules/.bin/nbb
6
+
7
+ die() { echo >&2 "${*}"; exit 1; }
8
+
9
+ [ -e "${NBB}" ] || die "Missing ${NBB}. Maybe run 'npm install' in ${TOP_DIR}?"
10
+
11
+ exec ${NBB} -cp "${TOP_DIR}/src" "${TOP_DIR}"/${SCRIPT_NAME}.cljs "${@}"
12
+