03 Underlay Customization - fortinet-solutions-cse/sdwan-advpn-reference GitHub Wiki
Jinja Orchestrator versions: 7.2+
The profiles
structure describes all the device profiles in the project.
By device profiles we mainly mean the list of interfaces for each site, with the respective options for each interface.
Optionally, there can also be a list of bridges - the hardware switches built into certain FortiGate models, also known as "virtual-switches".
Thus, the profile describes the local topology and the connectivity options for each site:
{% set profiles = {
'Profile1': {
'bridges': [
{# Optional: virtual-switch (build-in hardware switch) parameters #}
{
{# Virtual-switch1 parameters #}
},
{
{# Virtual-switch2 parameters #}
}
{# ... #}
],
'interfaces': [
{
{# Interface1 parameters #}
},
{
{# Interface2 parameters #}
}
{# ... #}
]
},
'Profile2': {
'interfaces': [
{
{# Interface1 parameters #}
},
{
{# Interface2 parameters #}
}
{# ... #}
]
}
{# ... #}
}
%}
NOTE: All the devices (Spokes and Hubs!) must be assigned a profile!
It is important to distinguish between a profile assigned to a Hub and the definition of that same Hub in the hubs
structure
(described on this page). Both are required, as they both serve different purposes:
- The assigned profile will be used when rendering the configuration of the Hub itself, configuring its underlay interfaces
- The definitions in the
hubs
structure will be mainly used by the Spokes when building IPSEC tunnels towards this Hub
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
name |
profiles.interfaces | Interface name | e.g. 'port1' | - | no |
role |
profiles.interfaces | Interface role | <see below> | - | no |
At the very minimum, every interface must have a name
and a role
, for example:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'port1',
'role': 'wan',
# ...
}
]
}
}
%}
Interfaces for which the name is not set are automatically skipped. Since every value can be replaced by an external variable (which then can be set or not set by the user on per-device basis), this allows having generic device profiles with different number of interfaces. For example:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': isp1_intf,
'role': 'wan',
# ...
},
{
'name': isp2_intf,
'role': 'wan',
# ...
}
]
}
}
%}
This generic profile snippet describes devices with up to two WAN links. If a given device has only a single WAN link, the variable isp2_intf
can be simply left empty (unset), so that this interface will be automatically skipped during rendering.
Also, this profile snippet can easily be used for different hardware models (with different interface names).
The role
of the interface will determine other parameters that can be configured for it: while some parameters can apply to any interface, others
are available only for certain roles. The following roles are currently supported:
-
wan
: a WAN-facing Layer3 interface (incl. physical, VLAN, IRB...) -
lan
: a LAN-facing Layer3 interface (incl. physical, VLAN, IRB...) -
sd_branch
: a Fortilink member (usually connected to a FortiSwitch) -
bridge
: a virtual-switch (built-in hardware switch) member -
trunk
: 802.1Q trunk (for virtual-vlan-switch feature)
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
ip |
profiles.interfaces | Interface IP | e.g. '192.168.1.0/24' or 'dhcp' | - | yes |
For any Layer3 interface, an interface IP address is set by an ip
parameter. It can contain either a static IP value (most likely, an external per-device variable will be used for that) or a special value 'dhcp', enabling a DHCP client on this interface. Both options are demonstrated below:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': isp1_intf,
'role': 'wan',
'ip': isp1_ip
},
{
'name': isp2_intf,
'role': 'wan',
'ip': 'dhcp'
},
{
'name': 'internal5',
'role': 'lan',
'ip': lan_ip
}
]
}
}
%}
Note that the value of the variable (isp1_ip
and lan_ip
in the above example) must be in the right format, including the subnet mask (e.g. '192.168.1.1/24').
Jinja Orchestrator versions: 7.4+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
ip |
profiles.interfaces | Enable PPPoE | 'pppoe' | - | yes |
pppoe_username |
profiles.interfaces | PPPoE username | <str> | - | yes |
pppoe_password |
profiles.interfaces | PPPoE password | <str> | - | yes |
PPPoE is supported by setting the ip
parameter to another special value - 'pppoe'. Once set, the PPPoE credentials must also be specified:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'wan1',
'role': 'wan',
'ip': 'pppoe',
'pppoe_username': wan_user,
'pppoe_password': wan_password
}
]
}
}
%}
This is supported only on the Edge devices (Spokes).
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
vlanid |
profiles.interfaces | VLAN ID | e.g. '10' | - | no |
parent |
profiles.interfaces | Parent interface | e.g. 'port1' | - | no |
Example:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'vl_users',
'role': 'lan',
'ip': users_ip,
'vlanid': 10,
'parent': 'port1'
}
]
}
}
%}
Jinja Orchestrator versions: 7.4+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
aggregate |
profiles.interfaces | LAG Interface | true / false | false | no |
redundant |
profiles.interfaces | Redundant Interface | true / false | false | no |
-
The LAG Interface itself is identified by setting
aggregate
to 'true'. Apart from that, it is configured as any other L3 interface (e.g. it can be WAN-facing or LAN-facing, there can be additional VLAN interfaces defined on top of it and so on). -
The Redundant Interface is almost the same, except that we set
redundant
to 'true' (instead ofaggregate
). -
The LAG/Redundant members are identified by setting their
role
to 'lag_member'. They must also set their parent to the name of the LAG/Redundant interface.
Example (here two physical interfaces internal1 and internal2 form a LAG called lag_lan):
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'lag_lan',
'role': 'lan',
'ip': lan_ip,
'aggregate': true
},
{
'name': 'internal1',
'role': 'lag_member',
'parent': 'lag_lan'
},
{
'name': 'internal2',
'role': 'lag_member',
'parent': 'lag_lan'
}
]
}
}
%}
Here is a more complex example, with two VLANs defined on top of the LAG (note the role set to 'undefined' on the LAG interface):
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'lag_lan',
'role': 'undefined',
'aggregate': true
},
{
'name': 'internal1',
'role': 'lag_member',
'parent': 'lag_lan'
},
{
'name': 'internal2',
'role': 'lag_member',
'parent': 'lag_lan'
},
{
'name': 'vl_users',
'role': 'lan',
'ip': users_ip,
'vlanid': 10,
'parent': 'lag_lan'
},
{
'name': 'vl_servers',
'role': 'lan',
'ip': servers_ip,
'vlanid': 20,
'parent': 'lag_lan'
}
]
}
}
%}
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
vrf |
profiles.interfaces | VRF ID | e.g. '11' | - | yes |
allow_dia |
profiles.interfaces | Allow Internet access from this CE VRF | true / false | false | yes |
leak_npu_link |
profiles.options | Name of NP inter-VRF interface | e.g. 'npu_link' | sw vdom-link | no |
pe_vrf |
project | PE VRF for multi-VRF deployments (7.4) | <int> | 1 | yes |
Optionally, any Layer3 interface can be assigned to a custom VRF:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'internal5',
'role': 'lan',
'ip': lan_ip,
'vrf': 11
}
]
}
}
%}
The default VRF value differs between a single-VRF and a multi-VRF deployment. Here, by a multi-VRF deployment we specifically mean the
"Segmentation over Single Overlay" design. If the vrfs
list is defined under the region (as explained on this page), then we consider this to be a multi-VRF deployment.
-
In a multi-VRF deployment, any interface for which the VRF ID is not explicitly specified will be assigned to the PE VRF.
- The default value of the PE VRF is 1, which can be controlled by an optional global variable, as shown in the table.
-
In a single-VRF deployment, any interface for which the VRF ID is not explicitly specified will be assigned to VRF=0.
Note that even in a single-VRF deployment individual interfaces can be assigned to custom VRFs. However, it will not trigger any further configuration apart from this VRF assignment. That is, the overlay configuration will remain single-VRF. Nevertheless, this can be useful to separate the underlay interfaces into separate VRFs or to define a VRF which is not expected to be part of the SD-WAN overlay network.
In a multi-VRF deployment, Internet access can be provided for CE VRFs with an optional allow_dia
parameter (set per LAN interface,
although effectively it is applied per the entire CE VRF):
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'internal5',
'role': 'lan',
'ip': lan_ip,
'vrf': 11,
'allow_dia': true
}
]
}
}
%}
The Internet access is implemented by configuring an inter-VRF link from the specific CE VRF to the PE VRF (where all underlays and overlays are
located). By default, the inter-VRF link will be implemented using a software-based "vdom-link", which is the appropriate choice for non-ASIC
models (FortiGate-VM). To use a hardware-based (NPU) link instead, the interface name must be explicitly specified using the leak_npu_link
parameter in the profile options structure, since it may vary between the different hardware models:
{% set profiles = {
'MyBranch': {
'options': {
'leak_npu_link': 'npu_link'
},
'interfaces': [
{
'name': 'internal5',
'role': 'lan',
'ip': lan_ip,
'vrf': 11,
'allow_dia': true
}
]
}
}
%}
NOTE: The 'options' structure has been introduced only in the Jinja Orchestrator 7.4.
In the versions up to 7.2, the 'leak_npu_link' parameter is configured under the interface, same as the 'allow_dia'.
Note that the allow_dia
variable is stateful. It means that changing it to "false" (or removing it) will cause deletion of the
previously configured inter-VRF links and of the generated static default routes.
In FortiManager-based deployment, this functionality relies on the access to the device database (provided by FMG 7.4+), allowing the Jinja Orchestrator to get the current list of device interfaces and thus to figure out the existing inter-VRF links.
During offline rendering (without the FortiManager), this method is not available. As a result, stateful enforcement is somewhat limited. It is based on the list of VRFs configured under the region. It requires theforce_cleanup
mode to be enabled (unlike the FortiManager-based method which does not require extra configuration).
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
access |
profiles.interfaces | Custom list of services to allow access (such as FGFM, SSH etc.) | list, e.g. ['ping', 'fgfm'] | ['ping'] | yes |
Example:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'wan1',
'role': 'wan',
'ip': 'dhcp',
'access': [ 'fgfm', 'https' ]
}
]
}
}
%}
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
src_ip |
profiles.interfaces | Source IP for all local-out traffic (incl. IPSEC) | e.g. '1.2.3.4' | - | no |
Example:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'port1',
'role': 'wan',
'ip': 'dhcp',
'ol_type': 'ISP1',
'src_ip': isp1_lo
}
]
}
}
%}
When configured, the src_ip
value defines the IP address to be used as a source IP for all the local-out (outgoing) traffic from this
WAN interface. This means, for example, that the overlay IPSEC tunnels will be terminated on this IP.
The implementation will create a new loopback interface called Lo-wan<index>
(e.g. Lo-wan1
) with this IP.
The format is the same as for ip
(thus including the mask, e.g. "1.2.3.4/32").
NOTE: For the correct ADVPN operation, a firewall policy is required on the Spokes, to permit incoming traffic from the WAN interfaces to the new Lo-wan<*> interface. This is a standard FOS requirement for traffic destined to the loopback interfaces.
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
shaping_profile |
profiles.interfaces | Shaping profile to apply to this WAN interface | <str> | - | yes |
outbandwidth |
profiles.interfaces | Outbound bandwidth (kbps) for this WAN interface | e.g. '1000' | - | yes |
inbandwidth |
profiles.interfaces | Inbound bandwidth (kbps) for this WAN interface | e.g. '1000' | - | yes |
We support assigning egress and ingress shaping profiles to the WAN interfaces. The shaping profile itself must be defined externally (for example, using FortiManager tools).
- When
shaping_profile
andoutbandwidth
are both defined, the shaping profile will be applied as egress shaping profile. - When
shaping_profile
andinbandwidth
are both defined, the shaping profile will be applied as ingress shaping profile. - When all the three values are defined, the same shaping profile will be applied both as egress and as ingress shaping profile.
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
create_lan_dhcp_server |
project | Configure DHCP servers on all LAN interfaces | true / false | true | no |
dhcp_server_startip |
project or profiles.interfaces | Start IP for the DHCP range (index within the LAN subnet) | <int> | 4 | yes |
dhcp_server_endip |
project or profiles.interfaces | End IP for the DHCP range (index within the LAN subnet) | <int> | -5 | yes |
dhcp_server |
profiles.interfaces | Configure DHCP server on this LAN interface | true / false | true | no |
By default, we enable DHCP servers on all LAN interfaces.
This is controlled by the variable create_lan_dhcp_server
, which acts as a global switch: once it is disabled, no DHCP servers will be configured. But if it is enabled, individual LAN interfaces can be exempt using per-interface variable dhcp_server
:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'port5',
'role': 'lan',
'ip': port5_ip
},
{
'name': 'port6',
'role': 'lan',
'ip': port6_ip,
'dhcp_server': false
}
]
}
}
%}
Optionally, the DHCP pool can be customized, using the two variables described in the table. As can be seen, the default range is from the 4th IP of the LAN subnet until the 5th IP from the end of it (for a subnet like '10.0.1.0/24', this would give a range from 10.0.1.4 to 10.0.1.251). This default range can be overridden either globally or per-interface.
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
dhcp_relay |
profiles.interfaces | Enable DHCP relay on this LAN interface | true / false | false | yes |
dhcp_relay_servers |
profiles.interfaces | List of DHCP relay servers | true / false | - | yes |
DHCP Relay support per interface:
{% set profiles = {
'MyProfile': {
'interfaces': [
{
'name': 'port1',
'role': 'lan',
'dhcp_relay': true,
'dhcp_relay_servers': "10.1.1.1 10.2.2.2 10.3.3.3",
#...
},
For a given LAN interface, we consider DHCP server and DHCP relay to be mutually exclusive. Thus, if the DHCP relay is enabled on the interface,
the local DHCP Server will NOT be configured (same as adding dhcp_server: false
).
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
advertise |
profiles.interfaces | Advertise this LAN interface prefix into BGP | true / false | true | yes |
By default, all the LAN interface subnets will be advertised to the SD-WAN overlay network via BGP. This can be controlled, by explicitly excluding some of the LAN interfaces, for example:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'port10',
'role': 'lan',
'ip': lan_ip,
'advertise': 'false'
}
]
}
}
%}
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
name |
profiles.bridges | Bridge (virtual-switch) name | e.g. 'BR_LAN' | - | no |
vlanid |
profiles.bridges | VLAN ID (enables virtual-switch-vlan feature) | e.g. '10' | - | yes |
We support bridging using a hardware switch built into some FortiGate models. Also virtual VLAN switch is supported.
This is only supported on Edge devices (Spokes).
Note that we do not validate hardware support in any way. Therefore, it is the responsibility of the user to configure these features only when they are supported by the FortiGate devices in use.
Below is a complete configuration example of a hardware switch in the device profile:
{% set profiles = {
'MyBranch': {
'bridges': [
{
'name': 'BR_LAN',
'vlanid': 10
}
],
'interfaces': [
# ...
{
'name': 'BR_LAN',
'role': 'lan',
'ip': lan_ip
},
{
'name': 'internal5',
'role': 'bridge',
'parent': 'BR_LAN'
},
{
'name': 'internal6',
'role': 'bridge',
'parent': 'BR_LAN'
},
{
'name': 'internal7',
'role': 'trunk'
}
]
}
}
%}
There are four different configuration elements here:
-
First, the hardware switch is defined under the
bridges
list. Thevlanid
parameter is optional. If it is set, then the "virtual-vlan-switch" function is automatically enabled. -
Physical ports are added to the hardware switch in the
interfaces
list, by setting'role': 'bridge'
and specifying the name of the hardware switch in theparent
parameter. -
Physical ports can be configured as trunks (only valid when virtual-vlan-switch function is used), by setting
'role': 'trunk'
. -
Finally, the L3 interface of the switch can be configured as any other L3 interface, in the
interfaces
list. In the above example, that's a LAN-facing interface. Its name must be identical to the hardware switch name ("BR_LAN" in our example).
Note that, just like with the interfaces, also the bridges for which the name is not set are automatically skipped. Thus, by using an external variable (which is either set or not set on per-device basis), the profile can be kept generic.
One or more interfaces can be configured as members of the Fortilink bundle. Typically, those will be the interfaces to which a FortiSwitch device is connected, in order to operate in the Managed mode.
Note that FortiSwitch ports and VLANs must be configured externally (for example, using FortiManager tools). But the respective Layer3 interfaces can be configured in the device profile, as usual (normally, those will be the VLAN interfaces).
Below is the full example, in which a FortiSwitch is physically connected to the "port8" of the FortiGate and there is a VLAN 10 configured on it:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'port8',
'role': 'sd_branch'
},
{
'name': 'vl_users',
'role': 'lan',
'ip': users_ip,
'vlanid': 10,
'parent': 'fortilink'
}
]
}
}
%}
Note that the parent
of the VLAN interface is set to 'fortilink' (and not to 'port8'!).
We ensure that 'port8' is a member of the preconfigured Fortilink interface, thanks to its role
set to 'sd_branch'.
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
fex |
profiles.interfaces | Logical FEX interface | true / false | false | no |
We support configuring FortiExtender in the WAN Extension mode (CAPWAP). This is also known as "Managed FEX".
The logical FEX interface must be configured in the device profile as any other WAN interface, but in addition the fex
parameter must be set
and the parent
value must point to the physical interface to which the FEX is connected. For example:
{% set profiles = {
'MyBranch': {
'interfaces': [
{
'name': 'THE_FEX',
'role': 'wan',
'ip': 'dhcp',
'fex': true,
'parent': 'wan2'
}
]
}
}
%}
There is no need listing the parent interface separately in the profile ('wan2' in the above example). It will be automatically configured to accept FEX connection.
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
ha |
profiles | Device is in HA cluster | true / false | false | no |
HA clusters (FGCP) must be marked as such in the device profile. This is mainly used to skip certain configuration which is currently not allowed in HA mode, such as setting the hostname.
Example:
{% set profiles = {
'Profile1': {
'ha': true,
'interfaces': [
{# List of interfaces #}
]
}
%}
Jinja Orchestrator versions: 7.2+
Variable | Scope | Description | Values | Default | stateful |
---|---|---|---|---|---|
dia |
profiles.interfaces | WAN interface used for Direct Internet Access | true / false | false | no |
This parameter currently has significance only for the offline rendering (without FortiManager).
It specifies whether a given WAN interface is used for Direct Internet Access. If set to "true", this WAN interface will be configured as an SD-WAN member.