From f9f3f5fd1d81528effa07983b320557a5c72bd22 Mon Sep 17 00:00:00 2001 From: Matej Feder Date: Tue, 1 Oct 2024 12:40:17 +0200 Subject: [PATCH] Update SONiC docs Signed-off-by: Matej Feder --- documentation/sonic/{FAQ_SONiC.md => FAQ.md} | 0 .../sonic/{SONiC_Testing.md => Testing.md} | 12 +-- .../{gns3-testbed.md => GNS3_bgp_basic.md} | 4 +- .../sonic/testbed/GNS3_bgp_unified.md | 75 ++++++++++++++++++ .../testbed/{ => configs}/leaf1_frr.conf | 0 .../testbed/{ => configs}/leaf2_frr.conf | 0 .../testbed/{ => configs}/spine_frr.conf | 0 .../testbed/configs/sw1_frr_unified.json | 70 ++++++++++++++++ .../testbed/configs/sw2_frr_unified.json | 70 ++++++++++++++++ .../GNS3_bgp_basic.png} | Bin .../sonic/testbed/images/GNS3_bgp_unified.png | Bin 0 -> 20581 bytes 11 files changed, 224 insertions(+), 7 deletions(-) rename documentation/sonic/{FAQ_SONiC.md => FAQ.md} (100%) rename documentation/sonic/{SONiC_Testing.md => Testing.md} (87%) rename documentation/sonic/testbed/{gns3-testbed.md => GNS3_bgp_basic.md} (97%) create mode 100644 documentation/sonic/testbed/GNS3_bgp_unified.md rename documentation/sonic/testbed/{ => configs}/leaf1_frr.conf (100%) rename documentation/sonic/testbed/{ => configs}/leaf2_frr.conf (100%) rename documentation/sonic/testbed/{ => configs}/spine_frr.conf (100%) create mode 100644 documentation/sonic/testbed/configs/sw1_frr_unified.json create mode 100644 documentation/sonic/testbed/configs/sw2_frr_unified.json rename documentation/sonic/testbed/{gns3-testbed.png => images/GNS3_bgp_basic.png} (100%) create mode 100644 documentation/sonic/testbed/images/GNS3_bgp_unified.png diff --git a/documentation/sonic/FAQ_SONiC.md b/documentation/sonic/FAQ.md similarity index 100% rename from documentation/sonic/FAQ_SONiC.md rename to documentation/sonic/FAQ.md diff --git a/documentation/sonic/SONiC_Testing.md b/documentation/sonic/Testing.md similarity index 87% rename from documentation/sonic/SONiC_Testing.md rename to documentation/sonic/Testing.md index b552e919..4fcb1a16 100644 --- a/documentation/sonic/SONiC_Testing.md +++ b/documentation/sonic/Testing.md @@ -74,12 +74,14 @@ outdated and refers to the depreciated SoNiC P4 Software switch image). ```bash wget https://sonic.software/download-gns3a.sh chmod +x download-gns3a.sh - ./download-gns3a.sh # 202311 + ./download-gns3a.sh # master ``` - * The above will download the latest image for the giver release number and create a GNS3 appliance file named e.g. `SONiC-202012-27914.gns3a` - * Note that the 202405 release of SONiC VS image is not working due to [#19399](https://github.com/sonic-net/sonic-buildimage/issues/19399) - * The release 202311 has also some bugs, like [#13317](https://github.com/sonic-net/sonic-buildimage/issues/13317) but works "better" then 202405 (if you can live without sonic-cli) + * The above will download the latest image for the giver release number and create a GNS3 appliance file named e.g. `SONiC-master-656617.gns3a` + * Note that you may observe some issues with the stable SONiC VS builds: + * `202405` release, e.g. [#19399](https://github.com/sonic-net/sonic-buildimage/issues/19399) + * `202311` release, e.g. [#13317](https://github.com/sonic-net/sonic-buildimage/issues/13317) + * Keep in mind that these and other issues may cause some unexpected behaviour of SONiC * From this point you can follow the instructions provided in https://pine-networks.com/blog/setting-up-sonic-on-gns3/. - * Skip the initial instructions and start with the importing of appliance file you generated above e.g. `SONiC-202012-27914.gns3a` + * Skip the initial instructions and start with the importing of appliance file you generated above e.g. `SONiC-master-656617.gns3a` * Once you import the SONiC image you can create a new project or open the existing one and start using the SONiC appliance in GNS3 by dragging the SONiC appliance into the main window of your GNS3 project diff --git a/documentation/sonic/testbed/gns3-testbed.md b/documentation/sonic/testbed/GNS3_bgp_basic.md similarity index 97% rename from documentation/sonic/testbed/gns3-testbed.md rename to documentation/sonic/testbed/GNS3_bgp_basic.md index cdd47c7f..8358a4f1 100644 --- a/documentation/sonic/testbed/gns3-testbed.md +++ b/documentation/sonic/testbed/GNS3_bgp_basic.md @@ -5,7 +5,7 @@ The setup includes three SONiC switches (Spine, Leaf1, Leaf2) with community ima The guide also covers a basic BGP L3 underlay configuration using FRR. -![sonic-gns3-testbed.png](gns3-testbed.png) +![GNS3_basic.png](images/GNS3_basic.png) ## SONiC GNS3 testbed portable project @@ -74,7 +74,7 @@ To walk through the configuration, follow the steps outlined below. ``` * Save the interfaces configuration by running `config save -y` after making changes * Configure FRR BGP - * Find the FRR config files `leaf1_frr.conf`, `leaf2_frr.conf`, `spine_frr.conf`, and apply them as follows: + * Find the FRR config files `configs/leaf1_frr.conf`, `configs/leaf2_frr.conf`, `configs/spine_frr.conf`, and apply them as follows: ```bash sudo cp _frr.conf /etc/sonic/frr/frr.conf sudo chown 300:300 /etc/sonic/frr/frr.conf diff --git a/documentation/sonic/testbed/GNS3_bgp_unified.md b/documentation/sonic/testbed/GNS3_bgp_unified.md new file mode 100644 index 00000000..b78068c4 --- /dev/null +++ b/documentation/sonic/testbed/GNS3_bgp_unified.md @@ -0,0 +1,75 @@ +# SONiC GNS3 testbed - unified FRR configuration + +This tutorial walks you through setting up and configuring a testbed environment in the GNS3 simulation platform. +The setup includes just two SONiC switches (SW1, SW2) with community images and two PCs connected to them. + +The guide also covers an unnumbered BGP L3 underlay configuration using unified FRR and BGP unnumbered. + +![GNS3_basic.png](images/GNS3_bgp_unified.png) + +## Prerequisites + +* GNS3 + * Select the installer for your favourite OS: https://www.gns3.com/software/download +* SONiC GNS3 appliance + * Follow instructions [here](../general.md#gns3-simulation-environment) + * The tutorial is intended to use SONiC community images. It was tested with community image SONiC master build 656617 + +## SONiC GNS3 configuration + +* Drag and drop the SONiC switches and PCs, and wire them as shown in the architecture diagram +* Remove arbitrary config defaults + * The SONiC community image includes a default configuration that enables various ports and assigns arbitrary IP addresses + to them. Replace this configuration with another default setting that avoids arbitrary configurations. + For this purpose, we can use a predefined config template: + ```bash + sudo su - + sonic-cfggen -H --preset l3 -k Force10-S6000 > /etc/sonic/config_db.json + config reload -y + ``` +* Configure switches + * Find the FRR unified config files `configs/sw1_frr_unified.json`, `configs/sw1_frr_unified.json`, and apply them as follows: + ```bash + # copy _frr_unified.json file to the switch + sudo config load _frr_unified.json -y + docker restart bgp + # if you want to make the config persistent save it to the /etc/sonic.config_db.json + sudo config save -y + ``` +* Configure PC1 and PC2 + * Configure PC's IP address and proper gateway + ```text + PC1> ip 192.168.100.100/24 192.168.100.1 + PC2> ip 192.168.200.100/24 192.168.200.1 + ``` + +## Validate the testbed + +* Validate the interfaces' setup + * Connect to, for example, the switch 1 console (the default credential for login is admin/YourPaSsWoRd) and verify + the IPv6 link local mode is enabled for Ethernet4 (due to BGP unnumbered, for details read e.g. [this](https://support.edge-core.com/hc/en-us/articles/900002377366--Enterprise-SONiC-BGP-Unnumbered)) + ```yaml + $ show ipv6 link-local-mode | grep Enabled + | Ethernet4 | Enabled | + ``` + * Validate whether you see UP/UP state of connected interfaces via e.g. `$ show int status` + * Explore interfaces configuration via `show runningconfiguration interfaces` or via `sudo cat /etc/sonic/config_db.json` +* Validate the BGP configuration + * Connect to, for example, the Spine switch and verify the routes propagated by the BGP protocol + ```bash + $ show ip route + Codes: K - kernel route, C - connected, S - static, R - RIP, + O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, + F - PBR, f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + C>*10.0.0.1/32 is directly connected, Loopback0, 03:02:15 + B>*10.0.0.2/32 [20/0] via fe80::2047:61ff:feb2:b715, Ethernet4, 03:01:59 + C>*10.1.0.1/32 is directly connected, Loopback0, 03:02:15 + C>*192.168.100.0/24 is directly connected, Ethernet8, 03:02:15 + B>*192.168.200.0/24 [20/0] via fe80::2047:61ff:feb2:b715, Ethernet4, 03:01:59 + ``` + * Explore BGP configuration via `show runningconfiguration bgp` +* Open console of the PC1 or PC2 and try to `ping` the whole infrastructure + * SONiC switches should be reachable e.g. via its Loopback IPs and PC1 via 192.168.100.100 and PC2 via IP 192.168.200.100 diff --git a/documentation/sonic/testbed/leaf1_frr.conf b/documentation/sonic/testbed/configs/leaf1_frr.conf similarity index 100% rename from documentation/sonic/testbed/leaf1_frr.conf rename to documentation/sonic/testbed/configs/leaf1_frr.conf diff --git a/documentation/sonic/testbed/leaf2_frr.conf b/documentation/sonic/testbed/configs/leaf2_frr.conf similarity index 100% rename from documentation/sonic/testbed/leaf2_frr.conf rename to documentation/sonic/testbed/configs/leaf2_frr.conf diff --git a/documentation/sonic/testbed/spine_frr.conf b/documentation/sonic/testbed/configs/spine_frr.conf similarity index 100% rename from documentation/sonic/testbed/spine_frr.conf rename to documentation/sonic/testbed/configs/spine_frr.conf diff --git a/documentation/sonic/testbed/configs/sw1_frr_unified.json b/documentation/sonic/testbed/configs/sw1_frr_unified.json new file mode 100644 index 00000000..59b1973b --- /dev/null +++ b/documentation/sonic/testbed/configs/sw1_frr_unified.json @@ -0,0 +1,70 @@ +{ + "DEVICE_METADATA": { + "localhost": { + "docker_routing_config_mode": "unified", + "frr_mgmt_framework_config": "true", + "hostname": "sw1", + "mac": "0c:2e:02:80:00:01" + } + }, + "INTERFACE": { + "Ethernet4": { + "ipv6_use_link_local_only": "enable" + }, + "Ethernet8": {}, + "Ethernet8|192.168.100.1/24": {} + }, + "LOOPBACK_INTERFACE": { + "Loopback0": {}, + "Loopback0|10.0.0.1/32": {}, + "Loopback0|fd0c:cc24:75a0:1::1/128": {} + }, + "BGP_GLOBALS": { + "default": { + "local_asn": "65001", + "log_nbr_state_changes": "true", + "router_id": "10.0.0.1" + } + }, + "BGP_PEER_GROUP": { + "default|core": { + "peer_group_name": "core", + "admin_status": "true", + "asn": "external", + "peer_type": "external" + } + }, + "BGP_NEIGHBOR": { + "default|Ethernet4": { + "peer_group_name": "core" + } + }, + "BGP_NEIGHBOR_AF": { + "default|core|ipv4_unicast": { + "admin_status": "true", + "route_map_in": [ + "ALLOW" + ], + "route_map_out": [ + "ALLOW" + ] + }, + "default|core|ipv6_unicast": { + "admin_status": "true", + "route_map_in": [ + "ALLOW" + ], + "route_map_out": [ + "ALLOW" + ] + } + }, + "ROUTE_MAP": { + "ALLOW|1": { + "route_operation": "permit" + } + }, + "ROUTE_REDISTRIBUTE": { + "default|connected|bgp|ipv4": {} + } +} \ No newline at end of file diff --git a/documentation/sonic/testbed/configs/sw2_frr_unified.json b/documentation/sonic/testbed/configs/sw2_frr_unified.json new file mode 100644 index 00000000..ec1e79ac --- /dev/null +++ b/documentation/sonic/testbed/configs/sw2_frr_unified.json @@ -0,0 +1,70 @@ +{ + "DEVICE_METADATA": { + "localhost": { + "docker_routing_config_mode": "unified", + "frr_mgmt_framework_config": "true", + "hostname": "sw2", + "mac": "0c:2e:02:80:00:02" + } + }, + "INTERFACE": { + "Ethernet4": { + "ipv6_use_link_local_only": "enable" + }, + "Ethernet8": {}, + "Ethernet8|192.168.200.1/24": {} + }, + "LOOPBACK_INTERFACE": { + "Loopback0": {}, + "Loopback0|10.0.0.2/32": {}, + "Loopback0|fd0c:cc24:75a0:1::2/128": {} + }, + "BGP_GLOBALS": { + "default": { + "local_asn": "65002", + "log_nbr_state_changes": "true", + "router_id": "10.0.0.2" + } + }, + "BGP_PEER_GROUP": { + "default|core": { + "peer_group_name": "core", + "admin_status": "true", + "asn": "external", + "peer_type": "external" + } + }, + "BGP_NEIGHBOR": { + "default|Ethernet4": { + "peer_group_name": "core" + } + }, + "BGP_NEIGHBOR_AF": { + "default|core|ipv4_unicast": { + "admin_status": "true", + "route_map_in": [ + "ALLOW" + ], + "route_map_out": [ + "ALLOW" + ] + }, + "default|core|ipv6_unicast": { + "admin_status": "true", + "route_map_in": [ + "ALLOW" + ], + "route_map_out": [ + "ALLOW" + ] + } + }, + "ROUTE_MAP": { + "ALLOW|1": { + "route_operation": "permit" + } + }, + "ROUTE_REDISTRIBUTE": { + "default|connected|bgp|ipv4": {} + } +} \ No newline at end of file diff --git a/documentation/sonic/testbed/gns3-testbed.png b/documentation/sonic/testbed/images/GNS3_bgp_basic.png similarity index 100% rename from documentation/sonic/testbed/gns3-testbed.png rename to documentation/sonic/testbed/images/GNS3_bgp_basic.png diff --git a/documentation/sonic/testbed/images/GNS3_bgp_unified.png b/documentation/sonic/testbed/images/GNS3_bgp_unified.png new file mode 100644 index 0000000000000000000000000000000000000000..28993168b8861fe071ae4220cd7ac33f0ba1e6c1 GIT binary patch literal 20581 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