From e2456957f7be7d80d638dd5732c46ee6e7ad5b5a Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Thu, 21 Sep 2023 14:23:47 +0300 Subject: [PATCH] Introducing GRE tunneling support Currently YANET only supports the IPIP tunneling scheme for packet delivery to service backends. However, there is no native support for IPIP encapsulation on Windows platform we want to support services on, so we had to implement GRE tunnelling protocol. This commit allows one to configure a tunneling mode, whether IPIP or GRE, for each service inside balancer configuration using lvs_method option set to TUN (for IPIP) or GRE respectively. Commited by Steve Balayan (https://github.com/SteveBalayanAKAMedian) --- .../065_balancer_gre/001-expect.pcap | Bin 0 -> 496 bytes .../065_balancer_gre/001-send.pcap | Bin 0 -> 320 bytes .../065_balancer_gre/002-expect.pcap | Bin 0 -> 416 bytes .../065_balancer_gre/002-send.pcap | Bin 0 -> 320 bytes .../065_balancer_gre/003-expect.pcap | Bin 0 -> 576 bytes .../065_balancer_gre/003-send.pcap | Bin 0 -> 400 bytes .../065_balancer_gre/004-expect.pcap | Bin 0 -> 496 bytes .../065_balancer_gre/004-send.pcap | Bin 0 -> 400 bytes .../065_balancer_gre/autotest.yaml | 31 +++++++ .../065_balancer_gre/controlplane.conf | 49 +++++++++++ .../001_one_port/065_balancer_gre/gen.py | 80 ++++++++++++++++++ .../065_balancer_gre/services.conf | 54 ++++++++++++ common/balancer.h | 31 +++++++ common/controlplaneconfig.h | 2 + common/idp.h | 2 + controlplane/src/balancer.cpp | 16 ++-- controlplane/src/configconverter.cpp | 12 ++- controlplane/src/configparser.cpp | 22 ++++- dataplane/src/globalbase.cpp | 10 ++- dataplane/src/type.h | 2 + dataplane/src/worker.cpp | 53 +++++++++++- dataplane/src/worker.h | 2 +- 22 files changed, 348 insertions(+), 18 deletions(-) create mode 100644 autotests/units/001_one_port/065_balancer_gre/001-expect.pcap create mode 100644 autotests/units/001_one_port/065_balancer_gre/001-send.pcap create mode 100644 autotests/units/001_one_port/065_balancer_gre/002-expect.pcap create mode 100644 autotests/units/001_one_port/065_balancer_gre/002-send.pcap create mode 100644 autotests/units/001_one_port/065_balancer_gre/003-expect.pcap create mode 100644 autotests/units/001_one_port/065_balancer_gre/003-send.pcap create mode 100644 autotests/units/001_one_port/065_balancer_gre/004-expect.pcap create mode 100644 autotests/units/001_one_port/065_balancer_gre/004-send.pcap create mode 100644 autotests/units/001_one_port/065_balancer_gre/autotest.yaml create mode 100644 autotests/units/001_one_port/065_balancer_gre/controlplane.conf create mode 100755 autotests/units/001_one_port/065_balancer_gre/gen.py create mode 100644 autotests/units/001_one_port/065_balancer_gre/services.conf create mode 100644 common/balancer.h diff --git a/autotests/units/001_one_port/065_balancer_gre/001-expect.pcap b/autotests/units/001_one_port/065_balancer_gre/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..102f9a359511daad9ee41533925c7e46ac09e6fb GIT binary patch literal 496 zcmca|c+)~A1{MYw`2U}Qff2?5(rHi(7Gh)&R5Er6ZDe3bX}g;M64KGPS72b31~C~K z!5SGAKpX@B8pgrk%D|ujl67FqKMPXF1ypVj!w>*d7Qm#y5Ml!3k!ULuP#>cLkU#?H zww?jn%7oQcV}ve}{K^c}$EW}#kN~=^r-8OIW3|-?p^GG2K@r8M03?tAx~->xwz6Qg I)sTS!01HnlEC2ui literal 0 HcmV?d00001 diff --git a/autotests/units/001_one_port/065_balancer_gre/001-send.pcap b/autotests/units/001_one_port/065_balancer_gre/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/autotests/units/001_one_port/065_balancer_gre/002-expect.pcap b/autotests/units/001_one_port/065_balancer_gre/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..1739f9571e3f8fdbe40687a95080b5fd8052ad07 GIT binary patch literal 416 zcmca|c+)~A1{MYw`2U}Qff2?5(m_xR7Gh)&R5Er6ZDe3b;b3rOU~m8_wb$S5m%_jx z2EcE!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/autotests/units/001_one_port/065_balancer_gre/003-expect.pcap b/autotests/units/001_one_port/065_balancer_gre/003-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..1dd0b9a82a9262fb718ab7328fff79df7452a8e7 GIT binary patch literal 576 zcmca|c+)~A1{MYw`2U}Qff2?5(p69l7Gh)&R5Er6ZDe3bX}g;M5^~VDS72b32FpS; zGAckh2r;Ny5jF<}CKO3V1;%@8_q~UUF&fNf2!Qbdm=qWqLt#7;T>`R)Q2|IG0id^V zx`c_KOF|GPkrXD(Kz)n~KmrNia|ts+mjokBBFQD7NM=+35=a1_OIQfHB#40l01se0 Ao&W#< literal 0 HcmV?d00001 diff --git a/autotests/units/001_one_port/065_balancer_gre/003-send.pcap b/autotests/units/001_one_port/065_balancer_gre/003-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..09078ce5e85b7668af116ccd59ca09a593ceef38 GIT binary patch literal 400 zcmca|c+)~A1{MYw`2U}Qff2?5(tc3PAgE;Q5(<`JYGhzI(RMch#1Ub0P+$U!!U#qM z#(Qh`y@zob7!77K1i*L!ObQH*5L3WHB%97e(DV?PU1YeOnV{*x6qwFJ(DWb%1^@^! BFnj<2 literal 0 HcmV?d00001 diff --git a/autotests/units/001_one_port/065_balancer_gre/004-expect.pcap b/autotests/units/001_one_port/065_balancer_gre/004-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..96c305a2e22f1c49bc3c4c5e39093e9481cb7a6a GIT binary patch literal 496 zcmca|c+)~A1{MYw`2U}Qff2?5(rHi(7Gh)&R5Er6ZDe3b;b3rOU 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/autotests/units/001_one_port/065_balancer_gre/controlplane.conf b/autotests/units/001_one_port/065_balancer_gre/controlplane.conf new file mode 100644 index 00000000..6c3ba52d --- /dev/null +++ b/autotests/units/001_one_port/065_balancer_gre/controlplane.conf @@ -0,0 +1,49 @@ +{ + "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", + "default_wlc_power": 10, + "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/autotests/units/001_one_port/065_balancer_gre/gen.py b/autotests/units/001_one_port/065_balancer_gre/gen.py new file mode 100755 index 00000000..11b4007e --- /dev/null +++ b/autotests/units/001_one_port/065_balancer_gre/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="2000:51b::0101:0001:0:1", hlim=63, fl=0, nh=0x2f)/GRE(proto=0x0800)/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="2000:51b::0101:0002:0:1", hlim=63, fl=0, nh=0x2f)/GRE(proto=0x0800)/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="2000:51b::0101:0003:0:1", hlim=63, fl=0, nh=0x2f)/GRE(proto=0x0800)/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="2000:51b::0101:0004:0:1", hlim=63, fl=0, nh=0x2f)/GRE(proto=0x0800)/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="100.0.0.22", ttl=63)/GRE(proto=0x0800)/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="100.0.0.22", ttl=63)/GRE(proto=0x0800)/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="100.0.0.22", ttl=63)/GRE(proto=0x0800)/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="100.0.0.22", ttl=63)/GRE(proto=0x0800)/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="2000:51b::0001:0:1", hlim=63, fl=0, nh=0x2f) / GRE(proto=0x86DD) / 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="2000:51b::0002:0:1", hlim=63, fl=0, nh=0x2f) / GRE(proto=0x86DD) / 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="2000:51b::0003:0:1", hlim=63, fl=0, nh=0x2f) / GRE(proto=0x86DD) / 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="2000:51b::0004:0:1", hlim=63, fl=0, nh=0x2f) / GRE(proto=0x86DD) / 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="100.0.0.22", ttl=63)/ GRE(proto=0x86DD) /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="100.0.0.22", ttl=63)/ GRE(proto=0x86DD) /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="100.0.0.22", ttl=63)/ GRE(proto=0x86DD) /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="100.0.0.22", ttl=63)/ GRE(proto=0x86DD) /IPv6(dst="2001:dead:beef::2", src="2002::13", hlim=64)/TCP(dport=80, sport=12380), +) diff --git a/autotests/units/001_one_port/065_balancer_gre/services.conf b/autotests/units/001_one_port/065_balancer_gre/services.conf new file mode 100644 index 00000000..d5f990a7 --- /dev/null +++ b/autotests/units/001_one_port/065_balancer_gre/services.conf @@ -0,0 +1,54 @@ +[ + { + "vip": "10.0.0.1", + "proto": "tcp", + "vport": "80", + "scheduler": "rr", + "lvs_method": "GRE", + "reals": [ + { + "ip": "2000::1", + "port": "80" + } + ] + }, + { + "vip": "10.0.0.42", + "proto": "tcp", + "vport": "80", + "scheduler": "rr", + "lvs_method": "GRE", + "reals": [ + { + "ip": "100.0.0.42", + "port": "80" + } + ] + }, + { + "vip": "2001:dead:beef::1", + "proto": "tcp", + "vport": "80", + "scheduler": "rr", + "lvs_method": "GRE", + "reals": [ + { + "ip": "2000::1", + "port": "80" + } + ] + }, + { + "vip": "2001:dead:beef::2", + "proto": "tcp", + "vport": "80", + "scheduler": "rr", + "lvs_method": "GRE", + "reals": [ + { + "ip": "100.0.0.6", + "port": "80" + } + ] + } +] diff --git a/common/balancer.h b/common/balancer.h new file mode 100644 index 00000000..9879e581 --- /dev/null +++ b/common/balancer.h @@ -0,0 +1,31 @@ +#pragma once + +#include "type.h" + +namespace balancer +{ + +enum class tunnel : uint8_t +{ + ipip, // in services.conf it means lvs_method: TUN + gre, +}; + +constexpr const char* to_string(const tunnel& tunnel) +{ + switch (tunnel) + { + case tunnel::ipip: + { + return "ipip"; + } + case tunnel::gre: + { + return "gre"; + } + } + + return "unknown"; +} + +} diff --git a/common/controlplaneconfig.h b/common/controlplaneconfig.h index f2bd01b0..b74c0173 100644 --- a/common/controlplaneconfig.h +++ b/common/controlplaneconfig.h @@ -4,6 +4,7 @@ #include "stream.h" #include "type.h" +#include "balancer.h" #include "scheduler.h" namespace controlplane @@ -308,6 +309,7 @@ using service_t = std::tuple, ///< version ::balancer::scheduler, ::balancer::scheduler_params, + ::balancer::tunnel, uint8_t, ///< flags: mss_fix|ops std::vector>; diff --git a/common/idp.h b/common/idp.h index 946cd850..d778b662 100644 --- a/common/idp.h +++ b/common/idp.h @@ -17,6 +17,7 @@ #include "scheduler.h" #include "type.h" #include "acl.h" +#include "balancer.h" namespace common::idp { @@ -259,6 +260,7 @@ namespace updateGlobalBase uint8_t, ///< flags tCounterId, ///< size 4 balancer::scheduler, + balancer::tunnel, // tunneling method (default ipip) uint32_t, /// default_wlc_power uint32_t, ///< real_start uint32_t>; ///< real_size diff --git a/controlplane/src/balancer.cpp b/controlplane/src/balancer.cpp index 3f13d683..3d988280 100644 --- a/controlplane/src/balancer.cpp +++ b/controlplane/src/balancer.cpp @@ -224,7 +224,7 @@ 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, flags, reals] : balancer.services) + for (const auto& [service_id, virtual_ip, proto, virtual_port, version, scheduler, scheduler_params, tunnel, flags, reals] : balancer.services) { (void)service_id; (void)version; @@ -232,6 +232,7 @@ void balancer_t::reload(const controlplane::base_t& base_prev, (void)scheduler_params; (void)reals; (void)flags; + (void)tunnel; service_counters.remove({module_name, {virtual_ip, proto, virtual_port}}); @@ -255,13 +256,14 @@ 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, flags, reals] : balancer.services) + for (const auto& [service_id, virtual_ip, proto, virtual_port, version, scheduler, scheduler_params, tunnel, flags, reals] : balancer.services) { (void)service_id; (void)version; (void)scheduler; (void)scheduler_params; (void)flags; + (void)tunnel; service_counters.insert({module_name, {virtual_ip, proto, virtual_port}}); @@ -600,10 +602,11 @@ 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, flags, reals] : balancer.services) + for (const auto& [service_id, virtual_ip, proto, virtual_port, version, scheduler, scheduler_params, tunnel, flags, reals] : balancer.services) { (void) flags; (void) scheduler_params; + (void) tunnel; if (service_id >= YANET_CONFIG_BALANCER_SERVICES_SIZE) { @@ -684,7 +687,7 @@ 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, flags, reals] : balancer.services) + for (const auto& [service_id, virtual_ip, proto, virtual_port, version, scheduler, scheduler_params, tunnel, flags, reals] : balancer.services) { (void) scheduler_params; (void) version; @@ -732,6 +735,7 @@ void balancer_t::compile(common::idp::updateGlobalBase::request& globalbase, flags, counter_ids[0], scheduler, + tunnel, 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)}); @@ -753,12 +757,14 @@ 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, flags, reals] : balancer.services) + for (const auto& [service_id, virtual_ip, proto, virtual_port, version, scheduler, scheduler_params, tunnel, flags, reals] : balancer.services) { (void)flags; (void)scheduler; (void)scheduler_params; (void)version; + (void)tunnel; + if (service_id >= YANET_CONFIG_BALANCER_SERVICES_SIZE) { continue; diff --git a/controlplane/src/configconverter.cpp b/controlplane/src/configconverter.cpp index 465ac6a0..755f8598 100644 --- a/controlplane/src/configconverter.cpp +++ b/controlplane/src/configconverter.cpp @@ -587,7 +587,7 @@ void config_converter_t::processBalancer() balancer.source_ipv4, balancer.flow}); - for (const auto& [service_id, vip, proto, vport, version, scheduler, scheduler_params, flags, reals] : balancer.services) + for (const auto& [service_id, vip, proto, vport, version, scheduler, scheduler_params, tunnel, flags, reals] : balancer.services) { /// @todo: (void)vip; @@ -598,6 +598,7 @@ void config_converter_t::processBalancer() (void)flags; (void)reals; (void)version; + (void)tunnel; if (service_id >= YANET_CONFIG_BALANCER_SERVICES_SIZE) { @@ -1471,12 +1472,13 @@ 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, flags, reals] : balancer.services) + for (const auto& [service_id, vip, proto, vport, version, scheduler, scheduler_params, tunnel, flags, reals] : balancer.services) { (void)scheduler; (void)scheduler_params; (void)version; (void)flags; + (void)tunnel; if (reals.empty()) { @@ -1551,7 +1553,7 @@ 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, flags, reals] : balancer.services) + for (const auto& [service_id, vip, proto, vport, version, scheduler, scheduler_params, tunnel, flags, reals] : balancer.services) { (void)scheduler; (void)scheduler_params; @@ -1559,6 +1561,7 @@ void config_converter_t::acl_rules_balancer_icmp_reply(controlplane::base::acl_t (void)proto; (void)vport; (void)version; + (void)tunnel; if (reals.empty()) { @@ -1606,7 +1609,7 @@ 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, flags, reals] : balancer.services) + for (const auto& [service_id, vip, proto, vport, version, scheduler, scheduler_params, tunnel, flags, reals] : balancer.services) { (void)scheduler; (void)scheduler_params; @@ -1614,6 +1617,7 @@ void config_converter_t::acl_rules_balancer_icmp_forward(controlplane::base::acl (void)proto; (void)vport; (void)version; + (void)tunnel; if (reals.empty()) { diff --git a/controlplane/src/configparser.cpp b/controlplane/src/configparser.cpp index 14c3c094..996b1299 100644 --- a/controlplane/src/configparser.cpp +++ b/controlplane/src/configparser.cpp @@ -1577,6 +1577,25 @@ void config_parser_t::loadConfig_balancer_services(controlplane::base_t& baseNex throw error_result_t(eResult::invalidConfigurationFile, "unknown scheduler: " + scheduler_string); } + balancer::tunnel tunnel; + + if (!exist(service_json, "lvs_method")) + { + tunnel = balancer::tunnel::ipip; + } + else + { + std::string tunnel_string = service_json["lvs_method"]; + if (tunnel_string == "TUN") + { + tunnel = balancer::tunnel::ipip; + } + else + { + tunnel = balancer::tunnel::gre; + } + } + std::vector reals; for (const auto& real_json : service_json["reals"]) { @@ -1631,7 +1650,8 @@ void config_parser_t::loadConfig_balancer_services(controlplane::base_t& baseNex service_version, scheduler, scheduler_params, - flags, + tunnel, + flags, reals); baseNext.services_count++; diff --git a/dataplane/src/globalbase.cpp b/dataplane/src/globalbase.cpp index de623354..cabc94db 100644 --- a/dataplane/src/globalbase.cpp +++ b/dataplane/src/globalbase.cpp @@ -1177,7 +1177,7 @@ eResult generation::update_balancer_services(const common::idp::updateGlobalBase } balancer_services_count = 0; - for (const auto& [balancer_service_id, flags, counter_id, scheduler, default_wlc_power, real_start, real_size] : services) + for (const auto& [balancer_service_id, flags, counter_id, scheduler, tunnel, default_wlc_power, real_start, real_size] : services) { if (balancer_service_id >= YANET_CONFIG_BALANCER_SERVICES_SIZE) { @@ -1208,6 +1208,7 @@ eResult generation::update_balancer_services(const common::idp::updateGlobalBase balancer_service.real_size = real_size; balancer_service.scheduler = scheduler; balancer_service.wlc_power = default_wlc_power; + balancer_service.tunnel = tunnel; } const auto& reals = std::get<1>(request); @@ -1257,9 +1258,11 @@ eResult generation::update_balancer_services(const common::idp::updateGlobalBase } real_unordered.destination = addr; real_unordered.counter_id = counter_id; - real_unordered.flags = 0; - real_unordered.flags |= destination.is_ipv6() ? YANET_BALANCER_FLAG_DST_IPV6 : 0; + if (destination.is_ipv6()) + { + real_unordered.flags |= YANET_BALANCER_FLAG_DST_IPV6; + } } const auto& binding = std::get<2>(request); @@ -1280,6 +1283,7 @@ eResult generation::update_balancer_services(const common::idp::updateGlobalBase } std::copy(binding.begin(), binding.end(), balancer_service_reals); + evaluate_service_ring(balancer_service_ring_id); return eResult::success; diff --git a/dataplane/src/type.h b/dataplane/src/type.h index 6f2d379a..e6f2446d 100644 --- a/dataplane/src/type.h +++ b/dataplane/src/type.h @@ -5,6 +5,7 @@ #include "common/type.h" #include "common/scheduler.h" +#include "common/balancer.h" #include "common/fallback.h" #include "common/config.h" @@ -573,6 +574,7 @@ namespace globalBase uint32_t real_start; uint32_t real_size; ::balancer::scheduler scheduler; + ::balancer::tunnel tunnel; uint32_t wlc_power; }; diff --git a/dataplane/src/worker.cpp b/dataplane/src/worker.cpp index 34030a16..e050b514 100644 --- a/dataplane/src/worker.cpp +++ b/dataplane/src/worker.cpp @@ -3718,7 +3718,7 @@ inline void cWorker::balancer_handle() value->timestamp_last_packet = basePermanently.globalBaseAtomic->currentTime; locker->unlock(); - balancer_tunnel(mbuf, real_unordered, real_unordered.counter_id); + balancer_tunnel(mbuf, service, real_unordered, real_unordered.counter_id); counters[(service.atomic1 >> 8) + (tCounterId)balancer::service_counter::packets]++; counters[(service.atomic1 >> 8) + (tCounterId)balancer::service_counter::bytes] += mbuf->pkt_len; @@ -3803,7 +3803,7 @@ inline void cWorker::balancer_handle() locker->unlock(); - balancer_tunnel(mbuf, real_unordered, real_unordered.counter_id); + balancer_tunnel(mbuf, service, real_unordered, real_unordered.counter_id); counters[(service.atomic1 >> 8) + (tCounterId)balancer::service_counter::packets]++; counters[(service.atomic1 >> 8) + (tCounterId)balancer::service_counter::bytes] += mbuf->pkt_len; balancer_flow(mbuf, balancer.flow); @@ -3817,6 +3817,7 @@ inline void cWorker::balancer_handle() } inline void cWorker::balancer_tunnel(rte_mbuf* mbuf, + const dataplane::globalBase::balancer_service_t& service, const dataplane::globalBase::balancer_real_t& real, const tCounterId& real_counter_id) { @@ -3875,7 +3876,7 @@ inline void cWorker::balancer_tunnel(rte_mbuf* mbuf, rte_memcpy(ipv6Header->dst_addr, real.destination.bytes, 16); } } - else + else // IPV4 { rte_pktmbuf_prepend(mbuf, sizeof(rte_ipv4_hdr)); rte_memcpy(rte_pktmbuf_mtod(mbuf, char*), @@ -3917,6 +3918,50 @@ inline void cWorker::balancer_tunnel(rte_mbuf* mbuf, yanet_ipv4_checksum(ipv4Header); } + if (service.tunnel == balancer::tunnel::gre) + { + // update data in ip headers and insert gre + rte_pktmbuf_prepend(mbuf, sizeof(rte_gre_hdr)); + + if (real.flags & YANET_BALANCER_FLAG_DST_IPV6) + { + metadata->transport_headerOffset = metadata->network_headerOffset + sizeof(rte_ipv6_hdr); + + memmove(rte_pktmbuf_mtod(mbuf, char*), + rte_pktmbuf_mtod_offset(mbuf, char*, sizeof(rte_gre_hdr)), + metadata->transport_headerOffset); + + rte_ipv6_hdr* ipv6_header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv6_hdr*, metadata->network_headerOffset); + ipv6_header->proto = IPPROTO_GRE; + ipv6_header->payload_len = rte_cpu_to_be_16(rte_be_to_cpu_16(ipv6_header->payload_len) + sizeof(rte_gre_hdr)); + } + else // ipv4 + { + metadata->transport_headerOffset = metadata->network_headerOffset + sizeof(rte_ipv4_hdr); + + memmove(rte_pktmbuf_mtod(mbuf, char*), + rte_pktmbuf_mtod_offset(mbuf, char*, sizeof(rte_gre_hdr)), + metadata->transport_headerOffset); + + rte_ipv4_hdr* ipv4_header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv4_hdr*, metadata->network_headerOffset); + ipv4_header->next_proto_id = IPPROTO_GRE; + ipv4_header->total_length = rte_cpu_to_be_16(rte_be_to_cpu_16(ipv4_header->total_length) + sizeof(rte_gre_hdr)); + + yanet_ipv4_checksum(ipv4_header); + } + // add gre data + rte_gre_hdr* gre_header = rte_pktmbuf_mtod_offset(mbuf, rte_gre_hdr*, metadata->transport_headerOffset); + memset(gre_header, 0, sizeof(rte_gre_hdr)); + gre_header->ver= 0; // default version + if (ipv4HeaderInner) + { + gre_header->proto = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4); + } + else + { + gre_header->proto = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6); + } + } counters[real_counter_id + (tCounterId)balancer::real_counter::packets]++; counters[real_counter_id + (tCounterId)balancer::real_counter::bytes] += mbuf->pkt_len; @@ -4218,7 +4263,7 @@ inline void cWorker::balancer_icmp_forward_handle() value->timestamp_last_packet = basePermanently.globalBaseAtomic->currentTime; locker->unlock(); - balancer_tunnel(mbuf, real_unordered, real_unordered.counter_id); + balancer_tunnel(mbuf, service, real_unordered, real_unordered.counter_id); counters[(service.atomic1 >> 8) + (tCounterId)balancer::service_counter::packets]++; counters[(service.atomic1 >> 8) + (tCounterId)balancer::service_counter::bytes] += mbuf->pkt_len; diff --git a/dataplane/src/worker.h b/dataplane/src/worker.h index 81e9fe93..b7669779 100644 --- a/dataplane/src/worker.h +++ b/dataplane/src/worker.h @@ -151,7 +151,7 @@ class cWorker inline void balancer_icmp_forward_entry(rte_mbuf* mbuf); inline void balancer_fragment_entry(rte_mbuf* mbuf); inline void balancer_handle(); - inline void balancer_tunnel(rte_mbuf* mbuf, const dataplane::globalBase::balancer_real_t& real, const tCounterId& real_counter_id); + inline void balancer_tunnel(rte_mbuf* mbuf, const dataplane::globalBase::balancer_service_t& service, const dataplane::globalBase::balancer_real_t& real, const tCounterId& real_counter_id); inline void balancer_flow(rte_mbuf* mbuf, const common::globalBase::tFlow& flow); inline void balancer_icmp_reply_handle(); inline void balancer_icmp_forward_handle();