From 61569ef20e4243762fdb8004cf595419744dd330 Mon Sep 17 00:00:00 2001 From: Sergei Tolmachev Date: Thu, 30 Jan 2025 17:16:25 +0300 Subject: [PATCH] fix balancer: add pure round robin --- .../001-expect.pcap | Bin 0 -> 1248 bytes .../001-send.pcap | Bin 0 -> 768 bytes .../autotest.yaml | 14 +++++ .../controlplane.conf | 46 ++++++++++++++++ .../080_balancer_pure_round_robin/gen.py | 50 ++++++++++++++++++ .../services.conf | 40 ++++++++++++++ common/define.h | 1 + controlplane/configparser.cpp | 5 ++ dataplane/worker.cpp | 5 +- dataplane/worker.h | 1 + 10 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 autotest/units/001_one_port/080_balancer_pure_round_robin/001-expect.pcap create mode 100644 autotest/units/001_one_port/080_balancer_pure_round_robin/001-send.pcap create mode 100644 autotest/units/001_one_port/080_balancer_pure_round_robin/autotest.yaml create mode 100644 autotest/units/001_one_port/080_balancer_pure_round_robin/controlplane.conf create mode 100755 autotest/units/001_one_port/080_balancer_pure_round_robin/gen.py create mode 100644 autotest/units/001_one_port/080_balancer_pure_round_robin/services.conf diff --git a/autotest/units/001_one_port/080_balancer_pure_round_robin/001-expect.pcap b/autotest/units/001_one_port/080_balancer_pure_round_robin/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..61f77c512dfa7b7cb54c7fbe7fae437d89261ca7 GIT binary patch literal 1248 zcmca|c+)~A1{MYw`2U}Qff2?5(qT{x7Gh)&R5Er6ZDe3bX}g;M5|UxDS72b31~C~K z!5SGAKpX^Mas{da$v6n+p8=`iVqjo4h+zm|;5ecSQ%12Z%yhAZkuJ83hS+Et!^|&% Q!2F^^wfurBB@a7W01qZ_{Qv*} literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/080_balancer_pure_round_robin/001-send.pcap b/autotest/units/001_one_port/080_balancer_pure_round_robin/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..893fb53ebe034623b4e3549491865a412b86818b GIT binary patch literal 768 zcmca|c+)~A1{MYw`2U}Qff2?5(t1$LAgE;Q5(<`JYGhzI!NK6lz#s!s>L8eZhLMqh ik&A(W*&v1?fPv$PF3f;Y-NQcA0)g?ZLw0-*xNZQdmQwrx literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/080_balancer_pure_round_robin/autotest.yaml b/autotest/units/001_one_port/080_balancer_pure_round_robin/autotest.yaml new file mode 100644 index 00000000..429015cb --- /dev/null +++ b/autotest/units/001_one_port/080_balancer_pure_round_robin/autotest.yaml @@ -0,0 +1,14 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- cli: + - balancer real enable balancer0 10.0.0.3 udp 80 2000::1 80 + - balancer real enable balancer0 10.0.0.3 udp 80 2000::2 80 + - balancer real enable balancer0 10.0.0.3 udp 80 2000::3 80 + - balancer real enable balancer0 10.0.0.3 udp 81 2000::1 81 + - balancer real enable balancer0 10.0.0.3 udp 81 2000::2 81 + - balancer real flush +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap diff --git a/autotest/units/001_one_port/080_balancer_pure_round_robin/controlplane.conf b/autotest/units/001_one_port/080_balancer_pure_round_robin/controlplane.conf new file mode 100644 index 00000000..40f772fa --- /dev/null +++ b/autotest/units/001_one_port/080_balancer_pure_round_robin/controlplane.conf @@ -0,0 +1,46 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "balancer0", + "route0" + ] + }, + "balancer0": { + "type": "balancer", + "source": "2000:51b::1", + "services": "services.conf", + "nextModule": "route0" + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:00:00:01", + "nextModule": "lp0.100" + }, + "kni0.200": { + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:00:00:02", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/080_balancer_pure_round_robin/gen.py b/autotest/units/001_one_port/080_balancer_pure_round_robin/gen.py new file mode 100755 index 00000000..f517b6d5 --- /dev/null +++ b/autotest/units/001_one_port/080_balancer_pure_round_robin/gen.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +write_pcap("001-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=81, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=81, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=81, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=81, sport=12380)) + +write_pcap("001-expect.pcap", + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::2", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::3", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::1", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::2", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::3", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::1", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::2", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::3", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::1", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=81, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::1", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=81, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::1", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=81, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="2000::1", src="2000:51b::0101:0001:0:1", hlim=63, fl=0)/IP(dst="10.0.0.3", src="1.1.0.1", ttl=64)/UDP(dport=81, sport=12380)) diff --git a/autotest/units/001_one_port/080_balancer_pure_round_robin/services.conf b/autotest/units/001_one_port/080_balancer_pure_round_robin/services.conf new file mode 100644 index 00000000..06e70850 --- /dev/null +++ b/autotest/units/001_one_port/080_balancer_pure_round_robin/services.conf @@ -0,0 +1,40 @@ +[ + { + "vip": "10.0.0.3", + "proto": "udp", + "vport": "80", + "scheduler": "rr", + "pure_round_robin": true, + "ops": true, + "reals": [ + { + "ip": "2000::1", + "port": "80" + }, + { + "ip": "2000::2", + "port": "80" + }, + { + "ip": "2000::3", + "port": "80" + } + ] + }, + { + "vip": "10.0.0.3", + "proto": "udp", + "vport": "81", + "scheduler": "rr", + "reals": [ + { + "ip": "2000::1", + "port": "81" + }, + { + "ip": "2000::2", + "port": "81" + } + ] + } +] diff --git a/common/define.h b/common/define.h index 47cc5fd0..b090da18 100644 --- a/common/define.h +++ b/common/define.h @@ -101,6 +101,7 @@ extern LogPriority logPriority; #define YANET_BALANCER_OPS_FLAG ((uint8_t)(1u << 1)) #define YANET_BALANCER_PURE_L3 ((uint8_t)(1u << 2)) +#define YANET_BALANCER_PURE_ROUND_ROBIN ((uint8_t)(1u << 3)) #define CALCULATE_LOGICALPORT_ID(portId, vlanId) ((portId << 13) | ((vlanId & 0xFFF) << 1) | 1) diff --git a/controlplane/configparser.cpp b/controlplane/configparser.cpp index 92054e4c..b3cc079c 100644 --- a/controlplane/configparser.cpp +++ b/controlplane/configparser.cpp @@ -1743,6 +1743,11 @@ void config_parser_t::loadConfig_balancer_services(controlplane::base_t& baseNex flags |= YANET_BALANCER_OPS_FLAG; } + if (service_json.value("pure_round_robin", false)) + { + flags |= YANET_BALANCER_PURE_ROUND_ROBIN; + } + balancer.services.emplace_back(baseNext.services_count + 1, ///< 0 is invalid id service_json["vip"].get(), proto, diff --git a/dataplane/worker.cpp b/dataplane/worker.cpp index 7a1ad8e5..17e3b6f5 100644 --- a/dataplane/worker.cpp +++ b/dataplane/worker.cpp @@ -47,6 +47,7 @@ cWorker::cWorker(cDataPlane* dataPlane) : ring_lowPriority(nullptr), ring_toFreePackets(nullptr), ring_log(nullptr), + roundRobinCounter(0), packetsToSWNPRemainder(dataPlane->config.SWNormalPriorityRateLimitPerWorker) { } @@ -4117,7 +4118,9 @@ inline void cWorker::balancer_handle() continue; } - const auto& real_id = ring->reals[range->start + (metadata->hash % range->size)]; + + const auto& reals_shift = service.flags & YANET_BALANCER_PURE_ROUND_ROBIN ? ++roundRobinCounter : metadata->hash; + const auto& real_id = ring->reals[range->start + (reals_shift % range->size)]; const auto& real_unordered = base.globalBase->balancer_reals[real_id]; if (!value) { diff --git a/dataplane/worker.h b/dataplane/worker.h index 1ed5774f..9d42377a 100644 --- a/dataplane/worker.h +++ b/dataplane/worker.h @@ -354,6 +354,7 @@ class cWorker uint64_t* bursts; // CONFIG_YADECAP_MBUFS_BURST_SIZE + 1 uint64_t* counters; // YANET_CONFIG_COUNTERS_SIZE uint64_t* aclCounters; // YANET_CONFIG_ACL_COUNTERS_SIZE + uint64_t roundRobinCounter; // will decrease with each new packet sent to slow worker, replenishes each N mseconds int32_t packetsToSWNPRemainder;