From 27d4ec61944f0bfa579e1ab0df0b70b89601e9f5 Mon Sep 17 00:00:00 2001 From: Pim van Pelt Date: Thu, 13 Oct 2022 20:41:34 +0200 Subject: [PATCH] initial checkin - a start of the generator, and some config files and overlays --- .gitignore | 3 + README.md | 102 +++++++ build/default/vpp0-0/etc/bird/bfd.conf | 6 + build/default/vpp0-0/etc/bird/bird.conf | 19 ++ build/default/vpp0-0/etc/bird/ibgp.conf | 1 + build/default/vpp0-0/etc/bird/ospf.conf | 21 ++ build/default/vpp0-0/etc/bird/static.conf | 11 + build/default/vpp0-0/etc/hostname | 1 + build/default/vpp0-0/etc/hosts | 7 + .../default/vpp0-0/etc/netplan/01-netcfg.yaml | 14 + build/default/vpp0-0/etc/vpp/bootstrap.vpp | 38 +++ build/default/vpp0-1/etc/bird/bfd.conf | 6 + build/default/vpp0-1/etc/bird/bird.conf | 19 ++ build/default/vpp0-1/etc/bird/ibgp.conf | 1 + build/default/vpp0-1/etc/bird/ospf.conf | 21 ++ build/default/vpp0-1/etc/bird/static.conf | 11 + build/default/vpp0-1/etc/hostname | 1 + build/default/vpp0-1/etc/hosts | 7 + .../default/vpp0-1/etc/netplan/01-netcfg.yaml | 14 + build/default/vpp0-1/etc/vpp/bootstrap.vpp | 38 +++ build/default/vpp0-2/etc/bird/bfd.conf | 6 + build/default/vpp0-2/etc/bird/bird.conf | 19 ++ build/default/vpp0-2/etc/bird/ibgp.conf | 1 + build/default/vpp0-2/etc/bird/ospf.conf | 21 ++ build/default/vpp0-2/etc/bird/static.conf | 11 + build/default/vpp0-2/etc/hostname | 1 + build/default/vpp0-2/etc/hosts | 7 + .../default/vpp0-2/etc/netplan/01-netcfg.yaml | 14 + build/default/vpp0-2/etc/vpp/bootstrap.vpp | 38 +++ build/default/vpp0-3/etc/bird/bfd.conf | 6 + build/default/vpp0-3/etc/bird/bird.conf | 19 ++ build/default/vpp0-3/etc/bird/ibgp.conf | 1 + build/default/vpp0-3/etc/bird/ospf.conf | 21 ++ build/default/vpp0-3/etc/bird/static.conf | 11 + build/default/vpp0-3/etc/hostname | 1 + build/default/vpp0-3/etc/hosts | 7 + .../default/vpp0-3/etc/netplan/01-netcfg.yaml | 14 + build/default/vpp0-3/etc/vpp/bootstrap.vpp | 38 +++ config/common/generic.yaml | 21 ++ config/hvn0.lab.ipng.ch.yaml | 22 ++ generate | 270 ++++++++++++++++++ overlays/bird/templates/etc/bird/bfd.conf.j2 | 6 + overlays/bird/templates/etc/bird/bird.conf.j2 | 19 ++ overlays/bird/templates/etc/bird/ibgp.conf.j2 | 1 + overlays/bird/templates/etc/bird/ospf.conf.j2 | 21 ++ .../bird/templates/etc/bird/static.conf.j2 | 11 + overlays/bird/templates/etc/hostname.j2 | 1 + overlays/bird/templates/etc/hosts.j2 | 7 + .../templates/etc/netplan/01-netcfg.yaml.j2 | 14 + .../bird/templates/etc/vpp/bootstrap.vpp.j2 | 38 +++ 50 files changed, 1008 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 build/default/vpp0-0/etc/bird/bfd.conf create mode 100644 build/default/vpp0-0/etc/bird/bird.conf create mode 100644 build/default/vpp0-0/etc/bird/ibgp.conf create mode 100644 build/default/vpp0-0/etc/bird/ospf.conf create mode 100644 build/default/vpp0-0/etc/bird/static.conf create mode 100644 build/default/vpp0-0/etc/hostname create mode 100644 build/default/vpp0-0/etc/hosts create mode 100644 build/default/vpp0-0/etc/netplan/01-netcfg.yaml create mode 100644 build/default/vpp0-0/etc/vpp/bootstrap.vpp create mode 100644 build/default/vpp0-1/etc/bird/bfd.conf create mode 100644 build/default/vpp0-1/etc/bird/bird.conf create mode 100644 build/default/vpp0-1/etc/bird/ibgp.conf create mode 100644 build/default/vpp0-1/etc/bird/ospf.conf create mode 100644 build/default/vpp0-1/etc/bird/static.conf create mode 100644 build/default/vpp0-1/etc/hostname create mode 100644 build/default/vpp0-1/etc/hosts create mode 100644 build/default/vpp0-1/etc/netplan/01-netcfg.yaml create mode 100644 build/default/vpp0-1/etc/vpp/bootstrap.vpp create mode 100644 build/default/vpp0-2/etc/bird/bfd.conf create mode 100644 build/default/vpp0-2/etc/bird/bird.conf create mode 100644 build/default/vpp0-2/etc/bird/ibgp.conf create mode 100644 build/default/vpp0-2/etc/bird/ospf.conf create mode 100644 build/default/vpp0-2/etc/bird/static.conf create mode 100644 build/default/vpp0-2/etc/hostname create mode 100644 build/default/vpp0-2/etc/hosts create mode 100644 build/default/vpp0-2/etc/netplan/01-netcfg.yaml create mode 100644 build/default/vpp0-2/etc/vpp/bootstrap.vpp create mode 100644 build/default/vpp0-3/etc/bird/bfd.conf create mode 100644 build/default/vpp0-3/etc/bird/bird.conf create mode 100644 build/default/vpp0-3/etc/bird/ibgp.conf create mode 100644 build/default/vpp0-3/etc/bird/ospf.conf create mode 100644 build/default/vpp0-3/etc/bird/static.conf create mode 100644 build/default/vpp0-3/etc/hostname create mode 100644 build/default/vpp0-3/etc/hosts create mode 100644 build/default/vpp0-3/etc/netplan/01-netcfg.yaml create mode 100644 build/default/vpp0-3/etc/vpp/bootstrap.vpp create mode 100644 config/common/generic.yaml create mode 100644 config/hvn0.lab.ipng.ch.yaml create mode 100755 generate create mode 100644 overlays/bird/templates/etc/bird/bfd.conf.j2 create mode 100644 overlays/bird/templates/etc/bird/bird.conf.j2 create mode 100644 overlays/bird/templates/etc/bird/ibgp.conf.j2 create mode 100644 overlays/bird/templates/etc/bird/ospf.conf.j2 create mode 100644 overlays/bird/templates/etc/bird/static.conf.j2 create mode 100644 overlays/bird/templates/etc/hostname.j2 create mode 100644 overlays/bird/templates/etc/hosts.j2 create mode 100644 overlays/bird/templates/etc/netplan/01-netcfg.yaml.j2 create mode 100644 overlays/bird/templates/etc/vpp/bootstrap.vpp.j2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..07410ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.json +__pycache__/ +.peeringdb/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4b69e4 --- /dev/null +++ b/README.md @@ -0,0 +1,102 @@ +# IPng Networks Lab environment + + +## High level overview + +There's a disk image on each hypervisor called the `proto` image, which serves as the base +image for all VMs on it. Every now and again, the proto image is updated (Debian, FRR and VPP) +and from that base image, lab VMs are cloned from it and local filesystem overrides are put +in place on each clone. The lab is used, and when we're done with it, we simply destroy all +clones. This way, each time the lab is started, it is in a pristine state. + +The `proto` image is shared among the hypervisors. Typically, maintenance will be performed +on one of the hypervisors, and then the `proto` image is snapshotted and copied to the other +machines. + +### Proto maintenance + +The main `vpp-proto` image runs on `hvn0.chbtl0.ipng.ch` with a VM called `vpp-proto`. +When you want to refresh the image, you can + +``` +spongebob:~$ ssh -A root@hvn0.chbtl0.ipng.ch + +SNAP=$(date +%Y%m%d) ## 20221012 +zfs snapshot ssd-vol0/vpp-proto-disk0@${SNAP}-before +virsh start --console vpp-proto + +## Do the upgrades, make changes to vpp-proto's disk image +## You can always roll back to the -before image if you'd like to revert + +virsh shutdown --console vpp-proto +zfs snapshot ssd-vol0/vpp-proto-disk0@${SNAP}-release +zrepl signal wakeup vpp-proto-snapshots +``` + +There is a `zrepl` running on this machine, which can pick up the snapshot by manually +waking up the daemon (see the last command above). Each of the hypervisors in the fleet +will watch this replication endpoint, and if they see new snapshots arrive, they will +do an incremental pull of the data to their own ZFS filesystem as a snapshot. Old/current +running labs will not be disrupted, as they will be cloned off of old snapshots. + +You will find the image as `ssd-vol0/hvn0.chbtl0.ipng.ch/ssd-vol0/vpp-proto-disk0`: +``` +spongebob:~$ ssh -A root@hvn0.lab.ipng.ch 'zfs list -t snap' +NAME USED AVAIL REFER MOUNTPOINT +ssd-vol0/hvn0.chbtl0.ipng.ch/ssd-vol0/vpp-proto-disk0@20221013-release 0B - 6.04G - +``` + +## Usage + +There are three hypervisor nodes each running one isolated lab environment: +* hvn0.lab.ipng.ch runs VPP lab0 +* hvn1.lab.ipng.ch runs VPP lab1 +* hvn2.lab.ipng.ch runs VPP lab2 + +Now that we have a base image (in the form of `vpp-proto-disk0@$(date)-release`), we can +make point-in-time clones of them, copy over any specifics (like IP addresses, hostname, +SSH keys, Bird/FRR configs, etc). We do this on the lab controller `lab.ipng.ch` which: + +1. Looks on the hypervisor to see if there is a running VM, and if there is, bails +1. Looks on the hypervisor to see if there is an existing cloned image, and if there is bails +1. Builds a local overlay directory using a generator and Jinja2 (ie. `build/vpp0-0/`) +1. Creates a new cloned filesystem based off of a base `vpp-proto-disk0` snapshot on the hypervisor +1. Mounts that filesystem +1. Rsync's the built overlay into that filesystem +1. Unmounts the filesystem +1. Starts the VM using the newly built filesystem + +Of course, the first two steps are meant to ensure we don't clobber running labs, which can +be overridden with the `--force` flag. And when the lab is finished, it's common practice to +shut down the VMs and destroy the clones. + +``` +lab:~/src/ipng-lab$ ./destroy --host hvn0.lab.ipng.ch +lab:~/src/ipng-lab$ ./generate --host hvn0.lab.ipng.ch --overlay bird +lab:~/src/ipng-lab$ ./create --host hvn0.lab.ipng.ch --overlay bird +``` + +### Generate + +The generator reads input YAML files one after another merging and overriding them as it goes along, +then for each node building a `node` dictionary alongside the `lab` and other information from the +config files. Then, it read the `overlays` dictionary for a given --overlay type, reading all the +template files from that overlay directory and assembling an output directory which will hold the +per-node overrides, emitting them to the directory specified by the --build flag. It also copies in +any per-node files (if they exist) from the overlays/$(overlay)/blobs/$(node.hostname)/ giving full +control of the filesystem's contents. + +### Create + +Based on a generated directory and a lab YAML description, uses SSH to connect to the hypervisor, +create a clone of the base `vpp-proto` snapshot, mount it locally in a staging directory, then rsync +over the generated overlay from files from the generator output (build/$(overlay)/$(node.hostname)) +after which the directory is unmounted and the virtual machine booted from the clone. + +If the VM is running, or there exists a clone, an error is printed and the process skips over that +node. It's wise to run `destroy` before `create` to ensure the hypervisors are in a pristine state. + +### Destroy + +Ensures that both the VMs are not running (and will stop them if they are), and their filesystem +clones are destroyed. Obviously this is the most dangerous operation of the bunch. diff --git a/build/default/vpp0-0/etc/bird/bfd.conf b/build/default/vpp0-0/etc/bird/bfd.conf new file mode 100644 index 0000000..b0f329b --- /dev/null +++ b/build/default/vpp0-0/etc/bird/bfd.conf @@ -0,0 +1,6 @@ +protocol bfd bfd1 { + interface "e*" { + interval 100 ms; + multiplier 20; + }; +} \ No newline at end of file diff --git a/build/default/vpp0-0/etc/bird/bird.conf b/build/default/vpp0-0/etc/bird/bird.conf new file mode 100644 index 0000000..c6cd170 --- /dev/null +++ b/build/default/vpp0-0/etc/bird/bird.conf @@ -0,0 +1,19 @@ +router id 192.168.10.0; + +protocol device { scan time 30; } +protocol direct { ipv4; ipv6; check link yes; } +protocol kernel kernel4 { + ipv4 { import none; export where source != RTS_DEVICE; }; + learn off; + scan time 300; +} +protocol kernel kernel6 { + ipv6 { import none; export where source != RTS_DEVICE; }; + learn off; + scan time 300; +} + +include "static.conf"; +include "bfd.conf"; +include "ospf.conf"; +include "ibgp.conf"; \ No newline at end of file diff --git a/build/default/vpp0-0/etc/bird/ibgp.conf b/build/default/vpp0-0/etc/bird/ibgp.conf new file mode 100644 index 0000000..69dd4d0 --- /dev/null +++ b/build/default/vpp0-0/etc/bird/ibgp.conf @@ -0,0 +1 @@ +# NOTE(ipng): Not created yet \ No newline at end of file diff --git a/build/default/vpp0-0/etc/bird/ospf.conf b/build/default/vpp0-0/etc/bird/ospf.conf new file mode 100644 index 0000000..98a97f1 --- /dev/null +++ b/build/default/vpp0-0/etc/bird/ospf.conf @@ -0,0 +1,21 @@ +protocol ospf v2 ospf4 { + ipv4 { export where source = RTS_DEVICE; import all; }; + area 0 { + interface "loop0" { stub yes; }; + interface "e0" { type pointopoint; cost 5; bfd off; }; + interface "e1" { type pointopoint; cost 5; bfd off; }; + interface "e2" { type pointopoint; cost 5; bfd off; }; + interface "e3" { type pointopoint; cost 5; bfd off; }; + }; +} + +protocol ospf v3 ospf6 { + ipv6 { export where source = RTS_DEVICE; import all; }; + area 0 { + interface "loop0" { stub yes; }; + interface "e0" { type pointopoint; cost 5; bfd off; }; + interface "e1" { type pointopoint; cost 5; bfd off; }; + interface "e2" { type pointopoint; cost 5; bfd off; }; + interface "e3" { type pointopoint; cost 5; bfd off; }; + }; +} \ No newline at end of file diff --git a/build/default/vpp0-0/etc/bird/static.conf b/build/default/vpp0-0/etc/bird/static.conf new file mode 100644 index 0000000..6ec5480 --- /dev/null +++ b/build/default/vpp0-0/etc/bird/static.conf @@ -0,0 +1,11 @@ +protocol static static4 { + ipv4 { export all; }; +# route 192.0.2.0/24 via 10.0.0.1; + route 192.168.10.0/24 unreachable; +} + +protocol static static6 { + ipv6 { export all; }; +# route 2001:db8:cafe::/48 via 2001:db8::1;; + route 2001:678:d78:200::/60 unreachable; +} \ No newline at end of file diff --git a/build/default/vpp0-0/etc/hostname b/build/default/vpp0-0/etc/hostname new file mode 100644 index 0000000..c390e56 --- /dev/null +++ b/build/default/vpp0-0/etc/hostname @@ -0,0 +1 @@ +vpp0-0 \ No newline at end of file diff --git a/build/default/vpp0-0/etc/hosts b/build/default/vpp0-0/etc/hosts new file mode 100644 index 0000000..a9fead4 --- /dev/null +++ b/build/default/vpp0-0/etc/hosts @@ -0,0 +1,7 @@ +127.0.0.1 localhost +127.0.1.1 vpp0-0.lab.ipng.ch vpp0-0 + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters \ No newline at end of file diff --git a/build/default/vpp0-0/etc/netplan/01-netcfg.yaml b/build/default/vpp0-0/etc/netplan/01-netcfg.yaml new file mode 100644 index 0000000..e97a348 --- /dev/null +++ b/build/default/vpp0-0/etc/netplan/01-netcfg.yaml @@ -0,0 +1,14 @@ +network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + optional: true + accept-ra: false + dhcp4: false + addresses: [ 192.168.1.80/24, 2001:678:d78:101::80/64 ] + gateway4: 192.168.1.252 + gateway6: 2001:678:d78:101::1 + nameservers: + addresses: [ "2001:678:d78::3", "2001:678:d78::4" ] + search: [ "lab.ipng.ch", "ipng.ch", "ipng.nl", "rfc1918.ipng.nl" ] \ No newline at end of file diff --git a/build/default/vpp0-0/etc/vpp/bootstrap.vpp b/build/default/vpp0-0/etc/vpp/bootstrap.vpp new file mode 100644 index 0000000..db0094a --- /dev/null +++ b/build/default/vpp0-0/etc/vpp/bootstrap.vpp @@ -0,0 +1,38 @@ +set logging class linux-cp rate-limit 1000 level warn syslog-level notice + +lcp default netns dataplane +lcp lcp-sync on +lcp lcp-auto-subint off + +comment { Create a loopback interface } +create loopback interface instance 0 +lcp create loop0 host-if loop0 +set interface state loop0 up +set interface ip address loop0 192.168.10.0/32 +set interface ip address loop0 2001:678:d78:200::/128 + +comment { Create one LinuxCP Interface Pair for each phy } +lcp create GigabitEthernet10/0/0 host-if e0 +lcp create GigabitEthernet10/0/1 host-if e1 +lcp create GigabitEthernet10/0/2 host-if e2 +lcp create GigabitEthernet10/0/3 host-if e3 + +comment { e0 is uplink to AS8298 } +set interface state GigabitEthernet10/0/0 up +set interface mtu packet 1500 GigabitEthernet10/0/0 +set interface ip address GigabitEthernet10/0/0 192.168.10.7/31 +set interface ip address GigabitEthernet10/0/0 2001:678:d78:201::00:00/112 + +comment { e1 is ptp with e0.vpp0-1 } +set interface state GigabitEthernet10/0/1 up +set interface mtu packet 9000 GigabitEthernet10/0/1 +set interface ip address GigabitEthernet10/0/1 192.168.10.8/31 +set interface ip address GigabitEthernet10/0/1 2001:678:d78:201::01:00/112 + +comment { e2 is free to use } +set interface state GigabitEthernet10/0/2 down +set interface mtu packet 9000 GigabitEthernet10/0/2 + +comment { e3 is free to use } +set interface state GigabitEthernet10/0/3 down +set interface mtu packet 9000 GigabitEthernet10/0/3 \ No newline at end of file diff --git a/build/default/vpp0-1/etc/bird/bfd.conf b/build/default/vpp0-1/etc/bird/bfd.conf new file mode 100644 index 0000000..b0f329b --- /dev/null +++ b/build/default/vpp0-1/etc/bird/bfd.conf @@ -0,0 +1,6 @@ +protocol bfd bfd1 { + interface "e*" { + interval 100 ms; + multiplier 20; + }; +} \ No newline at end of file diff --git a/build/default/vpp0-1/etc/bird/bird.conf b/build/default/vpp0-1/etc/bird/bird.conf new file mode 100644 index 0000000..0aaa7dd --- /dev/null +++ b/build/default/vpp0-1/etc/bird/bird.conf @@ -0,0 +1,19 @@ +router id 192.168.10.1; + +protocol device { scan time 30; } +protocol direct { ipv4; ipv6; check link yes; } +protocol kernel kernel4 { + ipv4 { import none; export where source != RTS_DEVICE; }; + learn off; + scan time 300; +} +protocol kernel kernel6 { + ipv6 { import none; export where source != RTS_DEVICE; }; + learn off; + scan time 300; +} + +include "static.conf"; +include "bfd.conf"; +include "ospf.conf"; +include "ibgp.conf"; \ No newline at end of file diff --git a/build/default/vpp0-1/etc/bird/ibgp.conf b/build/default/vpp0-1/etc/bird/ibgp.conf new file mode 100644 index 0000000..69dd4d0 --- /dev/null +++ b/build/default/vpp0-1/etc/bird/ibgp.conf @@ -0,0 +1 @@ +# NOTE(ipng): Not created yet \ No newline at end of file diff --git a/build/default/vpp0-1/etc/bird/ospf.conf b/build/default/vpp0-1/etc/bird/ospf.conf new file mode 100644 index 0000000..98a97f1 --- /dev/null +++ b/build/default/vpp0-1/etc/bird/ospf.conf @@ -0,0 +1,21 @@ +protocol ospf v2 ospf4 { + ipv4 { export where source = RTS_DEVICE; import all; }; + area 0 { + interface "loop0" { stub yes; }; + interface "e0" { type pointopoint; cost 5; bfd off; }; + interface "e1" { type pointopoint; cost 5; bfd off; }; + interface "e2" { type pointopoint; cost 5; bfd off; }; + interface "e3" { type pointopoint; cost 5; bfd off; }; + }; +} + +protocol ospf v3 ospf6 { + ipv6 { export where source = RTS_DEVICE; import all; }; + area 0 { + interface "loop0" { stub yes; }; + interface "e0" { type pointopoint; cost 5; bfd off; }; + interface "e1" { type pointopoint; cost 5; bfd off; }; + interface "e2" { type pointopoint; cost 5; bfd off; }; + interface "e3" { type pointopoint; cost 5; bfd off; }; + }; +} \ No newline at end of file diff --git a/build/default/vpp0-1/etc/bird/static.conf b/build/default/vpp0-1/etc/bird/static.conf new file mode 100644 index 0000000..6ec5480 --- /dev/null +++ b/build/default/vpp0-1/etc/bird/static.conf @@ -0,0 +1,11 @@ +protocol static static4 { + ipv4 { export all; }; +# route 192.0.2.0/24 via 10.0.0.1; + route 192.168.10.0/24 unreachable; +} + +protocol static static6 { + ipv6 { export all; }; +# route 2001:db8:cafe::/48 via 2001:db8::1;; + route 2001:678:d78:200::/60 unreachable; +} \ No newline at end of file diff --git a/build/default/vpp0-1/etc/hostname b/build/default/vpp0-1/etc/hostname new file mode 100644 index 0000000..03e6f98 --- /dev/null +++ b/build/default/vpp0-1/etc/hostname @@ -0,0 +1 @@ +vpp0-1 \ No newline at end of file diff --git a/build/default/vpp0-1/etc/hosts b/build/default/vpp0-1/etc/hosts new file mode 100644 index 0000000..5f0cb9e --- /dev/null +++ b/build/default/vpp0-1/etc/hosts @@ -0,0 +1,7 @@ +127.0.0.1 localhost +127.0.1.1 vpp0-1.lab.ipng.ch vpp0-1 + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters \ No newline at end of file diff --git a/build/default/vpp0-1/etc/netplan/01-netcfg.yaml b/build/default/vpp0-1/etc/netplan/01-netcfg.yaml new file mode 100644 index 0000000..bea2b4f --- /dev/null +++ b/build/default/vpp0-1/etc/netplan/01-netcfg.yaml @@ -0,0 +1,14 @@ +network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + optional: true + accept-ra: false + dhcp4: false + addresses: [ 192.168.1.81/24, 2001:678:d78:101::81/64 ] + gateway4: 192.168.1.252 + gateway6: 2001:678:d78:101::1 + nameservers: + addresses: [ "2001:678:d78::3", "2001:678:d78::4" ] + search: [ "lab.ipng.ch", "ipng.ch", "ipng.nl", "rfc1918.ipng.nl" ] \ No newline at end of file diff --git a/build/default/vpp0-1/etc/vpp/bootstrap.vpp b/build/default/vpp0-1/etc/vpp/bootstrap.vpp new file mode 100644 index 0000000..b8b3f14 --- /dev/null +++ b/build/default/vpp0-1/etc/vpp/bootstrap.vpp @@ -0,0 +1,38 @@ +set logging class linux-cp rate-limit 1000 level warn syslog-level notice + +lcp default netns dataplane +lcp lcp-sync on +lcp lcp-auto-subint off + +comment { Create a loopback interface } +create loopback interface instance 0 +lcp create loop0 host-if loop0 +set interface state loop0 up +set interface ip address loop0 192.168.10.1/32 +set interface ip address loop0 2001:678:d78:200::1/128 + +comment { Create one LinuxCP Interface Pair for each phy } +lcp create GigabitEthernet10/0/0 host-if e0 +lcp create GigabitEthernet10/0/1 host-if e1 +lcp create GigabitEthernet10/0/2 host-if e2 +lcp create GigabitEthernet10/0/3 host-if e3 + +comment { e0 is uplink to AS8298 } +set interface state GigabitEthernet10/0/0 up +set interface mtu packet 1500 GigabitEthernet10/0/0 +set interface ip address GigabitEthernet10/0/0 192.168.10.7/31 +set interface ip address GigabitEthernet10/0/0 2001:678:d78:201::00:00/112 + +comment { e1 is ptp with e0.vpp0-1 } +set interface state GigabitEthernet10/0/1 up +set interface mtu packet 9000 GigabitEthernet10/0/1 +set interface ip address GigabitEthernet10/0/1 192.168.10.8/31 +set interface ip address GigabitEthernet10/0/1 2001:678:d78:201::01:00/112 + +comment { e2 is free to use } +set interface state GigabitEthernet10/0/2 down +set interface mtu packet 9000 GigabitEthernet10/0/2 + +comment { e3 is free to use } +set interface state GigabitEthernet10/0/3 down +set interface mtu packet 9000 GigabitEthernet10/0/3 \ No newline at end of file diff --git a/build/default/vpp0-2/etc/bird/bfd.conf b/build/default/vpp0-2/etc/bird/bfd.conf new file mode 100644 index 0000000..b0f329b --- /dev/null +++ b/build/default/vpp0-2/etc/bird/bfd.conf @@ -0,0 +1,6 @@ +protocol bfd bfd1 { + interface "e*" { + interval 100 ms; + multiplier 20; + }; +} \ No newline at end of file diff --git a/build/default/vpp0-2/etc/bird/bird.conf b/build/default/vpp0-2/etc/bird/bird.conf new file mode 100644 index 0000000..7609eed --- /dev/null +++ b/build/default/vpp0-2/etc/bird/bird.conf @@ -0,0 +1,19 @@ +router id 192.168.10.2; + +protocol device { scan time 30; } +protocol direct { ipv4; ipv6; check link yes; } +protocol kernel kernel4 { + ipv4 { import none; export where source != RTS_DEVICE; }; + learn off; + scan time 300; +} +protocol kernel kernel6 { + ipv6 { import none; export where source != RTS_DEVICE; }; + learn off; + scan time 300; +} + +include "static.conf"; +include "bfd.conf"; +include "ospf.conf"; +include "ibgp.conf"; \ No newline at end of file diff --git a/build/default/vpp0-2/etc/bird/ibgp.conf b/build/default/vpp0-2/etc/bird/ibgp.conf new file mode 100644 index 0000000..69dd4d0 --- /dev/null +++ b/build/default/vpp0-2/etc/bird/ibgp.conf @@ -0,0 +1 @@ +# NOTE(ipng): Not created yet \ No newline at end of file diff --git a/build/default/vpp0-2/etc/bird/ospf.conf b/build/default/vpp0-2/etc/bird/ospf.conf new file mode 100644 index 0000000..98a97f1 --- /dev/null +++ b/build/default/vpp0-2/etc/bird/ospf.conf @@ -0,0 +1,21 @@ +protocol ospf v2 ospf4 { + ipv4 { export where source = RTS_DEVICE; import all; }; + area 0 { + interface "loop0" { stub yes; }; + interface "e0" { type pointopoint; cost 5; bfd off; }; + interface "e1" { type pointopoint; cost 5; bfd off; }; + interface "e2" { type pointopoint; cost 5; bfd off; }; + interface "e3" { type pointopoint; cost 5; bfd off; }; + }; +} + +protocol ospf v3 ospf6 { + ipv6 { export where source = RTS_DEVICE; import all; }; + area 0 { + interface "loop0" { stub yes; }; + interface "e0" { type pointopoint; cost 5; bfd off; }; + interface "e1" { type pointopoint; cost 5; bfd off; }; + interface "e2" { type pointopoint; cost 5; bfd off; }; + interface "e3" { type pointopoint; cost 5; bfd off; }; + }; +} \ No newline at end of file diff --git a/build/default/vpp0-2/etc/bird/static.conf b/build/default/vpp0-2/etc/bird/static.conf new file mode 100644 index 0000000..6ec5480 --- /dev/null +++ b/build/default/vpp0-2/etc/bird/static.conf @@ -0,0 +1,11 @@ +protocol static static4 { + ipv4 { export all; }; +# route 192.0.2.0/24 via 10.0.0.1; + route 192.168.10.0/24 unreachable; +} + +protocol static static6 { + ipv6 { export all; }; +# route 2001:db8:cafe::/48 via 2001:db8::1;; + route 2001:678:d78:200::/60 unreachable; +} \ No newline at end of file diff --git a/build/default/vpp0-2/etc/hostname b/build/default/vpp0-2/etc/hostname new file mode 100644 index 0000000..54f661c --- /dev/null +++ b/build/default/vpp0-2/etc/hostname @@ -0,0 +1 @@ +vpp0-2 \ No newline at end of file diff --git a/build/default/vpp0-2/etc/hosts b/build/default/vpp0-2/etc/hosts new file mode 100644 index 0000000..ac79f00 --- /dev/null +++ b/build/default/vpp0-2/etc/hosts @@ -0,0 +1,7 @@ +127.0.0.1 localhost +127.0.1.1 vpp0-2.lab.ipng.ch vpp0-2 + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters \ No newline at end of file diff --git a/build/default/vpp0-2/etc/netplan/01-netcfg.yaml b/build/default/vpp0-2/etc/netplan/01-netcfg.yaml new file mode 100644 index 0000000..5861047 --- /dev/null +++ b/build/default/vpp0-2/etc/netplan/01-netcfg.yaml @@ -0,0 +1,14 @@ +network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + optional: true + accept-ra: false + dhcp4: false + addresses: [ 192.168.1.82/24, 2001:678:d78:101::82/64 ] + gateway4: 192.168.1.252 + gateway6: 2001:678:d78:101::1 + nameservers: + addresses: [ "2001:678:d78::3", "2001:678:d78::4" ] + search: [ "lab.ipng.ch", "ipng.ch", "ipng.nl", "rfc1918.ipng.nl" ] \ No newline at end of file diff --git a/build/default/vpp0-2/etc/vpp/bootstrap.vpp b/build/default/vpp0-2/etc/vpp/bootstrap.vpp new file mode 100644 index 0000000..de80238 --- /dev/null +++ b/build/default/vpp0-2/etc/vpp/bootstrap.vpp @@ -0,0 +1,38 @@ +set logging class linux-cp rate-limit 1000 level warn syslog-level notice + +lcp default netns dataplane +lcp lcp-sync on +lcp lcp-auto-subint off + +comment { Create a loopback interface } +create loopback interface instance 0 +lcp create loop0 host-if loop0 +set interface state loop0 up +set interface ip address loop0 192.168.10.2/32 +set interface ip address loop0 2001:678:d78:200::2/128 + +comment { Create one LinuxCP Interface Pair for each phy } +lcp create GigabitEthernet10/0/0 host-if e0 +lcp create GigabitEthernet10/0/1 host-if e1 +lcp create GigabitEthernet10/0/2 host-if e2 +lcp create GigabitEthernet10/0/3 host-if e3 + +comment { e0 is uplink to AS8298 } +set interface state GigabitEthernet10/0/0 up +set interface mtu packet 1500 GigabitEthernet10/0/0 +set interface ip address GigabitEthernet10/0/0 192.168.10.7/31 +set interface ip address GigabitEthernet10/0/0 2001:678:d78:201::00:00/112 + +comment { e1 is ptp with e0.vpp0-1 } +set interface state GigabitEthernet10/0/1 up +set interface mtu packet 9000 GigabitEthernet10/0/1 +set interface ip address GigabitEthernet10/0/1 192.168.10.8/31 +set interface ip address GigabitEthernet10/0/1 2001:678:d78:201::01:00/112 + +comment { e2 is free to use } +set interface state GigabitEthernet10/0/2 down +set interface mtu packet 9000 GigabitEthernet10/0/2 + +comment { e3 is free to use } +set interface state GigabitEthernet10/0/3 down +set interface mtu packet 9000 GigabitEthernet10/0/3 \ No newline at end of file diff --git a/build/default/vpp0-3/etc/bird/bfd.conf b/build/default/vpp0-3/etc/bird/bfd.conf new file mode 100644 index 0000000..b0f329b --- /dev/null +++ b/build/default/vpp0-3/etc/bird/bfd.conf @@ -0,0 +1,6 @@ +protocol bfd bfd1 { + interface "e*" { + interval 100 ms; + multiplier 20; + }; +} \ No newline at end of file diff --git a/build/default/vpp0-3/etc/bird/bird.conf b/build/default/vpp0-3/etc/bird/bird.conf new file mode 100644 index 0000000..c4e463e --- /dev/null +++ b/build/default/vpp0-3/etc/bird/bird.conf @@ -0,0 +1,19 @@ +router id 192.168.10.3; + +protocol device { scan time 30; } +protocol direct { ipv4; ipv6; check link yes; } +protocol kernel kernel4 { + ipv4 { import none; export where source != RTS_DEVICE; }; + learn off; + scan time 300; +} +protocol kernel kernel6 { + ipv6 { import none; export where source != RTS_DEVICE; }; + learn off; + scan time 300; +} + +include "static.conf"; +include "bfd.conf"; +include "ospf.conf"; +include "ibgp.conf"; \ No newline at end of file diff --git a/build/default/vpp0-3/etc/bird/ibgp.conf b/build/default/vpp0-3/etc/bird/ibgp.conf new file mode 100644 index 0000000..69dd4d0 --- /dev/null +++ b/build/default/vpp0-3/etc/bird/ibgp.conf @@ -0,0 +1 @@ +# NOTE(ipng): Not created yet \ No newline at end of file diff --git a/build/default/vpp0-3/etc/bird/ospf.conf b/build/default/vpp0-3/etc/bird/ospf.conf new file mode 100644 index 0000000..98a97f1 --- /dev/null +++ b/build/default/vpp0-3/etc/bird/ospf.conf @@ -0,0 +1,21 @@ +protocol ospf v2 ospf4 { + ipv4 { export where source = RTS_DEVICE; import all; }; + area 0 { + interface "loop0" { stub yes; }; + interface "e0" { type pointopoint; cost 5; bfd off; }; + interface "e1" { type pointopoint; cost 5; bfd off; }; + interface "e2" { type pointopoint; cost 5; bfd off; }; + interface "e3" { type pointopoint; cost 5; bfd off; }; + }; +} + +protocol ospf v3 ospf6 { + ipv6 { export where source = RTS_DEVICE; import all; }; + area 0 { + interface "loop0" { stub yes; }; + interface "e0" { type pointopoint; cost 5; bfd off; }; + interface "e1" { type pointopoint; cost 5; bfd off; }; + interface "e2" { type pointopoint; cost 5; bfd off; }; + interface "e3" { type pointopoint; cost 5; bfd off; }; + }; +} \ No newline at end of file diff --git a/build/default/vpp0-3/etc/bird/static.conf b/build/default/vpp0-3/etc/bird/static.conf new file mode 100644 index 0000000..6ec5480 --- /dev/null +++ b/build/default/vpp0-3/etc/bird/static.conf @@ -0,0 +1,11 @@ +protocol static static4 { + ipv4 { export all; }; +# route 192.0.2.0/24 via 10.0.0.1; + route 192.168.10.0/24 unreachable; +} + +protocol static static6 { + ipv6 { export all; }; +# route 2001:db8:cafe::/48 via 2001:db8::1;; + route 2001:678:d78:200::/60 unreachable; +} \ No newline at end of file diff --git a/build/default/vpp0-3/etc/hostname b/build/default/vpp0-3/etc/hostname new file mode 100644 index 0000000..08b4f17 --- /dev/null +++ b/build/default/vpp0-3/etc/hostname @@ -0,0 +1 @@ +vpp0-3 \ No newline at end of file diff --git a/build/default/vpp0-3/etc/hosts b/build/default/vpp0-3/etc/hosts new file mode 100644 index 0000000..a2ad3f9 --- /dev/null +++ b/build/default/vpp0-3/etc/hosts @@ -0,0 +1,7 @@ +127.0.0.1 localhost +127.0.1.1 vpp0-3.lab.ipng.ch vpp0-3 + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters \ No newline at end of file diff --git a/build/default/vpp0-3/etc/netplan/01-netcfg.yaml b/build/default/vpp0-3/etc/netplan/01-netcfg.yaml new file mode 100644 index 0000000..fe65c2a --- /dev/null +++ b/build/default/vpp0-3/etc/netplan/01-netcfg.yaml @@ -0,0 +1,14 @@ +network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + optional: true + accept-ra: false + dhcp4: false + addresses: [ 192.168.1.83/24, 2001:678:d78:101::83/64 ] + gateway4: 192.168.1.252 + gateway6: 2001:678:d78:101::1 + nameservers: + addresses: [ "2001:678:d78::3", "2001:678:d78::4" ] + search: [ "lab.ipng.ch", "ipng.ch", "ipng.nl", "rfc1918.ipng.nl" ] \ No newline at end of file diff --git a/build/default/vpp0-3/etc/vpp/bootstrap.vpp b/build/default/vpp0-3/etc/vpp/bootstrap.vpp new file mode 100644 index 0000000..a4f23ce --- /dev/null +++ b/build/default/vpp0-3/etc/vpp/bootstrap.vpp @@ -0,0 +1,38 @@ +set logging class linux-cp rate-limit 1000 level warn syslog-level notice + +lcp default netns dataplane +lcp lcp-sync on +lcp lcp-auto-subint off + +comment { Create a loopback interface } +create loopback interface instance 0 +lcp create loop0 host-if loop0 +set interface state loop0 up +set interface ip address loop0 192.168.10.3/32 +set interface ip address loop0 2001:678:d78:200::3/128 + +comment { Create one LinuxCP Interface Pair for each phy } +lcp create GigabitEthernet10/0/0 host-if e0 +lcp create GigabitEthernet10/0/1 host-if e1 +lcp create GigabitEthernet10/0/2 host-if e2 +lcp create GigabitEthernet10/0/3 host-if e3 + +comment { e0 is uplink to AS8298 } +set interface state GigabitEthernet10/0/0 up +set interface mtu packet 1500 GigabitEthernet10/0/0 +set interface ip address GigabitEthernet10/0/0 192.168.10.7/31 +set interface ip address GigabitEthernet10/0/0 2001:678:d78:201::00:00/112 + +comment { e1 is ptp with e0.vpp0-1 } +set interface state GigabitEthernet10/0/1 up +set interface mtu packet 9000 GigabitEthernet10/0/1 +set interface ip address GigabitEthernet10/0/1 192.168.10.8/31 +set interface ip address GigabitEthernet10/0/1 2001:678:d78:201::01:00/112 + +comment { e2 is free to use } +set interface state GigabitEthernet10/0/2 down +set interface mtu packet 9000 GigabitEthernet10/0/2 + +comment { e3 is free to use } +set interface state GigabitEthernet10/0/3 down +set interface mtu packet 9000 GigabitEthernet10/0/3 \ No newline at end of file diff --git a/config/common/generic.yaml b/config/common/generic.yaml new file mode 100644 index 0000000..8294f30 --- /dev/null +++ b/config/common/generic.yaml @@ -0,0 +1,21 @@ +pubkeys: + root: + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8X6oRdLn7PckWIRL+Fgp46qN+fglQLBJIvPHJ2P277v4tx/qlELaT8w45YyEPrUZ4XbbNIB4P59H63wPxIpk/d15k0C7Zx3kTESaEQuts3fne3ZFmrWm0dLD2yDTiB0zCraiQ5a0w++xuGEC3wdWPV+FHZh5Ea+WCd91g2xXPHJeosAQzBBBBaC9Shhx91h6lbCm4evvgqLnwt7JgnI2N4w2qr13lDDaRD4BXfyFrtLSTdhBgYEaFnUd6Afz5ilfDYXQW/yTSHZOIQ/vNVFpFxYrtmwHDdrSMiDpz0FE/4LLBG/rFl2VvRTmTEyjvwpGpEVaivMOLo/jRc3TA7jKB pim@ipng.nl" + - "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKDP/hLZusPNfKTy3t9bbbOHyczX+UACc4rYstc3QEDBDfxBnCZcMKN5Mv10o+q/+ap7wyFhONlz/qcUhEMbI1k=" + ipng: + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8X6oRdLn7PckWIRL+Fgp46qN+fglQLBJIvPHJ2P277v4tx/qlELaT8w45YyEPrUZ4XbbNIB4P59H63wPxIpk/d15k0C7Zx3kTESaEQuts3fne3ZFmrWm0dLD2yDTiB0zCraiQ5a0w++xuGEC3wdWPV+FHZh5Ea+WCd91g2xXPHJeosAQzBBBBaC9Shhx91h6lbCm4evvgqLnwt7JgnI2N4w2qr13lDDaRD4BXfyFrtLSTdhBgYEaFnUd6Afz5ilfDYXQW/yTSHZOIQ/vNVFpFxYrtmwHDdrSMiDpz0FE/4LLBG/rFl2VvRTmTEyjvwpGpEVaivMOLo/jRc3TA7jKB pim@ipng.nl" + - "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKDP/hLZusPNfKTy3t9bbbOHyczX+UACc4rYstc3QEDBDfxBnCZcMKN5Mv10o+q/+ap7wyFhONlz/qcUhEMbI1k=" + + +overlays: + default: + path: overlays/bird/ + build: build/default/ + + bird: + path: overlays/bird/ + build: build/bird/ + + frr: + path: overlays/frr/ + build: build/frr/ diff --git a/config/hvn0.lab.ipng.ch.yaml b/config/hvn0.lab.ipng.ch.yaml new file mode 100644 index 0000000..b1ffe93 --- /dev/null +++ b/config/hvn0.lab.ipng.ch.yaml @@ -0,0 +1,22 @@ +lab: + id: 0 + mgmt: + ipv4: 192.168.1.80/24 + ipv6: 2001:678:d78:101::80/64 + gw4: 192.168.1.252 + gw6: 2001:678:d78:101::1 + ipv4: 192.168.10.0/24 + ipv6: 2001:678:d78:200::/60 + hypervisor: hvn0.lab.ipng.ch + nodes: 4 + +## for i in lab.nodes; do +# node: +# hostname: "vpp" + lab.id + "-" + i +# id: i +# mgmt: +# ipv4: lab.mgmt.ipv4 + node.id +# ipv6: lab.mgmt.ipv6 + node.id +# loopback: +# ipv4: lab.ipv4 + node.id + "/32" +# ipv6: lab.ipv6 + node.id + "/128" diff --git a/generate b/generate new file mode 100755 index 0000000..32ef53c --- /dev/null +++ b/generate @@ -0,0 +1,270 @@ +#!/usr/bin/env python3 +""" + Labs for IPng Networks + + (c) 2022- Pim van Pelt + +""" + +from jinja2 import Environment, FileSystemLoader +from jinja2_ansible_filters import AnsibleCoreFiltersExtension + +import hiyapyco +import traceback +import os +import sys +import pprint +import logging +import ipaddress +import re + +try: + import argparse +except ImportError: + print("ERROR: install argparse manually") + print("HINT: sudo pip install argparse") + sys.exit(2) + +log = logging.getLogger("generate") +log.setLevel(logging.INFO) +formatter = logging.Formatter( + "[%(levelname)-8s] %(name)17s - %(funcName)-15s: %(message)s" +) +ch = logging.StreamHandler() +ch.setLevel(logging.DEBUG) +ch.setFormatter(formatter) +log.addHandler(ch) + + +def toyaml(d, indent=0, result=""): + for key, value in d.items(): + result += " " * indent + str(key) + ": " + if isinstance(value, dict): + result = toyaml(value, indent + 2, result + "\n") + else: + if isinstance(value, str) and [ + e for e in [" ", ":", "{", "}", "[", "]", "#"] if e in value + ]: + result += "'" + str(value) + "'\n" + else: + result += str(value) + "\n" + return result + + +def render(tpl_path, data, trim=True): + path, filename = os.path.split(tpl_path) + env = Environment( + loader=FileSystemLoader(path or "./"), extensions=[AnsibleCoreFiltersExtension] + ) + env.trim_blocks = trim + env.lstrip_blocks = trim + env.rstrip_blocks = trim + env.filters["toyaml"] = toyaml + + return env.get_template(filename).render(data) + + +def tpl2fn(tpl, prefix): + fn = tpl[len(prefix) :] + if fn.endswith(".j2"): + fn = fn[:-3] + return fn + + +def find(file_or_dir_list): + log.info("Finding templates in %s" % file_or_dir_list) + ret = {} + for e in file_or_dir_list: + if e.startswith("_"): + continue + if os.path.isfile(e): + ret[e] = tpl2fn(e, e) + elif os.path.isdir(e): + for root, dirnames, filenames in os.walk(e): + for filename in filenames: + if filename.startswith("_"): + continue + tpl = os.path.join(root, filename) + ret[tpl] = tpl2fn(tpl, e) + + log.debug("Templates: %s" % ret) + return ret + + +def generate(templates, data, debug=False): + output = {} + for tpl, fn in templates.items(): + log.info("Rendering %s into %s" % (tpl, fn)) + try: + output[fn] = render(tpl, data) + except: + log.error("Could not render %s!" % tpl) + if debug: + traceback.print_exc(file=sys.stderr) + return None + return output + + +def emit(output, outdir): + log.debug("Emitting to %s" % outdir) + for fn, contents in output.items(): + if outdir == "-": + log.info("Emitting %s" % fn) + print(contents) + continue + + outfile = os.path.join(outdir, fn) + log.info("Emitting %s into %s" % (fn, outfile)) + basedir = os.path.dirname(outfile) + os.makedirs(basedir, exist_ok=True) + f = open(outfile, "w") + f.write(contents) + f.close() + + +def prune(output, outdir): + if outdir == "-": + log.info("Skipping pruning, output is stdout") + return True + + for root, dirnames, filenames in os.walk(outdir): + for filename in filenames: + fn = os.path.join(root, filename) # build/frggh0.ipng.ch/bird/bird.conf + rel_fn = fn.replace(outdir, "") # /bird/bird.conf + if rel_fn[0] == "/": + rel_fn = rel_fn[1:] # bird/bird.conf + if not rel_fn in output: + log.info("Pruning file %s (%s)" % (rel_fn, fn)) + os.remove(fn) + + for root, dirnames, filenames in os.walk(outdir): + for dirname in dirnames: + dn = os.path.join(root, dirname) # build/frggh0.ipng.ch/bird/empty + if not os.listdir(dn): + log.info("Pruning dir %s" % (dn)) + os.rmdir(dn) + + +def create_node(lab, node_id): + v4_base, v4_plen = lab["mgmt"]["ipv4"].split("/") + v6_base, v6_plen = lab["mgmt"]["ipv6"].split("/") + lo4_base = lab["ipv4"].split("/")[0] + lo6_base = lab["ipv6"].split("/")[0] + ret = { + "hostname": "vpp%d-%d" % (lab["id"], node_id), + "id": node_id, + "mgmt": { + "ipv4": "%s/%s" + % ( + ipaddress.IPv4Address(v4_base) + lab["nodes"] * lab["id"] + node_id, + v4_plen, + ), + "ipv6": "%s/%s" + % ( + ipaddress.IPv6Address(v6_base) + lab["nodes"] * lab["id"] + node_id, + v6_plen, + ), + "gw4": lab["mgmt"]["gw4"], + "gw6": lab["mgmt"]["gw6"], + }, + "loopback": { + "ipv4": "%s/32" % (ipaddress.IPv4Address(lo4_base) + node_id), + "ipv6": "%s/128" % (ipaddress.IPv6Address(lo6_base) + node_id), + }, + } + return ret + + +def main(): + + parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument( + "-d", dest="debug", action="store_true", help="""Enable debug""" + ) + parser.add_argument( + "-q", dest="quiet", action="store_true", help="""Quiet output""" + ) + parser.add_argument("--host", dest="hostname", help="""Hostname to configure for""") + parser.add_argument( + "--yaml", + dest="yamldata", + default=["config/common/generic.yaml"], + type=str, + nargs="*", + help="""Location of YAML data file(s)""", + ) + parser.add_argument( + "--overlay", + dest="overlay", + default="default", + type=str, + help="""Type of lab setup (defined in config/common/generic.yaml 'overlays' dictionary, defaults to 'default')""", + ) + parser.add_argument( + "-o", + dest="output", + type=str, + default=None, + help="Output directory (default: overlay.build)", + ) + + args = parser.parse_args() + if args.debug and args.quiet: + parser.print_help() + return + + if not args.hostname: + parser.print_help() + return + + if args.quiet: + log.setLevel(logging.ERROR) + elif args.debug: + log.setLevel(logging.DEBUG) + + yamldata = "config/%s.yaml" % args.hostname + if not os.path.exists(yamldata): + log.error("Can't read config file %s" % yamldata) + return + log.info("Generating host %s" % (args.hostname)) + + # Assemble the YAML dictionary + yamldata = args.yamldata + [yamldata] + log.debug("YAML data: %s" % yamldata) + data = hiyapyco.load(*yamldata, method=hiyapyco.METHOD_MERGE, interpolate=True) + if args.debug: + log.debug("YAML merged configuration") + print(hiyapyco.dump(data, default_flow_style=False)) + + if not args.overlay in data["overlays"]: + log.error("Overlay not defined, bailing.") + return + + # Assemble a dictionary of tpl=>fn + overlay = data["overlays"][args.overlay] + template_root = overlay["path"] + "templates/" + templates = find([template_root]) + + for node_id in range(data["lab"]["nodes"]): + log.info("Generating for node %d" % node_id) + data["node"] = create_node(data["lab"], node_id) + log.debug("node: %s" % data["node"]) + + # Assemble a dictionary of fn=>output + build = generate(templates, data, args.debug) + if not build: + return + + # Emit the output (fn=>output) + if not args.output and "build" in overlay: + output = overlay["build"] + data["node"]["hostname"] + else: + output = "-" + emit(build, output) + + # Remove all files/dirs not in (fn=>output) + # prune(output, args.output) + + +if __name__ == "__main__": + main() diff --git a/overlays/bird/templates/etc/bird/bfd.conf.j2 b/overlays/bird/templates/etc/bird/bfd.conf.j2 new file mode 100644 index 0000000..350e594 --- /dev/null +++ b/overlays/bird/templates/etc/bird/bfd.conf.j2 @@ -0,0 +1,6 @@ +protocol bfd bfd1 { + interface "e*" { + interval 100 ms; + multiplier 20; + }; +} diff --git a/overlays/bird/templates/etc/bird/bird.conf.j2 b/overlays/bird/templates/etc/bird/bird.conf.j2 new file mode 100644 index 0000000..083d5ca --- /dev/null +++ b/overlays/bird/templates/etc/bird/bird.conf.j2 @@ -0,0 +1,19 @@ +router id {{ node.loopback.ipv4.split("/")[0] }}; + +protocol device { scan time 30; } +protocol direct { ipv4; ipv6; check link yes; } +protocol kernel kernel4 { + ipv4 { import none; export where source != RTS_DEVICE; }; + learn off; + scan time 300; +} +protocol kernel kernel6 { + ipv6 { import none; export where source != RTS_DEVICE; }; + learn off; + scan time 300; +} + +include "static.conf"; +include "bfd.conf"; +include "ospf.conf"; +include "ibgp.conf"; diff --git a/overlays/bird/templates/etc/bird/ibgp.conf.j2 b/overlays/bird/templates/etc/bird/ibgp.conf.j2 new file mode 100644 index 0000000..4f17e36 --- /dev/null +++ b/overlays/bird/templates/etc/bird/ibgp.conf.j2 @@ -0,0 +1 @@ +# NOTE(ipng): Not created yet diff --git a/overlays/bird/templates/etc/bird/ospf.conf.j2 b/overlays/bird/templates/etc/bird/ospf.conf.j2 new file mode 100644 index 0000000..f29d79f --- /dev/null +++ b/overlays/bird/templates/etc/bird/ospf.conf.j2 @@ -0,0 +1,21 @@ +protocol ospf v2 ospf4 { + ipv4 { export where source = RTS_DEVICE; import all; }; + area 0 { + interface "loop0" { stub yes; }; + interface "e0" { type pointopoint; cost 5; bfd off; }; + interface "e1" { type pointopoint; cost 5; bfd off; }; + interface "e2" { type pointopoint; cost 5; bfd off; }; + interface "e3" { type pointopoint; cost 5; bfd off; }; + }; +} + +protocol ospf v3 ospf6 { + ipv6 { export where source = RTS_DEVICE; import all; }; + area 0 { + interface "loop0" { stub yes; }; + interface "e0" { type pointopoint; cost 5; bfd off; }; + interface "e1" { type pointopoint; cost 5; bfd off; }; + interface "e2" { type pointopoint; cost 5; bfd off; }; + interface "e3" { type pointopoint; cost 5; bfd off; }; + }; +} diff --git a/overlays/bird/templates/etc/bird/static.conf.j2 b/overlays/bird/templates/etc/bird/static.conf.j2 new file mode 100644 index 0000000..4dc7334 --- /dev/null +++ b/overlays/bird/templates/etc/bird/static.conf.j2 @@ -0,0 +1,11 @@ +protocol static static4 { + ipv4 { export all; }; +# route 192.0.2.0/24 via 10.0.0.1; + route {{lab.ipv4}} unreachable; +} + +protocol static static6 { + ipv6 { export all; }; +# route 2001:db8:cafe::/48 via 2001:db8::1;; + route {{lab.ipv6}} unreachable; +} diff --git a/overlays/bird/templates/etc/hostname.j2 b/overlays/bird/templates/etc/hostname.j2 new file mode 100644 index 0000000..c4f53f7 --- /dev/null +++ b/overlays/bird/templates/etc/hostname.j2 @@ -0,0 +1 @@ +{{ node.hostname }} diff --git a/overlays/bird/templates/etc/hosts.j2 b/overlays/bird/templates/etc/hosts.j2 new file mode 100644 index 0000000..e5dce8d --- /dev/null +++ b/overlays/bird/templates/etc/hosts.j2 @@ -0,0 +1,7 @@ +127.0.0.1 localhost +127.0.1.1 {{node.hostname}}.lab.ipng.ch {{node.hostname}} + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters diff --git a/overlays/bird/templates/etc/netplan/01-netcfg.yaml.j2 b/overlays/bird/templates/etc/netplan/01-netcfg.yaml.j2 new file mode 100644 index 0000000..beaa5f4 --- /dev/null +++ b/overlays/bird/templates/etc/netplan/01-netcfg.yaml.j2 @@ -0,0 +1,14 @@ +network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + optional: true + accept-ra: false + dhcp4: false + addresses: [ {{node.mgmt.ipv4}}, {{node.mgmt.ipv6}} ] + gateway4: {{lab.mgmt.gw4}} + gateway6: {{lab.mgmt.gw6}} + nameservers: + addresses: [ "2001:678:d78::3", "2001:678:d78::4" ] + search: [ "lab.ipng.ch", "ipng.ch", "ipng.nl", "rfc1918.ipng.nl" ] diff --git a/overlays/bird/templates/etc/vpp/bootstrap.vpp.j2 b/overlays/bird/templates/etc/vpp/bootstrap.vpp.j2 new file mode 100644 index 0000000..27010ea --- /dev/null +++ b/overlays/bird/templates/etc/vpp/bootstrap.vpp.j2 @@ -0,0 +1,38 @@ +set logging class linux-cp rate-limit 1000 level warn syslog-level notice + +lcp default netns dataplane +lcp lcp-sync on +lcp lcp-auto-subint off + +comment { Create a loopback interface } +create loopback interface instance 0 +lcp create loop0 host-if loop0 +set interface state loop0 up +set interface ip address loop0 {{ node.loopback.ipv4 }} +set interface ip address loop0 {{ node.loopback.ipv6 }} + +comment { Create one LinuxCP Interface Pair for each phy } +lcp create GigabitEthernet10/0/0 host-if e0 +lcp create GigabitEthernet10/0/1 host-if e1 +lcp create GigabitEthernet10/0/2 host-if e2 +lcp create GigabitEthernet10/0/3 host-if e3 + +comment { e0 is uplink to AS8298 } +set interface state GigabitEthernet10/0/0 up +set interface mtu packet 1500 GigabitEthernet10/0/0 +set interface ip address GigabitEthernet10/0/0 192.168.10.7/31 +set interface ip address GigabitEthernet10/0/0 2001:678:d78:201::00:00/112 + +comment { e1 is ptp with e0.vpp0-1 } +set interface state GigabitEthernet10/0/1 up +set interface mtu packet 9000 GigabitEthernet10/0/1 +set interface ip address GigabitEthernet10/0/1 192.168.10.8/31 +set interface ip address GigabitEthernet10/0/1 2001:678:d78:201::01:00/112 + +comment { e2 is free to use } +set interface state GigabitEthernet10/0/2 down +set interface mtu packet 9000 GigabitEthernet10/0/2 + +comment { e3 is free to use } +set interface state GigabitEthernet10/0/3 down +set interface mtu packet 9000 GigabitEthernet10/0/3