mwan3 (nftables unofficial)

mwan3 is OpenWrt's multi-WAN policy routing framework. It classifies packets using firewall marks, then uses ip rule entries to route marked packets through per-interface routing tables.

The official mwan3 is the original iptables version maintained by feckert. Community member dl12345 has ported the original mwan3 codebase to be compatible with nftables and firewall4. To help distinguish between the two different versions, the nftables version is referred to as mwan3-nft. This documentation has been cloned from the original iptables version and updated to match the functionality and behaviour changes in the nftables version.

Key changes:

  • All iptables/ipset usage with nftables equivalents
  • IP Set interface and automatic configuration with dnsmasq
  • IPv6 extensions for IPv6 multihoming (3.7 BETA only)
  • Create traffic rules by source MAC address
  • Traffic Path Simulator (LuCI)
  • Refactored policy builder interface (LuCI)
  • Various bug fixes reported in the iptables version
  • mwan3rtmon has been ported to a ucode implementation

The overall IP rule/route management is largely unchanged.

This version is currently not available in official OpenWrt package feeds until sufficient feedback from user testing is obtained to ensure the nftables version stable and working before this happens. If you are currently using or have previously used the iptables version of mwan3, please try out the nftables version and report your findings and testing on the community forum thread, you can also report any bugs on GitHub.

The nftables version of mwan3 is only supported on OpenWrt 25.12 or newer releases.

While OpenWrt itself has moved to firewall4 and nftables since 22.03, compatibility with older versions of OpenWrt has not been verified or tested with this version of mwan3 and opkg packages do not exist for the nftables version.

A VLAN capable router is highly recommended for being able to configure multiple WAN interfaces, e.g. configuring LAN ports as WAN ports.

:!: Before installing mwan3 it is important verify the WAN connections you wish to use are working before trying to implement routing policies. You can follow the checklists below before installing and configuring mwan3.

This version of mwan3 is currently not available in the OpenWrt packages feed, but can be installed with apk manually.

As the package is currently not included in any OpenWrt package feeds at this time, you will need to obtain the apk package via GitHub and install manually. A mwan3-nft-update.sh script has been created to help install this version of mwan3 either via the latest pre-release or stable package in the meantime. You can also manually download and install any release without this.

As the version number of the mwan3 nftables package is higher than the current mwan3 iptables package, apk will perform an upgrade if the older mwan3 iptables version is installed. There is a one-time run migration that is automatically triggered on post-install to update your previous iptables mwan3 config to the nftables version.

:!: If you use any firmware upgrade or image builder that automatically installs packages, note that currently if you select mwan3 this will install the iptables version and you will need to manually overwrite this on each sysupgrade currently. As a workaround, you should not include mwan3 in any firmware image and then install either using the update script or manually after.

The latest stable version is currently: v3.6.12-1

Download the update script and install the latest release:

cd /tmp
wget https://gist.githubusercontent.com/jamesmacwhite/7f6463ae7b307692c26a81be5cddbdcf/raw/70088070644b1a95222f14d2f4b86d6bf7fdec32/mwan3-nft-update.sh -O mwan3-nft-update.sh
chmod +x /tmp/mwan3-nft-update.sh
./mwan3-nft-update.sh
Usage:
  mwan3-nft-update.sh [options]
 
Options:
  -c, --check           Only check for updates, don't download/install
  -f, --force            Reinstall even if the latest version is already installed
  -k, --keep             Keep the downloaded .apk file(s) in /tmp after install
  -p, --pre-release       Also consider pre-releases (default: stable releases only)
  -l, --luci              Also fetch and install the companion luci-app-mwan3 package
  -a, --arch ARCH         Override detected arch (skip /etc/apk/arch lookup)
  -o, --openwrt-ver VER      OpenWrt version string to match in the mwan3 asset name (default: auto-detected, falls back to 25.12)
  -r, --repo OWNER/REPO   Override the mwan3 GitHub repo (default: dl12345/mwan3)
  --luci-repo OWNER/REPO  Override the luci-app-mwan3 GitHub repo (default: dl12345/luci-app-mwan3)
  -h, --help              Show this help and exit

Running the script without any parameters or flags will query the GitHub repository for the latest release, detect your router arch to select the right package, download and then install it via apk. If you want to also install the LuCI management interface luci-app-mwan3, pass the LuCI flag.

./mwan3-nft-update.sh -l

If for whatever reason the arch detection does not work, you can also specify this via a flag to bypass the detection logic:

./mwan3-nft-update.sh -a arm_cortex-a9_vfpv3-d16 -l

Various other flags and parameters can be used if needed.

  1. Go to the mwan3 nftables repository and browse the releases tab.
  2. Select Assets and find the correct apk package for your router. If the arch for your router is not available, create an issue or GitHub or post in the community forum topic to request this.
  3. On your router you can directly use wget or curl to download a release and install with apk.

To install with apk you will need to use the --allow-untrusted flag currently as the packages are not signed or provided by a OpenWrt packages feed.

On your router, download the release that matches your routers arch. For example installing for arm_cortex-a9_vfpv3-d16.

cd /tmp
wget https://github.com/dl12345/mwan3/releases/download/v3.6.11-1/mwan3-3.6.11-1_openwrt-25.12_arm_cortex-a9_vfpv3-d16.apk
apk add mwan3-3.6.11-1_openwrt-25.12_arm_cortex-a9_vfpv3-d16.apk --allow-untrusted

Optionally, if you also want to manage your mwan3 configuration via LuCI, install the mwan3 nftables LuCI package. The LuCI package is arch independent.

cd /tmp
wget https://github.com/dl12345/luci-app-mwan3/releases/download/v3.6.10-1/luci-app-mwan3_26.999.3.6.10.apk
apk add luci-app-mwan3_26.999.3.6.10.apk --allow-untrusted

mwan3 configuration consists of six major areas:

  • Globals - Global settings that apply to the operation of mwan3 overall.
  • Interfaces - Network interfaces to be used/tracked by mwan3, the interfaces configured in mwan3 need to match what is set in /etc/config/network.
  • Members - How a network interface is to be used in mwan3, it must be defined as a member, which can then be used in policies.
  • Policies - How the traffic should be routed according to the metric value and weight set in the member configuration. This allows you to define configurations like load balancing/failover or always routing traffic through a specific interface/WAN.
  • Rules - Defining one or more specific routing rules according to the defined policy set. A variety of rules can be configured using source/destination IP/port, domain names (using IP sets) and more.
  • IP sets - IP sets are nftables address sets referenced by mwan3 rules. Sets can be populated with static entries, loaded from a file, or populated at runtime by dnsmasq name resolution.

The default mwan3 configuration provided by this package has all interfaces disabled by default, but provides a template for two WAN interfaces as dual stack IPv4 and IPv6, with a set of default members and policies to achieve load balancing, failover and specific WAN routing. You can find more details about each of these traffic management policies below.

This config file is located at /etc/config/mwan3. The entire configuration can be modified as required, the most common approach is using the base configuration as a starting point and adding or amending any policies or rules needed.

/etc/config/mwan3
config globals 'globals'
	option mmx_mask '0x3F00'
	# option iif_rule_base '1000'
	# option fwmark_rule_base '2000'
	# option unreachable_rule_base '3000'
 
config interface 'wan'
	option enabled '0'
	list track_ip '1.0.0.1'
	list track_ip '1.1.1.1'
	list track_ip '208.67.222.222'
	list track_ip '208.67.220.220'
	option family 'ipv4'
	option reliability '2'
 
config interface 'wan6'
	option enabled '0'
	list track_ip '2606:4700:4700::1001'
	list track_ip '2606:4700:4700::1111'
	list track_ip '2620:0:ccd::2'
	list track_ip '2620:0:ccc::2'
	option family 'ipv6'
	option reliability '2'
 
config interface 'wanb'
	option enabled '0'
	list track_ip '1.0.0.1'
	list track_ip '1.1.1.1'
	list track_ip '208.67.222.222'
	list track_ip '208.67.220.220'
	option family 'ipv4'
	option reliability '1'
 
config interface 'wanb6'
	option enabled '0'
	list track_ip '2606:4700:4700::1001'
	list track_ip '2606:4700:4700::1111'
	list track_ip '2620:0:ccd::2'
	list track_ip '2620:0:ccc::2'
	option family 'ipv6'
	option reliability '1'
 
config member 'wan_m1_w3'
	option interface 'wan'
	option metric '1'
	option weight '3'
 
config member 'wan_m2_w3'
	option interface 'wan'
	option metric '2'
	option weight '3'
 
config member 'wanb_m1_w2'
	option interface 'wanb'
	option metric '1'
	option weight '2'
 
config member 'wanb_m1_w3'
	option interface 'wanb'
	option metric '1'
	option weight '3'
 
config member 'wanb_m2_w2'
	option interface 'wanb'
	option metric '2'
	option weight '2'
 
config member 'wan6_m1_w3'
	option interface 'wan6'
	option metric '1'
	option weight '3'
 
config member 'wan6_m2_w3'
	option interface 'wan6'
	option metric '2'
	option weight '3'
 
config member 'wanb6_m1_w2'
	option interface 'wanb6'
	option metric '1'
	option weight '2'
 
config member 'wanb6_m1_w3'
	option interface 'wanb6'
	option metric '1'
	option weight '3'
 
config member 'wanb6_m2_w2'
	option interface 'wanb6'
	option metric '2'
	option weight '2'
 
config policy 'wan_only'
	list use_member 'wan_m1_w3'
	list use_member 'wan6_m1_w3'
 
config policy 'wanb_only'
	list use_member 'wanb_m1_w2'
	list use_member 'wanb6_m1_w2'
 
config policy 'balanced'
	list use_member 'wan_m1_w3'
	list use_member 'wanb_m1_w3'
	list use_member 'wan6_m1_w3'
	list use_member 'wanb6_m1_w3'
 
config policy 'wan_wanb'
	list use_member 'wan_m1_w3'
	list use_member 'wanb_m2_w2'
	list use_member 'wan6_m1_w3'
	list use_member 'wanb6_m2_w2'
 
config policy 'wanb_wan'
	list use_member 'wan_m2_w3'
	list use_member 'wanb_m1_w2'
	list use_member 'wan6_m2_w3'
	list use_member 'wanb6_m1_w2'
 
config rule 'https'
	option enabled '0'
	option sticky '1'
	option dest_port '443'
	option proto 'tcp'
	option use_policy 'balanced'
 
config rule 'default_rule_v4'
	option enabled '0'
	option dest_ip '0.0.0.0/0'
	option use_policy 'balanced'
	option family 'ipv4'
 
config rule 'default_rule_v6'
	option enabled '0'
	option dest_ip '::/0'
	option use_policy 'balanced'
	option family 'ipv6'

The globals configuration provides the following options.

Name Type Required Default Description
mmx_mask string Yes 0x3f00 Firewall mask value as a hex value
iif_rule_base number Yes 1000 Base priority for per-interface incoming interface ip rules. Default preserves historical behaviour.
fwmark_rule_base number Yes 2000 Base priority for per-interface fwmark lookup ip rules. Must be at least 61 above IIF rule base.
unreachable_rule_base number Yes 3000 Base priority for per-interface fwmark unreachable ip rules. Must be at least 62 above Fwmark rule base.
logging boolean No 0 Global firewall logging. This must be enabled for any rule specific logging to occur.
verbose_logging boolean No 0 Enables debug level logging for mwan3
loglevel string No notice Firewall loglevel. Valid options are: emerg, alert, crit, error, warning, notice, info, debug
rt_table_lookup mixed No (none) Networks from these routing tables bypass mwan3 policy routing and use the default route. Enter routing table number or name (see /etc/iproute2/rt_tables).
bypass_network string No (none) Traffic to these networks bypasses mwan3 policy routing and uses the default route. Enter IPv4 or IPv6 CIDR.
ipv6_routing string No (none) :!: Only available in version 3.7 or later.
Enable mwan3 IPv6 routing features.
ipv6_failover_type string No (off) :!: Only available in version 3.7 or later.
Configure the IPv6 routing failover method. Valid values are off, translate, deprecate

For each WAN interface configure an interface section and define how each WAN interface is tested for up/down status. Each interface section must have a name that corresponds with the interface name in your network config. The settings are described below.

Name Type Required Default Description
Interface name string yes (none) The OpenWrt interface name as defined in /etc/config/network. Do not use interface names like pppoe-wanX.
track_gateway boolean no 0 Automatically track the next hop peer. Applies only to point to point connections.
track_method string yes ping Tracking method to use for this interface with mwan3track. Valid options are: ping arping httping nping-tcp nping-udp nping-icmp nping-arp. Additional tracking methods will only be available if the required packages are installed.
enabled boolean no 0 Should mwan3 run on/track this interface?
track_ip list of ip addresses no (none) The host(s) to test if interface is still alive. If this value is missing the interface is always considered up.
flush_conntrack list no (none) Flush global firewall conntrack table on interface events. See conntrack flushing behaviour for a list of interface events.
reliability number no 1 Number of track_ip hosts that must reply for the test to be considered as successful. Ensure there are at least this many track_ip hosts defined or the interface will always be considered down.
count number no 1 Number of checks to send to each host with each test.
timeout number no 4 Number of seconds to wait for an echo-reply after an echo-request.
interval number no 10 Number of seconds between each test.
failure_interval number no <interval> Number of seconds between each test during teardown on failure detection.
recovery_interval number no <interval> Number of seconds between each test during tearup on recovery detection.
keep_failure_interval boolean no 0 In the event of an error, keep the number of seconds between each test during teardown (failure detection).
check_quality boolean no 0 In addition to the interface being up, the check_quality options can check the overall link quality with packet loss and/or latency measurements.
failure_latency number no 1000 Maximum packet latency milliseconds when check_quality is enabled.
recovery_latency number no 500 Minimum packet latency in milliseconds when check_quality is enabled.
failure_loss number no 40 Maximum packet loss as a percentage when check_quality is enabled.
recovery_loss number no 10 Minimum packet loss as a percentage when check_quality is enabled.
initial_state string no online If the value is offline, then traffic goes via this interface only if mwan3track checked the connection first. If the value is online, then the mwan3track test is ignored and the interface is marked as online immediately. Valid options are: online or offline.
family string no ipv4 The specific protocol family this interface handles. Valid options are: ipv4 or ipv6.
max_ttl number no 60 Time to live (TTL) or hop limit. Only valid if track_method is ping.
size number no 56 Size of ping packets to use in bytes. Only valid if track_method is ping.
up number no 5 Number of successful tests to considered link as alive.
down number no 5 Number of failed tests to considered link as dead.
snat6 boolean no 0 :!: Only available in version 3.7 or later.
SNAT to the IPv6 interface's primary global address
ipv6_translate_prefix_<wan> list no one prefix per delegation :!: Only available in version 3.7 or later.
Map the named WAN's whole delegation(s) onto explicit target prefix(es), preserving their internal layout. Takes precedence over the pool carve.
ipv6_translate_pool string no (auto)/IPv6 prefix) :!: Only available in version 3.7 or later.
For 1:1 IPv6 prefix translation.
ipv6_translate_ula list no auto and/or ULA prefixes :!: Only available in version 3.7 or later.
Carry ULA LAN segments by 1:1 translation. auto discovers them, an explicit prefix names one directly. Requires ipv6_translate_pool.

In most cases the default values should work for most configurations. The primary reason to change the default settings is to shorten the time before an interface is failed-over (by reducing the ping interval and number of pings before the interface is down) or lengthen the time to avoid a false link failure report. Please note that if you change the timeout value on low bandwidth interfaces (e.g. 3G) or busy interfaces, that false positives of marking a WAN down can occur. A timeout value of less then 2 seconds is not recommended.

A typical interface section using the default tracking method of ping looks like this, mostly using the default values of all options described above:

config interface 'wan'
	option enabled '1'
	list track_ip '1.0.0.1'
	list track_ip '1.1.1.1'
	list track_ip '208.67.222.222'
	list track_ip '208.67.220.220'
	option family 'ipv4'

Reliable public IP addresses to ping (DNS providers)

Below are a collection of public IPv4 and IPv6 DNS resolvers that accept ICMP and can be used with mwan3track for tracking the connection state of interfaces. These are public DNS resolvers with high availability and generally reliable to use as endpoints to confirm network connectivity. Alternatively you can also use your ISPs DNS resolvers. Where possible you want to have the shortest hops for checking if a WAN is up or not.

Note: Some public DNS services may not respond to ICMP requests or intermittently drop requests due to throttling or rate limiting. You may see mwan3track ping failures due to this behaviour. To avoid this scenario marking an interface as down, ensure you have multiple track_ip options configured across different providers and that the reliability setting is set to a value to tolerate occasional brief failures to avoid triggering the WAN interface to be marked as down.

Provider IPv4 resolvers IPv6 resolvers
Level 3 communications 209.244.0.3
209.244.0.4
4.2.2.1
4.2.2.2
4.2.2.3
4.2.2.4
4.2.2.5
4.2.2.6
Google DNS 8.8.8.8
8.8.4.4
2001:4860:4860::8888
2001:4860:4860::8844
OpenDNS 208.67.222.222
208.67.220.220
2620:0:ccc::2
2620:0:ccd::2
Cloudflare 1.1.1.1
1.0.0.1
2606:4700:4700::1111
2606:4700:4700::1001
Hurricane Electric (HE.net) 74.82.42.42 2001:470:20::2
Quad9 9.9.9.9
149.112.112.112
2620:fe::fe
2620:fe::9
Yandex 77.88.8.8
77.88.8.1
2a02:6b8::feed:0ff
2a02:6b8:0:1::feed:0ff
Verisign 64.6.64.6
64.6.65.6
2620:74:1b::1:1
2620:74:1c::2:2
OpenNIC 185.121.177.177
169.239.202.202
2a05:dfc7:5::53
2a05:dfc7:5353::53
Neustar 156.154.70.1
156.154.71.1
2610:a1:1018::1
2610:a1:1019::1

You can find additional public DNS resolvers to use at publicdns.xyz.

Flushing conntrack

mwan3 handles conntrack differently compared to the original iptables version. On the first packet of a new flow, mwan3 stamps the packet with an interface fwmark and saves that mark into the conntrack entry's ct mark field. All subsequent packets in the same connection restore the ct mark back to the packet mark at the start of the prerouting/output chain, bypassing policy re-evaluation entirely. This means that routing policy changes do not take effect for established connections until their conntrack entries are removed.

Conntrack flushes are automatic and more targeted rather than globally. Conntrack flushes always occur on an interface fail, never on a recovery. On a fail, any active connections would be interrupted given a WAN interface signalling an down/offline state. Global conntrack flushing is usually not necessary, but can be customised if required.

If you need a more targeted conntrack flush (for example your backup WAN is metered or much lower performance), you can use a custom hook.

Each member represents an interface with a metric and a weight value. Members are referenced in policies to define a pool of interfaces with corresponding metric and load-balancing weight. Members can't be used for rules directly. The default settings are described below:

Name Type Required Default Description
Member name string yes (none) The name of this member configuration, which is then referenced in policies
interface string yes (none) Member applies to this interface (use the same interface name as used in the mwan3 interface section, above)
metric number no 1 Members within one policy with a lower metric have precedence over higher metric members
weight number no 1 Members with same metric will distribute load based on this weight value

A typical member section looks like this:

config member 'wan_m1_w3'
	option interface 'wan'
	option metric '1'
	option weight '3'

Policies define how traffic is routed through the different WAN interface(s). Every policy has to have one or more members assigned to it, which defines the policy's traffic behaviour. If a policy has a single member, traffic will only go out that member. If a policy has more than one member, it will either load-balance among members or use one member but fail-over to another, depending on how the members are configured.

If there is more than one member assigned to a policy, members within the policy with a lower metric have precedence over higher metric members. Members with the same metric will load-balance. Load-balancing members (with same metric) will distribute load based on assigned weights values.

Key points about policies:

  • Policies are profiles grouping one or more members controlling how mwan3 distributes traffic.
  • Member interfaces with lower metrics are used first.
  • Member interfaces with the same metric will be load-balanced.
  • Load-balanced member interfaces distribute more traffic out those with higher weights.
  • Names may contain characters A-Z, a-z, 0-9, _ and no spaces.
  • Names must be 15 characters or less
  • Policies may not share the same name as configured interfaces, members or rules.
Name Type Required Default Description
Policy name string yes (none) :!: Must be no more than 15 characters
Unique name for the policy.
use_member list yes (none) One or more members assigned to this policy.
last_resort string no unreachable Determine the fallback routing behaviour if all WAN members in the policy are down.
Valid options are:
unreachable (reject)
blackhole (drop)
default (use main routing table)

A typical policy section looks like this:

config policy 'balanced'
	list use_member 'wan_m1_w3'
	list use_member 'wanb_m1_w3'
	list use_member 'wan6_m1_w3'
	list use_member 'wanb6_m1_w3'
	option last_resort 'unreachable'
  • If a policy is not referenced by a specific traffic rule, the policy will not do anything, so it is fine to leave unused policies in place in case they are desired in the future.
  • If you have a traffic rule that matches a policy, but all the members (interfaces) for that policy are down, the exit strategy for that policy defaults to unreachable.
  • A working mwan3 config has at least 1 policy configured.

A rule describes what traffic to match and what policy to assign for that traffic.

Key points about rules:

  • Rules specify how traffic will be routed and policy is applied.
  • Rules can be based on source MAC, source/destination IP address, TCP/UDP port, or a specific protocol type.
  • Rules are matched in the order of top to bottom.
  • When the first rule is matched all rules below any matched rule are ignored.
  • Traffic not matching any defined rule will be routed using the main routing table.
  • Traffic destined for known (other than default) networks is handled by the main routing table.
  • Traffic matching a rule where all interfaces for that policy are down will be blackholed.
  • Rule names may contain characters A-Z, a-z, 0-9, _ and no spaces.
  • Rules may not share the same name as configured interfaces, members or policies.
Name Type Required Default Description
Rule name string yes (none) The unique name of the rule.
:!: Must be no more than 15 characters
enabled boolean yes 1 If the rule is enabled in the mwan3 configuration
use_policy string yes (none) Use this policy for traffic that matches or set to default to use the default routing table to lookup
src_ip IP address no any Match traffic from the specified source IP address
src_mac list no (none) Match the MAC address of the client device as seen on the local network. The match sees the last layer 2 hop, so every client behind a downstream router presents that router's address.
src_port port or range no any Match traffic from the specified source port or port range, if relevant proto is specified
proto string no all Match traffic using the given protocol. Valid options are: tcp, udp, icmp or all
dest_ip IP address no any Match traffic directed to the specified destination IP address
dest_port port or range no any Match traffic directed at the given destination port or port range, if relevant proto is specified
fwmark string no (none) Match packet mark; enter value/mask in hex. Mask must not overlap mwan3 internal mark bits.
sticky boolean no 0 Allow traffic from the same source IP address within the timeout limit to use same wan interface as prior session
timeout number no 600 Stickiness timeout value in seconds
family string no any Address family for which to apply the rule. Valid options are: ipv4, ipv6 or any
logging boolean no 0 Enables firewall rule logging (global mwan3 logging setting must also be enabled)
ipset_src list no none Source NFT set. Match source addresses against this nft set
ipset list no none Destination NFT set. Match destination addresses against this nft set (declare sets in /etc/config/mwan3; dnsmasq syntax: nftset=/youtube.com/4#inet#mwan3#youtube)

The default configuration provides three standard rules, a https sticky rule for both IPv4 and IPv6 and two default rules (one for IPv4 and one for IPv6) to match any other traffic which would not have been matched by any preceding rules. You can add your rules above these or modify them as needed.

A typical rule section looks like this:

config rule 'default_rule_v4'
	option dest_ip '0.0.0.0/0'
	option family 'ipv4'
	option use_policy 'wan_wanb'

It is also possible to group multiple ports or source/destination IP addresses under a single rule using a comma.

config rule 'multi_ip_rule'
       option dest_ip '1.1.1.1,2.2.2.2,3.3.3.3,4.4.4.4'
       option family 'ipv4'
       option use_policy 'wan_only'

The comma will be translated and correctly create the required entries from a single rule definition.

For rules that require a large amount of destination IP addresses, it is recommended to use IP sets as this more optimised to group large amounts of IP addresses, or CIDR ranges.

Sticky support

Sticky (or sticky sessions) can be enabled on a per-rule basis and lets you route a new session over the same WAN interface as the previous session, as long as the time between the new and the previous session is shorter then the specified timeout value. This is mainly useful for load balanced routing and can solve some problems with TLS sessions which don't allow a new source address within the same session on some websites.

The default configuration mwan3 has a rule that treats all TCP 443 (SSL/TLS) for both IPv4 and IPv6 traffic with a sticky rule to help prevent issues.

config rule 'https'
    option sticky '1'
    option dest_port '443'
    option proto 'tcp'
    option use_policy 'balanced'

When applying the “sticky” option, any traffic matching this rule will now use the sticky behaviour. When a packet for a new session matches this rule, its source IP address and interface mark are stored in an ipmark. When a packet for a second new session from the same LAN host within the timeout period matches this rule, it will use the same WAN interface as the first packet and the timeout counter is reset back to the specified timeout value.

The default timeout value is 600 seconds (10 minutes).

IP sets are nftables address sets referenced by mwan3 rules. Sets can be populated with static entries, loaded from a file, or populated at runtime by dnsmasq name resolution.

Name Type Required Default Description
name string yes (none) The unique name of the IP set.
:!: Set names must not begin with “mwan3_” (reserved for internal use).
enabled boolean no 1 When an IP set is attached to one or more enabled rule, this cannot be changed in the LuCI interface.
family string yes ipv4 The IP version of the set, either ipv4 or ipv6
entry list no (none) Static entries: IP addresses or CIDR subnets (eg “192.168.1.1” or “10.0.0.0/8”).
domain list no (none) Domain names resolved by dnsmasq and added to the set at runtime (eg “youtube.com”)
loadfile file no (none) File of IP addresses or CIDRs, one per line; lines beginning with # are ignored
maxelem number no unlimited Maximum number of elements in the set. Leave empty for no limit.
timeout number no 0 Entry lifetime in seconds. 0 means entries do not expire.
counters number no 0 Track per-element packet and byte counts.

An example IP set in the mwan3 config:

config ipset
        option name 'wan'
        option family 'ipv4'
        list domain 'example.net'

You can then reference the IP set in a rule:

config rule 'ipset_wan'
        option ipset 'wan'
        option use_policy 'wan_only'
        option family 'ipv4'

IPv6 extensions are currently in BETA and require running mwan3 3.7 BETA, which is currently a pre-release build. If you are currently using masq6 on any firewall zones, you should disable this before using IPv6 extensions in mwan3.

mwan3 can manage IPv6 across multiple WAN connections with the same facilities it provides for IPv4: failover, load balancing and policy-based steering. IPv6 needs different machinery from IPv4 because there is normally no NAT: each WAN delegates its own globally routable prefix, your LAN devices hold addresses from those prefixes, and a device's source address ties each connection to one WAN.

By default everything is routed natively with no translation, and translation is applied automatically only to the specific connections that are steered, balanced or failed over onto a WAN that does not route the prefix.

To use IPv6 extensions you must opt-in via the globals config option:

config globals 'globals'
	option ipv6_routing 'on'

With ipv6_routing set to “on”, mwan3 takes ownership of IPv6 routing. Forwarded IPv6 traffic is routed by its source prefix: devices using WAN A's prefix go out WAN A, devices using WAN B's prefix go out WAN B, and addresses are untouched on the wire.

Define IPv6 WANs as mwan3 interfaces with option family 'ipv6' and tracking hosts, exactly as you would for IPv4. With the option off (the default), mwan3 leaves IPv6 routing exactly as it was before.

:!: When using mwan3 IPv6 extensions you should turn off IPv6 masquerading (option masq6 '1') on any firewall zone if it is enabled. mwan3 translates exactly the connections that need it and leaves all other IPv6 traffic untouched, so blanket masquerading is unnecessary and defeats the transparency of the native path. If you have any other NAT6 firewall configuration applied at the firewall level this should also be removed.

Load balancing and steering

IPv6 rules, members and policies work exactly as they do for IPv4: a rule with option family 'ipv6', or one with no family option at all (which applies to both families), can steer matched traffic to a chosen WAN or balance it across several.

When a rule or policy sends a connection out a WAN that does not own its source prefix, mwan3 automatically translates the source address so the traffic is valid on that WAN, either using 1:1 translation if defined, or the fallback masquerade if 1:1 is not configured.

Nothing needs to be configured for translation to work: every IPv6 WAN carries an always-on masquerade fallback for foreign sources, and it does nothing until a connection actually needs it. The 1:1 translation is optional and requires an explicit configuration parameter to enable.

mwan3 has two ways of making a foreign source valid on a WAN, and you choose between them on a per WAN basis:

  • Masquerade (the default, no configuration needed): all foreign source connections are masqueraded to the WAN's own address, source ports may be rewritten, and the carried devices are not reachable from outside. This is how IPv4 NAT behaves.
  • 1:1 prefix translation (opt-in): every carried device gets its own stable external address, keeping the host part of the address it already has, but under a different prefix. Ports are never rewritten, the mapping is the same every time, and each device remains individually reachable from outside (subject to your firewall rules). Enable it with ipv6_translate_pool on the carrying WAN.

The masquerade also acts as the safety net for 1:1 translation: if a 1:1 mapping cannot be set up for some LAN segment (no space left in the pool, or a configuration problem), connections from that segment use the masquerade instead, with an explicitly logged warning. Traffic is never dropped for wont of a mapping.

Configuring 1:1 prefix translation

On the WAN that will carry another WAN's traffic, set:

config interface 'wan6b'
	option enabled '1'
	option family 'ipv6'
	option ipv6_translate_pool 'auto'

With auto, mwan3 carves translation prefixes out of the WAN's own delegation, automatically avoiding every prefix the router already uses. All in-use GUA segments are discovered automatically by mwan3.

If the delegation has no spare space, it is possible to set an explicit spare prefix instead, for example option ipv6_translate_pool '2001:db8:f000::/56'.

A manually specified pool must be a prefix that is routed to this WAN. Each carried LAN segment gets its own equal-sized block from the pool, so different segments never collide on the wire.

For finer-grained control, an override list maps a specific WAN's whole delegation onto a target prefix of your choosing, preserving its internal subnet layout. The list lives on the carrying WAN and is named after the carried WAN:

config interface 'wan6b'
	option enabled '1'
	option family 'ipv6'
	option ipv6_translate_pool 'auto'
	list ipv6_translate_prefix_wan6 '2001:db8:ff00::/56'

If the carried WAN holds more than one delegated prefix, add one list entry per delegation: the entries pair up with the delegations in the order they are discovered, first entry to first delegation, and mwan3 logs a warning if the counts differ.

Each target must be at least as large as the delegation it maps. An unusable entry is skipped with a warning and that delegation is then handled by the automated allocator or, as a fallback, the masquerade instead. Mapping overrides take precedence over the automated allocation for the WAN they name.

Segments are discovered from the WAN delegations, so a LAN numbered from a ULA prefix is never carried automatically and its connections use the masquerade.

To give ULA addressed devices the benefits of 1:1 translation, opt their segments in with the ipv6_translate_ula list on the carrying WAN. An entry of auto carries every ULA prefix the router assigns or has delegated downstream. An explicit prefix entry carries a segment mwan3 cannot discover, such as a ULA network behind a downstream router reached by a static route. The two kinds of entry can be mixed.

config interface 'wan6b'
	option enabled '1'
	option family 'ipv6'
	option ipv6_translate_pool 'auto'
	list ipv6_translate_ula 'auto'

ULA segments take their targets from the same translation, so ipv6_translate_pool must be set. Without a pool the list ipv6_translate_ula is ignored with a logged warning and the masquerade carries the traffic. An entry that is not a ULA prefix is also ignored with a warning.

Failover

Failover for IPv6 is selected globally:

config globals 'globals'
	option ipv6_routing 'on'
	option ipv6_failover_type 'translate'

Both failover modes require ipv6_routing 'on'.

Translate

When tracking declares an IPv6 WAN down, traffic from its prefix is carried over a surviving WAN for the duration of the outage, using that WAN's translation: 1:1 if you configured it there, masquerade otherwise.

When the failed WAN recovers, new connections return to it natively, and connections that failed over are left to finish on the survivor rather than being cut. The survivor is the first enabled, online IPv6 interface in your configuration order, other than the failed one, so order your interface sections with the preferred fallback first.

If you have an explicitly configured mwan3 rule, for example a catch_all rule that uses a failover policy, the WAN named as the higher metric failover member will carry the flow during the outage rather than falling back to the configured order of interface definition.

Deprecate

The no-NAT alternative for networks where the LAN holds addresses from every WAN's prefix (each WAN's prefix delegated to the LAN, with devices addressing themselves by SLAAC).

On a failure, mwan3 marks the failed WAN's prefix as deprecated in router advertisements. Devices then prefer their surviving-prefix address for new connections, which leave through the surviving WAN natively with no translation at all. The prefix is restored on recovery. This mode relies on LAN devices honouring address deprecation, which is a standard part of a host network stack and requires no explicit configuration.

No failover (off)

This is the default behaviour.

When a WAN fails, connections that already exist at the moment of failover are broken. Under translate, because the surviving WAN gives them a different, translated source that the far end rejects and under deprecate because the failed WAN's path is gone. Under translate and deprecate, new connections recover immediately. This is inherent to IPv6 multihoming, not a limitation of mwan3.

Configuration examples

All of these configurations require the addition of track_ip options, which are not shown here. The options below are confined to the IPv6-specific options.

Simplest configuration. Masquerade will be used.

config globals 'globals'
	option ipv6_routing 'on'
	option ipv6_failover_type 'translate'
 
config interface 'wan6'
	option enabled '1'
	option family 'ipv6'
 
config interface 'wan6b'
	option enabled '1'
	option family 'ipv6'

Simplest configuration for 1:1 translation. Each WAN will use its own delegation and translate foreign sources onto this delegation, assuming it's large enough

config globals 'globals'
	option ipv6_routing 'on'
	option ipv6_failover_type 'translate'
 
config interface 'wan6'
	option enabled '1'
	option family 'ipv6'
	option ipv6_translate_pool 'auto'
 
config interface 'wan6b'
	option enabled '1'
	option family 'ipv6'
	option ipv6_translate_pool 'auto'

Use 1:1 translation for failover. Have wan6b allocate 1:1 translation from its own delegated prefix. Have wan6 translate 1:1 to a separately ISP-delegated prefix. Both fall back to masquerade if a 1:1 map produces a collision.

config globals 'globals'
	option ipv6_routing 'on'
	option ipv6_failover_type 'translate'
 
config interface 'wan6'
	option enabled '1'
	option family 'ipv6'
	option ipv6_translate_pool '2001:db8:ff00::/48'
 
config interface 'wan6b'
	option enabled '1'
	option family 'ipv6'
	option ipv6_translate_pool 'auto'

Use prefix deprecation for failover. Have wan6 allocate 1:1 translation from its own delegated prefix. Have wan6b translate 1:1 to a specifically defined prefix for wan6, fall back to the autocarve for any other carried IPv6 interface and fall back to masquerade if a 1:1 map produces a collision.

Since failover in this example is deprecate, the 1:1 translation is only applied for rule steering and load balancing.

config globals 'globals'
	option ipv6_routing 'on'
	option ipv6_failover_type 'deprecate'
 
config interface 'wan6'
	option enabled '1'
	option family 'ipv6'
	option ipv6_translate_pool 'auto'
 
config interface 'wan6b'
	option enabled '1'
	option family 'ipv6'
	option ipv6_translate_pool 'auto'
	list ipv6_translate_prefix_wan6 '2001:db8:ff00::/56'

Carry a ULA-numbered LAN with 1:1 translation over wan6b, discovering the ULA segments automatically. wan6 carries any steered or failed-over traffic with the masquerade.

config globals 'globals'
	option ipv6_routing 'on'
	option ipv6_failover_type 'translate'
 
config interface 'wan6'
	option enabled '1'
	option family 'ipv6'
 
config interface 'wan6b'
	option enabled '1'
	option family 'ipv6'
	option ipv6_translate_pool 'auto'
	list ipv6_translate_ula 'auto'

Limitations of mwan3 and IPv6 extensions

  • Translation requires connection tracking. Forwarded flows you have exempted from tracking with firewall notrack rules are not translated and cannot be carried across WANs. On their own WAN they work as normal.
  • Inbound connections to 1:1 translated addresses are still subject to your firewall rules: the translation gives a device a reachable address, and the firewall decides whether anything gets through to it. A rule that admits an inbound connection must match the device's real address, not the translated one, because the translation is undone before the firewall sees the packet.
  • Existing connections do not survive a failover, as described above.
  • The router applies ULA changes made in the network configuration without any event mwan3 can react to. After adding or removing a ULA prefix or its LAN assignment, reload mwan3.
  • Android devices acquire a ULA address only from a SLAAC-only advertisement, with no DHCPv6 served on the segment, and will not join a network whose only addressing is ULA. Keep IPv4 available on LANs with Android clients.
  • On a dual-stack LAN, hosts normally prefer IPv4 over a ULA source for global destinations (RFC 6724), so the ULA path sees most use on segments without IPv4. Current Android is a notable exception and uses its ULA freely.

mwan3 can be managed entirely via command line and config files or through the LuCI interface, which will modify the config files for you.

#mwan3
Syntax: mwan3 [command]

Available commands:
start                    Load nftables rules, ip rules and ip routes
stop                     Unload nftables rules, ip rules and ip routes
restart                  Reload nftables rules, ip rules and ip routes
ifup <iface>             Load rules and routes for specific interface
ifdown <iface>           Unload rules and routes for specific interface
interfaces               Show interfaces status
policies                 Show currently active policy
connected                Show directly connected networks
rules                    Show active rules
status                   Show all status
internal <ipv4|ipv6>     Show internal configuration <default: ipv4>
use <iface> <cmd>        Run a command bound to <iface> and avoid mwan3 rules

Key user configuration files:

  • /etc/config/mwan3
  • /etc/mwan3.user

For diagnostic purposes, there is also a mwan3-diag command which will provide various routing and configuration data information, useful for debugging. Public IPv4 or IPv6 values are automatically obfuscated and replaced with placeholders like PUB4_ or PUB6_ You can directly write this diagnostic data to your router filesystem (providing you have enough space in ramdisk or have external storage).

Note: Sharing this data may require you upload it to a service like pastebin.com due to the large amount of characters produced which may exceed limits on forums or other services.

mwan3-diag > /tmp/mwan3-diagnostics

When mwan3 is enabled traffic originating from the router or any LAN client will follow the policy and rules defined in the mwan3 config. If you need to test routing/traffic on a specific WAN interface, outside of the rules set the mwan3 use command allows you to test individual WAN interfaces bypassing existing rules and using the routing table for that WAN interface.

Ping google.co.uk with an interface named “wan”:

mwan3 use wan ping -4 google.co.uk

Make a traceroute request over IPv4 to openwrt.org with an interface named “wanb”:

mwan3 use wanb traceroute -4 -w 1 openwrt.org

If you have installed the LuCI web interface page, this adds a MultiWAN Manager entry in two places:

  • Status > MultiWAN Manager
  • Network > MultiWan Manager

The status section is generally for viewing the current state of configured WAN interfaces, the current configuration of mwan3 e.g. active rules IP sets, routing table configuration and other diagnostic and troubleshooting options.

The network section is for managing the configuration of mwan3, being able to modify globals, interfaces, policies, members, rules and IP sets, which automatically writes to the mwan3 config for you via UCI. You can also edit the /etc/mwan3.user file through LuCI here.

In addition to multi-WAN functionality, mwan3 implements policy-based routing (PBR), which allows you to configure a variety of traffic policies for specific protocols, destination addresses or domains. The easiest way to think about policies is to reverse the configuration order:

Traffic rule → Policy → Member → Network interface

  • Traffic rule: This defines which specific traffic you want to match to route accordingly.
  • Policy: This is the specific policy you want to use for this traffic rule.
  • Member: The configuration that outlines how the defined policy will work.
  • Interface: The network interface the traffic will go through/use.

Load balancing is using multiple internet connections and distributing traffic across them. This is often used when you have multiple WAN connections with similar speeds or bandwidth, but this is not a strict requirement. The traffic can often be distributed evenly in a 50/50 configuration, but you can also have uneven traffic distribution such as 60/40, 80/20 etc. You control this with the defined member policies, using metric and weighting values. Load balancing will route traffic across multiple WANs, so you would see different outbound IP addresses for various requests in a sequence.

One caveat to be aware of with load balancing is TLS traffic. Having an IP address change within the same TLS session is often problematic and may break some websites or services. To resolve this, mwan3 implements a default sticky rule for TLS traffic. This ensures TLS traffic that was originally routed over a specific network interface continues to go over this WAN interface when within the defined timeout period. While this does technically remove true load balancing for TLS traffic, it is often needed to maintain stable and working TLS sessions for various websites or services.

Another scenario to be aware of with load balancing is that if one of the interfaces being used for load balancing is down, depending on the distribution pattern of the traffic, you will see some traffic start to fail and not work until all interfaces in the load balancing policy are working.

Failover is network redundancy, essentially having an additional one or more WAN connections as a backup or standby ready to be used if your primary WAN goes down. Unlike load balancing, a failover WAN does not need to be the same speed as the primary WAN and could often be a 4G/5G mobile connection, but any internet connection can be used.

The idea is that your secondary WAN connection should not really be used too often, only for testing its availability and when your primary WAN fails. For true failover/redundancy your secondary WAN should not be associated or related to your primary WAN in any way, i.e. different network providers, two separate physical incoming connections using different infrastructure.

When your primary WAN fails and you have configured your mwan3 configuration to use failover, mwan3 will route all traffic through your secondary WAN, until the primary WAN recovers.

For further redundancy, you can also consider having an uninterruptible power supply (UPS) which your main OpenWrt router and ONT/modems for your WAN connections are plugged into to maintain power and network during a power outage.

Split tunnelling is dividing network/internet traffic into two separate paths. The most common approach is splitting traffic between a normal WAN connection and a VPN e.g. Wireguard. It is possible to combine split tunnelling with load balancing/failover management policies, but more often than not, split tunnelling is usually used to ensure that certain traffic always exits through a specific interface.

The approach you use to achieve split tunnelling is entirely dependent on your requirements. You can use a policy of everything defaulting to your main WAN and select traffic using a VPN, or the reverse, whereby all traffic is routed over a VPN and you specify specific traffic to bypass this and use your WAN.

To make split tunneling easier, IP sets can be used to automatically route traffic via domain name rules, where the underlying IP addresses are resolved via DNS resolution and stored in an nftset, which can be used in one or more traffic rule.

While the simulator evaluates the current mwan3 rules and config to determine how the traffic will be routed, you should always verify using network tests like traceroute or curl to confirm traffic is being routed as expected.

When using the LuCI web interface, a traffic path simulator is available at Network > MultiWAN Manager > Simulator to help with testing rules. This option can help test rules to make your traffic policies are correctly configured.

You can enter one or more traffic parameters to simulate which mwan3 rule matches and which policy would handle the traffic. IP fields accept addresses or hostnames - hostnames are resolved via the local DNS server e.g. dnsmasq. Rules with a constraint on a field you leave blank will not match.

Example tests using the simulator feature:

Simulating traffic to 8.8.8.8 (Google DNS resolver)

# No rule specifically matched so the default fallback IPv4 rule was used

First matching rule: default_rule_v4
Match: IPv4 | dst 0.0.0.0/0
Policy: wan_wanb

Live member state:
wan (metric 1, weight 1) — 100%
wanb (metric 2, weight 1) — online
Traffic will use: wan

Also matched (shadowed by first rule)

Shadowed rule	Match	Policy
default_rule_v6	IPv6 | dst ::/0	wan_wanb

Simulating traffic to mullvad.net which is included in an IP set policy

# mullvad.net is included in an existing IP set and a specific IP set rule exists so it is matched

First matching rule: ipset_vpn
Match: IPv4 | nftset vpn
Policy: wg_wgb

Live member state:
wg (metric 1, weight 1) — 100%
wgb (metric 2, weight 1) — offline
Traffic will use: wg

Also matched (shadowed by first rule)
Shadowed rule	Match	Policy
default_rule_v4	IPv4 | dst 0.0.0.0/0	wan_wanb
default_rule_v6	IPv6 | dst ::/0	wan_wanb

While the Traffic Simulator feature is useful for quick testing, you should use one or more direct traffic/routing tests to confirm your routing policies are working. You'll first want to ensure your WAN interfaces and routing tables are correctly setup and reporting as online and healthy, then you'll want to proceed with your network testing.

  1. Confirm WAN interfaces are showing as online.
  2. Confirm routing tables are correct for each WAN interface.
  3. Verify load balancing policy behaviour (if applicable).
  4. Verify failover policy behaviour (if applicable).
  5. Verify specific WAN policies (if applicable)

Generating network traffic from any LAN client is the best way to verify traffic rules. You can run a small script which executes a curl request frequently, like the example below. It is also possible to use other tools like traceroute when not specifically testing a single protocol or port.

for i in $(seq 1 20); do echo -n "$i: "; curl -4s --max-time 10 http://ifconfig.me; echo; sleep 3; done

This script will make a curl request to ifconfig.me every 4 seconds and return the IP address of the WAN interface used for the traffic, this will help determine which WAN interface was used for the request.

Note: This script uses plain HTTP to avoid triggering the default “sticky” rule which would send TLS traffic over the same WAN IP within the timeout threshold. See sticky support for further details on this behaviour.

You should see an alternating response of different IP addresses matching your configured policy and rules. The rotating nature of IP addresses will vary based on the member and metric values configured for the traffic policy being used. This could be in a 50/50, 60/40, or other scenario. This will depend on the metric/weighting configuration defined.

The key point is that you should see regular rotation of the outgoing IP address in network tests.

To simulate a failover event, you can do any of the following:

  1. Issue an ifdown event on any WAN interface
  2. Temporarily block pings to a specified track_ip being used via the firewall.
  3. Stop the primary WAN network interface.
  4. Physically remove or disconnect the ethernet cable for the primary WAN to allow mwan3 to fail the primary WAN interface and trigger failover.

Start by running the curl test before you fail the primary WAN. You should see your primary WAN as the outgoing IP address. Now use any of the methods above to trigger a failover event to have mwan3 mark the primary WAN as “down”.

From the curl requests, you should now see the secondary WAN IP address being returned once the interface has been marked as down.

Now recover the primary WAN interface and wait for mwan3 to mark the interface as online again. You should now see the primary WAN IP address being returned once mwan3 has determined the interface as online again.

When verifying a specific policy, you can use a variety of tools like curl, wget, traceroute or traceroute6 to confirm traffic/routing, providing you are using option proto 'all'. If you are using a specific protocol, you will need to test with a method which matches that protocol.

Example if the request of mullvad.net was routed via a Wireguard interface using any protocol, on a traceroute you'd expect to see the local Wireguard gateway and then the various exit nodes which Mullvad use for the region configured.

traceroute to mullvad.net (45.83.223.209), 30 hops max, 46 byte packets
 1  10.64.0.1 (10.64.0.1)  7.453 ms  7.541 ms  5.656 ms
 2  irb-317.as15-10g.lon3.uk.m247.ro (89.238.154.5)  24.423 ms  62.571 ms  21.894 ms
 3  irb-1996.agg1v.lon3.uk.m247.ro (82.102.29.185)  36.338 ms  40.462 ms  41.811 ms
 4  *  *  *
 5  146.70.4.121 (146.70.4.121)  7.797 ms  146.70.4.123 (146.70.4.123)  6.591 ms  *
 6  *  ldn-b3-link.ip.twelve99.net (213.248.75.200)  7.832 ms  7.808 ms
 7  ldn-b3-link.ip.twelve99.net (213.248.75.200)  6.258 ms  7.012 ms  8.373 ms
 8  ldn-bb1-link.ip.twelve99.net (62.115.120.74)  34.419 ms  prs-bb1-link.ip.twelve99.net (62.115.135.25)  36.659 ms  ldn-bb1-link.ip.twelve99.net (62.115.140.72)  34.239 ms
 9  prs-bb1-link.ip.twelve99.net (62.115.135.25)  34.880 ms  35.200 ms  35.687 ms
10  ffm-bb1-link.ip.twelve99.net (62.115.123.12)  36.080 ms  35.232 ms  *
11  31173services-ic-352031.ip.twelve99-cust.net (62.115.185.13)  30.048 ms  zch-b3-link.ip.twelve99.net (62.115.126.199)  30.751 ms  30.372 ms
12  *  *  31173services-ic-352031.ip.twelve99-cust.net (62.115.185.13)  30.298 ms
...

There are additional testing methods available, these are just examples to help verify traffic policies.

mwan3 includes in a /etc/mwan3.user file which is interpreted as a shell script. Here you can extend mwan3 to perform additional actions or notifications on certain hotplug events for one or more interfaces which mwan3 is tracking. e.g. When an interface goes down or up.

This file must always start with a shebang (#!/bin/sh) and provides the following environment variables for use with additional custom logic requirements.

Variable name Definition
$ACTION Hotplug events mwan3 uses. Which are ifdown, ifup, connected, disconnected
$INTERFACE Name of the interface which an hotplug event relates to (e.g. wan or wwan)
$DEVICE Physical device name which an hotplug event relates to (e.g. eth0 or wwan0)

The /etc/mwan3.user file in some cases will also be able to target additional iface hotplug events that mwan3 doesn't directly use but netifd does e.g. ifupdate. While these events are not directly used by mwan3track, they are still available to hook into in this script.

Note: $DEVICE is not populated on an ifdown event, use $INTERFACE instead for this event.

There are various use cases for the /etc/mwan3.user file. Specific conntrack flushing behaviour, implementing custom notifications when an interface state changes i.e. email notifications.

Be mindful when implementing something like notifications without limiting what $ACTION you wish to target you will have multiple notifications per interface when the state changes. This will further increase for each interface you have configured with mwan3track. You can use conditional statements to limit your custom logic only applying to certain events, below are a couple of examples of demonstrating this.

Example 1: Specific conntrack flushing behaviour

#!/bin/sh
 
[ "$ACTION" = "connected" ] || [ "$ACTION" = "ifup" ] || exit 0
 
. /lib/functions.sh
. /lib/mwan3/common.sh
. /lib/mwan3/mwan3.sh
 
config_load mwan3
mwan3_init
mwan3_flush_marked_conntrack

Example 2: Targeting the ifup event on a specific WAN interface

#!/bin/sh
if [ "${ACTION}" = "ifup" ] && [ "${INTERFACE}" = "wan" ] ; then
   # Do something on an ifup event for the wan interface only
fi

Example 3: Email notifications for specific interface events

#!/bin/sh
if [ "${ACTION}" = "ifdown" ] || [ "${ACTION}" = "ifup" ] ; then
 # Only on either an ifdown or ifup event for any interface
 if [ "${INTERFACE}" != "loopback" ] && [ "${INTERFACE}" != "self" ] ; then
 # Exclude events for interfaces loopback and self
   (/bin/sleep 180; /usr/bin/mailsend -to alerts@example.com -from alerts@example.com -ssl -port 465 -auth \
   -smtp mail.example.com -sub "$HOSTNAME $ACTION $INTERFACE $DEVICE" +cc +bc -user "alerts@example.com" \
   -pass "user_password" -cs "us-ascii" -enc-type "7bit" -M "mwan3: $ACTION $INTERFACE $DEVICE" >/dev/null) &
 fi
fi

Some notes about the last example:

  • The “sleep 180” statement, a somewhat artificial delay, is required in cases when /etc/mwan3.user gets executed before connectivity is completely “settled” (for instance: ifup of the first active wan interface)
  • mailsend with SSL support was chosen as mail client, for other options and SMTP clients: smtp.client
  • Finally observe that the whole sleep/mailsend statement is parenthesis enclosed and ended with and & (ampersand) sending its execution to background so that /etc/mwan3.user finishes in a timely manner
  • Last modified: 2026/08/31 09:25
  • by jamesmacwhite