From 49e3b7b37f7defaa583fdc936fe0530f4f91c43d Mon Sep 17 00:00:00 2001 From: saushew Date: Thu, 12 Oct 2023 17:16:05 +0300 Subject: [PATCH] Add support of IPv4/v6 outer source network for services --- .../001-expect.pcap | Bin 0 -> 480 bytes .../001-send.pcap | Bin 0 -> 320 bytes .../002-expect.pcap | Bin 0 -> 400 bytes .../002-send.pcap | Bin 0 -> 320 bytes .../003-expect.pcap | Bin 0 -> 560 bytes .../003-send.pcap | Bin 0 -> 400 bytes .../004-expect.pcap | Bin 0 -> 480 bytes .../004-send.pcap | Bin 0 -> 400 bytes .../autotest.yaml | 31 ++++++ .../controlplane.conf | 48 ++++++++++ .../068_balancer_outer_source_network/gen.py | 80 ++++++++++++++++ .../services.conf | 58 ++++++++++++ common/controlplaneconfig.h | 2 + common/idp.h | 4 +- controlplane/balancer.cpp | 76 +++++++++++++-- controlplane/configconverter.cpp | 88 ++++++++++++++---- controlplane/configparser.cpp | 7 ++ dataplane/globalbase.cpp | 43 +++++++-- dataplane/type.h | 22 +++++ dataplane/worker.cpp | 76 +++++++++++++-- dataplane/worker.h | 3 + 21 files changed, 494 insertions(+), 44 deletions(-) create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/001-expect.pcap create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/001-send.pcap create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/002-expect.pcap create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/002-send.pcap create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/003-expect.pcap create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/003-send.pcap create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/004-expect.pcap create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/004-send.pcap create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/autotest.yaml create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/controlplane.conf create mode 100755 autotest/units/001_one_port/068_balancer_outer_source_network/gen.py create mode 100644 autotest/units/001_one_port/068_balancer_outer_source_network/services.conf diff --git a/autotest/units/001_one_port/068_balancer_outer_source_network/001-expect.pcap b/autotest/units/001_one_port/068_balancer_outer_source_network/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..c62c542f2cf1f9161d4ae3e07a5b0168113cd9d2 GIT binary patch literal 480 zcmca|c+)~A1{MYw`2U}Qff2?5(n(MZ7Gh)&R5Er6ZDe3bX}g;M64GF?S75xicHeuT zE=I6MMg@>K0x-G)Re@w2*z(VU)Nlcn8pJRJz?1|qDKLbXz<4Cu$OP2Kr~o980J4o| zfHpE=wb2-%gCsvP1NAW~00|_3Y~yL5jm%hWG(zYg$wpA*Fe(5EB!Fz=DWHukSZy?9 GU;qFs<~5W6 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/068_balancer_outer_source_network/001-send.pcap b/autotest/units/001_one_port/068_balancer_outer_source_network/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..0e7b98fa554c4f165b3b4500d0134a1502279938 GIT binary patch literal 320 zcmca|c+)~A1{MYw`2U}Qff2?5(pFH+AgE;Q5(<`JYGhzI!NK6lz@PzA>cEzNmXVQx zkqfBNAci3Tra6E~fg!{M#v{_CGeDD=u$p8{qDiNLCNX0*$%sUgP616~!D^Br0|Nj6 CoF7sE literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/068_balancer_outer_source_network/002-expect.pcap b/autotest/units/001_one_port/068_balancer_outer_source_network/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..6a239f79f45609b6e70b4e51c17204a06d585b47 GIT binary patch literal 400 zcmca|c+)~A1{MYw`2U}Qff2?5(tc137Gh)&R5Er6ZDe3b;b3rOV6XuxwP%^rUd_P3 zlfuBD1r*Z&i8-+4FJWY4VB`Xd8N@IIzzhsvQeX(-hVdvceKF8cE!2gprYf zk&A&r%OHj!0H!&BNr54R8^$Bjq{Tp!n6R1z6odhy+_VU25;InlIAP`x>86E1lUT5t I#KFJ-0J3Est^fc4 literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/068_balancer_outer_source_network/003-expect.pcap b/autotest/units/001_one_port/068_balancer_outer_source_network/003-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..6cac11d337d74b210f7ba29312776eceffe505cf GIT binary patch literal 560 zcmca|c+)~A1{MYw`2U}Qff2?5(q&K#7Gh)&R5Er6ZDe3bX}g;M60*^>S75xicHes; z6Ce+ykx>CiAOXe%5J!Z~L4gTL6r>KU4=%=NFqh-Fj&5=a1-D_97+B8Y(j08 200.0.0.1" + - "100.0.0.0/8 -> 100.0.0.5" +- ipv6Update: "::/0 -> fe80::1" +- cli: + - balancer real enable balancer0 10.0.0.1 tcp 80 2000::1 80 + - balancer real enable balancer0 10.0.0.42 tcp 80 100.0.0.42 80 + - balancer real enable balancer0 2001:dead:beef::1 tcp 80 2000::1 80 + - balancer real enable balancer0 2001:dead:beef::2 tcp 80 100.0.0.6 80 + - balancer real flush +- sleep: 1 +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap \ No newline at end of file diff --git a/autotest/units/001_one_port/068_balancer_outer_source_network/controlplane.conf b/autotest/units/001_one_port/068_balancer_outer_source_network/controlplane.conf new file mode 100644 index 00000000..5fef64d1 --- /dev/null +++ b/autotest/units/001_one_port/068_balancer_outer_source_network/controlplane.conf @@ -0,0 +1,48 @@ +{ + "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", + "source_ipv4": "100.0.0.22", + "services": "services.conf", + "nextModule": "route0" + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "neighborIPv6Address": "fe80::1", + "neighborIPv4Address": "100.0.0.5", + "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/068_balancer_outer_source_network/gen.py b/autotest/units/001_one_port/068_balancer_outer_source_network/gen.py new file mode 100755 index 00000000..4772d929 --- /dev/null +++ b/autotest/units/001_one_port/068_balancer_outer_source_network/gen.py @@ -0,0 +1,80 @@ +#!/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.1", src="1.1.0.1", ttl=64) / TCP(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.1", src="1.1.0.2", ttl=64) / TCP(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.1", src="1.1.0.3", ttl=64) / TCP(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.1", src="1.1.0.4", ttl=64) / TCP(dport=80, 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::1", src="2001:dead:beef::0101:0001:0:1", hlim=63)/IP(dst="10.0.0.1", src="1.1.0.1", ttl=64)/TCP(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="2001:dead:beef::0101:0002:0:1", hlim=63)/IP(dst="10.0.0.1", src="1.1.0.2", ttl=64)/TCP(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="2001:dead:beef::0101:0003:0:1", hlim=63)/IP(dst="10.0.0.1", src="1.1.0.3", ttl=64)/TCP(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="2001:dead:beef::0101:0004:0:1", hlim=63)/IP(dst="10.0.0.1", src="1.1.0.4", ttl=64)/TCP(dport=80, sport=12380), +) + + +write_pcap("002-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.42", src="1.1.0.1", ttl=64)/TCP(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.42", src="1.1.0.2", ttl=64)/TCP(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.42", src="1.1.0.3", ttl=64)/TCP(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.42", src="1.1.0.4", ttl=64)/TCP(dport=80, sport=12380), +) + +write_pcap("002-expect.pcap", + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="100.0.0.42", src="123.0.0.12", ttl=63)/IP(dst="10.0.0.42", src="1.1.0.1", ttl=64)/TCP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="100.0.0.42", src="123.0.0.12", ttl=63)/IP(dst="10.0.0.42", src="1.1.0.2", ttl=64)/TCP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="100.0.0.42", src="123.0.0.12", ttl=63)/IP(dst="10.0.0.42", src="1.1.0.3", ttl=64)/TCP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="100.0.0.42", src="123.0.0.12", ttl=63)/IP(dst="10.0.0.42", src="1.1.0.4", ttl=64)/TCP(dport=80, sport=12380), +) + +write_pcap("003-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02") / Dot1Q(vlan=200) / IPv6(dst="2001:dead:beef::1", src="2002::1", hlim=64) / TCP(dport=80, sport=12443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02") / Dot1Q(vlan=200) / IPv6(dst="2001:dead:beef::1", src="2002::2", hlim=64) / TCP(dport=80, sport=12443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02") / Dot1Q(vlan=200) / IPv6(dst="2001:dead:beef::1", src="2002::3", hlim=64) / TCP(dport=80, sport=12443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02") / Dot1Q(vlan=200) / IPv6(dst="2001:dead:beef::1", src="2002::4", hlim=64) / TCP(dport=80, sport=12443) +) + +write_pcap("003-expect.pcap", + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55") / Dot1Q(vlan=100) / IPv6(dst="2000::1", src="2001:dead:beef:1234::0001:0:1", hlim=63) / IPv6(dst="2001:dead:beef::1", src="2002::1", hlim=64) / TCP(dport=80, sport=12443), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55") / Dot1Q(vlan=100) / IPv6(dst="2000::1", src="2001:dead:beef:1234::0002:0:1", hlim=63) / IPv6(dst="2001:dead:beef::1", src="2002::2", hlim=64) / TCP(dport=80, sport=12443), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55") / Dot1Q(vlan=100) / IPv6(dst="2000::1", src="2001:dead:beef:1234::0003:0:1", hlim=63) / IPv6(dst="2001:dead:beef::1", src="2002::3", hlim=64) / TCP(dport=80, sport=12443), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55") / Dot1Q(vlan=100) / IPv6(dst="2000::1", src="2001:dead:beef:1234::0004:0:1", hlim=63) / IPv6(dst="2001:dead:beef::1", src="2002::4", hlim=64) / TCP(dport=80, sport=12443) +) + + +write_pcap("004-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="2001:dead:beef::2", src="2002::10", hlim=64)/TCP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="2001:dead:beef::2", src="2002::11", hlim=64)/TCP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="2001:dead:beef::2", src="2002::12", hlim=64)/TCP(dport=80, sport=12380), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="2001:dead:beef::2", src="2002::13", hlim=64)/TCP(dport=80, sport=12380), +) + +write_pcap("004-expect.pcap", + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="100.0.0.6", src="123.0.12.0", ttl=63) /IPv6(dst="2001:dead:beef::2", src="2002::10", hlim=64)/TCP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="100.0.0.6", src="123.0.12.0", ttl=63) /IPv6(dst="2001:dead:beef::2", src="2002::11", hlim=64)/TCP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="100.0.0.6", src="123.0.12.0", ttl=63) /IPv6(dst="2001:dead:beef::2", src="2002::12", hlim=64)/TCP(dport=80, sport=12380), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="100.0.0.6", src="123.0.12.0", ttl=63) /IPv6(dst="2001:dead:beef::2", src="2002::13", hlim=64)/TCP(dport=80, sport=12380), +) diff --git a/autotest/units/001_one_port/068_balancer_outer_source_network/services.conf b/autotest/units/001_one_port/068_balancer_outer_source_network/services.conf new file mode 100644 index 00000000..b2c02c15 --- /dev/null +++ b/autotest/units/001_one_port/068_balancer_outer_source_network/services.conf @@ -0,0 +1,58 @@ +[ + { + "vip": "10.0.0.1", + "proto": "tcp", + "vport": "80", + "scheduler": "wrr", + "ipv4_outer_source_network": "123.0.0.12/32", + "ipv6_outer_source_network": "2001:dead:beef::/64", + "reals": [ + { + "ip": "2000::1", + "port": "80" + } + ] + }, + { + "vip": "10.0.0.42", + "proto": "tcp", + "vport": "80", + "scheduler": "wrr", + "ipv4_outer_source_network": "123.0.0.12/32", + "ipv6_outer_source_network": "2001:dead:beef::/64", + "reals": [ + { + "ip": "100.0.0.42", + "port": "80" + } + ] + }, + { + "vip": "2001:dead:beef::1", + "proto": "tcp", + "vport": "80", + "scheduler": "wrr", + "ipv4_outer_source_network": "123.0.12.0/24", + "ipv6_outer_source_network": "2001:dead:beef:1234::/80", + "reals": [ + { + "ip": "2000::1", + "port": "80" + } + ] + }, + { + "vip": "2001:dead:beef::2", + "proto": "tcp", + "vport": "80", + "scheduler": "wrr", + "ipv4_outer_source_network": "123.0.12.0/24", + "ipv6_outer_source_network": "2001:dead:beef:1234::/80", + "reals": [ + { + "ip": "100.0.0.6", + "port": "80" + } + ] + } +] diff --git a/common/controlplaneconfig.h b/common/controlplaneconfig.h index be59c45b..3e526762 100644 --- a/common/controlplaneconfig.h +++ b/common/controlplaneconfig.h @@ -310,6 +310,8 @@ using service_t = std::tuple, ///< ipv4_outer_source_network + std::optional, ///< ipv6_outer_source_network std::vector>; class config_t diff --git a/common/idp.h b/common/idp.h index a2f52c3d..569085ca 100644 --- a/common/idp.h +++ b/common/idp.h @@ -265,7 +265,9 @@ using service = std::tuple; ///< real_size + uint32_t, ///< real_size + std::optional, ///< ipv4_outer_source_network + std::optional>; ///< ipv6_outer_source_network> using real = std::tuple; diff --git a/controlplane/balancer.cpp b/controlplane/balancer.cpp index ec5d8ec7..40a392b3 100644 --- a/controlplane/balancer.cpp +++ b/controlplane/balancer.cpp @@ -216,7 +216,18 @@ void balancer_t::reload(const controlplane::base_t& base_prev, for (const auto& [module_name, balancer] : base_prev.balancers) { - for (const auto& [service_id, virtual_ip, proto, virtual_port, version, scheduler, scheduler_params, forwarding_method, flags, reals] : balancer.services) + for (const auto& [service_id, + virtual_ip, + proto, + virtual_port, + version, + scheduler, + scheduler_params, + forwarding_method, + flags, + ipv4_outer_source_network, + ipv6_outer_source_network, + reals] : balancer.services) { (void)service_id; (void)version; @@ -225,6 +236,8 @@ void balancer_t::reload(const controlplane::base_t& base_prev, (void)reals; (void)flags; (void)forwarding_method; + (void)ipv4_outer_source_network; + (void)ipv6_outer_source_network; service_counters.remove({module_name, {virtual_ip, proto, virtual_port}}); @@ -248,7 +261,18 @@ void balancer_t::reload(const controlplane::base_t& base_prev, { std::unordered_set> vip_vport_proto; - for (const auto& [service_id, virtual_ip, proto, virtual_port, version, scheduler, scheduler_params, forwarding_method, flags, reals] : balancer.services) + for (const auto& [service_id, + virtual_ip, + proto, + virtual_port, + version, + scheduler, + scheduler_params, + forwarding_method, + flags, + ipv4_outer_source_network, + ipv6_outer_source_network, + reals] : balancer.services) { (void)service_id; (void)version; @@ -256,6 +280,8 @@ void balancer_t::reload(const controlplane::base_t& base_prev, (void)scheduler_params; (void)flags; (void)forwarding_method; + (void)ipv4_outer_source_network; + (void)ipv6_outer_source_network; service_counters.insert({module_name, {virtual_ip, proto, virtual_port}}); @@ -592,7 +618,18 @@ void balancer_t::update_service(const balancer::generation_config_t& generation_ uint64_t services_reals_enabled_count = 0; uint64_t services_reals_count = 0; - for (const auto& [service_id, virtual_ip, proto, virtual_port, version, scheduler, scheduler_params, forwarding_method, flags, reals] : balancer.services) + for (const auto& [service_id, + virtual_ip, + proto, + virtual_port, + version, + scheduler, + scheduler_params, + forwarding_method, + flags, + ipv4_outer_source_network, + ipv6_outer_source_network, + reals] : balancer.services) { (void)flags; (void)scheduler_params; @@ -676,7 +713,18 @@ void balancer_t::compile(common::idp::updateGlobalBase::request& globalbase, for (const auto& [module_name, balancer] : generation_config.config_balancers) { - for (const auto& [service_id, virtual_ip, proto, virtual_port, version, scheduler, scheduler_params, forwarding_method, flags, reals] : balancer.services) + for (const auto& [service_id, + virtual_ip, + proto, + virtual_port, + version, + scheduler, + scheduler_params, + forwarding_method, + flags, + ipv4_outer_source_network, + ipv6_outer_source_network, + reals] : balancer.services) { (void)scheduler_params; (void)version; @@ -725,9 +773,12 @@ void balancer_t::compile(common::idp::updateGlobalBase::request& globalbase, counter_ids[0], scheduler, forwarding_method, - balancer.default_wlc_power, //todo use scheduler_params.wlc_power when other services will be able to set it + balancer.default_wlc_power, // todo use scheduler_params.wlc_power when other services will be able to set it (uint32_t)real_start, - (uint32_t)(req_reals.size() - real_start)}); + (uint32_t)(req_reals.size() - real_start), + ipv4_outer_source_network, + ipv6_outer_source_network, + }); } } @@ -745,7 +796,18 @@ void balancer_t::flush_reals(common::idp::updateGlobalBaseBalancer::request& bal for (const auto& [module_name, balancer] : generation_config.config_balancers) { - for (const auto& [service_id, virtual_ip, proto, virtual_port, version, scheduler, scheduler_params, forwarding_method, flags, reals] : balancer.services) + for (const auto& [service_id, + virtual_ip, + proto, + virtual_port, + version, + scheduler, + scheduler_params, + forwarding_method, + flags, + ipv4_outer_source_network, + ipv6_outer_source_network, + reals] : balancer.services) { (void)flags; (void)scheduler; diff --git a/controlplane/configconverter.cpp b/controlplane/configconverter.cpp index 6bfb8c9d..a99cb16f 100644 --- a/controlplane/configconverter.cpp +++ b/controlplane/configconverter.cpp @@ -587,7 +587,18 @@ void config_converter_t::processBalancer() balancer.source_ipv4, balancer.flow}); - for (const auto& [service_id, vip, proto, vport, version, scheduler, scheduler_params, forwarding_method, flags, reals] : balancer.services) + for (const auto& [service_id, + vip, + proto, + vport, + version, + scheduler, + scheduler_params, + forwarding_method, + flags, + ipv4_outer_source_network, + ipv6_outer_source_network, + reals] : balancer.services) { /// @todo: (void)vip; @@ -599,6 +610,8 @@ void config_converter_t::processBalancer() (void)reals; (void)version; (void)forwarding_method; + (void)ipv4_outer_source_network; + (void)ipv6_outer_source_network; if (service_id >= YANET_CONFIG_BALANCER_SERVICES_SIZE) { @@ -1132,13 +1145,13 @@ void config_converter_t::acl_rules_nat64stateless_ingress(controlplane::base::ac /* @todo { - controlplane::base::acl_rule_transport_icmpv6_t rule_transport{range_t{0x00, 0xFF}, - range_t{0x00, 0xFF}, - ingressPortRange}; - acl.nextModuleRules.emplace_back(rule_network, - fragState::firstFragment, - rule_transport, - flow_fragmentation); + controlplane::base::acl_rule_transport_icmpv6_t rule_transport{range_t{0x00, 0xFF}, + range_t{0x00, 0xFF}, + ingressPortRange}; + acl.nextModuleRules.emplace_back(rule_network, + fragState::firstFragment, + rule_transport, + flow_fragmentation); } */ @@ -1390,13 +1403,13 @@ void config_converter_t::acl_rules_nat64stateless_egress(controlplane::base::acl /* @todo { - controlplane::base::acl_rule_transport_icmpv4_t rule_transport{range_t{0x00, 0xFF}, - range_t{0x00, 0xFF}, - egressPortRange}; - acl.nextModuleRules.emplace_back(rule_network, - fragState::firstFragment, - rule_transport, - flow_fragmentation); + controlplane::base::acl_rule_transport_icmpv4_t rule_transport{range_t{0x00, 0xFF}, + range_t{0x00, 0xFF}, + egressPortRange}; + acl.nextModuleRules.emplace_back(rule_network, + fragState::firstFragment, + rule_transport, + flow_fragmentation); } */ @@ -1470,13 +1483,26 @@ void config_converter_t::acl_rules_balancer(controlplane::base::acl_t& acl, auto flow = convertToFlow(nextModule); auto flow_fragment = convertToFlow(nextModule, "fragment"); ///< actually drop - for (const auto& [service_id, vip, proto, vport, version, scheduler, scheduler_params, forwarding_method, flags, reals] : balancer.services) + for (const auto& [service_id, + vip, + proto, + vport, + version, + scheduler, + scheduler_params, + forwarding_method, + flags, + ipv4_outer_source_network, + ipv6_outer_source_network, + reals] : balancer.services) { (void)scheduler; (void)scheduler_params; (void)version; (void)flags; (void)forwarding_method; + (void)ipv4_outer_source_network; + (void)ipv6_outer_source_network; if (reals.empty()) { @@ -1551,7 +1577,18 @@ void config_converter_t::acl_rules_balancer_icmp_reply(controlplane::base::acl_t auto flow = convertToFlow(nextModule, "icmp_reply"); - for (const auto& [service_id, vip, proto, vport, version, scheduler, scheduler_params, forwarding_method, flags, reals] : balancer.services) + for (const auto& [service_id, + vip, + proto, + vport, + version, + scheduler, + scheduler_params, + forwarding_method, + flags, + ipv4_outer_source_network, + ipv6_outer_source_network, + reals] : balancer.services) { (void)scheduler; (void)scheduler_params; @@ -1560,6 +1597,8 @@ void config_converter_t::acl_rules_balancer_icmp_reply(controlplane::base::acl_t (void)vport; (void)version; (void)forwarding_method; + (void)ipv4_outer_source_network; + (void)ipv6_outer_source_network; if (reals.empty()) { @@ -1607,7 +1646,18 @@ void config_converter_t::acl_rules_balancer_icmp_forward(controlplane::base::acl ranges_t icmpv6_forward_types(values_t({ICMP6_DST_UNREACH, ICMP6_TIME_EXCEEDED, ICMP6_PARAM_PROB, ICMP6_PACKET_TOO_BIG})); controlplane::base::acl_rule_transport_icmpv6_t rule_icmpv6_forward(icmpv6_forward_types); - for (const auto& [service_id, vip, proto, vport, version, scheduler, scheduler_params, forwarding_method, flags, reals] : balancer.services) + for (const auto& [service_id, + vip, + proto, + vport, + version, + scheduler, + scheduler_params, + forwarding_method, + flags, + ipv4_outer_source_network, + ipv6_outer_source_network, + reals] : balancer.services) { (void)scheduler; (void)scheduler_params; @@ -1616,6 +1666,8 @@ void config_converter_t::acl_rules_balancer_icmp_forward(controlplane::base::acl (void)vport; (void)version; (void)forwarding_method; + (void)ipv4_outer_source_network; + (void)ipv6_outer_source_network; if (reals.empty()) { diff --git a/controlplane/configparser.cpp b/controlplane/configparser.cpp index 920418b1..8dbc7d79 100644 --- a/controlplane/configparser.cpp +++ b/controlplane/configparser.cpp @@ -1553,6 +1553,11 @@ void config_parser_t::loadConfig_balancer_services(controlplane::base_t& baseNex std::optional service_version = exist(service_json, "version") ? std::make_optional(service_json["version"].get()) : std::nullopt; + std::optional ipv4_outer_source_network = + exist(service_json, "ipv4_outer_source_network") ? std::make_optional(service_json["ipv4_outer_source_network"].get()) : std::nullopt; + std::optional ipv6_outer_source_network = + exist(service_json, "ipv6_outer_source_network") ? std::make_optional(service_json["ipv6_outer_source_network"].get()) : std::nullopt; + std::string scheduler_string = service_json["scheduler"]; balancer::scheduler scheduler; @@ -1653,6 +1658,8 @@ void config_parser_t::loadConfig_balancer_services(controlplane::base_t& baseNex scheduler_params, forwarding_method, flags, + ipv4_outer_source_network, + ipv6_outer_source_network, reals); baseNext.services_count++; diff --git a/dataplane/globalbase.cpp b/dataplane/globalbase.cpp index af61823c..fe7657b0 100644 --- a/dataplane/globalbase.cpp +++ b/dataplane/globalbase.cpp @@ -325,16 +325,16 @@ eResult generation::get(const common::idp::getGlobalBase::request& request, /** @todo for (const auto& interfaceId : std::get<2>(request)) { - if (interfaceId >= CONFIG_YADECAP_INTERFACES_SIZE) - { - YADECAP_LOG_ERROR("invalid interfaceId: '%u'\n", interfaceId); - return eResult::invalidInterfaceId; - } + if (interfaceId >= CONFIG_YADECAP_INTERFACES_SIZE) + { + YADECAP_LOG_ERROR("invalid interfaceId: '%u'\n", interfaceId); + return eResult::invalidInterfaceId; + } - const auto& interface = interfaces[interfaceId]; + const auto& interface = interfaces[interfaceId]; - std::get<2>(globalBaseResponse)[interfaceId] = {convert(interface.neighborEtherAddress), - interface.flow}; + std::get<2>(globalBaseResponse)[interfaceId] = {convert(interface.neighborEtherAddress), + interface.flow}; } */ @@ -1181,7 +1181,16 @@ eResult generation::update_balancer_services(const common::idp::updateGlobalBase } balancer_services_count = 0; - for (const auto& [balancer_service_id, flags, counter_id, scheduler, forwarding_method, default_wlc_power, real_start, real_size] : services) + for (const auto& [balancer_service_id, + flags, + counter_id, + scheduler, + forwarding_method, + default_wlc_power, + real_start, + real_size, + ipv4_outer_source_network, + ipv6_outer_source_network] : services) { if (balancer_service_id >= YANET_CONFIG_BALANCER_SERVICES_SIZE) { @@ -1203,6 +1212,20 @@ eResult generation::update_balancer_services(const common::idp::updateGlobalBase return eResult::invalidCount; } + dataplane::globalBase::ipv4_prefix_t ipv4_prefix; + if (ipv4_outer_source_network) + { + ipv4_prefix.set = 1; + ipv4_prefix.prefix = ipv4_outer_source_network.value(); + } + + dataplane::globalBase::ipv6_prefix_t ipv6_prefix; + if (ipv6_outer_source_network) + { + ipv6_prefix.set = 1; + ipv6_prefix.prefix = ipv6_outer_source_network.value(); + } + balancer_active_services[balancer_services_count++] = balancer_service_id; auto& balancer_service = balancer_services[balancer_service_id]; @@ -1213,6 +1236,8 @@ eResult generation::update_balancer_services(const common::idp::updateGlobalBase balancer_service.scheduler = scheduler; balancer_service.wlc_power = default_wlc_power; balancer_service.forwarding_method = forwarding_method; + balancer_service.ipv4_outer_source_network = ipv4_prefix; + balancer_service.ipv6_outer_source_network = ipv6_prefix; } const auto& reals = std::get<1>(request); diff --git a/dataplane/type.h b/dataplane/type.h index 376b5cb8..5a12153e 100644 --- a/dataplane/type.h +++ b/dataplane/type.h @@ -556,6 +556,26 @@ struct balancer_service_ring_t static_assert(YANET_CONFIG_COUNTERS_SIZE <= 0xFFFFFF, "invalid size"); +struct ipv4_prefix_t +{ + ipv4_prefix_t() : + set(0) + {} + + uint8_t set; + common::ipv4_prefix_t prefix; +}; + +struct ipv6_prefix_t +{ + ipv6_prefix_t() : + set(0) + {} + + uint8_t set; + common::ipv6_prefix_t prefix; +}; + struct balancer_service_t { /// @todo @@ -576,6 +596,8 @@ struct balancer_service_t ::balancer::scheduler scheduler; ::balancer::forwarding_method forwarding_method; uint32_t wlc_power; + ipv4_prefix_t ipv4_outer_source_network; + ipv6_prefix_t ipv6_outer_source_network; }; static_assert(YANET_CONFIG_BALANCER_REALS_SIZE <= 0xFFFFFFFF, "invalid YANET_CONFIG_BALANCER_REALS_SIZE"); diff --git a/dataplane/worker.cpp b/dataplane/worker.cpp index a0a0d05b..257218bb 100644 --- a/dataplane/worker.cpp +++ b/dataplane/worker.cpp @@ -3881,16 +3881,15 @@ inline void cWorker::balancer_tunnel(rte_mbuf* mbuf, rte_ipv6_hdr* ipv6Header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv6_hdr*, metadata->network_headerOffset); + set_ipv6_source(ipv6Header, balancer.source_ipv6, service.ipv6_outer_source_network, ipv4HeaderInner, ipv6HeaderInner); + rte_memcpy(ipv6Header->dst_addr, real.destination.bytes, 16); + if (ipv4HeaderInner) { ipv6Header->vtc_flow = rte_cpu_to_be_32((0x6 << 28) | (ipv4HeaderInner->type_of_service << 20)); ///< @todo: flow label ipv6Header->payload_len = ipv4HeaderInner->total_length; ipv6Header->proto = IPPROTO_IPIP; ipv6Header->hop_limits = ipv4HeaderInner->time_to_live; - - rte_memcpy(ipv6Header->src_addr, balancer.source_ipv6.bytes, 16); - ((uint32_t*)ipv6Header->src_addr)[2] = ipv4HeaderInner->src_addr; - rte_memcpy(ipv6Header->dst_addr, real.destination.bytes, 16); } else { @@ -3898,10 +3897,6 @@ inline void cWorker::balancer_tunnel(rte_mbuf* mbuf, ipv6Header->payload_len = rte_cpu_to_be_16(sizeof(rte_ipv6_hdr) + rte_be_to_cpu_16(ipv6HeaderInner->payload_len)); ipv6Header->proto = IPPROTO_IPV6; ipv6Header->hop_limits = ipv6HeaderInner->hop_limits; - - rte_memcpy(ipv6Header->src_addr, balancer.source_ipv6.bytes, 16); - ((uint32_t*)ipv6Header->src_addr)[2] = ((uint32_t*)ipv6HeaderInner->src_addr)[2] ^ ((uint32_t*)ipv6HeaderInner->src_addr)[3]; - rte_memcpy(ipv6Header->dst_addr, real.destination.bytes, 16); } } else // IPV4 @@ -3941,7 +3936,7 @@ inline void cWorker::balancer_tunnel(rte_mbuf* mbuf, ipv4Header->next_proto_id = IPPROTO_IPV6; } - ipv4Header->src_addr = balancer.source_ipv4.address; + set_ipv4_source(ipv4Header, balancer.source_ipv4, service.ipv4_outer_source_network); ipv4Header->dst_addr = real.destination.mapped_ipv4_address.address; yanet_ipv4_checksum(ipv4Header); @@ -3998,6 +3993,69 @@ inline void cWorker::balancer_tunnel(rte_mbuf* mbuf, preparePacket(mbuf); } +/// Sets the IPv6 source address for the packet, taking into account the address set for the service. +/// In order to optimize the distribution of packets across the queues of the NIC installed on the servers +/// to which the packet will be sent, the source address is (if possible) randomized taking into account the mask. +inline void cWorker::set_ipv6_source(rte_ipv6_hdr* header, + const ipv6_address_t& balancer_src, + const dataplane::globalBase::ipv6_prefix_t& service_src, + const rte_ipv4_hdr* ipv4HeaderInner, + const rte_ipv6_hdr* ipv6HeaderInner) +{ + uint32_t rndm; + if (ipv4HeaderInner) + { + rndm = ipv4HeaderInner->src_addr; + } + else + { + rndm = ((uint32_t*)ipv6HeaderInner->src_addr)[2] ^ ((uint32_t*)ipv6HeaderInner->src_addr)[3]; + } + + if (!service_src.set) + { + rte_memcpy(header->src_addr, balancer_src.bytes, 16); + ((uint32_t*)header->src_addr)[2] = rndm; + return; + } + + rte_memcpy(header->src_addr, service_src.prefix.address().data(), 16); + + uint8_t mask = service_src.prefix.mask(); + if (mask <= 4 * 16) /// 64 + { + ((uint32_t*)header->src_addr)[2] = rndm; + ((uint32_t*)header->src_addr)[3] = ((uint32_t*)balancer_src.bytes)[3]; + } + else if (mask <= 5 * 16) /// 80 + { + ((uint16_t*)header->src_addr)[5] = static_cast((rndm >> 16) & 0xFFFF); + ((uint16_t*)header->src_addr)[6] = static_cast(rndm & 0xFFFF); + ((uint16_t*)header->src_addr)[7] = ((uint16_t*)balancer_src.bytes)[7]; + } + else if (mask <= 6 * 16) /// 96 + { + ((uint32_t*)header->src_addr)[3] = rndm; + } + else if (mask <= 7 * 16) /// 112 + { + ((uint16_t*)header->src_addr)[7] = static_cast((rndm >> 16) & 0xFFFF) ^ static_cast(rndm & 0xFFFF); + } +} + +/// Sets the IPv4 source address for the packet, taking into account the address set for the service. +inline void cWorker::set_ipv4_source(rte_ipv4_hdr* header, + const ipv4_address_t& balancer_src, + const dataplane::globalBase::ipv4_prefix_t& service_src) +{ + if (!service_src.set) + { + header->src_addr = balancer_src.address; + return; + } + header->src_addr = rte_cpu_to_be_32(service_src.prefix.address()); +} + inline void cWorker::balancer_flow(rte_mbuf* mbuf, const common::globalBase::tFlow& flow) { diff --git a/dataplane/worker.h b/dataplane/worker.h index 55dd889f..256fd440 100644 --- a/dataplane/worker.h +++ b/dataplane/worker.h @@ -157,6 +157,9 @@ class cWorker inline void balancer_icmp_reply_handle(); inline void balancer_icmp_forward_handle(); + inline void set_ipv6_source(rte_ipv6_hdr* header, const ipv6_address_t& balancer_src, const dataplane::globalBase::ipv6_prefix_t& service_src, const rte_ipv4_hdr* ipv4HeaderInner, const rte_ipv6_hdr* ipv6HeaderInner); + inline void set_ipv4_source(rte_ipv4_hdr* header, const ipv4_address_t& balancer_src, const dataplane::globalBase::ipv4_prefix_t& service_src); + /// fw state inline bool acl_try_keepstate(rte_mbuf* mbuf); inline bool acl_try_keepstate(rte_mbuf* mbuf, dataplane::globalBase::fw_state_value_t* value, dataplane::spinlock_nonrecursive_t* locker);