diff --git a/docs/HLD/vpp-lag.md b/docs/HLD/vpp-lag.md new file mode 100644 index 0000000..1954b68 --- /dev/null +++ b/docs/HLD/vpp-lag.md @@ -0,0 +1,84 @@ +# SONIC VPP LAG Bridging support +Rev v0.1 + +
+
+ +## Table of Contents + +1. [Revisions](#item-1) +2. [Scope](#item-2) +3. [Definitions/Abbreviations](#item-3) +4. [Introduction](#item-4) +5. [LAG and Bridging](#item-5) + +
+
+ + +## Revisions + +| Rev | Date | Author(s) | +|-----|------|-----------| +|v0.1 | 25/02/2024 | Bendrapu Balareddy (Cisco), Sameer Nanajkar (Cisco) | + + +
+
+ + +## Scope +This document describes the high level design of integrating LAG and bridging functionality between SONIC and VPP. It provides + - LAG + - 802.1Q bridging + +
+ + +## Definitions/Abbreviations +**VPP**: Vector Packet Processing (VPP) technology based high performance packet processing stack that can run on commodity CPUs. For more details see [What is VPP](https://wiki.fd.io/view/VPP/What_is_VPP%3F) + +**LAG**: Ling Aggregation Group + + +
+
+ + +## Introduction +LAG functionality is supported in SONiC with port channel interfaces. +VPP port channel supports modes as active-standby , active-active or LACP mode. But SONiC does not have a way program +this through configuration. Hence the portchannel mode as default active-active by giving ROUND_ROBIN value. Similarly +VPP supports different load balancing algorithms for distributing the traffic in active-active mode. But again SONIC +does not support a way to configure any load balancing algorithm, hence it's programmed as BOND_API_LB_ALGO_L2 by default. +If there is any defined requirement in future to use different load balancing algorithm to use by default, it can be +changed accordingly. + +Some parameters the SONIC supports are not supported by VPP. The attributes like min-links for portchannel group, fast-rate +etc are not supported by VPP. + +To enable LACP on VPP, the VPP should be rebuilt with LACP plugin added. Currently sonic-platform-vpp repo uses prebuilt +vpp binary. Hence it needs some changes the way this repo is using the VPP + + + +![LAG Bridging](../LAG-Dot1q-Bridging-Topo.png) + +SONiC supports port channel interfaces. These interfaces can be configured for layer routing or as members of a vlan + - Access port + config vlan member add -u creates an un tagged bridge port. This will be translated to vpp in two steps + 1. creates a bridge with given vlan id as bridge id if the bridge with given id doesnot exist. + 2. set the port as member of bridge with appropriate tag rewrite + - Trunk port + config vlan member add creates a tagged port bridge port. This will be translated to vpp in three steps + 1. creates a bridge with given vlan id as bridge id if the bridge with given aid does not exist. + 2. vpp trunk port operation is achieved through vlan subinterface. A subinterface is created for this vlan id. Note + that this subinterface is only specific to vpp and does not appear in SONiC control plane data bases. + 3. set the vlan subinterface as bridge port + + +## References + +[SONiC system architecture](https://github.com/sonic-net/SONiC/wiki/Architecture)\ +[What is VPP](https://s3-docs.fd.io/vpp/23.06/) + diff --git a/docs/LAG-Dot1q-Bridging-Topo.png b/docs/LAG-Dot1q-Bridging-Topo.png new file mode 100644 index 0000000..d23424c Binary files /dev/null and b/docs/LAG-Dot1q-Bridging-Topo.png differ diff --git a/docs/README.LAG.dot1q.bridging.topo.md b/docs/README.LAG.dot1q.bridging.topo.md new file mode 100644 index 0000000..eec13c4 --- /dev/null +++ b/docs/README.LAG.dot1q.bridging.topo.md @@ -0,0 +1,558 @@ +# LAG 8021q bridging Test + +LAG Bridging Simple Test Topology + +SONiC-A connections +``` +Host1-10.0.1.1/24--Ethernet0|-bvi10-10.0.1.10/24-|PortChannel10-trunk1 vlan 10 [members-Ethernet4,5] +Host2-10.0.2.1/24--Ethernet1|-bvi20-10.0.2.20/24-| Ethernet3-trunk vlan20 +Host3-10.0.3.1/24--Ethernet2|------SONiC-A-------| Ethernet3-trunk vlan30 +``` + + +SONiC-B connections +``` + PortChannel10-trunk1 vlan 10 [members-Ethernet2,3] |SONiC-B|Ethernet1 trunk2 vlan 10 + Ethernet0-trunk vlan20] |SONiC-B|Ethernet1 trunk2 vlan 20 + Ethernet0-trunk vlan30 |SONiC-B|Ethernet1 trunk2 vlan 30 +``` + +SONiC-C connections +``` +Ethernet3 trunk2 vlan 10|SONIC-C|Ethernet0-------|Host4-10.0.1.2/24 +Ethernet3 trunk2 vlan 20|SONIC-C|Ethernet1-------|Host5-10.0.2.2/24 +Ethernet3 trunk2 vlan 30|SONiC-C|Ethernet2-------|Host6-10.0.3.2/24 +``` + +Pre-requisites for testing + +Make sure the docker is installed on the Linux system. iproute2 and sudo packages should be installed. + +Load container images +``` +docker load < docker-sonic-vpp.gz +``` + +Check if images are listed +``` +docker images | grep "sonic-vpp\|pause" +``` + +Get the script to create and run the sonic container from the sonic-platform-vpp repo if you have not cloned the repo. +``` +wget https://raw.githubusercontent.com/sonic-net/sonic-platform-vpp/main/start_sonic_vpp.sh +``` +Set the execute bits of the downloaded script file +``` +chmod +x start_sonic_vpp.sh + +``` +Else if you have already cloned the sonic-platform-repo you can copy the script to the local directory and use it. + +On the host create veth interface pairs for vpp and host + +``` +sudo ip link add name veth_ac1 type veth peer name ac1 +sudo ip link add name veth_ac2 type veth peer name ac2 +sudo ip link add name veth_ac3 type veth peer name ac3 +sudo ip link add name veth_ac4 type veth peer name ac4 +sudo ip link add name veth_ac5 type veth peer name ac5 +sudo ip link add name veth_ac6 type veth peer name ac6 +sudo ip link add name veth_pc_member1 type veth peer name pc_member1 +sudo ip link add name veth_pc_member2 type veth peer name pc_member2 +sudo ip link add name veth_trunk1 type veth peer name trunk1 +sudo ip link add name veth_trunk2 type veth peer name trunk2 + +``` + +Create network namespace for end hosts and inject one end of veth pair + +``` +sudo ip netns add host-1.0 +sudo ip netns add host-2.0 +sudo ip netns add host-3.0 +sudo ip netns add host-4.0 +sudo ip netns add host-5.0 +sudo ip netns add host-6.0 +sudo ip link set dev veth_ac1 netns host-1.0 +sudo ip link set dev veth_ac2 netns host-2.0 +sudo ip link set dev veth_ac3 netns host-3.0 +sudo ip link set dev veth_ac4 netns host-4.0 +sudo ip link set dev veth_ac5 netns host-5.0 +sudo ip link set dev veth_ac6 netns host-6.0 +``` + +Configure IP addresses inside the host net namepaces + +``` +sudo ip netns exec host-1.0 bash +ip link set dev veth_ac1 up +ip addr add 10.0.1.1/24 dev veth_ac1 +ip addr add fd12:3456:789a:1::2/64 dev veth_ac1 +ip route add 10.0.2.0/24 via 10.0.1.10 +ip address show +ip route show +exit + +sudo ip netns exec host-2.0 bash +ip link set dev veth_ac2 up +ip addr add 10.0.2.1/24 dev veth_ac2 +ip addr add fd12:3456:789a:2::2/64 dev veth_ac2 +ip route add 10.0.1.0/24 via 10.0.2.20 +ip address show +ip route show +exit + +sudo ip netns exec host-3.0 bash +ip link set dev veth_ac3 up +ip addr add 10.0.3.1/24 dev veth_ac3 +ip addr add fd12:3456:789a:3::2/64 dev veth_ac3 +ip address show +ip route show +exit + +sudo ip netns exec host-4.0 bash +ip link set dev veth_ac4 up +ip addr add 10.0.1.2/24 dev veth_ac4 +ip addr add fd12:3456:789a:1::3/64 dev veth_ac4 +ip route add 10.0.2.0/24 via 10.0.1.10 +ip address show +ip route show +exit + +sudo ip netns exec host-5.0 bash +ip link set dev veth_ac5 up +ip addr add 10.0.2.2/24 dev veth_ac5 +ip addr add fd12:3456:789a:2::3/64 dev veth_ac5 +ip route add 10.0.1.0/24 via 10.0.2.20 +ip address show +ip route show +exit + +sudo ip netns exec host-6.0 bash +ip link set dev veth_ac6 up +ip addr add 10.0.3.2/24 dev veth_ac6 +ip addr add fd12:3456:789a:3::3/64 dev veth_ac6 +ip address show +ip route show +exit +``` + +Now start the sonic container and pass the veth interfaces to sonic-vpp +``` +sudo ./start_sonic_vpp.sh start -n SONIC-A -i ac1,ac2,ac3,trunk1,pc_member1,pc_member2 +``` + +start the second sonic container and pass the veth interfaces to sonic-vpp +``` +sudo ./start_sonic_vpp.sh start -n SONIC-B -i veth_trunk1,veth_trunk2,veth_pc_member1,veth_pc_member2 +``` + +start the third sonic container and pass the veth interfaces to sonic-vpp +``` +sudo ./start_sonic_vpp.sh start -n SONIC-C -i ac4,ac5,ac6,trunk2 +``` + +Get into SONIC-A container and configure vlan and vlan bridging + +SONIC-A: +``` +docker exec -it SONIC-A /bin/bash +show interface status +config interface startup Ethernet0 +config interface startup Ethernet1 +config interface startup Ethernet2 +config interface startup Ethernet3 +config interface startup Ethernet4 +config interface startup Ethernet5 + +config portchannel add PortChannel10 +config portchannel member add PortChannel10 Ethernet4 +config portchannel member add PortChannel10 Ethernet5 + +config vlan add 10 +config vlan member add -u 10 Ethernet0 +config vlan member add 10 PortChannel10 + +config vlan add 20 +config vlan member add -u 20 Ethernet1 +config vlan member add 20 Ethernet3 + +config vlan add 30 +config vlan member add -u 30 Ethernet2 +config vlan member add 30 Ethernet3 + +config interface ip add Vlan10 10.0.1.10/24 +config interface ip add Vlan20 10.0.2.20/24 +``` + +Get into SONIC-B container and configure vlan, vlan bridging + +SONIC-B: +``` +docker exec -it SONIC-B /bin/bash +show interface status +config interface startup Ethernet0 +config interface startup Ethernet1 +config interface startup Ethernet2 +config interface startup Ethernet3 + +config portchannel add PortChannel10 +config portchannel member add PortChannel10 Ethernet1 +config portchannel member add PortChannel10 Ethernet2 + +config vlan add 10 +config vlan member add 10 PortChannel10 +config vlan member add 10 Ethernet3 + +config vlan add 20 +config vlan member add 20 Ethernet0 +config vlan member add 20 Ethernet3 + +config vlan add 30 +config vlan member add 30 Ethernet0 +config vlan member add 30 Ethernet3 +``` + +Get into SONIC-C container and configure vlan, vlan bridging + +SONIC-C: +``` +docker exec -it SONIC-C /bin/bash +show interface status +config interface startup Ethernet0 +config interface startup Ethernet1 +config interface startup Ethernet2 +config interface startup Ethernet3 + +config vlan add 10 +config vlan member add -u 10 Ethernet0 +config vlan member add 10 Ethernet3 + +config vlan add 20 +config vlan member add -u 20 Ethernet1 +config vlan member add 20 Ethernet3 + +config vlan add 30 +config vlan member add -u 30 Ethernet2 +config vlan member add 30 Ethernet3 +``` + +Test the SONiC vlan briding function across 3 VLAN bridge domains + +``` +sudo ip netns exec host-1.0 bash +ping -c5 10.0.1.2 -- same bridge domain +ping -c5 10.0.2.1 -- route to different bridge domain +ping -c5 10.0.2.2 -- route to different bridge domain +ping -c5 10.0.3.1 -- ping fails +ping -c5 10.0.3.2 -- ping fails +exit + +sudo ip netns exec host-2.0 bash +ping -c5 10.0.2.2 -- same bridge domain +ping -c5 10.0.1.1 -- route to different bridge domain +ping -c5 10.0.1.2 -- route to different bridge domain +ping -c5 10.0.3.1 -- ping fails as no routing for this +ping -c5 10.0.3.2 -- ping fail as no routing for this +exit + +sudo ip netns exec host-3.0 bash +ping -c5 10.0.3.2 +ping6 fd12:3456:789a:3::3 -c 5 +ping -c5 10.0.1.1 -- ping fails as no routing for this +ping -c5 10.0.1.2 -- ping fails as no routing for this +ping -c5 10.0.2.1 -- ping fails as no routing for this +ping -c5 10.0.2.2 -- ping fails as no routing for this +exit + +sudo ip netns exec host-4.0 bash +ping -c5 10.0.1.1 +ping -c5 10.0.2.1 -- route to different bridge domain +ping -c5 10.0.2.2 -- route to different bridge domain +ping -c5 10.0.3.1 -- ping fails as no routing for this +ping -c5 10.0.3.2 -- ping fails as no routing for this +exit + +sudo ip netns exec host-5.0 bash +ping -c5 10.0.2.1 +ping -c5 10.0.1.1 -- route to different bridge domain +ping -c5 10.0.1.2 -- route to different bridge domain +ping -c5 10.0.3.1 -- ping fails as no routing for this +ping -c5 10.0.3.2 -- ping fails as no routing for this +exit + +sudo ip netns exec host-6.0 bash +ping -c5 10.0.3.1 +ping6 -c5 fd12:3456:789a:3::3 +ping -c5 10.0.1.1 -- ping fails as no routing for this +ping -c5 10.0.1.2 -- ping fails as no routing for this +ping -c5 10.0.2.1 -- ping fails as no routing for this +ping -c5 10.0.2.2 -- ping fails as no routing for this +exit + +``` + +You should see the ping reachability from host1 to host4, host2 to host5 and host3 to host6. + +Use below command to stop the sonic-vpp containers +``` +sudo ./start_sonic_vpp.sh stop -n sonic-br1 +sudo ./start_sonic_vpp.sh stop -n sonic-br2 +sudo ./start_sonic_vpp.sh stop -n sonic-br3 +``` + +Show command outputs sonic-br1 +``` +show interface status +``` +``` + Interface Lanes Speed MTU FEC Alias Vlan Oper Admin Type Asym PFC + +--------------------------------------------------------------------------------------------------------+ + Ethernet0 25,26,27,28 100G 9100 N/A fortyGigE0/0 routed up down N/A N/A + Ethernet1 29,30,31,32 100G 9100 N/A fortyGigE0/4 routed up down N/A N/A + Ethernet2 33,34,35,36 100G 9100 N/A fortyGigE0/8 routed up down N/A N/A + Ethernet3 37,38,39,40 100G 9100 N/A fortyGigE0/12 routed up down N/A N/A + Ethernet4 45,46,47,48 100G 9100 N/A fortyGigE0/16 routed up down N/A N/A + Ethernet5 41,42,43,44 100G 9100 N/A fortyGigE0/20 routed up down N/A N/A +``` +``` +show vlan brief +``` +``` ++-----------+--------------+---------------+----------------+-------------+ +| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | ++===========+==============+===============+================+=============+ +| 10 | 10.0.1.10/24 | Ethernet0 | untagged | disabled | +| | | PortChannel10 | tagged | | ++-----------+--------------+---------------+----------------+-------------+ +| 20 | 10.0.2.20/24 | Ethernet1 | untagged | disabled | +| | | Ethernet3 | tagged | | ++-----------+--------------+---------------+----------------+-------------+ +| 30 | | Ethernet2 | untagged | disabled | +| | | Ethernet3 | tagged | | ++-----------+--------------+---------------+----------------+-------------+ +``` +``` +show vlan config +``` +``` +Name VID Member Mode +------ ----- --------- -------- +Vlan10 10 Ethernet0 untagged +Vlan10 10 PortChannel10 tagged +Vlan20 20 Ethernet1 untagged +Vlan20 20 Ethernet3 tagged +Vlan30 30 Ethernet2 untagged +Vlan30 30 Ethernet3 tagged +``` +``` +vppctl show bridge +``` +``` + BD-ID Index BSN Age(min) Learning U-Forwrd UU-Flood Flooding ARP-Term arp-ufwd Learn-co Learn-li BVI-Intf + 10 1 0 off on on flood on off off 0 16777216 N/A + 20 2 0 off on on flood on off off 0 16777216 N/A + 30 3 0 off on on flood on off off 1 16777216 N/A +``` +``` +vppctl show bridge 10 detail +``` +``` + BD-ID Index BSN Age(min) Learning U-Forwrd UU-Flood Flooding ARP-Term arp-ufwd Learn-co Learn-li BVI-Intf + 10 1 0 off on on flood on on off 0 16777216 bvi10 +span-l2-input l2-input-classify l2-input-feat-arc l2-policer-classify l2-input-acl vpath-input-l2 l2-ip-qos-record l2-input-vtr l2-learn l2-rw l2-fwd l2-flood arp-term-l2bd l2-flood l2-output + + Interface If-idx ISN SHG BVI TxFlood VLAN-Tag-Rewrite + bvi10 19 1 0 * * push-1 dot1q 10 + host-ac1 1 1 0 - * push-1 dot1q 10 + BondEthernet0.10 14 1 0 - * none + + IP4/IP6 to MAC table for ARP Termination +``` +``` +vppctl show bridge 20 detail +``` +``` + BD-ID Index BSN Age(min) Learning U-Forwrd UU-Flood Flooding ARP-Term arp-ufwd Learn-co Learn-li BVI-Intf + 20 2 0 off on on flood on on off 0 16777216 bvi20 +span-l2-input l2-input-classify l2-input-feat-arc l2-policer-classify l2-input-acl vpath-input-l2 l2-ip-qos-record l2-input-vtr l2-learn l2-rw l2-fwd l2-flood arp-term-l2bd l2-flood l2-output + + Interface If-idx ISN SHG BVI TxFlood VLAN-Tag-Rewrite + bvi20 20 1 0 * * push-1 dot1q 20 + host-ac2 2 1 0 - * push-1 dot1q 20 + host-trunk1.20 15 1 0 - * none + + IP4/IP6 to MAC table for ARP Termination +``` +``` +vppctl show bridge 30 detail +``` +``` + BD-ID Index BSN Age(min) Learning U-Forwrd UU-Flood Flooding ARP-Term arp-ufwd Learn-co Learn-li BVI-Intf + 30 3 0 off on on flood on off off 0 16777216 N/A +span-l2-input l2-input-classify l2-input-feat-arc l2-policer-classify l2-input-acl vpath-input-l2 l2-ip-qos-record l2-input-vtr l2-learn l2-rw l2-fwd l2-flood l2-flood l2-output + + Interface If-idx ISN SHG BVI TxFlood VLAN-Tag-Rewrite + host-ac3 3 1 0 - * push-1 dot1q 30 + host-trunk1.30 17 1 0 - * none +``` +``` +vppctl show ip4 neighbors +``` +``` + + Time IP Flags Ethernet Interface + 17703.4524 10.0.1.2 D 52:84:76:96:2c:b7 bvi10 + 17717.2684 10.0.1.1 D 6e:21:47:49:58:49 bvi10 + 17693.9802 10.0.2.1 D da:9c:93:33:db:af bvi20 + 17717.0202 10.0.2.2 D 7e:ef:f5:5c:0f:2a bvi20 +``` +``` +vppctl show interfaces +``` +``` + Name Idx State MTU (L3/IP4/IP6/MPLS) Counter Count +BondEthernet0 13 up 9000/0/0/0 +BondEthernet0.10 14 up 0/0/0/0 +bvi10 19 up 9000/0/0/0 +bvi20 20 up 9000/0/0/0 +host-ac1 1 up 9122/0/0/0 +host-ac2 2 up 9122/0/0/0 +host-ac3 3 up 9122/0/0/0 +host-pc_member1 5 up 9122/0/0/0 +host-pc_member2 6 up 9122/0/0/0 +host-trunk1 4 up 9122/0/0/0 +host-trunk1.20 15 up 0/0/0/0 +host-trunk1.30 17 up 0/0/0/0 +local0 0 down 0/0/0/0 +tap1 8 up 9000/0/0/0 +tap2 7 up 9000/0/0/0 +tap3 9 up 9000/0/0/0 +tap4 10 up 9000/0/0/0 +tap4.20 16 up 0/0/0/0 +tap4.30 18 up 0/0/0/0 +tap5 12 up 9000/0/0/0 +tap6 11 up 9000/0/0/0 +``` +``` +ip addr show +``` +``` +60: Vlan10@Bridge: mtu 9100 qdisc noqueue state UP group default qlen 1000 + link/ether 02:42:ac:11:00:05 brd ff:ff:ff:ff:ff:ff + inet 10.0.1.10/24 brd 10.0.1.255 scope global Vlan10 + valid_lft forever preferred_lft forever + inet6 fd12:3456:789a:1::1/64 scope global + valid_lft forever preferred_lft forever + inet6 fe80::42:acff:fe11:5/64 scope link + valid_lft forever preferred_lft forever +61: Vlan20@Bridge: mtu 9100 qdisc noqueue state UP group default qlen 1000 + link/ether 02:42:ac:11:00:05 brd ff:ff:ff:ff:ff:ff + inet 10.0.2.20/24 brd 10.0.2.255 scope global Vlan20 + valid_lft forever preferred_lft forever + inet6 fd12:3456:789a:2::1/64 scope global + valid_lft forever preferred_lft forever + inet6 fe80::42:acff:fe11:5/64 scope link + valid_lft forever preferred_lft forever +``` + +``` +vppctl show ip fib +``` +``` + +ipv4-VRF:0, fib_index:0, flow hash:[src dst sport dport proto flowlabel ] epoch:0 flags:none locks:[adjacency:1, default-route:1, ] +0.0.0.0/0 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:1 buckets:1 uRPF:0 to:[0:0]] + [0] [@0]: dpo-drop ip4 +0.0.0.0/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:2 buckets:1 uRPF:1 to:[0:0]] + [0] [@0]: dpo-drop ip4 +10.0.1.0/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:9 buckets:1 uRPF:9 to:[0:0]] + [0] [@0]: dpo-drop ip4 +10.0.1.1/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:17 buckets:1 uRPF:20 to:[5:420]] + [0] [@5]: ipv4 via 10.0.1.1 bvi10: mtu:9000 next:10 flags:[] 6e21474958490242ac1100050800 +10.0.1.2/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:19 buckets:1 uRPF:22 to:[1:84]] + [0] [@5]: ipv4 via 10.0.1.2 bvi10: mtu:9000 next:10 flags:[] 528476962cb70242ac1100050800 +10.0.1.0/24 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:8 buckets:1 uRPF:8 to:[2:168]] + [0] [@4]: ipv4-glean: [src:10.0.1.0/24] bvi10: mtu:9000 next:1 flags:[] ffffffffffff0242ac1100050806 +10.0.1.10/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:11 buckets:1 uRPF:13 to:[0:0]] + [0] [@12]: dpo-receive: 10.0.1.10 on bvi10 +10.0.1.255/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:10 buckets:1 uRPF:11 to:[0:0]] + [0] [@0]: dpo-drop ip4 +10.0.2.0/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:13 buckets:1 uRPF:15 to:[0:0]] + [0] [@0]: dpo-drop ip4 +10.0.2.1/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:18 buckets:1 uRPF:21 to:[1:84]] + [0] [@5]: ipv4 via 10.0.2.1 bvi20: mtu:9000 next:9 flags:[] da9c9333dbaf0242ac1100050800 +10.0.2.2/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:16 buckets:1 uRPF:18 to:[6:504]] + [0] [@5]: ipv4 via 10.0.2.2 bvi20: mtu:9000 next:9 flags:[] 7eeff55c0f2a0242ac1100050800 +10.0.2.0/24 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:12 buckets:1 uRPF:14 to:[2:168]] + [0] [@4]: ipv4-glean: [src:10.0.2.0/24] bvi20: mtu:9000 next:2 flags:[] ffffffffffff0242ac1100050806 +10.0.2.20/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:15 buckets:1 uRPF:19 to:[0:0]] + [0] [@12]: dpo-receive: 10.0.2.20 on bvi20 +10.0.2.255/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:14 buckets:1 uRPF:17 to:[0:0]] + [0] [@0]: dpo-drop ip4 +224.0.0.0/4 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:4 buckets:1 uRPF:3 to:[0:0]] + [0] [@0]: dpo-drop ip4 +240.0.0.0/4 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:3 buckets:1 uRPF:2 to:[0:0]] + [0] [@0]: dpo-drop ip4 +255.255.255.255/32 + unicast-ip4-chain + [@0]: dpo-load-balance: [proto:ip4 index:5 buckets:1 uRPF:4 to:[0:0]] + [0] [@0]: dpo-drop ip4 +``` + +``` +check the connectivity on portchannel interface by starting ping between vlan 10 hosts + +ping 10.0.1.2 +PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data. +64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=27.7 ms +64 bytes from 10.0.1.2: icmp_seq=2 ttl=64 time=41.6 ms + +check the packets on portchannel member interfaces + +1. shutdown one member interface of portchannel, verify the connectivity still fine and verify portchannel member counters +2. shutdown second member interface of portchannel, verify the connectivity is lost and verify portchannel member counters +3. bring up second member interface of portchannel back, verify the connectivity is restored and verify portchannel member counters +4. bring up other member interface of portchannel back, verify the connectivity is restored and verify portchannel member counters +``` +Verification of packet on VPP data plane for vlan tagging +Start the ping and then do show trace + +``` +vppctl +trace add af-packet-input 10 +show trace +``` diff --git a/platform/saivpp/vpplib/SwitchStateBase.cpp b/platform/saivpp/vpplib/SwitchStateBase.cpp index 646133e..1433425 100644 --- a/platform/saivpp/vpplib/SwitchStateBase.cpp +++ b/platform/saivpp/vpplib/SwitchStateBase.cpp @@ -253,6 +253,19 @@ sai_status_t SwitchStateBase::create( return createVlanMember(object_id, switch_id, attr_count, attr_list); } + if (object_type == SAI_OBJECT_TYPE_LAG ) + { + sai_object_id_t object_id; + sai_deserialize_object_id(serializedObjectId, object_id); + return createLag(object_id, switch_id, attr_count, attr_list); + } + if (object_type == SAI_OBJECT_TYPE_LAG_MEMBER) + { + sai_object_id_t object_id; + sai_deserialize_object_id(serializedObjectId, object_id); + return createLagMember(object_id, switch_id, attr_count, attr_list); + } + return create_internal(object_type, serializedObjectId, switch_id, attr_count, attr_list); } @@ -527,6 +540,18 @@ sai_status_t SwitchStateBase::remove( sai_deserialize_object_id(serializedObjectId, objectId); return removeVlanMember(objectId); } + else if (object_type == SAI_OBJECT_TYPE_LAG) + { + sai_object_id_t objectId; + sai_deserialize_object_id(serializedObjectId, objectId); + return removeLag(objectId); + } + else if (object_type == SAI_OBJECT_TYPE_LAG_MEMBER) + { + sai_object_id_t objectId; + sai_deserialize_object_id(serializedObjectId, objectId); + return removeLagMember(objectId); + } return remove_internal(object_type, serializedObjectId); } diff --git a/platform/saivpp/vpplib/SwitchStateBase.h b/platform/saivpp/vpplib/SwitchStateBase.h index 87f056b..473873e 100644 --- a/platform/saivpp/vpplib/SwitchStateBase.h +++ b/platform/saivpp/vpplib/SwitchStateBase.h @@ -163,6 +163,32 @@ namespace saivpp _In_ const sai_attribute_t *attr_list); sai_status_t vpp_delete_bvi_interface( _In_ sai_object_id_t bvi_obj_id); + sai_status_t createLag( + _In_ sai_object_id_t object_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + sai_status_t vpp_create_lag( + _In_ sai_object_id_t lag_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + sai_status_t removeLag( + _In_ sai_object_id_t lag_oid); + sai_status_t vpp_remove_lag( + _In_ sai_object_id_t lag_oid); + sai_status_t createLagMember( + _In_ sai_object_id_t object_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + sai_status_t vpp_create_lag_member( + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + sai_status_t removeLagMember( + _In_ sai_object_id_t lag_member_oid); + sai_status_t vpp_remove_lag_member( + _In_ sai_object_id_t lag_member_oid); + protected: virtual sai_status_t create_port_dependencies( @@ -1016,6 +1042,8 @@ namespace saivpp void populate_if_mapping(); const char *tap_to_hwif_name(const char *name); const char *hwif_to_tap_name(const char *name); + uint32_t lag_to_bond_if_idx (const sai_object_id_t lag_id); + int remove_lag_to_bond_entry (const sai_object_id_t lag_id); void vppProcessEvents (); void startVppEventsThread(); @@ -1029,6 +1057,7 @@ namespace saivpp bool m_run_vpp_events_thread = true; bool VppEventsThreadStarted = false; std::shared_ptr m_vpp_thread; + std::map m_lag_bond_map; private: static int currentMaxInstance; diff --git a/platform/saivpp/vpplib/SwitchStateBaseFdb.cpp b/platform/saivpp/vpplib/SwitchStateBaseFdb.cpp index 4ba2b90..6552949 100644 --- a/platform/saivpp/vpplib/SwitchStateBaseFdb.cpp +++ b/platform/saivpp/vpplib/SwitchStateBaseFdb.cpp @@ -678,7 +678,7 @@ sai_status_t SwitchStateBase::vpp_create_vlan_member( if (obj_type != SAI_OBJECT_TYPE_BRIDGE_PORT) { - SWSS_LOG_ERROR("SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID=%s expected to be PORT but is: %s", + SWSS_LOG_ERROR("SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID=%s expected to be BRIDGE PORT but is: %s", sai_serialize_object_id(br_port_id).c_str(), sai_serialize_object_type(obj_type).c_str()); @@ -686,28 +686,43 @@ sai_status_t SwitchStateBase::vpp_create_vlan_member( } const char *hwifname = nullptr; + uint32_t lag_swif_idx; + auto br_port_attrs = m_objectHash.at(SAI_OBJECT_TYPE_BRIDGE_PORT).at(sai_serialize_object_id(br_port_id)); auto meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_BRIDGE_PORT, SAI_BRIDGE_PORT_ATTR_PORT_ID); auto bp_attr = br_port_attrs[meta->attridname]; auto port_id = bp_attr->getAttr()->value.oid; obj_type = objectTypeQuery(port_id); - if (obj_type != SAI_OBJECT_TYPE_PORT) + if (obj_type != SAI_OBJECT_TYPE_PORT && obj_type != SAI_OBJECT_TYPE_LAG ) { - SWSS_LOG_NOTICE("SAI_BRIDGE_PORT_ATTR_PORT_ID=%s expected to be PORT but is: %s", + SWSS_LOG_NOTICE("SAI_BRIDGE_PORT_ATTR_PORT_ID=%s expected to be PORT or LAG but is: %s", sai_serialize_object_id(port_id).c_str(), sai_serialize_object_type(obj_type).c_str()); return SAI_STATUS_FAILURE; } - std::string if_name; - bool found = getTapNameFromPortId(port_id, if_name); - if (found == true) + if (obj_type == SAI_OBJECT_TYPE_PORT) { - hwifname = tap_to_hwif_name(if_name.c_str()); - }else { - SWSS_LOG_NOTICE("No ports found for bridge port id :%s",sai_serialize_object_id(br_port_id).c_str()); - return SAI_STATUS_FAILURE; + std::string if_name; + bool found = getTapNameFromPortId(port_id, if_name); + if (found == true) + { + hwifname = tap_to_hwif_name(if_name.c_str()); + }else { + SWSS_LOG_NOTICE("No ports found for bridge port id :%s",sai_serialize_object_id(br_port_id).c_str()); + return SAI_STATUS_FAILURE; + } + } else if (obj_type == SAI_OBJECT_TYPE_LAG) { + lag_swif_idx = lag_to_bond_if_idx(port_id); + SWSS_LOG_NOTICE("lag swif idx :%d",lag_swif_idx); + hwifname = vpp_get_swif_name(lag_swif_idx); + SWSS_LOG_NOTICE("lag swif idx :%d swif_name:%s",lag_swif_idx, hwifname); + if (hwifname == NULL) + { + SWSS_LOG_NOTICE("LAG is not found for bridge port id :%s",sai_serialize_object_id(br_port_id).c_str()); + return SAI_STATUS_FAILURE; + } } auto attr_vlan_member = sai_metadata_get_attr_by_id(SAI_VLAN_MEMBER_ATTR_VLAN_ID, attr_count, attr_list); @@ -865,24 +880,37 @@ sai_status_t SwitchStateBase::vpp_remove_vlan_member( auto port_id = bp_attr->getAttr()->value.oid; obj_type = objectTypeQuery(port_id); - if (obj_type != SAI_OBJECT_TYPE_PORT) + if (obj_type != SAI_OBJECT_TYPE_PORT && obj_type != SAI_OBJECT_TYPE_LAG) { - SWSS_LOG_NOTICE("SAI_BRIDGE_PORT_ATTR_PORT_ID=%s expected to be PORT but is: %s", + SWSS_LOG_NOTICE("SAI_BRIDGE_PORT_ATTR_PORT_ID=%s expected to be PORT or LAG but is: %s", sai_serialize_object_id(port_id).c_str(), sai_serialize_object_type(obj_type).c_str()); return SAI_STATUS_FAILURE; } - std::string if_name; - bool found = getTapNameFromPortId(port_id, if_name); - if (found == true) + + if (obj_type == SAI_OBJECT_TYPE_PORT) { - hw_ifname = tap_to_hwif_name(if_name.c_str()); - }else { - SWSS_LOG_NOTICE("No ports found for bridge port id :%s",sai_serialize_object_id(br_port_oid).c_str()); - return SAI_STATUS_FAILURE; + std::string if_name; + bool found = getTapNameFromPortId(port_id, if_name); + if (found == true) + { + hw_ifname = tap_to_hwif_name(if_name.c_str()); + }else { + SWSS_LOG_NOTICE("No ports found for bridge port id :%s",sai_serialize_object_id(br_port_oid).c_str()); + return SAI_STATUS_FAILURE; + } + } else if (obj_type == SAI_OBJECT_TYPE_LAG) { + uint32_t lag_swif_idx = lag_to_bond_if_idx(port_id); + SWSS_LOG_NOTICE("lag swif idx :%d",lag_swif_idx); + hw_ifname = vpp_get_swif_name(lag_swif_idx); + SWSS_LOG_NOTICE("lag swif idx :%d swif_name:%s",lag_swif_idx, hw_ifname); + if (hw_ifname == NULL) + { + SWSS_LOG_NOTICE("LAG port is not found for bridge port id :%s",sai_serialize_object_id(port_id).c_str()); + return SAI_STATUS_FAILURE; + } } - attr.id = SAI_VLAN_MEMBER_ATTR_VLAN_TAGGING_MODE; status = get(SAI_OBJECT_TYPE_VLAN_MEMBER, vlan_member_oid, 1, &attr); @@ -1082,3 +1110,264 @@ sai_status_t SwitchStateBase::vpp_delete_bvi_interface( return SAI_STATUS_SUCCESS; } + +uint32_t SwitchStateBase::lag_to_bond_if_idx (const sai_object_id_t lag_id) +{ + auto it = m_lag_bond_map.find(lag_id); + + if (it == m_lag_bond_map.end()) + { + SWSS_LOG_ERROR("failed to find bond if idx for lag id: %x",lag_id); + return ~0; + } + return it->second; +} + +int SwitchStateBase::remove_lag_to_bond_entry(const sai_object_id_t lag_oid) +{ + auto it = m_lag_bond_map.find(lag_oid); + + if (it == m_lag_bond_map.end()) + { + SWSS_LOG_ERROR("failed to find lag swif index for : %s", sai_serialize_object_id(lag_oid).c_str()); + return ~0; + } + + SWSS_LOG_NOTICE("Removing lag object swif index: %s", sai_serialize_object_id(lag_oid).c_str()); + m_lag_bond_map.erase(it); + return 0; +} + +sai_status_t SwitchStateBase:: createLag( + _In_ sai_object_id_t object_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + SWSS_LOG_ENTER(); + + auto sid = sai_serialize_object_id(object_id); + CHECK_STATUS(create_internal(SAI_OBJECT_TYPE_LAG, sid, switch_id, attr_count, attr_list)); + return vpp_create_lag(object_id, attr_count, attr_list); + +} + +sai_status_t SwitchStateBase::vpp_create_lag( + _In_ sai_object_id_t lag_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + uint32_t bond_id, mode, lb; + uint32_t swif_idx = ~0; + const char *hw_ifname; + SWSS_LOG_ENTER(); + + //set mode and lb. ONiC config does not have provision to pass mode and load balancing algorithm + mode = VPP_BOND_API_MODE_ROUND_ROBIN; + + //if LACP is to be enabled in VPP + //mode = VPP_BOND_API_MODE_LACP; + lb = VPP_BOND_API_LB_ALGO_L2; + bond_id = ~0; + + create_bond_interface(bond_id, mode, lb, &swif_idx); + SWSS_LOG_NOTICE("vpp bond interfae created if index:%d\n", swif_idx); + //update the lag to bond map + m_lag_bond_map[lag_id] = swif_idx; + refresh_interfaces_list(); + + // Set the bond interface state up + hw_ifname = vpp_get_swif_name(swif_idx); + SWSS_LOG_NOTICE("Setting lag hw interface state to up :%s",hw_ifname); + interface_set_state(hw_ifname, true); + return SAI_STATUS_SUCCESS; +} + +sai_status_t SwitchStateBase:: removeLag( + _In_ sai_object_id_t lag_oid) +{ + SWSS_LOG_ENTER(); + + vpp_remove_lag(lag_oid); + auto sid = sai_serialize_object_id(lag_oid); + CHECK_STATUS(remove_internal(SAI_OBJECT_TYPE_LAG, sid)); + return SAI_STATUS_SUCCESS; +} + +sai_status_t SwitchStateBase::vpp_remove_lag( + _In_ sai_object_id_t lag_oid) +{ + SWSS_LOG_ENTER(); + + uint32_t lag_swif_idx = lag_to_bond_if_idx(lag_oid); + SWSS_LOG_NOTICE("lag swif idx :%d",lag_swif_idx); + auto lag_ifname = vpp_get_swif_name(lag_swif_idx); + SWSS_LOG_NOTICE("lag swif idx :%d swif_name:%s",lag_swif_idx, lag_ifname); + if (lag_ifname == NULL) + { + SWSS_LOG_NOTICE("LAG interface name is not found for LAG PORT :%s",sai_serialize_object_id(lag_oid).c_str()); + return SAI_STATUS_FAILURE; + } + + //Delete the Bond interface + delete_bond_interface(lag_ifname); + remove_lag_to_bond_entry(lag_oid); + + return SAI_STATUS_SUCCESS; +} + +sai_status_t SwitchStateBase:: createLagMember( + _In_ sai_object_id_t object_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + SWSS_LOG_ENTER(); + + auto sid = sai_serialize_object_id(object_id); + + CHECK_STATUS(create_internal(SAI_OBJECT_TYPE_LAG_MEMBER, sid, switch_id, attr_count, attr_list)); + return vpp_create_lag_member(attr_count, attr_list); +} + +sai_status_t SwitchStateBase::vpp_create_lag_member( + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + bool is_long_timeout = false; + bool is_passive = false; + uint32_t bond_if_idx; + sai_object_id_t lag_oid, lag_port_oid; + SWSS_LOG_ENTER(); + + //Get the bond interface index from attr SAI_LAG_MEMBER_ATTR_LAG_ID + auto attr_type = sai_metadata_get_attr_by_id(SAI_LAG_MEMBER_ATTR_LAG_ID, attr_count, attr_list); + if (attr_type == NULL) + { + SWSS_LOG_ERROR("attr SAI_LAG_MEMBER_ATTR_LAG_ID was not passed"); + return SAI_STATUS_FAILURE; + } + lag_oid = attr_type->value.oid; + sai_object_type_t obj_type = objectTypeQuery(lag_oid); + + if (obj_type != SAI_OBJECT_TYPE_LAG) + { + SWSS_LOG_ERROR(" SAI_LAG_MEMBER_ATTR_LAG_ID = %s expected to be LAG ID but is: %s", + sai_serialize_object_id(lag_oid).c_str(), + sai_serialize_object_type(obj_type).c_str()); + return SAI_STATUS_FAILURE; + } + bond_if_idx = lag_to_bond_if_idx(lag_oid); + SWSS_LOG_NOTICE("bond if index is %d\n",bond_if_idx); + + attr_type = sai_metadata_get_attr_by_id(SAI_LAG_MEMBER_ATTR_PORT_ID, attr_count, attr_list); + + if (attr_type == NULL) + { + SWSS_LOG_ERROR("attr SAI_LAG_MEMBER_ATTR_PORT_ID was not present\n"); + return SAI_STATUS_FAILURE; + } + + lag_port_oid = attr_type->value.oid; + SWSS_LOG_NOTICE("lag port id is %s",sai_serialize_object_id(lag_port_oid).c_str()); + obj_type = objectTypeQuery(lag_port_oid); + if (obj_type != SAI_OBJECT_TYPE_PORT) + { + SWSS_LOG_NOTICE("SAI_BRIDGE_PORT_ATTR_PORT_ID=%s expected to be PORT but is: %s", + sai_serialize_object_id(lag_port_oid).c_str(), + sai_serialize_object_type(obj_type).c_str()); + return SAI_STATUS_FAILURE; + } + + std::string if_name; + bool found = getTapNameFromPortId(lag_port_oid, if_name); + const char *hwifname; + if (found == true) + { + hwifname = tap_to_hwif_name(if_name.c_str()); + SWSS_LOG_NOTICE("hwif name for port is %s",hwifname); + }else { + SWSS_LOG_NOTICE("No ports found for lag port id :%s",sai_serialize_object_id(lag_port_oid).c_str()); + return SAI_STATUS_FAILURE; + } + + create_bond_member(bond_if_idx, hwifname,is_passive,is_long_timeout); + return SAI_STATUS_SUCCESS; +} + +sai_status_t SwitchStateBase::removeLagMember( + _In_ sai_object_id_t lag_member_oid) +{ + SWSS_LOG_ENTER(); + + vpp_remove_lag_member(lag_member_oid); + + auto sid = sai_serialize_object_id(lag_member_oid); + + CHECK_STATUS(remove_internal(SAI_OBJECT_TYPE_LAG_MEMBER, sid)); + + return SAI_STATUS_SUCCESS; +} + +sai_status_t SwitchStateBase::vpp_remove_lag_member( + _In_ sai_object_id_t lag_member_oid) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + + attr.id = SAI_LAG_MEMBER_ATTR_LAG_ID; + + sai_status_t status = get(SAI_OBJECT_TYPE_LAG_MEMBER, lag_member_oid, 1, &attr); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("attr SAI_LAG_MEMBER_ATTR_LAG_ID is not present"); + + return SAI_STATUS_FAILURE; + } + sai_object_id_t lag_oid = attr.value.oid; + + sai_object_type_t obj_type = objectTypeQuery(lag_oid); + + if (obj_type != SAI_OBJECT_TYPE_LAG) + { + SWSS_LOG_ERROR("attr SAI_LAG_MEMBER_ATTR_LAG_ID is not valid"); + return SAI_STATUS_FAILURE; + } + + attr.id = SAI_LAG_MEMBER_ATTR_PORT_ID; + + status = get(SAI_OBJECT_TYPE_LAG_MEMBER, lag_member_oid, 1, &attr); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("attr SAI_LAG_MEMBER_ATTR_PORT_ID is not present"); + + return SAI_STATUS_FAILURE; + } + sai_object_id_t port_oid = attr.value.oid; + + obj_type = objectTypeQuery(port_oid); + + if (obj_type != SAI_OBJECT_TYPE_PORT) + { + SWSS_LOG_ERROR("attr SAI_LAG_MEMBER_ATTR_PORT_ID is not valid"); + return SAI_STATUS_FAILURE; + } + + std::string if_name; + bool found = getTapNameFromPortId(port_oid, if_name); + const char *lag_member_ifname; + if (found == true) + { + lag_member_ifname = tap_to_hwif_name(if_name.c_str()); + SWSS_LOG_NOTICE("hwif name for port is %s",lag_member_ifname); + } else { + SWSS_LOG_NOTICE("No ports found for lag port id :%s",sai_serialize_object_id(port_oid).c_str()); + return SAI_STATUS_FAILURE; + } + + delete_bond_member(lag_member_ifname); + return SAI_STATUS_SUCCESS; +} diff --git a/platform/saivpp/vpplib/vppxlate/SaiVppXlate.c b/platform/saivpp/vpplib/vppxlate/SaiVppXlate.c index 8cb2d73..57ca20f 100644 --- a/platform/saivpp/vpplib/vppxlate/SaiVppXlate.c +++ b/platform/saivpp/vpplib/vppxlate/SaiVppXlate.c @@ -53,6 +53,9 @@ #include #include +#include +#include + /* l2 API inclusion */ #define vl_typedefs @@ -187,6 +190,28 @@ #include #undef vl_api_version +/* BOND API inclusion */ + +#define vl_typedefs +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_printfun +#include +#undef vl_printfun + +#define vl_calcsizefun +#include +#undef vl_calcsizefun + +#define vl_api_version(n, v) static u32 bond_api_version = v; +#include +#undef vl_api_version + /* memclnt API inclusion */ #define vl_typedefs /* define message structures */ @@ -675,6 +700,49 @@ vl_api_bridge_domain_details_t_handler (vl_api_bridge_domain_details_t *mp) return; } +static void +vl_api_bond_create_reply_t_handler (vl_api_bond_create_reply_t *msg) +{ + set_reply_status(ntohl(msg->retval)); + + if (msg->context) { + u32 *swif_idx = (u32 *) get_index_ptr(msg->context); + *swif_idx = ntohl(msg->sw_if_index); + } + + SAIVPP_WARN("bond add %s(%d)", msg->retval ? "failed" : "successful", msg->retval); + if (!msg->retval) + { + uint32_t bond_if_index = ntohl(msg->sw_if_index); + SAIVPP_WARN("created bond if index%d", bond_if_index); + } + //SAIVPP_ERROR("l2 add del reply handler called %s(%d)",msg->retval ? "failed" : "successful", msg->retval); + +} + +static void +vl_api_bond_delete_reply_t_handler (vl_api_bond_delete_reply_t *msg) +{ + set_reply_status(ntohl(msg->retval)); + + SAIVPP_WARN("bond delete %s(%d)", msg->retval ? "failed" : "successful", msg->retval); +} + +static void +vl_api_bond_add_member_reply_t_handler (vl_api_bond_add_member_reply_t *msg) +{ + set_reply_status(ntohl(msg->retval)); + + SAIVPP_WARN("bond add member %s(%d)", msg->retval ? "failed" : "successful", msg->retval); +} + +static void +vl_api_bond_detach_member_reply_t_handler (vl_api_bond_detach_member_reply_t *msg) +{ + set_reply_status(ntohl(msg->retval)); + + SAIVPP_WARN("bond detach member %s(%d)", msg->retval ? "failed" : "successful", msg->retval); +} #define vl_api_get_first_msg_id_reply_t_handler vl_noop_handler #define vl_api_get_first_msg_id_reply_t_handler_json vl_noop_handler @@ -686,6 +754,7 @@ vl_api_bridge_domain_details_t_handler (vl_api_bridge_domain_details_t *mp) static u16 interface_msg_id_base, memclnt_msg_id_base, __plugin_msg_base; static u16 l2_msg_id_base; +static u16 bond_msg_id_base; static void vpp_base_vpe_init(void) { @@ -716,6 +785,10 @@ static void vpp_base_vpe_init(void) #define L2_MSG_ID(id) \ (VL_API_##id + l2_msg_id_base) +#define BOND_MSG_ID(id) \ + (VL_API_##id + bond_msg_id_base) + + #define foreach_vpe_ext_api_reply_msg \ _(INTERFACE_MSG_ID(SW_INTERFACE_DETAILS), sw_interface_details) \ _(INTERFACE_MSG_ID(CREATE_LOOPBACK_INSTANCE_REPLY), create_loopback_instance_reply) \ @@ -739,7 +812,11 @@ static void vpp_base_vpe_init(void) _(L2_MSG_ID(BRIDGE_DOMAIN_DETAILS), bridge_domain_details) \ _(L2_MSG_ID(BVI_CREATE_REPLY), bvi_create_reply) \ _(L2_MSG_ID(BVI_DELETE_REPLY), bvi_delete_reply) \ - _(L2_MSG_ID(BRIDGE_FLAGS_REPLY), bridge_flags_reply) + _(L2_MSG_ID(BRIDGE_FLAGS_REPLY), bridge_flags_reply) \ + _(BOND_MSG_ID(BOND_CREATE_REPLY), bond_create_reply) \ + _(BOND_MSG_ID(BOND_DELETE_REPLY), bond_delete_reply) \ + _(BOND_MSG_ID(BOND_ADD_MEMBER_REPLY), bond_add_member_reply) \ + _(BOND_MSG_ID(BOND_DETACH_MEMBER_REPLY), bond_detach_member_reply) static u16 interface_msg_id_base, ip_msg_id_base, ip_nbr_msg_id_base, lcp_msg_id_base, memclnt_msg_id_base, __plugin_msg_base; static u16 acl_msg_id_base; @@ -864,6 +941,10 @@ static void get_base_msg_id() //SAIVPP_ERROR("DELME: l2_msg_id_base %s msg_base_lookup_name:%s l2_api_version:%08x\n", l2_msg_id_base,msg_base_lookup_name,l2_api_version); //printf("DELME: New change added l2_msg_id_base %s\n", l2_msg_id_base); + msg_base_lookup_name = format (0, "bond_%08x%c", bond_api_version, 0); + bond_msg_id_base = vl_client_get_first_plugin_msg_id ((char *) msg_base_lookup_name); + SAIVPP_WARN("BALA: bond_msg_id_base is %d",bond_msg_id_base); + assert(bond_msg_id_base != (u16) ~0); memclnt_msg_id_base = 0; } @@ -1011,6 +1092,20 @@ static u32 get_swif_idx (vat_main_t *vam, const char *ifname) return ((u32) -1); } +static const char * get_swif_name (vat_main_t *vam, const u32 swif_idx) +{ + hash_pair_t *p; + u8 *name; + u32 value; + + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, ({ + name = (u8 *) (p->key); + value = (u32) p->value[0]; + if (value == swif_idx) return name; + })); + return NULL; +} + static int config_lcp_hostif (vat_main_t *vam, vl_api_interface_index_t if_idx, const char *hostif_name, @@ -2252,3 +2347,160 @@ int set_bridge_domain_flags(uint32_t bd_id, vpp_bd_flags_t flag, bool enable) return ret; } + +int create_bond_interface(uint32_t bond_id, uint32_t mode, uint32_t lb, uint32_t *swif_idx) +{ + vat_main_t *vam = &vat_main; + vl_api_bond_create_t * mp; + int ret; + + + SAIVPP_WARN("Creating bd interface: \n"); + VPP_LOCK(); + + __plugin_msg_base = bond_msg_id_base; + + M (BOND_CREATE, mp); + + mp->id = htonl(bond_id); + mp->mode = htonl(mode); + mp->lb = htonl(lb); + mp->numa_only = false; + mp->use_custom_mac = false; + mp->context = store_ptr(swif_idx); + + S (mp); + + W (ret); + + VPP_UNLOCK(); + + return ret; +} + +int delete_bond_interface(const char *hwif_name) +{ + vat_main_t *vam = &vat_main; + vl_api_bond_delete_t * mp; + int ret; + + + SAIVPP_WARN("Removing bond interface: \n"); + VPP_LOCK(); + + __plugin_msg_base = bond_msg_id_base; + + + M (BOND_DELETE, mp); + + if (hwif_name) { + u32 idx; + + idx = get_swif_idx(vam, hwif_name); + if (idx != (u32) -1) { + mp->sw_if_index = htonl(idx); + } else { + SAIVPP_ERROR("Unable to get sw_index for %s\n", hwif_name); + VPP_UNLOCK(); + return -EINVAL; + } + } else { + VPP_UNLOCK(); + return -EINVAL; + } + + S (mp); + + W (ret); + + VPP_UNLOCK(); + + return ret; +} +int create_bond_member(uint32_t bond_sw_if_index, const char *hwif_name, bool is_passive, bool is_long_timeout) +{ + vat_main_t *vam = &vat_main; + vl_api_bond_add_member_t * mp; + int ret; + + + SAIVPP_WARN("Adding member to bond interface: \n"); + VPP_LOCK(); + + __plugin_msg_base = bond_msg_id_base; + + + M (BOND_ADD_MEMBER, mp); + + if (hwif_name) { + u32 idx; + + idx = get_swif_idx(vam, hwif_name); + if (idx != (u32) -1) { + mp->sw_if_index = htonl(idx); + } else { + SAIVPP_ERROR("Unable to get sw_index for %s\n", hwif_name); + VPP_UNLOCK(); + return -EINVAL; + } + } else { + VPP_UNLOCK(); + return -EINVAL; + } + mp->bond_sw_if_index = htonl(bond_sw_if_index); + mp->is_passive = is_passive; + mp->is_long_timeout = is_long_timeout; + + S (mp); + + W (ret); + + VPP_UNLOCK(); + + return ret; +} + +const char * vpp_get_swif_name (const u32 swif_idx) +{ + vat_main_t *vam = &vat_main; + return get_swif_name(vam, swif_idx); +} + + +int delete_bond_member(const char * hwif_name) +{ + vat_main_t *vam = &vat_main; + vl_api_bond_detach_member_t *mp; + int ret; + + VPP_LOCK(); + + __plugin_msg_base = bond_msg_id_base; + + M (BOND_DETACH_MEMBER, mp); + + if (hwif_name) { + u32 idx; + + idx = get_swif_idx(vam, hwif_name); + if (idx != (u32) -1) { + mp->sw_if_index = htonl(idx); + } else { + SAIVPP_ERROR("Unable to get sw_index for %s\n", hwif_name); + VPP_UNLOCK(); + return -EINVAL; + } + } else { + VPP_UNLOCK(); + return -EINVAL; + } + + S (mp); + + W (ret); + + VPP_UNLOCK(); + + return ret; +} + diff --git a/platform/saivpp/vpplib/vppxlate/SaiVppXlate.h b/platform/saivpp/vpplib/vppxlate/SaiVppXlate.h index 1a2daf5..0dc5220 100644 --- a/platform/saivpp/vpplib/vppxlate/SaiVppXlate.h +++ b/platform/saivpp/vpplib/vppxlate/SaiVppXlate.h @@ -156,7 +156,23 @@ typedef enum { VPP_BD_FLAG_ARP_UFWD = 32, } vpp_bd_flags_t; +typedef enum { + VPP_BOND_API_MODE_ROUND_ROBIN = 1, + VPP_BOND_API_MODE_ACTIVE_BACKUP = 2, + VPP_BOND_API_MODE_XOR = 3, + VPP_BOND_API_MODE_BROADCAST = 4, + VPP_BOND_API_MODE_LACP = 5, +} vpp_bond_mode; + +typedef enum { + VPP_BOND_API_LB_ALGO_L2 = 0, + VPP_BOND_API_LB_ALGO_L34 = 1, + VPP_BOND_API_LB_ALGO_L23 = 2, + VPP_BOND_API_LB_ALGO_RR = 3, + VPP_BOND_API_LB_ALGO_BC = 4, + VPP_BOND_API_LB_ALGO_AB = 5, +} vpp_bond_lb_algo; extern vpp_event_info_t * vpp_ev_dequeue(); extern void vpp_ev_free(vpp_event_info_t *evp); @@ -200,6 +216,11 @@ typedef enum { extern int create_bvi_interface(uint8_t *mac_address, uint32_t instance); extern int delete_bvi_interface(const char *hwif_name); extern int set_bridge_domain_flags(uint32_t bd_id, vpp_bd_flags_t flag, bool enable); + extern int create_bond_interface(uint32_t bond_id, uint32_t mode, uint32_t lb, uint32_t *swif_idx); + extern int delete_bond_interface(const char *hwif_name); + extern int create_bond_member(uint32_t bond_sw_if_index, const char *hwif_name, bool is_passive, bool is_long_timeout); + extern int delete_bond_member(const char * hwif_name); + extern const char * vpp_get_swif_name(const uint32_t swif_idx); #ifdef __cplusplus }