Blogs

FortiGate Software Switch Offloading

24 Jul 2026

FTNT_TechXperts_1024x600px_260520.jpg

Software switches aren't exactly popular on a FortiGate, but sometimes they're necessary. One issue is that the traffic can't be routed to the Network Processing Unit (NPU). This means the CPU has to take over that task, which is inefficient and can lead to performance problems.

It would be great if traffic in a software switch could be sent to the NPU instead, taking advantage of one of FortiGate's biggest strengths: offloading. That's exactly what this article looks at.

The setup:
  • FortiGate 70G on 7.6.7
  • FortiSwitch 424E on 7.6.6
  • FortiAP 241K on 7.6.5
  • Windows 11 client
  • Android Smartphone

An SSW VLAN was created (SSW stands for "Software SWitch" in this post), along with a tunnel SSW SSID, both part of the software switch SSW-LAB.

fgt_software_switch_offloading.drawio.png

 

The Software Switch

As the name suggests, a software switch is a virtual component (technically, it's a bridge group), with its own advantages and disadvantages. One advantage is that more types of interfaces can be added to the switch, such as tunnel SSIDs. One disadvantage, as mentioned above, is the offloading issue.
When creating the software switch, it's important to decide between an implicit and an explicit intra-switch policy, since this setting can't be changed later.

intra_switch_setting.png

The basic difference between the two settings is that with implicit, no firewall policies need to be created for switch members to communicate with each other. With explicit, firewall policies must be created.
Implicit also has a distinct quirk: no sessions are created for traffic between members, which is exactly why offloading to the NPU doesn't work. The FortiGate CPU maintains a table of MAC-to-port information, and that's our bottleneck.
Without a session, this traffic also won't show up in debug flows or in the logs. With explicit, sessions are created and are visible.

How do we get offloading to work?

If the software switch is created with the explicit intra-switch policy, firewall policies need to be created to allow or deny traffic, just as with any other policy. This can be as strict or as loose as needed — if all that's required is offloading, without any real firewalling, this can be achieved with the classic any-any permit policy.
For this article, a web server was set up on Windows 11 client, accessed from Android smartphone.
With a suitable policy allowing traffic from the SSID to the VLAN, the connection can be tested and a session generated.

intra_policy.png

After loading the website, offloading can be verified. First, in the FortiView Session Monitor on the dashboard:

fortiview_sessions_offload.png

The NPU Accelerate column shows both the status and the processor type.
On the CLI, the command diagnose sys session list can be used (it's recommended to configure a filter beforehand, e.g., diagnose sys session filter dst x.x.x.x).

 

session info: proto=6 proto_state=05 duration=1 expire=0 timeout=3600 refresh_dir=both flags=00000000 socktype=0 sockport=0 av_idx=0 use=3 
origin-shaper= 
reply-shaper= 
per_ip_shaper= 
class_id=0 ha_id=0 policy_dir=0 tunnel=/ vlan_cos=0/0 
state=log may_dirty br npu f00 
statistic(bytes/packets/allow_err): org=3207/12/1 reply=2415/9/1 tuples=2 
tx speed(Bps/kbps): 2853/22 rx speed(Bps/kbps): 2148/17 
orgin->sink: org pre->post, reply pre->post dev=37->38/38->37 gwy=0.0.0.0/0.0.0.0 
hook=pre dir=org act=noop 192.168.101.20:60844->192.168.101.22:443(0.0.0.0:0) 
hook=post dir=reply act=noop 192.168.101.22:443->192.168.101.20:60844(0.0.0.0:0) 
pos/(before,after) 0/(0,0), 0/(0,0) 
misc=0 policy_id=10 pol_uuid_idx=695 auth_info=0 chk_client_info=0 vd=0 
serial=000042af tos=ff/ff app_list=0 app=0 url_cat=0 
rpdb_link_id=00000000 ngfwid=n/a 
npu_state=0x000c00 ofld-O ofld-R 
npu info: flag=0x00/0x00, offload=0/0, ips_offload=0/0, epid=16/23, ipid=23/16, vlan=0x0000/0x0078 
vlifid=23/16, vtag_in=0x0000/0x0078 in_npu=1/1, out_npu=1/1, fwd_en=0/0, qid=2/5, ha_divert=0/0 
no_ofld_reason: 
hrx info: valid=0/0, qid=0/0, npuid=0/0, sublink=0/0 

session info: proto=6 proto_state=05 duration=1 expire=0 timeout=3600 refresh_dir=both flags=00000000 socktype=0 sockport=0 av_idx=0 use=3 
origin-shaper= 
reply-shaper= 
per_ip_shaper= 
class_id=0 ha_id=0 policy_dir=0 tunnel=/ vlan_cos=0/0 
state=log may_dirty br npu f00 
statistic(bytes/packets/allow_err): org=2366/9/1 reply=1730/6/1 tuples=2 
tx speed(Bps/kbps): 2053/16 rx speed(Bps/kbps): 1501/12 
orgin->sink: org pre->post, reply pre->post dev=37->38/38->37 gwy=0.0.0.0/0.0.0.0 
hook=pre dir=org act=noop 192.168.101.20:60842->192.168.101.22:443(0.0.0.0:0) 
hook=post dir=reply act=noop 192.168.101.22:443->192.168.101.20:60842(0.0.0.0:0) 
pos/(before,after) 0/(0,0), 0/(0,0) 
misc=0 policy_id=10 pol_uuid_idx=695 auth_info=0 chk_client_info=0 vd=0 
serial=000042ae tos=ff/ff app_list=0 app=0 url_cat=0 
rpdb_link_id=00000000 ngfwid=n/a 
npu_state=0x000c00 ofld-O ofld-R 
npu info: flag=0x00/0x00, offload=0/0, ips_offload=0/0, epid=16/23, ipid=23/16, vlan=0x0000/0x0078 
vlifid=23/16, vtag_in=0x0000/0x0078 in_npu=1/1, out_npu=1/1, fwd_en=0/0, qid=7/4, ha_divert=0/0 
no_ofld_reason: 
hrx info: valid=0/0, qid=0/0, npuid=0/0, sublink=0/0 

 

The most important lines are npu state and npu info, since these only appear if the session was actually offloaded.
In the Forward Traffic log, we can see that the interfaces are the individual software switch members.

forward_traffic_ssw.png

With this simple configuration — an explicit intra-switch policy software switch and a matching firewall policy — the goal of traffic offloading has been achieved.
What about traffic that doesn't pass between software switch members?

When traffic leaves the software switch

Here's the bad news. Regardless of whether the intra-switch policy is explicit or implicit, the same rule applies: traffic between software switch members and other interfaces can't be offloaded.
In these situations, traffic always originates from the software switch as the source interface, never from the individual members.
Here's an example with WAN traffic:

wan_traffic.png

If we check the FortiView Sessions Monitor, we can also see the missing offloading in the NPU Accelerated column:

fortiview_sessions_no_offload.png

On the CLI, we can also see the reason why:

session info: proto=6 proto_state=01 duration=3552 expire=3434 timeout=3600 refresh_dir=both flags=00000000 socktype=0 sockport=0 av_idx=0 use=3 
origin-shaper= 
reply-shaper= 
per_ip_shaper= 
class_id=0 ha_id=0 policy_dir=0 tunnel=/ vlan_cos=0/255 
state=log may_dirty f00 
statistic(bytes/packets/allow_err): org=1966/16/1 reply=1802/16/1 tuples=2 
tx speed(Bps/kbps): 0/0 rx speed(Bps/kbps): 0/0 
orgin->sink: org pre->post, reply pre->post dev=39->3/3->39 gwy=192.168.1.1/0.0.0.0 
hook=post dir=org act=snat 192.168.101.20:53654->142.251.127.188:5228(192.168.1.202:53654) 
hook=pre dir=reply act=dnat 142.251.127.188:5228->192.168.1.202:53654(192.168.101.20:53654) 
pos/(before,after) 0/(0,0), 0/(0,0) 
misc=0 policy_id=14 pol_uuid_idx=697 auth_info=0 chk_client_info=0 vd=0 
serial=000036d0 tos=ff/ff app_list=0 app=0 url_cat=0 
rpdb_link_id=80000000 ngfwid=n/a 
npu_state=0x040108 
no_ofld_reason: non-npu-intf 
hrx info: valid=0/0, qid=0/0, npuid=0/0, sublink=0/0 

 

The reason is no_ofld_reason: non-npu-intf, which unfortunately can't be resolved, since the CPU is fully involved in this type of traffic.

Wrapping Up

Hopefully this article on software switch offloading was useful, and offers something worth keeping in mind for the future.
If you have suggestions for future posts, would like to see configurations, also in video format, or want to give feedback, please send them to techxperts_central@exclusive-networks.com

Latest blogs

View all Blogs

Start growing your business

Whether you need a quote, advice, want to become a partner, or want to take advantage of our global services, we are here to help.

Get in touch