03 Underlay Customization - fortinet-solutions-cse/sdwan-advpn-reference GitHub Wiki

Profiles

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

General Interface Options

Basic Parameters

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)

IP Address

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').

PPPoE

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).

VLANs

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'
        }
      ]
    }     
  }
%}

LAG (802.3ad) and Redundant Interface

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 of aggregate).

  • 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'
         }       
       ]
    }     

  }
%}

VRFs

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 the force_cleanup mode to be enabled (unlike the FortiManager-based method which does not require extra configuration).

Inbound Access

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' ]
        }
      ]
    }     
  }
%}

WAN Services

Underlay Loopbacks

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.

QoS

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 and outbandwidth are both defined, the shaping profile will be applied as egress shaping profile.
  • When shaping_profile and inbandwidth 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.

LAN Services

DHCP Server

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.

DHCP Relay

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).

Excluding from SD-WAN

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'
        }
      ]
    }     
  }
%}

Bridging

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. The vlanid 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 the parent 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.

SD-Branch Support

Managed FortiSwitch (Fortilink)

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'.

Managed FortiExtender (FEX)

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.

Other Settings

HA

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 #}
      ]
    }
%}

DIA

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.

⚠️ **GitHub.com Fallback** ⚠️