diff --git a/images/frr/Dockerfile b/images/frr/Dockerfile new file mode 100644 index 00000000..b17e45c2 --- /dev/null +++ b/images/frr/Dockerfile @@ -0,0 +1,26 @@ +FROM debian:stable + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -qy \ + && apt-get upgrade -qy \ + && apt-get install -y \ + bridge-utils \ + iproute2 \ + python3-ipy \ + socat \ + screen \ + qemu-kvm \ + ssh \ + tcpdump \ + ethtool \ + telnet \ + procps \ + && rm -rf /var/lib/apt/lists/* + +COPY frr.qcow2 /frr.qcow2 +COPY launch.sh / + +EXPOSE 22 161/udp 830 5000 10000-10099 +ENTRYPOINT ["/launch.sh"] + diff --git a/images/frr/Makefile b/images/frr/Makefile new file mode 100644 index 00000000..df226032 --- /dev/null +++ b/images/frr/Makefile @@ -0,0 +1,11 @@ +# SHELL=/bin/bash + +TARGET_VERSION ?= latest + +all: docker + +docker: + gsutil cp "gs://nrelabs-curriculum-base-images/frr-7.2-dev/frr-7.2-dev.qcow2" "./frr.qcow2" + docker build --pull --no-cache -t cloudtoad/frr:$(TARGET_VERSION) . + docker push cloudtoad/frr:$(TARGET_VERSION) + diff --git a/images/frr/launch.sh b/images/frr/launch.sh new file mode 100755 index 00000000..dd3151a1 --- /dev/null +++ b/images/frr/launch.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +mount -o rw,remount /sys + +random_mac () { + hexchars="0123456789abcdef" + end=$( for i in {1..6} ; do echo -n ${hexchars:$(( $RANDOM % 16 )):1} ; done | sed -e 's/\(..\)/:\1/g' ) + + # QEMU OUI space - important to use this + echo 52:54:00$end +} + +ethlist=$(ls /sys/class/net | grep 'net' | grep -v 'eth0') + +NETDEVS="" + +COUNTER=0 +for eth in $ethlist +do + + let COUNTER1=COUNTER+1 + + net="net$COUNTER1" + tap="tap$COUNTER" + bridge=br$net$tap + + ip link add $bridge type bridge + ip addr flush dev $net + ip link set $net master $bridge + ip tuntap add dev $tap mode tap + ip link set $tap master $bridge + ip link set $bridge up + ip link set $tap up + + # Enable LLDP + echo 16384 > /sys/class/net/$bridge/bridge/group_fwd_mask + + NETDEVS="$NETDEVS -netdev tap,id=dev$COUNTER,ifname=$tap,script=no,downscript=no -device virtio-net-pci,netdev=dev$COUNTER,id=eth$COUNTER1,mac=$(random_mac),addr=1.$COUNTER1" + let COUNTER=COUNTER+1 +done + +printf "%s\n" $NETDEVS + +screen -d -m socat TCP-LISTEN:22,fork TCP:127.0.0.1:2022 +screen -d -m socat UDP-LISTEN:161,fork UDP:127.0.0.1:2161 +screen -d -m socat TCP-LISTEN:830,fork TCP:127.0.0.1:2830 +screen -d -m socat TCP-LISTEN:8080,fork TCP:127.0.0.1:2880 + + + +/usr/bin/qemu-system-x86_64 \ + --enable-kvm \ + -cpu host \ + -display none \ + -machine pc \ + -m 2048 \ + -serial telnet:0.0.0.0:5000,server,nowait \ + -drive if=ide,file=/frr.qcow2,index=0 \ + -net nic,model=virtio-net-pci,macaddr=$(random_mac),addr=1.0 \ + -net user,net=10.0.0.0/24,tftp=/tftpboot,hostfwd=tcp::2022-10.0.0.15:22,hostfwd=udp::2161-10.0.0.15:161,hostfwd=tcp::2830-10.0.0.15:830,hostfwd=tcp::2880-10.0.0.15:8080 \ + $NETDEVS + diff --git a/lessons/fundamentals/lesson-98-frr/lesson.meta.yaml b/lessons/fundamentals/lesson-98-frr/lesson.meta.yaml new file mode 100644 index 00000000..b131f1e3 --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/lesson.meta.yaml @@ -0,0 +1,77 @@ +--- +lessonName: Cumulus in NRELabs +lessonId: 90 +category: fundamentals +lessondiagram: https://raw.githubusercontent.com/nre-learning/nrelabs-curriculum/v0.3.2/lessons/lesson-99/lessondiagram.png +tier: ptr +prereqs: + - 22 # Python + - 23 # Linux +description: Cumulus in NRELabs +slug: Cumulus demo +tags: +- troubleshooting +- tshoot + +endpoints: +- name: linux1 + image: antidotelabs/utility + presentations: + - name: cli + port: 22 + type: ssh + +- name: linux2 + image: antidotelabs/utility + presentations: + - name: cli + port: 22 + type: ssh + +- name: linux3 + image: antidotelabs/utility + presentations: + - name: cli + port: 22 + type: ssh + +- name: hub + image: antidotelabs/frr + configurationType: python + presentations: + - name: cli + port: 22 + type: ssh + +- name: branch-1 + image: antidotelabs/frr + configurationType: python + presentations: + - name: cli + port: 22 + type: ssh + +- name: branch-2 + image: antidotelabs/frr + configurationType: python + presentations: + - name: cli + port: 22 + type: ssh + +connections: +- a: hub + b: branch-1 +- a: hub + b: branch-2 +- a: hub + b: linux1 +- a: branch-1 + b: linux2 +- a: branch-2 + b: linux3 + +stages: + - id: 1 + description: FRR in NRELabs + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1.py b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1.py new file mode 100644 index 00000000..f95261a3 --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1.py @@ -0,0 +1,46 @@ +import paramiko +import os +from scp import SCPClient + +host=os.environ['SYRINGE_TARGET_HOST'] + +def createSSHClient(server, port, user, password): + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(server, port, user, password) + return client + +ssh=createSSHClient(host,22,"antidote","antidotepassword") + +scp=SCPClient(ssh.get_transport()) + +#Change hostname + +ssh.exec_command("sudo sed -E -i 's/^(127\.0\.1\.1\s+).*/\\1branch-1/' /etc/hosts") +ssh.exec_command("sudo printf '%s' 'branch-1' > /etc/hostname") +ssh.exec_command("sudo hostname branch-1") + +#Copy configuration files over +scp.put('/antidote/stage1/configs/branch-1/interfaces', '/home/antidote/interfaces') +scp.put('/antidote/stage1/configs/branch-1/daemons', '/home/antidote/daemons') +scp.put('/antidote/stage1/configs/branch-1/*.conf', '/home/antidote/*.conf') + + +ssh.exec_command('sudo cp /home/antidote/interfaces /etc/network/interfaces') +ssh.exec_command('sudo cp /home/antidote/daemons /etc/frr/daemons') +ssh.exec_command('sudo cp /home/antidote/*.conf /etc/frr/*.conf') + + +ssh.exec_command('sudo chown frr:frr /etc/frr/*.conf') +ssh.exec_command('sudo chown frr:frrvty /etc/frr/vtysh.conf') +ssh.exec_command('sudo chmod 640 /etc/frr/*.conf') + +#Restart FRR and bump interfaces +ssh.exec_command('sudo systemctl restart frr.service') +ssh.exec_command('sudo ifreload -a') + +scp.close() +ssh.close() + + + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1/bgpd.conf b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1/bgpd.conf new file mode 100644 index 00000000..fd12da94 --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1/bgpd.conf @@ -0,0 +1,23 @@ +! +! Zebra configuration saved from vty +! 2019/09/26 08:24:11 +! +frr version 7.2-dev +frr defaults traditional +! +hostname branch-1 +log file /var/log/frr/frr.log +! +! +! +router bgp 65001 + bgp router-id 1.1.1.2 + neighbor 10.10.10.1 remote-as 65000 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! +! +line vty +! diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1/daemons b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1/daemons new file mode 100644 index 00000000..2d68a88c --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1/daemons @@ -0,0 +1,27 @@ +# This file tells the frr package which daemons to start. +# +# Sample configurations for these daemons can be found in +# /usr/share/doc/frr/examples/. +# +# ATTENTION: +# +# When activating a daemon for the first time, a config file, even if it is +# empty, has to be present *and* be owned by the user and group "frr", else +# the daemon will not be started by /etc/init.d/frr. The permissions should +# be u=rw,g=r,o=. +# When using "vtysh" such a config file is also needed. It should be owned by +# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. +# +# The watchfrr and zebra daemons are always started. +bgpd=yes + +# +# +# If this option is set the /etc/init.d/frr script automatically loads +# the config via "vtysh -b" when the servers are started. +# Check /etc/pam.d/frr if you intend to use "vtysh"! +# +vtysh_enable=yes +zebra_options=" -M sysrepo -A 127.0.0.1 -s 90000000" +bgpd_options=" -A 127.0.0.1" + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1/interfaces b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1/interfaces new file mode 100644 index 00000000..a640b0f2 --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-1/interfaces @@ -0,0 +1,15 @@ +auto lo +iface lo inet loopback + address 10.1.1.2/32 + +auto enp1s0 +iface enp1s0 inet dhcp + +auto enp1s1 +iface enp1s1 inet static + address 10.10.10.2/30 + +auto enp1s2 +iface enp1s2 inet static + address 10.10.100.1/30 + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2.py b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2.py new file mode 100644 index 00000000..69e36d62 --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2.py @@ -0,0 +1,46 @@ +import paramiko +import os +from scp import SCPClient + +host=os.environ['SYRINGE_TARGET_HOST'] + +def createSSHClient(server, port, user, password): + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(server, port, user, password) + return client + +ssh=createSSHClient(host,22,"antidote","antidotepassword") + +scp=SCPClient(ssh.get_transport()) + +#Change hostname + +ssh.exec_command("sudo sed -E -i 's/^(127\.0\.1\.1\s+).*/\\1branch-2/' /etc/hosts") +ssh.exec_command("sudo printf '%s' 'branch-2' > /etc/hostname") +ssh.exec_command("sudo hostname branch-2") + +#Copy configuration files over +scp.put('/antidote/stage1/configs/branch-2/interfaces', '/home/antidote/interfaces') +scp.put('/antidote/stage1/configs/branch-2/daemons', '/home/antidote/daemons') +scp.put('/antidote/stage1/configs/branch-2/*.conf', '/home/antidote/*.conf') + + +ssh.exec_command('sudo cp /home/antidote/interfaces /etc/network/interfaces') +ssh.exec_command('sudo cp /home/antidote/daemons /etc/frr/daemons') +ssh.exec_command('sudo cp /home/antidote/*.conf /etc/frr/*.conf') + + +ssh.exec_command('sudo chown frr:frr /etc/frr/*.conf') +ssh.exec_command('sudo chown frr:frrvty /etc/frr/vtysh.conf') +ssh.exec_command('sudo chmod 640 /etc/frr/*.conf') + +#Restart FRR and bump interfaces +ssh.exec_command('sudo systemctl restart frr.service') +ssh.exec_command('sudo ifreload -a') + +scp.close() +ssh.close() + + + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2/daemons b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2/daemons new file mode 100644 index 00000000..4ff95c9f --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2/daemons @@ -0,0 +1,3 @@ +zebra=yes +bgpd=yes + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2/frr.conf b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2/frr.conf new file mode 100644 index 00000000..cf81b767 --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2/frr.conf @@ -0,0 +1,7 @@ +router bgp 65003 + bgp router-id 10.1.1.3 + neighbor 10.10.20.1 remote-as 65001 + address-family ipv4 unicast + neighbor 10.10.20.1 activate + redistribute connected + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2/interfaces b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2/interfaces new file mode 100644 index 00000000..06f0f306 --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/branch-2/interfaces @@ -0,0 +1,23 @@ +auto lo +iface lo inet loopback + address 10.1.1.3/32 + +auto eth0 +iface eth0 inet dhcp + vrf mgmt + +auto mgmt +iface mgmt + address 127.0.0.1/8 + vrf-table auto + +auto swp1 +allow-uplink swp1 +iface swp1 inet static + address 10.10.20.2/30 + +auto swp2 +allow-uplink swp2 +iface swp2 inet static + address 10.10.200.1/30 + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/hub.py b/lessons/fundamentals/lesson-98-frr/stage1/configs/hub.py new file mode 100644 index 00000000..f3d71ff8 --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/hub.py @@ -0,0 +1,46 @@ +import paramiko +import os +from scp import SCPClient + +host=os.environ['SYRINGE_TARGET_HOST'] + +def createSSHClient(server, port, user, password): + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(server, port, user, password) + return client + +ssh=createSSHClient(host,22,"antidote","antidotepassword") + +scp=SCPClient(ssh.get_transport()) + +#Change hostname + +ssh.exec_command("sudo sed -E -i 's/^(127\.0\.1\.1\s+).*/\\1hub/' /etc/hosts") +ssh.exec_command("sudo printf '%s' 'hub' > /etc/hostname") +ssh.exec_command("sudo hostname hub") + +#Copy configuration files over +scp.put('/antidote/stage1/configs/hub/interfaces', '/home/antidote/interfaces') +scp.put('/antidote/stage1/configs/hub/daemons', '/home/antidote/daemons') +scp.put('/antidote/stage1/configs/hub/*.conf', '/home/antidote/*.conf') + + +ssh.exec_command('sudo cp /home/antidote/interfaces /etc/network/interfaces') +ssh.exec_command('sudo cp /home/antidote/daemons /etc/frr/daemons') +ssh.exec_command('sudo cp /home/antidote/*.conf /etc/frr/*.conf') + + +ssh.exec_command('sudo chown frr:frr /etc/frr/*.conf') +ssh.exec_command('sudo chown frr:frrvty /etc/frr/vtysh.conf') +ssh.exec_command('sudo chmod 640 /etc/frr/*.conf') + +#Restart FRR and bump interfaces +ssh.exec_command('sudo systemctl restart frr.service') +ssh.exec_command('sudo ifreload -a') + +scp.close() +ssh.close() + + + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/bgpd.conf b/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/bgpd.conf new file mode 100644 index 00000000..38a494db --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/bgpd.conf @@ -0,0 +1,23 @@ +! +! Zebra configuration saved from vty +! 2019/09/26 08:24:11 +! +frr version 7.2-dev +frr defaults traditional +! +hostname hub +log file /var/log/frr/frr.log +! +! +! +router bgp 65000 + neighbor 10.10.10.2 remote-as 65001 + neighbor 10.10.20.2 remote-as 65002 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! +! +line vty +! diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/daemons b/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/daemons new file mode 100644 index 00000000..4ff95c9f --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/daemons @@ -0,0 +1,3 @@ +zebra=yes +bgpd=yes + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/frr.conf b/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/frr.conf new file mode 100644 index 00000000..38e8e5ee --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/frr.conf @@ -0,0 +1,9 @@ +router bgp 65001 + bgp router-id 10.1.1.1 + neighbor 10.10.10.2 remote-as 65002 + neighbor 10.10.20.2 remote-as 65003 + address-family ipv4 unicast + neighbor 10.10.10.2 activate + neighbor 10.10.20.2 activate + redistribute connected + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/interfaces b/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/interfaces new file mode 100644 index 00000000..56039e97 --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/hub/interfaces @@ -0,0 +1,23 @@ +auto lo +iface lo inet loopback + address 10.1.1.1/32 + +auto eth0 +iface eth0 inet dhcp + vrf mgmt + +auto mgmt +iface mgmt + address 127.0.0.1/8 + vrf-table auto + +auto swp1 +allow-uplink swp1 +iface swp1 inet static + address 10.10.10.1/30 + +auto swp2 +allow-uplink swp2 +iface swp2 inet static + address 10.10.20.1/30 + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/configs/lessontools.py b/lessons/fundamentals/lesson-98-frr/stage1/configs/lessontools.py new file mode 100644 index 00000000..6626bc0a --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/configs/lessontools.py @@ -0,0 +1,11 @@ +def update_hostname (ssh_client, hostname): + + ssh.exec_command("sudo sed -E -i 's/^(127\.0\.1\.1\s+).*/\1" + hostname + "/ /etc/hosts") + ssh.exec_command("sudo printf '%s' '" + hostname + "' > /etc/hostname") + ssh.exec_command("sudo hostname " + hostname) + +return + + + + diff --git a/lessons/fundamentals/lesson-98-frr/stage1/guide.md b/lessons/fundamentals/lesson-98-frr/stage1/guide.md new file mode 100644 index 00000000..9a027425 --- /dev/null +++ b/lessons/fundamentals/lesson-98-frr/stage1/guide.md @@ -0,0 +1 @@ +FRR in NRELabs!