Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions autotest/units/001_one_port/061_nat64stateful/autotest.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
steps:
- ipv4Update: "0.0.0.0/0 -> 200.0.0.1"
- ipv6Update: "::/0 -> fe80::1"
- cli_check: |
YANET_FORMAT_COLUMNS=module,source_ipv6_prefixes nat64stateful
module source_ipv6_prefixes
------ --------------------
nat0 ::/0
- sendPackets:
- port: kni0
send: 001-send.pcap
Expand Down
6 changes: 4 additions & 2 deletions cli/nat64stateful.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ void summary()
TablePrinter table;
table.insert_row("module",
"ipv4_pool_size",
"next_module");
"next_module",
"source_ipv6_prefixes");

for (const auto& [name, nat64stateful] : response)
{
Expand All @@ -29,7 +30,8 @@ void summary()

table.insert_row(name,
ipv4_pool_size,
nat64stateful.next_module);
nat64stateful.next_module,
nat64stateful.source_ipv6_prefixes);
}

table.Print();
Expand Down
3 changes: 2 additions & 1 deletion common/controlplaneconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,14 +293,15 @@ class config_t
public:
config_t() = default;

SERIALIZABLE(nat64stateful_id, dscp_mark_type, dscp, ipv6_prefixes, ipv4_prefixes, announces, next_module, vrf_lan_name, vrf_wan_name, vrf_lan, vrf_wan);
SERIALIZABLE(nat64stateful_id, dscp_mark_type, dscp, ipv6_prefixes, ipv4_prefixes, announces, next_module, vrf_lan_name, vrf_wan_name, vrf_lan, vrf_wan, source_ipv6_prefixes);

public:
nat64stateful_id_t nat64stateful_id;
common::eDscpMarkType dscp_mark_type{common::eDscpMarkType::never};
uint8_t dscp{};
std::vector<common::ipv6_prefix_t> ipv6_prefixes;
std::vector<common::ipv4_prefix_t> ipv4_prefixes;
std::vector<common::ipv6_prefix_t> source_ipv6_prefixes{common::ipv6_prefix_default};
std::set<common::ip_prefix_t> announces;
std::string vrf_lan_name;
std::string vrf_wan_name;
Expand Down
16 changes: 11 additions & 5 deletions controlplane/configconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1018,10 +1018,16 @@ void config_converter_t::acl_rules_nat64stateful(controlplane::base::acl_t& acl,
{
const auto& nat64stateful = baseNext.nat64statefuls.at(next_module);

std::set<common::ipv6_prefix_t> ipv6_prefixes;
std::set<common::ipv6_prefix_t> destination_ipv6_prefixes;
for (const auto& ipv6_prefix : nat64stateful.ipv6_prefixes)
{
ipv6_prefixes.emplace(ipv6_prefix);
destination_ipv6_prefixes.emplace(ipv6_prefix);
}

std::set<common::ipv6_prefix_t> source_ipv6_prefixes;
for (const auto& ipv6_prefix : nat64stateful.source_ipv6_prefixes)
{
source_ipv6_prefixes.emplace(ipv6_prefix);
}

std::set<common::ipv4_prefix_t> ipv4_prefixes;
Expand All @@ -1038,7 +1044,7 @@ void config_converter_t::acl_rules_nat64stateful(controlplane::base::acl_t& acl,

/// ipv6
{
controlplane::base::acl_rule_network_ipv6_t rule_network({common::ipv6_prefix_default}, ipv6_prefixes);
controlplane::base::acl_rule_network_ipv6_t rule_network(source_ipv6_prefixes, destination_ipv6_prefixes);

controlplane::base::acl_rule_t rule(rule_network, flow_drop);
rule.fragment = {fragState::firstFragment, fragState::notFirstFragment};
Expand All @@ -1061,7 +1067,7 @@ void config_converter_t::acl_rules_nat64stateful(controlplane::base::acl_t& acl,
{
auto flow = convertToFlow(next_module, "lan");

controlplane::base::acl_rule_network_ipv6_t rule_network({common::ipv6_prefix_default}, ipv6_prefixes);
controlplane::base::acl_rule_network_ipv6_t rule_network(source_ipv6_prefixes, destination_ipv6_prefixes);

acl.nextModuleRules.emplace_back(rule_network,
controlplane::acl_rule_transport_tcp_any,
Expand Down Expand Up @@ -1101,7 +1107,7 @@ void config_converter_t::acl_rules_nat64stateful(controlplane::base::acl_t& acl,

/// ipv6
{
controlplane::base::acl_rule_network_ipv6_t rule_network({common::ipv6_prefix_default}, ipv6_prefixes);
controlplane::base::acl_rule_network_ipv6_t rule_network(source_ipv6_prefixes, destination_ipv6_prefixes);
acl.nextModuleRules.emplace_back(rule_network, flow_drop);
}

Expand Down
54 changes: 54 additions & 0 deletions controlplane/configparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,60 @@ void config_parser_t::loadConfig_nat64stateful(controlplane::base_t& baseNext,
nat64stateful.ipv6_prefixes.emplace_back(ipv6_prefix);
}

if (exist(moduleJson, "source_ipv6_prefixes"))
{
const auto& source_json = moduleJson["source_ipv6_prefixes"];

if (!source_json.is_array())
{
throw error_result_t(eResult::invalidConfigurationFile, "nat64stateful: source_ipv6_prefixes must be an array");
}
if (source_json.empty())
{
throw error_result_t(eResult::invalidConfigurationFile, "nat64stateful: source_ipv6_prefixes must not be empty");
}

std::vector<common::ipv6_prefix_t> source_ipv6_prefixes;
for (const auto& prefix_json : source_json)
{
if (!prefix_json.is_string())
{
throw error_result_t(eResult::invalidConfigurationFile, "nat64stateful: source_ipv6_prefixes element must be a string");
}

const std::string prefix_string = prefix_json.get<std::string>();

const auto slash_pos = prefix_string.find('/');
if (slash_pos != std::string::npos)
{
const std::string mask_string = prefix_string.substr(slash_pos + 1);

if (mask_string.empty() ||
prefix_string.find('/', slash_pos + 1) != std::string::npos ||
mask_string.find_first_not_of("0123456789") != std::string::npos)
{
throw error_result_t(eResult::invalidConfigurationFile, "nat64stateful: invalid source_ipv6_prefix mask: " + prefix_string);
}

if (std::stoul(mask_string) > 128)
{
throw error_result_t(eResult::invalidConfigurationFile, "nat64stateful: source_ipv6_prefix mask out of range [0..128]: " + prefix_string);
}
}

common::ipv6_prefix_t source_ipv6_prefix(prefix_string);
if (!source_ipv6_prefix.isValid())
{
throw error_result_t(eResult::invalidConfigurationFile, "nat64stateful: source_ipv6_prefix has host bits set: " + prefix_string);
}

source_ipv6_prefixes.emplace_back(source_ipv6_prefix);
}

/// assign only after full validation succeeds; this replaces the default ::/0
nat64stateful.source_ipv6_prefixes = std::move(source_ipv6_prefixes);
}

for (const auto& prefix_json : moduleJson["ipv4_prefixes"])
{
common::ipv4_prefix_t ipv4_prefix(prefix_json.get<std::string>());
Expand Down