mirror of
https://github.com/Telecominfraproject/ols-ucentral-schema.git
synced 2025-10-29 01:02:20 +00:00
217 lines
7.0 KiB
Ucode
217 lines
7.0 KiB
Ucode
{%
|
|
let has_downstream_relays = false;
|
|
let dest;
|
|
|
|
// Skip interfaces previously marked as conflicting.
|
|
if (interface.conflicting) {
|
|
warn("Skipping conflicting interface declaration");
|
|
|
|
return;
|
|
}
|
|
|
|
// Skip upstream interfaces that try to use a wireguard overlay
|
|
if (interface.role == 'upstream' && 'wireguard-overlay' in interface.services) {
|
|
warn("Skipping interface. wireguard-overlay is not allowed on upstream interfaces.");
|
|
|
|
return;
|
|
}
|
|
|
|
// Check this interface for role/vlan uniqueness...
|
|
let this_vid = interface.vlan.id || interface.vlan.dyn_id;
|
|
|
|
for (let other_interface in state.interfaces) {
|
|
if (other_interface == interface)
|
|
continue;
|
|
|
|
if (!other_interface.ethernet && length(interface.ssids) == 1)
|
|
continue;
|
|
|
|
let other_vid = other_interface.vlan.id || '';
|
|
|
|
if (interface.role === other_interface.role && this_vid === other_vid) {
|
|
warn("Multiple interfaces with same role and VLAN ID defined, ignoring conflicting interface");
|
|
other_interface.conflicting = true;
|
|
}
|
|
|
|
if (other_interface.role == 'downstream' &&
|
|
other_interface.ipv6 &&
|
|
other_interface.ipv6.dhcpv6 &&
|
|
other_interface.ipv6.dhcpv6.mode == 'relay')
|
|
has_downstream_relays = true;
|
|
}
|
|
|
|
// check if a downstream interface with a vlan has a matching upstream interface
|
|
if (ethernet.has_vlan(interface) && interface.role == "downstream" && index(vlans, this_vid) < 0) {
|
|
warn("Trying to create a downstream interface with a VLAN ID, without matching upstream interface.");
|
|
return;
|
|
}
|
|
|
|
// reject static config that has no subnet
|
|
if (interface.role == 'upstream' && interface.ipv4?.addressing == 'static')
|
|
if (!interface.ipv4?.subnet || !interface.ipv4?.use_dns || !interface.ipv4?.gateway)
|
|
die('invalid static interface settings');
|
|
|
|
// resolve auto prefixes
|
|
if (wildcard(interface.ipv4?.subnet, 'auto/*')) {
|
|
try {
|
|
interface.ipv4.subnet = ipcalc.generate_prefix(state, interface.ipv4.subnet, false);
|
|
}
|
|
catch (e) {
|
|
warn("Unable to allocate a suitable IPv4 prefix: %s, ignoring interface", e);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (wildcard(interface.ipv6?.subnet, 'auto/*')) {
|
|
try {
|
|
interface.ipv6.subnet = ipcalc.generate_prefix(state, interface.ipv6.subnet, true);
|
|
}
|
|
catch (e) {
|
|
warn("Unable to allocate a suitable IPv6 prefix: %s, ignoring interface", e);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Captive Portal is only supported on downstream interfaces
|
|
if (interface.captive && interface.role != 'downstream') {
|
|
warn("Trying to create a Captive Portal on a none downstream interface.");
|
|
return;
|
|
}
|
|
|
|
// Port forwardings are only supported on downstream interfaces
|
|
if ((interface.ipv4?.port_forward || interface.ipv6?.port_forward) && interface.role != 'downstream') {
|
|
warn("Port forwardings are only supported on downstream interfaces.");
|
|
return;
|
|
}
|
|
|
|
// Traffic accept rules are only supported on downstream interfaces
|
|
if (interface.ipv6?.traffic_allow && interface.role != 'downstream') {
|
|
warn("Traffic accept rules are only supported on downstream interfaces.");
|
|
return;
|
|
}
|
|
|
|
// Gather related BSS modes and ethernet ports.
|
|
let bss_modes = map(interface.ssids, ssid => ssid.bss_mode);
|
|
let eth_ports = ethernet.lookup_by_interface_vlan(interface);
|
|
let swconfig;
|
|
if (interface.role == 'upstream')
|
|
swconfig = ethernet.switch_by_interface_vlan(interface);
|
|
|
|
// If at least one station mode SSID is part of this interface then we must
|
|
// not bridge at all. Having any other SSID or any number of matching ethernet
|
|
// ports in such a case is a semantic error.
|
|
if ('sta' in bss_modes && (length(eth_ports) > 0 || length(bss_modes) > 1)) {
|
|
warn("Station mode SSIDs cannot be bridged with ethernet ports or other SSIDs, ignoring interface");
|
|
|
|
return;
|
|
}
|
|
|
|
// Compute unique logical name and netdev name to use
|
|
let name = ethernet.calculate_name(interface);
|
|
let bridgedev = 'up';
|
|
if (capab.platform != "switch" && interface.role == "downstream")
|
|
bridgedev = 'down';
|
|
let netdev = name;
|
|
let network = name;
|
|
|
|
// Determine the IPv4 and IPv6 configuration modes and figure out if we
|
|
// can set them both in a single interface (automatic) or whether we need
|
|
// two logical interfaces due to different protocols.
|
|
let ipv4_mode = interface.ipv4 ? interface.ipv4.addressing : 'none';
|
|
let ipv6_mode = interface.ipv6 ? interface.ipv6.addressing : 'none';
|
|
|
|
// If no metric is defined explicitly, any upstream interfaces will default
|
|
// to 5 and downstream interfaces will default to 10
|
|
if (!interface.metric && interface.role == "upstream")
|
|
interface.metric = 5;
|
|
if (!interface.metric && interface.role == "downstream")
|
|
interface.metric = 10;
|
|
|
|
// If this interface is a tunnel, we need to create the interface
|
|
// in a different way
|
|
let tunnel_proto = interface.tunnel ? interface.tunnel.proto : '';
|
|
|
|
//
|
|
// Create the actual UCI sections
|
|
//
|
|
|
|
if (interface.broad_band) {
|
|
include("interface/broadband.uc", { interface, name, location, eth_ports, raw_ports });
|
|
return;
|
|
}
|
|
|
|
// tunnel interfaces need additional sections
|
|
if (tunnel_proto in [ "mesh", "l2tp", "vxlan", "gre", "gre6" ])
|
|
include("interface/" + tunnel_proto + ".uc", { interface, name, eth_ports, location, netdev, ipv4_mode, ipv6_mode, this_vid });
|
|
|
|
if (!interface.ethernet && length(interface.ssids) == 1 && !tunnel_proto && !("vxlan-overlay" in interface.services)) {
|
|
if (interface.role == 'downstream')
|
|
interface.type = 'bridge';
|
|
netdev = '';
|
|
} else if (tunnel_proto == 'vxlan') {
|
|
netdev = '@' + name + '_vx';
|
|
interface.type = 'bridge';
|
|
} else if (tunnel_proto != 'gre' && tunnel_proto != 'gre6')
|
|
// anything else requires a bridge-vlan
|
|
include("interface/bridge-vlan.uc", { interface, name, eth_ports, this_vid, bridgedev, swconfig });
|
|
|
|
if (interface.role == "downstream" && "wireguard-overlay" in interface.services)
|
|
dest = 'unet';
|
|
|
|
include("interface/common.uc", {
|
|
name, this_vid, netdev,
|
|
ipv4_mode, ipv4: interface.ipv4 || {},
|
|
ipv6_mode, ipv6: interface.ipv6 || {}
|
|
});
|
|
|
|
include('interface/firewall.uc', { name, ipv4_mode, ipv6_mode, dest });
|
|
|
|
if (interface.ipv4 || interface.ipv6) {
|
|
include('interface/dhcp.uc', {
|
|
ipv4: interface.ipv4 || {},
|
|
ipv6: interface.ipv6 || {},
|
|
has_downstream_relays
|
|
});
|
|
}
|
|
|
|
let count = 0;
|
|
for (let i, ssid in interface.ssids) {
|
|
let modes = (ssid.bss_mode == "wds-repeater") ?
|
|
[ "wds-sta", "wds-ap" ] : [ ssid.bss_mode ];
|
|
for (let mode in modes) {
|
|
include('interface/ssid.uc', {
|
|
location: location + '/ssids/' + i,
|
|
ssid: { ...ssid, bss_mode: mode },
|
|
count,
|
|
name,
|
|
network,
|
|
});
|
|
if (ssid?.encryption?.proto == 'owe-transition') {
|
|
ssid.encryption.proto = 'none';
|
|
include('interface/ssid.uc', {
|
|
location: location + '/ssids/' + i + '_owe',
|
|
ssid: { ...ssid, bss_mode: mode },
|
|
count,
|
|
name,
|
|
network,
|
|
owe: true,
|
|
});
|
|
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (interface.captive)
|
|
include('interface/captive.uc', { name });
|
|
%}
|
|
{% if (tunnel_proto == 'mesh'): %}
|
|
set network.{{ name }}.batman=1
|
|
{% endif %}
|
|
|
|
{% if (interface.role == "downstream" && "wireguard-overlay" in interface.services): %}
|
|
add network rule
|
|
set network.@rule[-1].in='{{name}}'
|
|
set network.@rule[-1].lookup='{{ routing_table.get('wireguard_overlay') }}'
|
|
{% endif %}
|