diff --git a/autotest/autotest.cpp b/autotest/autotest.cpp index 5a3cef86..55928aeb 100644 --- a/autotest/autotest.cpp +++ b/autotest/autotest.cpp @@ -978,7 +978,7 @@ bool tAutotest::step_sleep(const YAML::Node& yamlStep) bool tAutotest::step_rib_insert(const YAML::Node& yaml) { - common::icp::rib_update::insert request = {"autotest", "default", YANET_RIB_PRIORITY_DEFAULT, {}}; + common::icp::rib_update::insert request = {"autotest", YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, {}}; auto& [protocol, vrf, priority, attribute_tables] = request; if (yaml["attribute"].IsDefined()) @@ -1094,7 +1094,7 @@ bool tAutotest::step_rib_insert(const YAML::Node& yaml) bool tAutotest::step_rib_remove(const YAML::Node& yaml) { - common::icp::rib_update::remove request = {"autotest", "default", YANET_RIB_PRIORITY_DEFAULT, {}}; + common::icp::rib_update::remove request = {"autotest", YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, {}}; auto& [protocol, vrf, priority, tables] = request; if (yaml["attribute"].IsDefined()) @@ -1523,7 +1523,7 @@ void tAutotest::convert_ipv4Update(const std::string& string) for (const auto& nexthop : utils::split(nexthops, ' ')) { - common::icp::rib_update::insert request = {"autotest", "default", YANET_RIB_PRIORITY_DEFAULT, {}}; + common::icp::rib_update::insert request = {"autotest", YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, {}}; std::get<3>(request)[attribute_default]["ipv4"][nexthop].emplace_back(prefix, std::to_string(pathInformations_ipv4Update[prefix].size()), std::vector()); @@ -1539,7 +1539,7 @@ void tAutotest::convert_ipv4Remove(const std::string& string) { for (const auto& pathInformation : pathInformations_ipv4Update[string]) { - common::icp::rib_update::remove request = {"autotest", "default", YANET_RIB_PRIORITY_DEFAULT, {}}; + common::icp::rib_update::remove request = {"autotest", YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, {}}; std::get<3>(request)[{}]["ipv4"].emplace_back(ip_prefix_t(string), pathInformation, std::vector()); @@ -1566,7 +1566,7 @@ void tAutotest::convert_ipv4LabelledUpdate(const std::string& string) std::vector labels; labels.emplace_back(std::stoll(label, nullptr, 0)); - common::icp::rib_update::insert request = {"autotest", "default", YANET_RIB_PRIORITY_DEFAULT, {}}; + common::icp::rib_update::insert request = {"autotest", YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, {}}; std::get<3>(request)[attribute_default]["ipv4 mpls"][nexthop].emplace_back(prefix, std::to_string(pathInformations_ipv4LabelledUpdate[prefix].size()) + ":10001", labels); @@ -1585,7 +1585,7 @@ void tAutotest::convert_ipv4LabelledRemove(const std::string& string) for (const auto& pathInformation : pathInformations_ipv4LabelledUpdate[string]) { - common::icp::rib_update::remove request = {"autotest", "default", YANET_RIB_PRIORITY_DEFAULT, {}}; + common::icp::rib_update::remove request = {"autotest", YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, {}}; std::get<3>(request)[{}]["ipv4 mpls"].emplace_back(ip_prefix_t(string), pathInformation, labels); @@ -1604,7 +1604,7 @@ void tAutotest::convert_ipv6Update(const std::string& string) for (const auto& nexthop : utils::split(nexthops, ' ')) { - common::icp::rib_update::insert request = {"autotest", "default", YANET_RIB_PRIORITY_DEFAULT, {}}; + common::icp::rib_update::insert request = {"autotest", YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, {}}; std::get<3>(request)[attribute_default]["ipv6"][nexthop].emplace_back(prefix, nexthop, std::vector()); @@ -1627,7 +1627,7 @@ void tAutotest::convert_ipv6LabelledUpdate(const std::string& string) std::vector labels; labels.emplace_back(std::stoll(label, nullptr, 0)); - common::icp::rib_update::insert request = {"autotest", "default", YANET_RIB_PRIORITY_DEFAULT, {}}; + common::icp::rib_update::insert request = {"autotest", YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, {}}; std::get<3>(request)[attribute_default]["ipv6 mpls"][nexthop].emplace_back(prefix, label + ":10001", ///< @todo: nexthop_label labels); diff --git a/autotest/units/001_one_port/078_vrf_route/001-expect.pcap b/autotest/units/001_one_port/078_vrf_route/001-expect.pcap new file mode 100644 index 00000000..140b2de7 Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route/001-expect.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route/001-send.pcap b/autotest/units/001_one_port/078_vrf_route/001-send.pcap new file mode 100644 index 00000000..75e60cdd Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route/001-send.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route/002-expect.pcap b/autotest/units/001_one_port/078_vrf_route/002-expect.pcap new file mode 100644 index 00000000..193d8e5b Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route/002-expect.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route/002-send.pcap b/autotest/units/001_one_port/078_vrf_route/002-send.pcap new file mode 100644 index 00000000..16f3b350 Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route/002-send.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route/003-expect.pcap b/autotest/units/001_one_port/078_vrf_route/003-expect.pcap new file mode 100644 index 00000000..b34d5000 Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route/003-expect.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route/003-send.pcap b/autotest/units/001_one_port/078_vrf_route/003-send.pcap new file mode 100644 index 00000000..75e60cdd Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route/003-send.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route/004-expect.pcap b/autotest/units/001_one_port/078_vrf_route/004-expect.pcap new file mode 100644 index 00000000..05774885 Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route/004-expect.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route/004-send.pcap b/autotest/units/001_one_port/078_vrf_route/004-send.pcap new file mode 100644 index 00000000..16f3b350 Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route/004-send.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route/autotest.yaml b/autotest/units/001_one_port/078_vrf_route/autotest.yaml new file mode 100644 index 00000000..513c6cc8 --- /dev/null +++ b/autotest/units/001_one_port/078_vrf_route/autotest.yaml @@ -0,0 +1,68 @@ +steps: +- cli: + - rib static insert default 0.0.0.0/0 200.0.10.1 + - rib static insert default 1.0.0.0/24 200.0.20.1 + - rib static insert default 2.0.0.0/24 200.0.40.1 + - rib static insert red 0.0.0.0/0 200.0.30.1 + - rib static insert red 1.0.0.0/24 200.0.10.1 + - rib static insert red 2.0.0.0/24 200.0.20.1 + - rib static insert white 1.0.0.0/24 200.0.40.1 + - rib static insert white 1.0.0.16/28 200.0.10.1 + - rib static insert white 1.0.0.16/30 200.0.20.1 +- cli: + - rib static insert default ::/0 c0de::10:1 + - rib static insert default 7e01::/64 c0de::20:1 + - rib static insert default 7e02::/64 c0de::40:1 + - rib static insert red ::/0 c0de::30:1 + - rib static insert red 7e01::/64 c0de::10:1 + - rib static insert red 7e02::/64 c0de::20:1 + - rib static insert white 7e01::/64 c0de::40:1 + - rib static insert white 7e01::/96 c0de::10:1 + - rib static insert white 7e01::/128 c0de::20:1 +- cli: + - rib prefixes + +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap + +- cli: + - rib static remove default 1.0.0.0/24 200.0.20.1 + - rib static remove red 0.0.0.0/0 200.0.30.1 + - rib static remove white 1.0.0.16/30 200.0.20.1 + - rib static remove default 7e01::/64 c0de::20:1 + - rib static remove red ::/0 c0de::30:1 + - rib static remove white 7e01::/128 c0de::20:1 +- cli: + - rib prefixes + +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap + +- cli: + - rib static remove default 0.0.0.0/0 200.0.10.1 + - rib static remove default 2.0.0.0/24 200.0.40.1 + - rib static remove red 1.0.0.0/24 200.0.10.1 + - rib static remove red 2.0.0.0/24 200.0.20.1 + - rib static remove white 1.0.0.0/24 200.0.40.1 + - rib static remove white 1.0.0.16/28 200.0.10.1 +- cli: + - rib static remove default ::/0 c0de::10:1 + - rib static remove default 7e02::/64 c0de::40:1 + - rib static remove red 7e01::/64 c0de::10:1 + - rib static remove red 7e02::/64 c0de::20:1 + - rib static remove white 7e01::/64 c0de::40:1 + - rib static remove white 7e01::/96 c0de::10:1 +- cli: + - rib prefixes diff --git a/autotest/units/001_one_port/078_vrf_route/controlplane.conf b/autotest/units/001_one_port/078_vrf_route/controlplane.conf new file mode 100644 index 00000000..4a8eb240 --- /dev/null +++ b/autotest/units/001_one_port/078_vrf_route/controlplane.conf @@ -0,0 +1,67 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "route0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "route0" + }, + "lp0.300": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "300", + "macAddress": "00:11:22:33:44:55", + "nextModule": "route0", + "vrf": "red" + }, + "lp0.400": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "400", + "macAddress": "00:11:22:33:44:55", + "nextModule": "route0", + "vrf": "white" + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv4Prefix": "200.0.10.0/24", + "neighborIPv4Address": "200.0.10.1", + "neighborIPv6Address": "c0de::10:1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.20.0/24", + "neighborIPv4Address": "200.0.20.1", + "neighborIPv6Address": "c0de::20:1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + }, + "kni0.300": { + "ipv4Prefix": "200.0.30.0/24", + "neighborIPv4Address": "200.0.30.1", + "neighborIPv6Address": "c0de::30:1", + "neighborMacAddress": "00:00:00:33:33:33", + "nextModule": "lp0.300" + }, + "kni0.400": { + "ipv4Prefix": "200.0.40.0/24", + "neighborIPv4Address": "200.0.40.1", + "neighborIPv6Address": "c0de::40:1", + "neighborMacAddress": "00:00:00:44:44:44", + "nextModule": "lp0.400" + } + } + } + } +} diff --git a/autotest/units/001_one_port/078_vrf_route/gen.py b/autotest/units/001_one_port/078_vrf_route/gen.py new file mode 100755 index 00000000..40f47d39 --- /dev/null +++ b/autotest/units/001_one_port/078_vrf_route/gen.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * +from scapy.contrib.mpls import MPLS + + +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) + +# IPv4 + +def write_pcap_ipv4(filename): + write_pcap(filename, + # vlan 100, 200 - default vrf + # + # 0.0.0.0/0 -> 200.0.10.1 + # 1.0.0.0/24 -> 200.0.20.1 ! only in 001 + # 2.0.0.0/24 -> 200.0.40.1 + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="2.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="3.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=200)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=200)/IP(dst="2.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=200)/IP(dst="3.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + + # vlan 300 - vrf "red" + # + # 0.0.0.0/0 -> 200.0.30.1 ! only in 001 + # 1.0.0.0/24 -> 200.0.10.1 + # 2.0.0.0/24 -> 200.0.20.1 + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=300)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=300)/IP(dst="2.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=300)/IP(dst="3.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + + # vlan 400 - vrf "white" + # + # 1.0.0.0/24 -> 200.0.40.1 + # 1.0.0.16/28 -> 200.0.10.1 ! only in 001 + # 1.0.0.16/30 -> 200.0.20.2 + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=400)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=400)/IP(dst="1.0.0.17", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=400)/IP(dst="1.0.0.21", src="222.222.222.222", ttl=64)/TCP(), + # no route for these 2 packets: + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=400)/IP(dst="2.0.0.1", src="222.222.222.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=400)/IP(dst="3.0.0.1", src="222.222.222.222", ttl=64)/TCP()) + +write_pcap_ipv4("001-send.pcap") +write_pcap("001-expect.pcap", + # vlan 100, 200 - default vrf + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IP(dst="2.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="3.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IP(dst="2.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="3.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + + # vlan 300 - vrf "red" + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="2.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:33:33:33", src="00:11:22:33:44:55")/Dot1Q(vlan=300)/IP(dst="3.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + + # vlan 400 - vrf "white" + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="1.0.0.17", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="1.0.0.21", src="222.222.222.222", ttl=63)/TCP()) + +write_pcap_ipv4("003-send.pcap") +write_pcap("003-expect.pcap", + # vlan 100, 200 - default vrf + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IP(dst="2.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="3.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IP(dst="2.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="3.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + + # vlan 300 - vrf "red" + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="2.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + + # vlan 400 - vrf "white" + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IP(dst="1.0.0.1", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="1.0.0.17", src="222.222.222.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="1.0.0.21", src="222.222.222.222", ttl=63)/TCP()) + +# IPv6 + +def write_pcap_ipv6(filename): + write_pcap(filename, + # vlan 100, 200 - default vrf + # + # ::/0 -> c0de::10:1 + # 7e01::/64 -> c0de::20:1 ! only in 001 + # 7e02::/64 -> c0de::40:1 + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IPv6(dst="7e01::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IPv6(dst="7e02::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IPv6(dst="7e03::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=200)/IPv6(dst="7e01::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=200)/IPv6(dst="7e02::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=200)/IPv6(dst="7e03::1", src="2222::2222")/TCP(), + + # vlan 300 - vrf "red" + # + # ::/0 -> c0de::30:1 ! only in 001 + # 7e01::/64 -> c0de::10:1 + # 7e02::/64 -> c0de::20:1 + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=300)/IPv6(dst="7e01::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=300)/IPv6(dst="7e02::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=300)/IPv6(dst="7e03::1", src="2222::2222")/TCP(), + + # vlan 400 - vrf "white" + # + # 7e01::/64 -> c0de::40:1 + # 7e01::/96 -> c0de::10:1 + # 7e01::/128 -> c0de::20:1 ! only in 001 + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=400)/IPv6(dst="7e01:0::1:0:0:1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=400)/IPv6(dst="7e01::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=400)/IPv6(dst="7e01::0", src="2222::2222")/TCP(), + # no route for these 2 packets: + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=400)/IPv6(dst="7e02::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=400)/IPv6(dst="7e03::1", src="2222::2222")/TCP()) + +write_pcap_ipv6("002-send.pcap") +write_pcap("002-expect.pcap", + # vlan 100, 200 - default vrf + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IPv6(dst="7e02::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e03::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IPv6(dst="7e02::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e03::1", src="2222::2222", hlim=63)/TCP(), + + # vlan 300 - vrf "red" + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IPv6(dst="7e02::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:33:33:33", src="00:11:22:33:44:55")/Dot1Q(vlan=300)/IPv6(dst="7e03::1", src="2222::2222", hlim=63)/TCP(), + + # vlan 400 - vrf "white" + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IPv6(dst="7e01:0::1:0:0:1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IPv6(dst="7e01::0", src="2222::2222", hlim=63)/TCP()) + +write_pcap_ipv6("004-send.pcap") +write_pcap("004-expect.pcap", + # vlan 100, 200 - default vrf + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IPv6(dst="7e02::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e03::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IPv6(dst="7e02::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e03::1", src="2222::2222", hlim=63)/TCP(), + + # vlan 300 - vrf "red" + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IPv6(dst="7e02::1", src="2222::2222", hlim=63)/TCP(), + + # vlan 400 - vrf "white" + Ether(dst="00:00:00:44:44:44", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/IPv6(dst="7e01:0::1:0:0:1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="7e01::0", src="2222::2222", hlim=63)/TCP()) diff --git a/autotest/units/001_one_port/078_vrf_route_nat64stateful/001-expect.pcap b/autotest/units/001_one_port/078_vrf_route_nat64stateful/001-expect.pcap new file mode 100644 index 00000000..b0de9d1d Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route_nat64stateful/001-expect.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route_nat64stateful/001-send.pcap b/autotest/units/001_one_port/078_vrf_route_nat64stateful/001-send.pcap new file mode 100644 index 00000000..5246ebc6 Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route_nat64stateful/001-send.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route_nat64stateful/002-expect.pcap b/autotest/units/001_one_port/078_vrf_route_nat64stateful/002-expect.pcap new file mode 100644 index 00000000..76766fff Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route_nat64stateful/002-expect.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route_nat64stateful/002-send.pcap b/autotest/units/001_one_port/078_vrf_route_nat64stateful/002-send.pcap new file mode 100644 index 00000000..9aad3bcc Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route_nat64stateful/002-send.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route_nat64stateful/003-expect.pcap b/autotest/units/001_one_port/078_vrf_route_nat64stateful/003-expect.pcap new file mode 100644 index 00000000..456db472 Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route_nat64stateful/003-expect.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route_nat64stateful/003-send.pcap b/autotest/units/001_one_port/078_vrf_route_nat64stateful/003-send.pcap new file mode 100644 index 00000000..6431f2f2 Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route_nat64stateful/003-send.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route_nat64stateful/autotest.yaml b/autotest/units/001_one_port/078_vrf_route_nat64stateful/autotest.yaml new file mode 100644 index 00000000..8d36b34c --- /dev/null +++ b/autotest/units/001_one_port/078_vrf_route_nat64stateful/autotest.yaml @@ -0,0 +1,23 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- cli: + - rib static insert red 0.0.0.0/0 200.0.0.1 + - rib static insert blue 0.0.0.0/0 200.0.0.1 + - rib static insert white ::/0 fe80::1 + - rib static insert green ::/0 fe80::1 + - rib prefixes +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- cli: + - counter interface_lookupMisses diff --git a/autotest/units/001_one_port/078_vrf_route_nat64stateful/controlplane.conf b/autotest/units/001_one_port/078_vrf_route_nat64stateful/controlplane.conf new file mode 100644 index 00000000..142a75b0 --- /dev/null +++ b/autotest/units/001_one_port/078_vrf_route_nat64stateful/controlplane.conf @@ -0,0 +1,82 @@ +{ + "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": [ + "nat0", + "nat1", + "nat2" + ] + }, + "nat0": { + "type": "nat64stateful", + "ipv6_prefixes": [ + "2000:9999::/96" + ], + "ipv4_prefixes": [ + "122.122.122.122" + ], + "dscpMarkType": "never", + "nextModule": "vrf0" + }, + "nat1": { + "type": "nat64stateful", + "ipv6_prefixes": [ + "2000:2345::/96" + ], + "ipv4_prefixes": [ + "122.122.154.0/24" + ], + "vrfLan": "red", + "vrfWan": "white", + "dscpMarkType": "onlyDefault", + "dscp": 10, + "nextModule": "vrf0" + }, + "nat2": { + "type": "nat64stateful", + "ipv6_prefixes": [ + "2000:abcd::/96" + ], + "ipv4_prefixes": [ + "122.122.155.0/25" + ], + "vrfLan": "blue", + "vrfWan": "green", + "dscpMarkType": "always", + "dscp": 20, + "nextModule": "vrf0" + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/078_vrf_route_nat64stateful/gen.py b/autotest/units/001_one_port/078_vrf_route_nat64stateful/gen.py new file mode 100755 index 00000000..13a4f646 --- /dev/null +++ b/autotest/units/001_one_port/078_vrf_route_nat64stateful/gen.py @@ -0,0 +1,78 @@ +#!/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) + + +# check lan (ipv6 -> ipv4). create state, check source ip +write_pcap("001-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x4, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x80, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xfc, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xff, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x4, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x80, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xfc, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xff, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x4, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0x80, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xfc, hlim=64)/TCP(dport=443, sport=2048), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::102.124.0.0/120", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", tc=0xff, hlim=64)/TCP(dport=443, sport=2048)) + +write_pcap("001-expect.pcap", + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.122.122", ttl=63, id=0, tos=0)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.122.122", ttl=63, id=0, tos=0x4)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.122.122", ttl=63, id=0, tos=0x80)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.122.122", ttl=63, id=0, tos=0xfc)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.122.122", ttl=63, id=0, tos=0xff)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.154.171", ttl=63, id=0, tos=0x28)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.154.171", ttl=63, id=0, tos=0x4)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.154.171", ttl=63, id=0, tos=0x80)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.154.171", ttl=63, id=0, tos=0xfc)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.154.171", ttl=63, id=0, tos=0xff)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.155.43", ttl=63, id=0, tos=0x50)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.155.43", ttl=63, id=0, tos=0x50)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.155.43", ttl=63, id=0, tos=0x50)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.155.43", ttl=63, id=0, tos=0x50)/TCP(dport=443, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="102.124.0.0/24", src="122.122.155.43", ttl=63, id=0, tos=0x53)/TCP(dport=443, sport=2048)) + + +# check wan (ipv4 -> ipv6) +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="122.122.122.122", src="102.124.0.0/24", ttl=64)/TCP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="122.122.154.171", src="102.124.0.0/24", ttl=64)/TCP(dport=2048, sport=443), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IP(dst="122.122.155.43", src="102.124.0.0/24", ttl=64)/TCP(dport=2048, sport=443)) + +write_pcap("002-expect.pcap", + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", src="2000:9999::102.124.0.0/120", hlim=63, fl=0)/TCP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", src="2000:2345::102.124.0.0/120", hlim=63, fl=0)/TCP(dport=2048, sport=443), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb", src="2000:abcd::102.124.0.0/120", hlim=63, fl=0)/TCP(dport=2048, sport=443)) + + +# check lan (ipv6 -> ipv4). create state, check source ip, check source port (1024 .. 65535) +write_pcap("003-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:9999::142.199.99.99", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb/118", tc=0x50, hlim=64)/TCP(dport=443, sport=4444), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:2345::142.199.99.99", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb/118", tc=0x50, hlim=64)/TCP(dport=443, sport=4444), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2000:abcd::142.199.99.99", src="bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb:bbbb/118", tc=0x50, hlim=64)/TCP(dport=443, sport=4444)) + +# 003-expect.pcap - dumped diff --git a/autotest/units/001_one_port/078_vrf_route_tunnel/001-expect.pcap b/autotest/units/001_one_port/078_vrf_route_tunnel/001-expect.pcap new file mode 100644 index 00000000..ba1e5c53 Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route_tunnel/001-expect.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route_tunnel/001-send.pcap b/autotest/units/001_one_port/078_vrf_route_tunnel/001-send.pcap new file mode 100644 index 00000000..2bc66de6 Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route_tunnel/001-send.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route_tunnel/002-expect.pcap b/autotest/units/001_one_port/078_vrf_route_tunnel/002-expect.pcap new file mode 100644 index 00000000..6c4a04af Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route_tunnel/002-expect.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route_tunnel/002-send.pcap b/autotest/units/001_one_port/078_vrf_route_tunnel/002-send.pcap new file mode 100644 index 00000000..8c67797b Binary files /dev/null and b/autotest/units/001_one_port/078_vrf_route_tunnel/002-send.pcap differ diff --git a/autotest/units/001_one_port/078_vrf_route_tunnel/autotest.yaml b/autotest/units/001_one_port/078_vrf_route_tunnel/autotest.yaml new file mode 100644 index 00000000..0c129dce --- /dev/null +++ b/autotest/units/001_one_port/078_vrf_route_tunnel/autotest.yaml @@ -0,0 +1,159 @@ +steps: +- rib_insert: + attribute: + protocol: autotest + vrf: default + tables: + - table_name: ipv4 mpls-vpn + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 88.88.88.1 + prefix: 1.0.0.0/24 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 88.88.88.2 + prefix: 2.0.0.0/24 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - nexthop: 88.88.88.3 + prefix: 3.0.0.0/24 + path_information: 88.88.88.3:10001 + labels: + - 1300 +- rib_insert: + attribute: + protocol: autotest + vrf: red + tables: + - table_name: ipv4 mpls-vpn + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 88.88.88.2 + prefix: 1.0.0.0/24 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - nexthop: 88.88.88.3 + prefix: 2.0.0.0/24 + path_information: 88.88.88.3:10001 + labels: + - 1300 + - nexthop: 88.88.88.1 + prefix: 3.0.0.0/24 + path_information: 88.88.88.1:10001 + labels: + - 1100 +- rib_insert: + attribute: + protocol: autotest + vrf: white + tables: + - table_name: ipv4 mpls-vpn + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 88.88.88.3 + prefix: 1.0.0.0/24 + path_information: 88.88.88.3:10001 + labels: + - 1300 + - nexthop: 88.88.88.1 + prefix: 2.0.0.0/24 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 88.88.88.2 + prefix: 3.0.0.0/24 + path_information: 88.88.88.1:10001 + labels: + - 1200 +- rib_insert: + attribute: + protocol: autotest + vrf: default + tables: + - table_name: ipv6 mpls-vpn + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 8888::1 + prefix: 7e01::/16 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 8888::2 + prefix: 7e02::/16 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - nexthop: 8888::3 + prefix: 7e03::/16 + path_information: 88.88.88.3:10001 + labels: + - 1300 +- rib_insert: + attribute: + protocol: autotest + vrf: red + tables: + - table_name: ipv6 mpls-vpn + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 8888::2 + prefix: 7e01::/16 + path_information: 88.88.88.3:10001 + labels: + - 1200 + - nexthop: 8888::3 + prefix: 7e02::/16 + path_information: 88.88.88.3:10001 + labels: + - 1300 + - nexthop: 8888::1 + prefix: 7e03::/16 + path_information: 88.88.88.1:10001 + labels: + - 1100 +- rib_insert: + attribute: + protocol: autotest + vrf: white + tables: + - table_name: ipv6 mpls-vpn + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 8888::3 + prefix: 7e01::/16 + path_information: 88.88.88.3:10001 + labels: + - 1300 + - nexthop: 8888::1 + prefix: 7e02::/16 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 8888::2 + prefix: 7e03::/16 + path_information: 88.88.88.2:10001 + labels: + - 1200 +- cli: + - rib prefixes +- ipv4Update: + - "0.0.0.0/0 -> 100.0.0.1" +- ipv6Update: + - "::/0 -> c0de::100:1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap diff --git a/autotest/units/001_one_port/078_vrf_route_tunnel/controlplane.conf b/autotest/units/001_one_port/078_vrf_route_tunnel/controlplane.conf new file mode 100644 index 00000000..66ac6ba7 --- /dev/null +++ b/autotest/units/001_one_port/078_vrf_route_tunnel/controlplane.conf @@ -0,0 +1,61 @@ +{ + "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", + "vrf": "red", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.300": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "300", + "vrf": "white", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "decap0" + ] + }, + "decap0": { + "type": "decap", + "ipv6DestinationPrefixes": [ + "2222::cccc/128" + ], + "ipv6_enabled": true, + "nextModule": "route0:tunnel" + }, + "route0": { + "type": "route", + "ipv4SourceAddress": "10.50.0.1", + "ipv6SourceAddress": "c0de::1", + "udpDestinationPort": 6635, + "interfaces": { + "kni0.100": { + "ipv4Prefix": "100.0.0.0/24", + "neighborIPv4Address": "100.0.0.1", + "neighborIPv6Address": "c0de::100:1", + "neighborMacAddress": "00:00:00:00:00:02", + "nextModule": "lp0.100" + } + }, + "peers": { + "1": "A", + "2": "B", + "3": "C" + } + } + } +} diff --git a/autotest/units/001_one_port/078_vrf_route_tunnel/gen.py b/autotest/units/001_one_port/078_vrf_route_tunnel/gen.py new file mode 100755 index 00000000..c6d81059 --- /dev/null +++ b/autotest/units/001_one_port/078_vrf_route_tunnel/gen.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * +from scapy.contrib.mpls import MPLS + + +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) + +# IPv4 + +write_pcap("001-send.pcap", + # vlan 100 - default vrf + # + # 1.0.0.0/24 -> 88.88.88.1 + # 2.0.0.0/24 -> 88.88.88.2 + # 3.0.0.0/24 -> 88.88.88.3 + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1")/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1")/IP(dst="2.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1")/IP(dst="3.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + + # vlan 200 - red vrf + # + # 1.0.0.0/24 -> 88.88.88.2 + # 2.0.0.0/24 -> 88.88.88.3 + # 3.0.0.0/24 -> 88.88.88.1 + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=200)/IPv6(dst="2222::cccc", src="::1")/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=200)/IPv6(dst="2222::cccc", src="::1")/IP(dst="2.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=200)/IPv6(dst="2222::cccc", src="::1")/IP(dst="3.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + + # vlan 300 - white vrf + # + # 1.0.0.0/24 -> 88.88.88.3 + # 2.0.0.0/24 -> 88.88.88.1 + # 3.0.0.0/24 -> 88.88.88.2 + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=300)/IPv6(dst="2222::cccc", src="::1")/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=300)/IPv6(dst="2222::cccc", src="::1")/IP(dst="2.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=300)/IPv6(dst="2222::cccc", src="::1")/IP(dst="3.0.0.1", src="0.0.0.0", ttl=64)/ICMP()) + +write_pcap("001-expect.pcap", + # vlan 100 - default vrf + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1")/UDP(dport=6635, sport=0xaa6c | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.2", src="10.50.0.1")/UDP(dport=6635, sport=0x1072 | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="2.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.3", src="10.50.0.1")/UDP(dport=6635, sport=0x2bd7 | 0xc000, chksum=0)/MPLS(label=1300, ttl=255)/IP(dst="3.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + + # vlan 200 - red vrf + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.2", src="10.50.0.1")/UDP(dport=6635, sport=0xaa6c | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.3", src="10.50.0.1")/UDP(dport=6635, sport=0x1072 | 0xc000, chksum=0)/MPLS(label=1300, ttl=255)/IP(dst="2.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1")/UDP(dport=6635, sport=0x2bd7 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="3.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + + # vlan 300 - white vrf + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.3", src="10.50.0.1")/UDP(dport=6635, sport=0xaa6c | 0xc000, chksum=0)/MPLS(label=1300, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1")/UDP(dport=6635, sport=0x1072 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="2.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.2", src="10.50.0.1")/UDP(dport=6635, sport=0x2bd7 | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="3.0.0.1", src="0.0.0.0", ttl=63)/ICMP()) + +# IPv6 + +write_pcap("002-send.pcap", + # vlan 100 - default vrf + # + # 7e01::/64 -> 8888::1 + # 7e02::/64 -> 8888::2 + # 7e03::/64 -> 8888::3 + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1")/IPv6(dst="7e01::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1")/IPv6(dst="7e02::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1")/IPv6(dst="7e03::1", src="2222::2222")/TCP(), + + # vlan 100 - red vrf + # + # 7e01::/64 -> 8888::2 + # 7e02::/64 -> 8888::3 + # 7e03::/64 -> 8888::1 + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=200)/IPv6(dst="2222::cccc", src="::1")/IPv6(dst="7e01::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=200)/IPv6(dst="2222::cccc", src="::1")/IPv6(dst="7e02::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=200)/IPv6(dst="2222::cccc", src="::1")/IPv6(dst="7e03::1", src="2222::2222")/TCP(), + + # vlan 100 - white vrf + # + # 7e01::/64 -> 8888::3 + # 7e02::/64 -> 8888::1 + # 7e03::/64 -> 8888::2 + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=300)/IPv6(dst="2222::cccc", src="::1")/IPv6(dst="7e01::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=300)/IPv6(dst="2222::cccc", src="::1")/IPv6(dst="7e02::1", src="2222::2222")/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=300)/IPv6(dst="2222::cccc", src="::1")/IPv6(dst="7e03::1", src="2222::2222")/TCP()) + + +write_pcap("002-expect.pcap", + # vlan 100 - default vrf + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="8888::1", src="c0de::1")/UDP(dport=6635, sport=0x1f99 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="8888::2", src="c0de::1")/UDP(dport=6635, sport=0x0fd1 | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IPv6(dst="7e02::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="8888::3", src="c0de::1")/UDP(dport=6635, sport=0x3fe9 | 0xc000, chksum=0)/MPLS(label=1300, ttl=255)/IPv6(dst="7e03::1", src="2222::2222", hlim=63)/TCP(), + + # vlan 100 - red vrf + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="8888::2", src="c0de::1")/UDP(dport=6635, sport=0x1f99 | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="8888::3", src="c0de::1")/UDP(dport=6635, sport=0x0fd1 | 0xc000, chksum=0)/MPLS(label=1300, ttl=255)/IPv6(dst="7e02::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="8888::1", src="c0de::1")/UDP(dport=6635, sport=0x3fe9 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IPv6(dst="7e03::1", src="2222::2222", hlim=63)/TCP(), + + # vlan 100 - white vrf + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="8888::3", src="c0de::1")/UDP(dport=6635, sport=0x1f99 | 0xc000, chksum=0)/MPLS(label=1300, ttl=255)/IPv6(dst="7e01::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="8888::1", src="c0de::1")/UDP(dport=6635, sport=0x0fd1 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IPv6(dst="7e02::1", src="2222::2222", hlim=63)/TCP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="8888::2", src="c0de::1")/UDP(dport=6635, sport=0x3fe9 | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IPv6(dst="7e03::1", src="2222::2222", hlim=63)/TCP()) diff --git a/cli/show.h b/cli/show.h index 41eafde2..52125323 100644 --- a/cli/show.h +++ b/cli/show.h @@ -80,6 +80,7 @@ inline void logicalPort() table.insert_row("moduleName", "physicalPortName", "vlanId", + "vrf", "macAddress", "promiscuousMode"); @@ -89,7 +90,8 @@ inline void logicalPort() std::get<0>(logicalPort), std::get<1>(logicalPort), std::get<2>(logicalPort), - std::get<3>(logicalPort) ? "true" : "false"); + std::get<3>(logicalPort), + std::get<4>(logicalPort) ? "true" : "false"); } table.Print(); diff --git a/common/controlplaneconfig.h b/common/controlplaneconfig.h index da9a6d4d..9eaeb664 100644 --- a/common/controlplaneconfig.h +++ b/common/controlplaneconfig.h @@ -107,7 +107,11 @@ class interface_t class config_t { public: - config_t() = default; + config_t() : + vrf(YANET_RIB_VRF_DEFAULT), + tunnel_enabled(false) + { + } /** @todo: tag:CP_MODULES void load(const nlohmann::json& json); @@ -289,7 +293,7 @@ class config_t public: config_t() = default; - SERIALIZABLE(nat64stateful_id, dscp_mark_type, dscp, ipv6_prefixes, ipv4_prefixes, announces, next_module); + SERIALIZABLE(nat64stateful_id, dscp_mark_type, dscp, ipv6_prefixes, ipv4_prefixes, announces, next_module, vrf_lan_name, vrf_wan_name, vrf_lan, vrf_wan); public: nat64stateful_id_t nat64stateful_id; @@ -298,6 +302,10 @@ class config_t std::vector ipv6_prefixes; std::vector ipv4_prefixes; std::set announces; + std::string vrf_lan_name; + std::string vrf_wan_name; + tVrfId vrf_lan; + tVrfId vrf_wan; controlplane::state_timeout state_timeout; std::string next_module; common::globalBase::flow_t flow; diff --git a/common/define.h b/common/define.h index 47cc5fd0..00bad545 100644 --- a/common/define.h +++ b/common/define.h @@ -118,6 +118,8 @@ extern LogPriority logPriority; #define YANET_RIB_PRIORITY_DEFAULT ((uint32_t)10000) #define YANET_RIB_PRIORITY_ROUTE_TUNNEL_FALLBACK ((uint32_t)11000) #define YANET_RIB_PRIORITY_ROUTE_REPEAT ((uint32_t)12000) +#define YANET_RIB_VRF_DEFAULT "default" +#define YANET_RIB_VRF_MAX_NUMBER 64 #define YANET_NETWORK_FLAG_FRAGMENT ((uint8_t)(1u << 0)) #define YANET_NETWORK_FLAG_NOT_FIRST_FRAGMENT ((uint8_t)(1u << 1)) diff --git a/common/icp.h b/common/icp.h index d5103a29..5786d5ce 100644 --- a/common/icp.h +++ b/common/icp.h @@ -357,6 +357,7 @@ namespace getLogicalPorts using response = std::map>; ///< promiscuousMode } diff --git a/common/idp.h b/common/idp.h index 8719cd0d..e5637e4f 100644 --- a/common/idp.h +++ b/common/idp.h @@ -111,9 +111,10 @@ using remove = std::vector; using clear = std::tuple<>; -using request = std::vector>; +using request = std::vector>>; } namespace updateGlobalBase @@ -171,6 +172,7 @@ namespace updateLogicalPort using request = std::tuple, ///< etherAddress uint8_t, ///< promiscuous mode common::globalBase::tFlow>; @@ -228,7 +230,9 @@ using request = std::tuple; + common::globalBase::flow_t, + tVrfId, ///< vrf_lan + tVrfId>; ///< vrf_wan } namespace nat64stateful_pool_update @@ -265,7 +269,9 @@ using request = std::tuple; + common::globalBase::flow_t, + tVrfId, ///< vrf_lan + tVrfId>; ///< vrf_wan } namespace update_balancer diff --git a/common/nat46clat.h b/common/nat46clat.h index 031aeaa5..5b261c73 100644 --- a/common/nat46clat.h +++ b/common/nat46clat.h @@ -19,7 +19,7 @@ class config public: config() = default; - SERIALIZABLE(nat46clat_id, ipv6_source, ipv6_destination, dscp_mark_type, dscp, ipv6_prefixes, ipv4_prefixes, announces, next_module); + SERIALIZABLE(nat46clat_id, ipv6_source, ipv6_destination, dscp_mark_type, dscp, ipv6_prefixes, ipv4_prefixes, announces, next_module, vrf_lan_name, vrf_wan_name, vrf_lan, vrf_wan); public: nat46clat_id_t nat46clat_id; @@ -30,6 +30,10 @@ class config std::set ipv6_prefixes; std::set ipv4_prefixes; std::set announces; + std::string vrf_lan_name; + std::string vrf_wan_name; + tVrfId vrf_lan; + tVrfId vrf_wan; std::string next_module; common::globalBase::flow_t flow; }; diff --git a/common/result.h b/common/result.h index e60719bc..edf9909a 100644 --- a/common/result.h +++ b/common/result.h @@ -39,6 +39,7 @@ enum class result_e : uint32_t invalidNexthop, invalidLogicalPortId, invalidVlanId, + invalidVrfId, invalidFlow, invalidDecapId, invalidInterfaceId, @@ -133,6 +134,8 @@ static constexpr const char* result_to_c_str(common::result_e e) return "invalidLogicalPortId"; case result_e::invalidVlanId: return "invalidVlanId"; + case result_e::invalidVrfId: + return "invalidVrfId"; case result_e::invalidFlow: return "invalidFlow"; case result_e::invalidDecapId: diff --git a/common/type.h b/common/type.h index 051ef803..ea510f97 100644 --- a/common/type.h +++ b/common/type.h @@ -42,6 +42,7 @@ using tun64_id_t = uint32_t; using coreId = uint32_t; using socketId = uint32_t; using counterId = uint32_t; +using tVrfId = uint16_t; namespace common { diff --git a/controlplane/base.h b/controlplane/base.h index 7f96a5e4..82cd3e3e 100644 --- a/controlplane/base.h +++ b/controlplane/base.h @@ -33,6 +33,8 @@ class logical_port_t uint8_t promiscuousMode{}; std::string nextModule; common::globalBase::tFlow flow; + std::string vrf; + tVrfId vrfId; }; class decap_t diff --git a/controlplane/configconverter.cpp b/controlplane/configconverter.cpp index 7062dcdb..fded13fc 100644 --- a/controlplane/configconverter.cpp +++ b/controlplane/configconverter.cpp @@ -358,6 +358,8 @@ void config_converter_t::processLogicalPorts() { throw error_result_t(eResult::invalidFlow, "invalid flow type for logical port: " + std::to_string(unsigned(logicalPort.flow.type))); } + + logicalPort.vrfId = controlplane_ptr->getVrfIdsStorage().GetOrCreateOrException(logicalPort.vrf, "Can't get id logicalPort.vrf: "); } } @@ -371,6 +373,7 @@ void config_converter_t::serializeLogicalPorts() common::idp::updateGlobalBase::updateLogicalPort::request{logicalPort.logicalPortId, logicalPort.physicalPortId, logicalPort.vlanId, + logicalPort.vrfId, logicalPort.macAddress, logicalPort.promiscuousMode, logicalPort.flow}); @@ -493,6 +496,9 @@ void config_converter_t::processNat64stateful() { throw error_result_t(eResult::invalidFlow, "invalid flow type for nat64stateful: " + std::string(eFlowType_toString(nat64stateful.flow.type))); } + + nat64stateful.vrf_lan = controlplane_ptr->getVrfIdsStorage().GetOrCreateOrException(nat64stateful.vrf_lan_name, "Can't get id nat64stateful.vrf_lan_name: "); + nat64stateful.vrf_wan = controlplane_ptr->getVrfIdsStorage().GetOrCreateOrException(nat64stateful.vrf_wan_name, "Can't get id nat64stateful.vrf_wan_name: "); } /// continue in nat64stateful_t::compile() @@ -601,6 +607,9 @@ void config_converter_t::processNat46clat() { throw error_result_t(eResult::invalidFlow, "invalid flow type for nat46clat: " + std::string(eFlowType_toString(nat46clat.flow.type))); } + + nat46clat.vrf_lan = controlplane_ptr->getVrfIdsStorage().GetOrCreateOrException(nat46clat.vrf_lan_name, "Can't get id nat46clat.vrf_lan_name: "); + nat46clat.vrf_wan = controlplane_ptr->getVrfIdsStorage().GetOrCreateOrException(nat46clat.vrf_wan_name, "Can't get id nat46clat.vrf_wan_name: "); } /// continue in nat46clat::manager::compile() diff --git a/controlplane/configconverter.h b/controlplane/configconverter.h index 7b5751d9..9b056d55 100644 --- a/controlplane/configconverter.h +++ b/controlplane/configconverter.h @@ -5,14 +5,15 @@ #include "base.h" #include "common/idp.h" #include "common/result.h" +#include "controlplane.h" class config_converter_t { public: - config_converter_t(cControlPlane* controlplane, + config_converter_t(cControlPlane* controlplane_ptr, controlplane::base_t baseNext, common::idp::limits::response limits) : - controlplane(controlplane), + controlplane_ptr(controlplane_ptr), baseNext(std::move(baseNext)), limits(std::move(limits)) { @@ -68,7 +69,7 @@ class config_converter_t void acl_rules_balancer_icmp_forward(controlplane::base::acl_t& acl, const std::string& nextModule) const; private: - cControlPlane* controlplane; + cControlPlane* controlplane_ptr; controlplane::base_t baseNext; common::idp::updateGlobalBase::request globalbase; diff --git a/controlplane/configparser.cpp b/controlplane/configparser.cpp index 92054e4c..692586fd 100644 --- a/controlplane/configparser.cpp +++ b/controlplane/configparser.cpp @@ -228,6 +228,8 @@ void config_parser_t::loadConfig_logicalPort(controlplane::base_t& baseNext, } } + logicalPort.vrf = moduleJson.value("vrf", YANET_RIB_VRF_DEFAULT); + logicalPort.nextModule = moduleJson.value("nextModule", ""); // @@ -294,10 +296,7 @@ void config_parser_t::loadConfig_route(controlplane::base_t& baseNext, } } - if (exist(moduleJson, "vrf")) - { - route.vrf = moduleJson["vrf"].get(); - } + route.vrf = moduleJson.value("vrf", YANET_RIB_VRF_DEFAULT); if (exist(moduleJson, "ignore_tables")) { @@ -581,6 +580,9 @@ void config_parser_t::loadConfig_nat64stateful(controlplane::base_t& baseNext, nat64stateful.state_timeout = moduleJson["state_timeout"]; } + nat64stateful.vrf_lan_name = moduleJson.value("vrfLan", YANET_RIB_VRF_DEFAULT); + nat64stateful.vrf_wan_name = moduleJson.value("vrfWan", YANET_RIB_VRF_DEFAULT); + nat64stateful.next_module = moduleJson.value("nextModule", ""); nat64stateful.nat64stateful_id = nat64stateful_id; @@ -1081,6 +1083,9 @@ void config_parser_t::loadConfig_nat46clat(controlplane::base_t& baseNext, } } + nat46clat.vrf_lan_name = moduleJson.value("vrfLan", YANET_RIB_VRF_DEFAULT); + nat46clat.vrf_wan_name = moduleJson.value("vrfWan", YANET_RIB_VRF_DEFAULT); + nat46clat.next_module = moduleJson.value("nextModule", ""); nat46clat.nat46clat_id = nat46clat_id; } diff --git a/controlplane/controlplane.cpp b/controlplane/controlplane.cpp index ae31b56d..942d8228 100644 --- a/controlplane/controlplane.cpp +++ b/controlplane/controlplane.cpp @@ -315,6 +315,7 @@ common::icp::getLogicalPorts::response cControlPlane::getLogicalPorts() const { response[logicalPortName] = {logicalPort.physicalPort, logicalPort.vlanId, + logicalPort.vrf, logicalPort.macAddress, logicalPort.promiscuousMode}; } @@ -1013,3 +1014,64 @@ std::vector cControlPlane::getAclCounters() return response; } + +VrfIdStorage& cControlPlane::getVrfIdsStorage() +{ + return vrfIds; +} + +std::optional VrfIdStorage::Get(const std::string& vrfName) +{ + if (vrfName.empty() || vrfName == YANET_RIB_VRF_DEFAULT) + { + return 0; + } + + std::shared_lock lock(mutex); + + auto iter = vrf_ids.find(vrfName); + if (iter != vrf_ids.end()) + { + return iter->second; + } + + return std::nullopt; +} + +std::optional VrfIdStorage::GetOrCreate(const std::string& vrfName) +{ + std::optional result = Get(vrfName); + if (result.has_value()) + { + return result; + } + + std::unique_lock lock(mutex); + + auto iter = vrf_ids.find(vrfName); + if (iter != vrf_ids.end()) + { + return iter->second; + } + + if (vrf_ids.size() + 1 >= YANET_RIB_VRF_MAX_NUMBER) + { + vrf_ids[vrfName] = std::nullopt; + YANET_LOG_ERROR("Error get id for vrf: '%s'. The number of different values has been exceeded: %d", vrfName.c_str(), YANET_RIB_VRF_MAX_NUMBER); + return std::nullopt; + } + + tVrfId new_id = vrf_ids.size() + 1; + vrf_ids[vrfName] = new_id; + return new_id; +} + +tVrfId VrfIdStorage::GetOrCreateOrException(const std::string& vrfName, const std::string& message) +{ + std::optional vrfId = GetOrCreate(vrfName); + if (!vrfId.has_value()) + { + throw error_result_t(eResult::invalidVrfId, message + vrfName); + } + return *vrfId; +} diff --git a/controlplane/controlplane.h b/controlplane/controlplane.h index 7f98d1a6..fff441b4 100644 --- a/controlplane/controlplane.h +++ b/controlplane/controlplane.h @@ -26,6 +26,18 @@ #include "tun64.h" #include "type.h" +class VrfIdStorage +{ +public: + std::optional Get(const std::string& vrfName); + std::optional GetOrCreate(const std::string& vrfName); + tVrfId GetOrCreateOrException(const std::string& vrfName, const std::string& message); + +private: + std::shared_mutex mutex; + std::unordered_map> vrf_ids; +}; + class cControlPlane { public: @@ -94,6 +106,7 @@ class cControlPlane } const common::sdp::DataPlaneInSharedMemory* getSdpData() const; + VrfIdStorage& getVrfIdsStorage(); protected: /** commands */ common::icp::getPhysicalPorts::response getPhysicalPorts() const; @@ -196,4 +209,6 @@ class cControlPlane void register_service(google::protobuf::Service* service); std::vector getAclCounters(); + + VrfIdStorage vrfIds; }; diff --git a/controlplane/nat46clat.cpp b/controlplane/nat46clat.cpp index cdbf0753..77dc8829 100644 --- a/controlplane/nat46clat.cpp +++ b/controlplane/nat46clat.cpp @@ -108,7 +108,9 @@ void manager::compile(common::idp::updateGlobalBase::request& globalbase, nat46clat.dscp_mark_type, nat46clat.dscp, counter_id, - nat46clat.flow)); + nat46clat.flow, + nat46clat.vrf_lan, + nat46clat.vrf_wan)); } } diff --git a/controlplane/nat64stateful.cpp b/controlplane/nat64stateful.cpp index f7f66d1a..5d9a031d 100644 --- a/controlplane/nat64stateful.cpp +++ b/controlplane/nat64stateful.cpp @@ -94,7 +94,9 @@ void nat64stateful_t::compile(common::idp::updateGlobalBase::request& globalbase pool_start, pool_size, nat64stateful.state_timeout, - nat64stateful.flow)); + nat64stateful.flow, + nat64stateful.vrf_lan, + nat64stateful.vrf_wan)); pool_start += pool_size; } diff --git a/controlplane/rib.cpp b/controlplane/rib.cpp index 2576a699..91972f4f 100644 --- a/controlplane/rib.cpp +++ b/controlplane/rib.cpp @@ -39,7 +39,7 @@ eResult rib_t::init() { /// @todo: move to config common::icp::rib_update::insert request_insert = {"static", - "default", + YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, {}}; @@ -49,7 +49,7 @@ eResult rib_t::init() prefixes.emplace_back("fe80::/64", "", std::vector()); common::icp::rib_update::eor request_eor = {"static", - "default", + YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, ip_address_t("::"), ""}; @@ -96,7 +96,7 @@ void rib_t::reload([[maybe_unused]] const controlplane::base_t& base_prev, if (base_next.rib.size()) { common::icp::rib_update::eor request_eor = {"config", - "default", + YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_DEFAULT, ip_address_t("::"), ""}; diff --git a/controlplane/route.cpp b/controlplane/route.cpp index 73e0380b..c3c7f7f0 100644 --- a/controlplane/route.cpp +++ b/controlplane/route.cpp @@ -25,7 +25,7 @@ eResult route_t::init() { common::idp::updateGlobalBase::request globalbase; globalbase.emplace_back(common::idp::updateGlobalBase::requestType::route_lpm_update, - common::idp::lpm::request({common::idp::lpm::clear()})); + common::idp::lpm::request({{0, common::idp::lpm::clear()}})); dataplane.updateGlobalBase(std::move(globalbase)); } @@ -93,27 +93,15 @@ void route_t::prefix_update(const std::tuple& vrf_priorit interface_destination_next; for (const auto& [pptn_index, path_info_to_nh_ptr] : *nexthops) { - const auto& table_name = std::get<2>(pptns[pptn_index]); - /// @todo: multi route. vrf - bool ignore = false; { + const auto& table_name = std::get<2>(pptns[pptn_index]); auto current_guard = generations.current_lock_guard(); - for (const auto& [name, module] : generations.current().routes) ///< @todo: DELETE + if (generations.current().is_ignored_table(table_name)) { - YANET_GCC_BUG_UNUSED(name); - - if (exist(module.ignore_tables, table_name)) - { - ignore = true; - break; - } + continue; } } - if (ignore) - { - continue; - } for (const auto& [path_info, nh_ptr] : path_info_to_nh_ptr) { @@ -900,12 +888,12 @@ void route_t::reload(const controlplane::base_t& base_prev, for (const auto& prefix : nat64stateless.nat64_prefixes) { - prefix_update({"default", YANET_RIB_PRIORITY_ROUTE_REPEAT}, + prefix_update({YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_ROUTE_REPEAT}, prefix.get_prefix(), {}, // TODO: get rid of third parameter std::monostate()); - tunnel_prefix_update({"default", YANET_RIB_PRIORITY_ROUTE_REPEAT}, + tunnel_prefix_update({YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_ROUTE_REPEAT}, prefix.get_prefix(), std::monostate()); } @@ -917,12 +905,12 @@ void route_t::reload(const controlplane::base_t& base_prev, for (const auto& prefix : nat64stateless.nat64_prefixes) { - prefix_update({"default", YANET_RIB_PRIORITY_ROUTE_REPEAT}, + prefix_update({YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_ROUTE_REPEAT}, prefix.get_prefix(), {}, // TODO: get rid of third parameter uint32_t(0)); ///< @todo: VIRTUAL_PORT - tunnel_prefix_update({"default", YANET_RIB_PRIORITY_ROUTE_REPEAT}, + tunnel_prefix_update({YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_ROUTE_REPEAT}, prefix.get_prefix(), uint32_t(0)); ///< @todo: VIRTUAL_PORT } @@ -934,7 +922,7 @@ void route_t::reload(const controlplane::base_t& base_prev, for (const auto& prefix : config_module.local_prefixes) { - tunnel_prefix_update({"default", YANET_RIB_PRIORITY_ROUTE_TUNNEL_FALLBACK}, + tunnel_prefix_update({YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_ROUTE_TUNNEL_FALLBACK}, prefix, std::monostate()); } @@ -946,7 +934,7 @@ void route_t::reload(const controlplane::base_t& base_prev, for (const auto& prefix : config_module.local_prefixes) { - tunnel_prefix_update({"default", YANET_RIB_PRIORITY_ROUTE_TUNNEL_FALLBACK}, + tunnel_prefix_update({YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_ROUTE_TUNNEL_FALLBACK}, prefix, std::tuple<>()); } @@ -964,7 +952,7 @@ void route_t::reload(const controlplane::base_t& base_prev, { if (!ip_prefix.is_host()) { - prefix_update({"default", YANET_RIB_PRIORITY_ROUTE_REPEAT}, + prefix_update({YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_ROUTE_REPEAT}, ip_prefix.applyMask(ip_prefix.mask()), {}, std::monostate()); @@ -986,7 +974,7 @@ void route_t::reload(const controlplane::base_t& base_prev, route::directly_connected_destination_t directly_connected = {interface.interfaceId, interface_name}; - prefix_update({"default", YANET_RIB_PRIORITY_ROUTE_REPEAT}, + prefix_update({YANET_RIB_VRF_DEFAULT, YANET_RIB_PRIORITY_ROUTE_REPEAT}, ip_prefix.applyMask(ip_prefix.mask()), {}, directly_connected); @@ -1027,7 +1015,12 @@ void route_t::prefix_flush_prefixes(common::idp::updateGlobalBase::request& glob for (auto& [vrf, priority_current_update] : prefixes) { - YANET_GCC_BUG_UNUSED(vrf); ///< @todo: VRF + std::optional vrfId = controlPlane->getVrfIdsStorage().GetOrCreate(vrf); + if (!vrfId.has_value()) + { + YANET_LOG_DEBUG("Can't get id for vrf: '%s'\n", vrf.c_str()); + continue; + } auto& [priority_current, update] = priority_current_update; @@ -1044,7 +1037,7 @@ void route_t::prefix_flush_prefixes(common::idp::updateGlobalBase::request& glob if (lpm_remove.size()) { - lpm_request.emplace_back(lpm_remove); + lpm_request.emplace_back(*vrfId, lpm_remove); } } @@ -1066,7 +1059,7 @@ void route_t::prefix_flush_prefixes(common::idp::updateGlobalBase::request& glob if (lpm_insert.size()) { - lpm_request.emplace_back(lpm_insert); + lpm_request.emplace_back(*vrfId, lpm_insert); } } } @@ -1093,7 +1086,12 @@ void route_t::tunnel_prefix_flush_prefixes(common::idp::updateGlobalBase::reques for (auto& [vrf, priority_current_update] : tunnel_prefixes) { - YANET_GCC_BUG_UNUSED(vrf); ///< @todo: VRF + std::optional vrfId = controlPlane->getVrfIdsStorage().GetOrCreate(vrf); + if (!vrfId.has_value()) + { + YANET_LOG_DEBUG("Can't get id for vrf: '%s'\n", vrf.c_str()); + continue; + } auto& [priority_current, update] = priority_current_update; @@ -1110,7 +1108,7 @@ void route_t::tunnel_prefix_flush_prefixes(common::idp::updateGlobalBase::reques if (lpm_remove.size()) { - lpm_request.emplace_back(lpm_remove); + lpm_request.emplace_back(*vrfId, lpm_remove); } } @@ -1132,7 +1130,7 @@ void route_t::tunnel_prefix_flush_prefixes(common::idp::updateGlobalBase::reques if (lpm_insert.size()) { - lpm_request.emplace_back(lpm_insert); + lpm_request.emplace_back(*vrfId, lpm_insert); } } } diff --git a/controlplane/route.h b/controlplane/route.h index 890bb7e9..368957c0 100644 --- a/controlplane/route.h +++ b/controlplane/route.h @@ -177,6 +177,19 @@ class generation_t } } + bool is_ignored_table(const std::string& table_name) const + { + for (const auto& [name, module] : routes) + { + YANET_GCC_BUG_UNUSED(name); + if (exist(module.ignore_tables, table_name)) + { + return true; + } + } + return false; + } + public: std::map routes; std::map> interface_by_neighbors; diff --git a/dataplane/controlplane.cpp b/dataplane/controlplane.cpp index 2165ac6f..6ae4d40f 100644 --- a/dataplane/controlplane.cpp +++ b/dataplane/controlplane.cpp @@ -810,6 +810,10 @@ common::idp::limits::response cControlPlane::limits() globalBase->updater.route_lpm6->limits(response); globalBase->updater.route_tunnel_lpm4->limits(response); globalBase->updater.route_tunnel_lpm6->limits(response); + globalBase->updater.vrf_route_lpm4->limits(response); + globalBase->updater.vrf_route_lpm6->limits(response); + globalBase->updater.vrf_route_tunnel_lpm4->limits(response); + globalBase->updater.vrf_route_tunnel_lpm6->limits(response); globalBase->updater.acl.network_table->limits(response); globalBase->updater.acl.transport_table->limits(response); diff --git a/dataplane/globalbase.cpp b/dataplane/globalbase.cpp index e199c004..d7a913fc 100644 --- a/dataplane/globalbase.cpp +++ b/dataplane/globalbase.cpp @@ -232,6 +232,58 @@ eResult generation::init() route_tunnel_lpm6 = updater.route_tunnel_lpm6->pointer(); } + { + updater.vrf_route_lpm4 = std::make_unique>("vrf_route.v4.lpm", + &dataPlane->memory_manager, + socketId); + result = updater.vrf_route_lpm4->init(); + if (result != eResult::success) + { + return result; + } + + vrf_route_lpm4.Update(updater.vrf_route_lpm4->GetLpms()); + } + + { + updater.vrf_route_lpm6 = std::make_unique, vrf_lpm6>>("vrf_route.v6.lpm", + &dataPlane->memory_manager, + socketId); + result = updater.vrf_route_lpm6->init(); + if (result != eResult::success) + { + return result; + } + + vrf_route_lpm6.Update(updater.vrf_route_lpm6->GetLpms()); + } + + { + updater.vrf_route_tunnel_lpm4 = std::make_unique>("vrf_route.tunnel.v4.lpm", + &dataPlane->memory_manager, + socketId); + result = updater.vrf_route_tunnel_lpm4->init(); + if (result != eResult::success) + { + return result; + } + + vrf_route_tunnel_lpm4.Update(updater.vrf_route_tunnel_lpm4->GetLpms()); + } + + { + updater.vrf_route_tunnel_lpm6 = std::make_unique, vrf_lpm6>>("vrf_route.tunnel.v6.lpm", + &dataPlane->memory_manager, + socketId); + result = updater.vrf_route_tunnel_lpm6->init(); + if (result != eResult::success) + { + return result; + } + + vrf_route_tunnel_lpm6.Update(updater.vrf_route_tunnel_lpm6->GetLpms()); + } + return result; } @@ -776,9 +828,10 @@ eResult generation::updateLogicalPort(const common::idp::updateGlobalBase::updat const auto& logicalPortId = std::get<0>(request); const auto& portId = std::get<1>(request); const auto& vlanId = std::get<2>(request); - const auto& etherAddress = std::get<3>(request); - const auto& promiscuousMode = std::get<4>(request); - const auto& flow = std::get<5>(request); + const auto& vrfId = std::get<3>(request); + const auto& etherAddress = std::get<4>(request); + const auto& promiscuousMode = std::get<5>(request); + const auto& flow = std::get<6>(request); if (logicalPortId >= CONFIG_YADECAP_LOGICALPORTS_SIZE) { @@ -795,6 +848,11 @@ eResult generation::updateLogicalPort(const common::idp::updateGlobalBase::updat YADECAP_LOG_ERROR("invalid vlanId: '%u'\n", vlanId); return eResult::invalidVlanId; } + if (vrfId >= YANET_RIB_VRF_MAX_NUMBER) + { + YADECAP_LOG_ERROR("invalid vrfId: '%u'\n", vrfId); + return eResult::invalidVrfId; + } if (flow.type != common::globalBase::eFlowType::acl_ingress && flow.type != common::globalBase::eFlowType::route && flow.type != common::globalBase::eFlowType::controlPlane && @@ -812,6 +870,7 @@ eResult generation::updateLogicalPort(const common::idp::updateGlobalBase::updat auto& logicalPort = logicalPorts[logicalPortId]; logicalPort.portId = portId; logicalPort.vlanId = rte_cpu_to_be_16(vlanId); + logicalPort.vrfId = vrfId; memcpy(logicalPort.etherAddress.addr_bytes, etherAddress.data(), 6); ///< @todo: convert logicalPort.flags = 0; @@ -1093,7 +1152,7 @@ eResult generation::updateInterface(const common::idp::updateGlobalBase::updateI eResult generation::nat64stateful_update(const common::idp::updateGlobalBase::nat64stateful_update::request& request) { - const auto& [nat64stateful_id, dscp_mark_type, dscp, counter_id, pool_start, pool_size, state_timeout, flow] = request; + const auto& [nat64stateful_id, dscp_mark_type, dscp, counter_id, pool_start, pool_size, state_timeout, flow, vrf_lan, vrf_wan] = request; if (nat64stateful_id >= YANET_CONFIG_NAT64STATEFULS_SIZE) { @@ -1168,6 +1227,9 @@ eResult generation::nat64stateful_update(const common::idp::updateGlobalBase::na nat64stateful.state_timeout.other = other; } + nat64stateful.vrf_lan = vrf_lan; + nat64stateful.vrf_wan = vrf_wan; + nat64stateful_enabled = 1; return eResult::success; @@ -1308,7 +1370,7 @@ eResult generation::updateNat64statelessTranslation(const common::idp::updateGlo eResult generation::nat46clat_update(const common::idp::updateGlobalBase::nat46clat_update::request& request) { - const auto& [nat46clat_id, ipv6_source, ipv6_destination, dscp_mark_type, dscp, counter_id, flow] = request; + const auto& [nat46clat_id, ipv6_source, ipv6_destination, dscp_mark_type, dscp, counter_id, flow, vrf_lan, vrf_wan] = request; if (nat46clat_id >= YANET_CONFIG_NAT46CLATS_SIZE) { @@ -1367,6 +1429,9 @@ eResult generation::nat46clat_update(const common::idp::updateGlobalBase::nat46c return eResult::invalidArguments; } + nat46clat.vrf_lan = vrf_lan; + nat46clat.vrf_wan = vrf_wan; + nat46clat_enabled = 1; return eResult::success; @@ -1698,7 +1763,7 @@ eResult generation::route_lpm_update(const common::idp::updateGlobalBase::route_ { eResult result = eResult::success; - for (const auto& action : request) + for (const auto& [vrfId, action] : request) { if (const auto update = std::get_if(&action)) { @@ -1706,15 +1771,35 @@ eResult generation::route_lpm_update(const common::idp::updateGlobalBase::route_ { if (prefix.is_ipv4()) { - result = updater.route_lpm4->insert(prefix.get_ipv4().address(), - prefix.get_ipv4().mask(), - value_id); + if (vrfId == 0) + { + result = updater.route_lpm4->insert(prefix.get_ipv4().address(), + prefix.get_ipv4().mask(), + value_id); + } + else + { + result = updater.vrf_route_lpm4->insert(vrfId, + prefix.get_ipv4().address(), + prefix.get_ipv4().mask(), + value_id); + } } else { - result = updater.route_lpm6->insert(prefix.get_ipv6().address(), - prefix.get_ipv6().mask(), - value_id); + if (vrfId == 0) + { + result = updater.route_lpm6->insert(prefix.get_ipv6().address(), + prefix.get_ipv6().mask(), + value_id); + } + else + { + result = updater.vrf_route_lpm6->insert(vrfId, + prefix.get_ipv6().address(), + prefix.get_ipv6().mask(), + value_id); + } } if (result != eResult::success) @@ -1729,13 +1814,31 @@ eResult generation::route_lpm_update(const common::idp::updateGlobalBase::route_ { if (prefix.is_ipv4()) { - result = updater.route_lpm4->remove(prefix.get_ipv4().address(), - prefix.get_ipv4().mask()); + if (vrfId == 0) + { + result = updater.route_lpm4->remove(prefix.get_ipv4().address(), + prefix.get_ipv4().mask()); + } + else + { + result = updater.vrf_route_lpm4->remove(vrfId, + prefix.get_ipv4().address(), + prefix.get_ipv4().mask()); + } } else { - result = updater.route_lpm6->remove(prefix.get_ipv6().address(), - prefix.get_ipv6().mask()); + if (vrfId == 0) + { + result = updater.route_lpm6->remove(prefix.get_ipv6().address(), + prefix.get_ipv6().mask()); + } + else + { + result = updater.vrf_route_lpm6->remove(vrfId, + prefix.get_ipv6().address(), + prefix.get_ipv6().mask()); + } } if (result != eResult::success) @@ -1751,6 +1854,9 @@ eResult generation::route_lpm_update(const common::idp::updateGlobalBase::route_ updater.route_lpm4->clear(); updater.route_lpm6->clear(); + updater.vrf_route_lpm4->clear(); + updater.vrf_route_lpm6->clear(); + return eResult::success; } } @@ -1758,6 +1864,9 @@ eResult generation::route_lpm_update(const common::idp::updateGlobalBase::route_ route_lpm4 = updater.route_lpm4->pointer(); route_lpm6 = updater.route_lpm6->pointer(); + vrf_route_lpm4.Update(updater.vrf_route_lpm4->GetLpms()); + vrf_route_lpm6.Update(updater.vrf_route_lpm6->GetLpms()); + return result; } @@ -1864,7 +1973,7 @@ eResult generation::route_tunnel_lpm_update(const common::idp::updateGlobalBase: { eResult result = eResult::success; - for (const auto& action : request) + for (const auto& [vrfId, action] : request) { if (const auto update = std::get_if(&action)) { @@ -1872,15 +1981,35 @@ eResult generation::route_tunnel_lpm_update(const common::idp::updateGlobalBase: { if (prefix.is_ipv4()) { - result = updater.route_tunnel_lpm4->insert(prefix.get_ipv4().address(), - prefix.get_ipv4().mask(), - value_id); + if (vrfId == 0) + { + result = updater.route_tunnel_lpm4->insert(prefix.get_ipv4().address(), + prefix.get_ipv4().mask(), + value_id); + } + else + { + result = updater.vrf_route_tunnel_lpm4->insert(vrfId, + prefix.get_ipv4().address(), + prefix.get_ipv4().mask(), + value_id); + } } else { - result = updater.route_tunnel_lpm6->insert(prefix.get_ipv6().address(), - prefix.get_ipv6().mask(), - value_id); + if (vrfId == 0) + { + result = updater.route_tunnel_lpm6->insert(prefix.get_ipv6().address(), + prefix.get_ipv6().mask(), + value_id); + } + else + { + result = updater.vrf_route_tunnel_lpm6->insert(vrfId, + prefix.get_ipv6().address(), + prefix.get_ipv6().mask(), + value_id); + } } if (result != eResult::success) @@ -1895,13 +2024,31 @@ eResult generation::route_tunnel_lpm_update(const common::idp::updateGlobalBase: { if (prefix.is_ipv4()) { - result = updater.route_tunnel_lpm4->remove(prefix.get_ipv4().address(), - prefix.get_ipv4().mask()); + if (vrfId == 0) + { + result = updater.route_tunnel_lpm4->remove(prefix.get_ipv4().address(), + prefix.get_ipv4().mask()); + } + else + { + result = updater.vrf_route_tunnel_lpm4->remove(vrfId, + prefix.get_ipv4().address(), + prefix.get_ipv4().mask()); + } } else { - result = updater.route_tunnel_lpm6->remove(prefix.get_ipv6().address(), - prefix.get_ipv6().mask()); + if (vrfId == 0) + { + result = updater.route_tunnel_lpm6->remove(prefix.get_ipv6().address(), + prefix.get_ipv6().mask()); + } + else + { + result = updater.vrf_route_tunnel_lpm6->remove(vrfId, + prefix.get_ipv6().address(), + prefix.get_ipv6().mask()); + } } if (result != eResult::success) @@ -1917,6 +2064,9 @@ eResult generation::route_tunnel_lpm_update(const common::idp::updateGlobalBase: updater.route_tunnel_lpm4->clear(); updater.route_tunnel_lpm6->clear(); + updater.vrf_route_tunnel_lpm4->clear(); + updater.vrf_route_tunnel_lpm6->clear(); + return eResult::success; } } @@ -1924,6 +2074,9 @@ eResult generation::route_tunnel_lpm_update(const common::idp::updateGlobalBase: route_tunnel_lpm4 = updater.route_tunnel_lpm4->pointer(); route_tunnel_lpm6 = updater.route_tunnel_lpm6->pointer(); + vrf_route_tunnel_lpm4.Update(updater.vrf_route_tunnel_lpm4->GetLpms()); + vrf_route_tunnel_lpm6.Update(updater.vrf_route_tunnel_lpm6->GetLpms()); + return result; } diff --git a/dataplane/globalbase.h b/dataplane/globalbase.h index fbb38538..5ea908bc 100644 --- a/dataplane/globalbase.h +++ b/dataplane/globalbase.h @@ -17,6 +17,7 @@ #include "lpm.h" #include "type.h" #include "updater.h" +#include "vrf.h" /// @todo: move #define YADECAP_GB_DSCP_FLAG_MARK ((uint8_t)1) @@ -133,6 +134,9 @@ class atomic class generation { public: + using vrf_lpm4 = lpm4_24bit_8bit_atomic; + using vrf_lpm6 = lpm6_8x16bit_atomic; + generation(cDataPlane* dataPlane, const tSocketId& socketId); ~generation() = default; @@ -213,6 +217,11 @@ class generation std::unique_ptr route_lpm6; std::unique_ptr route_tunnel_lpm4; std::unique_ptr route_tunnel_lpm6; + + std::unique_ptr> vrf_route_lpm4; + std::unique_ptr, vrf_lpm6>> vrf_route_lpm6; + std::unique_ptr> vrf_route_tunnel_lpm4; + std::unique_ptr, vrf_lpm6>> vrf_route_tunnel_lpm6; } updater; /// variables above are not needed for cWorker::mainThread() @@ -248,12 +257,16 @@ class generation lpm4_24bit_8bit_atomic* route_lpm4; lpm6_8x16bit_atomic* route_lpm6; + dataplane::vrflpm::VrfLookuper vrf_route_lpm4; + dataplane::vrflpm::VrfLookuper vrf_route_lpm6; route_value_t route_values[YANET_CONFIG_ROUTE_VALUES_SIZE]; YADECAP_CACHE_ALIGNED(align3); lpm4_24bit_8bit_atomic* route_tunnel_lpm4; lpm6_8x16bit_atomic* route_tunnel_lpm6; + dataplane::vrflpm::VrfLookuper vrf_route_tunnel_lpm4; + dataplane::vrflpm::VrfLookuper vrf_route_tunnel_lpm6; uint8_t route_tunnel_weights[YANET_CONFIG_ROUTE_TUNNEL_WEIGHTS_SIZE]; route_tunnel_value_t route_tunnel_values[YANET_CONFIG_ROUTE_TUNNEL_VALUES_SIZE]; ipv4_address_t nat64stateful_pool[YANET_CONFIG_NAT64STATEFUL_POOL_SIZE]; diff --git a/dataplane/metadata.h b/dataplane/metadata.h index 0cbaa1b2..24f13737 100644 --- a/dataplane/metadata.h +++ b/dataplane/metadata.h @@ -30,6 +30,7 @@ struct metadata uint32_t in_logicalport_id; uint32_t out_logicalport_id; common::globalBase::flow_t flow; + tVrfId vrfId; }; static_assert(sizeof(metadata) + sizeof(rte_ipv6_hdr) ///< encap diff --git a/dataplane/report.cpp b/dataplane/report.cpp index 3339c625..380de9b6 100644 --- a/dataplane/report.cpp +++ b/dataplane/report.cpp @@ -665,10 +665,15 @@ nlohmann::json cReport::convertGlobalBase(const dataplane::globalBase::generatio json["interfaces"].emplace_back(jsonInterface); } - globalBase->updater.route_lpm4->report(json); - globalBase->updater.route_lpm6->report(json); - globalBase->updater.route_tunnel_lpm4->report(json); - globalBase->updater.route_tunnel_lpm6->report(json); + globalBase->updater.route_lpm4->report(json["route_lpm4"]); + globalBase->updater.route_lpm6->report(json["route_lpm6"]); + globalBase->updater.route_tunnel_lpm4->report(json["route_tunnel_lpm4"]); + globalBase->updater.route_tunnel_lpm6->report(json["route_tunnel_lpm6"]); + + globalBase->updater.vrf_route_lpm4->report(json["vrf_route_lpm4"]); + globalBase->updater.vrf_route_lpm6->report(json["vrf_route_lpm6"]); + globalBase->updater.vrf_route_tunnel_lpm4->report(json["vrf_route_tunnel_lpm4"]); + globalBase->updater.vrf_route_tunnel_lpm6->report(json["vrf_route_tunnel_lpm6"]); globalBase->updater.acl.network_table->report(json["acl"]["network_table"]); globalBase->updater.acl.transport_table->report(json["acl"]["transport_table"]); diff --git a/dataplane/type.h b/dataplane/type.h index cf55b213..6365586f 100644 --- a/dataplane/type.h +++ b/dataplane/type.h @@ -259,6 +259,7 @@ struct tLogicalPort tPortId portId; uint16_t vlanId; ///< big endian + tVrfId vrfId; rte_ether_addr etherAddress; uint8_t flags; common::globalBase::tFlow flow; @@ -315,6 +316,8 @@ struct nat64stateful_t uint32_t pool_size{}; tCounterId counter_id; uint8_t ipv4_dscp_flags; + tVrfId vrf_lan; + tVrfId vrf_wan; struct { uint16_t tcp_syn; @@ -348,6 +351,8 @@ struct nat46clat_t ipv6_address_t ipv6_destination; tCounterId counter_id; uint8_t ipv4_dscp_flags; + tVrfId vrf_lan; + tVrfId vrf_wan; common::globalBase::tFlow flow; }; diff --git a/dataplane/updater.h b/dataplane/updater.h index b3b0dc04..281769c5 100644 --- a/dataplane/updater.h +++ b/dataplane/updater.h @@ -9,6 +9,7 @@ #include "hashtable.h" #include "lpm.h" #include "memory_manager.h" +#include "vrf.h" namespace dataplane { @@ -669,4 +670,118 @@ class updater_array object_type* pointer; }; +template +class updater_vrf_lpm +{ +public: + using stats_t = typename InnerLpmType::stats_t; + using UpdaterType = updater_lpm; + + updater_vrf_lpm(const char* name, + dataplane::memory_manager* memory_manager, + tSocketId socket_id) : + name_(name), + memory_manager_(memory_manager), + socket_id_(socket_id) + { + } + + eResult init() + { + return eResult::success; + } + + eResult insert(tVrfId vrf, + const Address& ip_address, + const uint8_t& mask, + const uint32_t& value_id) + { + if (vrf >= YANET_RIB_VRF_MAX_NUMBER) + { + return eResult::invalidId; + } + if (updaters_[vrf] == nullptr) + { + std::string name = std::string(name_) + ".vrf" + std::to_string(vrf); + updaters_[vrf] = std::make_unique(name.c_str(), memory_manager_, socket_id_); + if (updaters_[vrf] == nullptr) + { + return eResult::errorAllocatingMemory; + } + eResult result = updaters_[vrf]->init(); + if (result != eResult::success) + { + return result; + } + } + + return updaters_[vrf]->insert(ip_address, mask, value_id); + } + + eResult remove(tVrfId vrf, + const Address& ip_address, + const uint8_t& mask) + { + if (vrf >= YANET_RIB_VRF_MAX_NUMBER) + { + return eResult::invalidId; + } + else if (updaters_[vrf] == nullptr) + { + return eResult::success; + } + return updaters_[vrf]->remove(ip_address, mask); + } + + void limits(common::idp::limits::response& limits) const + { + for (size_t index = 0; index < YANET_RIB_VRF_MAX_NUMBER; index++) + { + if (updaters_[index]) + { + updaters_[index]->limits(limits); + } + } + } + + void report(nlohmann::json& report) const + { + for (size_t index = 0; index < YANET_RIB_VRF_MAX_NUMBER; index++) + { + if (updaters_[index]) + { + updaters_[index]->report(report); + } + } + } + + void clear() + { + for (size_t index = 0; index < YANET_RIB_VRF_MAX_NUMBER; index++) + { + if (updaters_[index]) + { + updaters_[index]->clear(); + updaters_[index] = nullptr; + } + } + } + + std::array GetLpms() const + { + std::array result; + for (size_t index = 0; index < YANET_RIB_VRF_MAX_NUMBER; index++) + { + result[index] = (updaters_[index] == nullptr ? nullptr : updaters_[index]->pointer()); + } + return result; + } + +private: + std::string name_; + dataplane::memory_manager* memory_manager_; + tSocketId socket_id_; + std::array, YANET_RIB_VRF_MAX_NUMBER> updaters_; +}; + } diff --git a/dataplane/vrf.h b/dataplane/vrf.h new file mode 100644 index 00000000..eab0451d --- /dev/null +++ b/dataplane/vrf.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include "lpm.h" +#include "type.h" + +namespace dataplane::vrflpm +{ + +template +class VrfLookuper +{ +public: + void Update(std::array lpms) + { + for (size_t index = 0; index < lpms_.size(); index++) + { + lpms_[index] = lpms[index]; + } + } + + void Lookup(const Address* ipAddresses, const tVrfId* vrfIds, uint32_t* valueIds, const unsigned int& count) const + { + for (unsigned int index = 0; index < count; index++) + { + valueIds[index] = lpmValueIdInvalid; + tVrfId vrf = vrfIds[index]; + if ((vrf < YANET_RIB_VRF_MAX_NUMBER) && (lpms_[vrf] != nullptr)) + { + lpms_[vrf]->lookup(ipAddresses + index, valueIds + index, 1); + } + } + } + +private: + std::array lpms_; +}; + +} // namespace dataplane diff --git a/dataplane/worker.cpp b/dataplane/worker.cpp index 88f3f720..836b1c2c 100644 --- a/dataplane/worker.cpp +++ b/dataplane/worker.cpp @@ -963,19 +963,19 @@ inline void cWorker::handlePackets() tsc_deltas->write(tsc_start, stack_size, tsc_deltas->balancer_icmp_forward_handle, base_values.balancer_icmp_forward_handle); } - stack_size = route_stack4.mbufsCount; + stack_size = route_stack4.mbufsCount + vrf_route_stack4.mbufsCount; route_handle4(); tsc_deltas->write(tsc_start, stack_size, tsc_deltas->route_handle4, base_values.route_handle4); - stack_size = route_stack6.mbufsCount; + stack_size = route_stack6.mbufsCount + vrf_route_stack6.mbufsCount; route_handle6(); tsc_deltas->write(tsc_start, stack_size, tsc_deltas->route_handle6, base_values.route_handle6); - stack_size = route_tunnel_stack4.mbufsCount; + stack_size = route_tunnel_stack4.mbufsCount + vrf_route_tunnel_stack4.mbufsCount; route_tunnel_handle4(); tsc_deltas->write(tsc_start, stack_size, tsc_deltas->route_tunnel_handle4, base_values.route_tunnel_handle4); - stack_size = route_tunnel_stack6.mbufsCount; + stack_size = route_tunnel_stack6.mbufsCount + vrf_route_tunnel_stack6.mbufsCount; route_tunnel_handle6(); tsc_deltas->write(tsc_start, stack_size, tsc_deltas->route_tunnel_handle6, base_values.route_tunnel_handle6); @@ -1120,6 +1120,7 @@ inline void cWorker::logicalPort_ingress_handle() rte_mbuf* mbuf = logicalPort_ingress_stack.mbufs[mbuf_i]; dataplane::metadata* metadata = YADECAP_METADATA(mbuf); const auto& logicalPort = base.globalBase->logicalPorts[metadata->flow.data.logicalPortId]; + metadata->vrfId = logicalPort.vrfId; generic_rte_ether_hdr* ethernetHeader = rte_pktmbuf_mtod(mbuf, generic_rte_ether_hdr*); @@ -2098,11 +2099,25 @@ inline void cWorker::route_entry(rte_mbuf* mbuf) if (metadata->network_headerType == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) { - route_stack4.insert(mbuf); + if (metadata->vrfId == 0) + { + route_stack4.insert(mbuf); + } + else + { + vrf_route_stack4.insert(mbuf); + } } else if (metadata->network_headerType == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) { - route_stack6.insert(mbuf); + if (metadata->vrfId == 0) + { + route_stack6.insert(mbuf); + } + else + { + vrf_route_stack6.insert(mbuf); + } } else { @@ -2119,10 +2134,14 @@ inline void cWorker::route_handle4() { const auto& base = bases[localBaseId & 1]; - if (unlikely(route_stack4.mbufsCount == 0)) + unsigned int countVrf0 = route_stack4.mbufsCount; + unsigned int countVrfOther = vrf_route_stack4.mbufsCount; + if (unlikely(countVrf0 + countVrfOther == 0)) { return; } + route_stack4.copy_from(vrf_route_stack4); + vrf_route_stack4.clear(); for (unsigned int mbuf_i = 0; mbuf_i < route_stack4.mbufsCount; @@ -2132,12 +2151,21 @@ inline void cWorker::route_handle4() dataplane::metadata* metadata = YADECAP_METADATA(mbuf); rte_ipv4_hdr* ipv4Header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv4_hdr*, metadata->network_headerOffset); - route_ipv4_keys[mbuf_i] = ipv4Header->dst_addr; + route_keys.ipv4[mbuf_i] = ipv4Header->dst_addr; + route_keys.vrfs[mbuf_i] = metadata->vrfId; calcHash(mbuf); } - base.globalBase->route_lpm4->lookup(route_ipv4_keys, route_ipv4_values, route_stack4.mbufsCount); + if (countVrf0 != 0) + { + base.globalBase->route_lpm4->lookup(route_keys.ipv4, route_ipv4_values, countVrf0); + } + if (countVrfOther != 0) + { + base.globalBase->vrf_route_lpm4.Lookup(route_keys.ipv4 + countVrf0, route_keys.vrfs + countVrf0, route_ipv4_values + countVrf0, countVrfOther); + } + for (unsigned int mbuf_i = 0; mbuf_i < route_stack4.mbufsCount; mbuf_i++) @@ -2247,10 +2275,14 @@ inline void cWorker::route_handle6() { const auto& base = bases[localBaseId & 1]; - if (unlikely(route_stack6.mbufsCount == 0)) + unsigned int countVrf0 = route_stack6.mbufsCount; + unsigned int countVrfOther = vrf_route_stack6.mbufsCount; + if (unlikely(countVrf0 + countVrfOther == 0)) { return; } + route_stack6.copy_from(vrf_route_stack6); + vrf_route_stack6.clear(); for (unsigned int mbuf_i = 0; mbuf_i < route_stack6.mbufsCount; @@ -2260,12 +2292,21 @@ inline void cWorker::route_handle6() dataplane::metadata* metadata = YADECAP_METADATA(mbuf); rte_ipv6_hdr* ipv6Header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv6_hdr*, metadata->network_headerOffset); - rte_memcpy(route_ipv6_keys[mbuf_i].bytes, ipv6Header->dst_addr, 16); + rte_memcpy(route_keys.ipv6[mbuf_i].bytes, ipv6Header->dst_addr, 16); + route_keys.vrfs[mbuf_i] = metadata->vrfId; calcHash(mbuf); } - base.globalBase->route_lpm6->lookup(route_ipv6_keys, route_ipv6_values, route_stack6.mbufsCount); + if (countVrf0 != 0) + { + base.globalBase->route_lpm6->lookup(route_keys.ipv6, route_ipv6_values, countVrf0); + } + if (countVrfOther != 0) + { + base.globalBase->vrf_route_lpm6.Lookup(route_keys.ipv6 + countVrf0, route_keys.vrfs + countVrf0, route_ipv6_values + countVrf0, countVrfOther); + } + for (unsigned int mbuf_i = 0; mbuf_i < route_stack6.mbufsCount; mbuf_i++) @@ -2439,11 +2480,25 @@ inline void cWorker::route_tunnel_entry(rte_mbuf* mbuf) if (metadata->network_headerType == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) { - route_tunnel_stack4.insert(mbuf); + if (metadata->vrfId == 0) + { + route_tunnel_stack4.insert(mbuf); + } + else + { + vrf_route_tunnel_stack4.insert(mbuf); + } } else if (metadata->network_headerType == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) { - route_tunnel_stack6.insert(mbuf); + if (metadata->vrfId == 0) + { + route_tunnel_stack6.insert(mbuf); + } + else + { + vrf_route_tunnel_stack6.insert(mbuf); + } } else { @@ -2455,10 +2510,14 @@ inline void cWorker::route_tunnel_handle4() { const auto& base = bases[localBaseId & 1]; - if (unlikely(route_tunnel_stack4.mbufsCount == 0)) + unsigned int countVrf0 = route_tunnel_stack4.mbufsCount; + unsigned int countVrfOther = vrf_route_tunnel_stack4.mbufsCount; + if (unlikely(countVrf0 + countVrfOther == 0)) { return; } + route_tunnel_stack4.copy_from(vrf_route_tunnel_stack4); + vrf_route_tunnel_stack4.clear(); for (unsigned int mbuf_i = 0; mbuf_i < route_tunnel_stack4.mbufsCount; @@ -2468,13 +2527,22 @@ inline void cWorker::route_tunnel_handle4() dataplane::metadata* metadata = YADECAP_METADATA(mbuf); rte_ipv4_hdr* ipv4Header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv4_hdr*, metadata->network_headerOffset); - route_ipv4_keys[mbuf_i] = ipv4Header->dst_addr; + route_keys.ipv4[mbuf_i] = ipv4Header->dst_addr; + route_keys.vrfs[mbuf_i] = metadata->vrfId; calcHash(mbuf); metadata->hash = rte_hash_crc(&metadata->flowLabel, 4, metadata->hash); } - base.globalBase->route_tunnel_lpm4->lookup(route_ipv4_keys, route_ipv4_values, route_tunnel_stack4.mbufsCount); + if (countVrf0 != 0) + { + base.globalBase->route_tunnel_lpm4->lookup(route_keys.ipv4, route_ipv4_values, countVrf0); + } + if (countVrfOther != 0) + { + base.globalBase->vrf_route_tunnel_lpm4.Lookup(route_keys.ipv4 + countVrf0, route_keys.vrfs + countVrf0, route_ipv4_values + countVrf0, countVrfOther); + } + for (unsigned int mbuf_i = 0; mbuf_i < route_tunnel_stack4.mbufsCount; mbuf_i++) @@ -2586,10 +2654,14 @@ inline void cWorker::route_tunnel_handle6() { const auto& base = bases[localBaseId & 1]; - if (unlikely(route_tunnel_stack6.mbufsCount == 0)) + unsigned int countVrf0 = route_tunnel_stack6.mbufsCount; + unsigned int countVrfOther = vrf_route_tunnel_stack6.mbufsCount; + if (unlikely(countVrf0 + countVrfOther == 0)) { return; } + route_tunnel_stack6.copy_from(vrf_route_tunnel_stack6); + vrf_route_tunnel_stack6.clear(); for (unsigned int mbuf_i = 0; mbuf_i < route_tunnel_stack6.mbufsCount; @@ -2599,13 +2671,22 @@ inline void cWorker::route_tunnel_handle6() dataplane::metadata* metadata = YADECAP_METADATA(mbuf); rte_ipv6_hdr* ipv6Header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv6_hdr*, metadata->network_headerOffset); - rte_memcpy(route_ipv6_keys[mbuf_i].bytes, ipv6Header->dst_addr, 16); + rte_memcpy(route_keys.ipv6[mbuf_i].bytes, ipv6Header->dst_addr, 16); + route_keys.vrfs[mbuf_i] = metadata->vrfId; calcHash(mbuf); metadata->hash = rte_hash_crc(&metadata->flowLabel, 4, metadata->hash); } - base.globalBase->route_tunnel_lpm6->lookup(route_ipv6_keys, route_ipv6_values, route_tunnel_stack6.mbufsCount); + if (countVrf0 != 0) + { + base.globalBase->route_tunnel_lpm6->lookup(route_keys.ipv6, route_ipv6_values, countVrf0); + } + if (countVrfOther != 0) + { + base.globalBase->vrf_route_tunnel_lpm6.Lookup(route_keys.ipv6 + countVrf0, route_keys.vrfs + countVrf0, route_ipv6_values + countVrf0, countVrfOther); + } + for (unsigned int mbuf_i = 0; mbuf_i < route_tunnel_stack6.mbufsCount; mbuf_i++) @@ -2970,6 +3051,10 @@ inline void cWorker::nat64stateful_lan_handle() const auto& key = nat64stateful_lan_keys[mbuf_i]; const auto& nat64stateful = base.globalBase->nat64statefuls[metadata->flow.data.nat64stateful_id]; + if (nat64stateful.vrf_lan != 0) + { + metadata->vrfId = nat64stateful.vrf_lan; + } dataplane::globalBase::nat64stateful_lan_value* value_lookup = nullptr; dataplane::spinlock_nonrecursive_t* locker = nullptr; @@ -3261,6 +3346,10 @@ inline void cWorker::nat64stateful_wan_handle() const auto& key = nat64stateful_wan_keys[mbuf_i]; const auto& nat64stateful = base.globalBase->nat64statefuls[metadata->flow.data.nat64stateful_id]; + if (nat64stateful.vrf_wan != 0) + { + metadata->vrfId = nat64stateful.vrf_wan; + } dataplane::globalBase::nat64stateful_wan_value* value_lookup = nullptr; dataplane::spinlock_nonrecursive_t* locker = nullptr; @@ -3663,6 +3752,10 @@ inline void cWorker::nat46clat_lan_handle() dataplane::metadata* metadata = YADECAP_METADATA(mbuf); const auto& nat46clat = base.globalBase->nat46clats[metadata->flow.data.nat46clat_id]; + if (nat46clat.vrf_lan != 0) + { + metadata->vrfId = nat46clat.vrf_lan; + } nat46clat_lan_translation(mbuf, nat46clat); @@ -3742,6 +3835,10 @@ inline void cWorker::nat46clat_wan_handle() dataplane::metadata* metadata = YADECAP_METADATA(mbuf); const auto& nat46clat = base.globalBase->nat46clats[metadata->flow.data.nat46clat_id]; + if (nat46clat.vrf_wan != 0) + { + metadata->vrfId = nat46clat.vrf_wan; + } nat46clat_wan_translation(mbuf, nat46clat); diff --git a/dataplane/worker.h b/dataplane/worker.h index 57e97976..6452f707 100644 --- a/dataplane/worker.h +++ b/dataplane/worker.h @@ -51,6 +51,11 @@ class tStack mbufsCount = 0; } + inline void copy_from(tStack& other) + { + insert(other.mbufs, other.mbufsCount); + } + public: unsigned int mbufsCount{}; rte_mbuf* mbufs[TSize]; @@ -271,9 +276,13 @@ class cWorker union { - uint32_t route_ipv4_keys[CONFIG_YADECAP_MBUFS_BURST_SIZE]; + struct + { + uint32_t ipv4[CONFIG_YADECAP_MBUFS_BURST_SIZE]; + ipv6_address_t ipv6[CONFIG_YADECAP_MBUFS_BURST_SIZE]; + tVrfId vrfs[CONFIG_YADECAP_MBUFS_BURST_SIZE]; + } route_keys; dataplane::globalBase::tun64mapping_key_t tun64_keys[CONFIG_YADECAP_MBUFS_BURST_SIZE]; - ipv6_address_t route_ipv6_keys[CONFIG_YADECAP_MBUFS_BURST_SIZE]; dataplane::globalBase::nat64stateful_lan_key nat64stateful_lan_keys[CONFIG_YADECAP_MBUFS_BURST_SIZE]; dataplane::globalBase::nat64stateful_wan_key nat64stateful_wan_keys[CONFIG_YADECAP_MBUFS_BURST_SIZE]; dataplane::globalBase::balancer_state_key_t balancer_keys[CONFIG_YADECAP_MBUFS_BURST_SIZE]; @@ -320,6 +329,10 @@ class cWorker worker::tStack<> route_stack6; worker::tStack<> route_tunnel_stack4; worker::tStack<> route_tunnel_stack6; + worker::tStack<> vrf_route_stack4; + worker::tStack<> vrf_route_stack6; + worker::tStack<> vrf_route_tunnel_stack4; + worker::tStack<> vrf_route_tunnel_stack6; worker::tStack<> nat64stateful_lan_stack; worker::tStack<> nat64stateful_wan_stack; worker::tStack<> nat64stateless_ingress_stack;