TP-Link Archer C7 v2 + openvpn DCO

Please help with openvpn DCO on subject device.

CPU still use 30-50% CPU per connection.

What should i do to make it work?

root@OpenWrt:~# uname -a
Linux OpenWrt 6.6.104 #0 Fri Sep 19 21:19:38 2025 mips GNU/Linux
root@OpenWrt:~# cat /etc/config/network

config interface 'loopback'
        option device 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option ula_prefix 'fd2f:8dd8:72db::/48'
        option packet_steering '1'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'eth1.1'
        list ports 'tap0'

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option ipaddr '192.168.234.1'
        option netmask '255.255.255.0'
        option ip6assign '60'

config interface 'wan'
        option device 'eth0.2'
        option proto 'dhcp'

config switch
        option name 'switch0'
        option reset '1'
        option enable_vlan '1'

config switch_vlan
        option device 'switch0'
        option vlan '1'
        option ports '2 3 4 5 0t'

config switch_vlan
        option device 'switch0'
        option vlan '2'
        option ports '1 6t'

root@OpenWrt:~# cat /etc/config/firewall

config defaults
        option syn_flood '1'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'

config zone
        option name 'lan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        list network 'lan'

config zone
        option name 'wan'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'
        list network 'wan'

config forwarding
        option src 'lan'
        option dest 'wan'

config rule
        option name 'Allow-DHCP-Renew'
        option src 'wan'
        option proto 'udp'
        option dest_port '68'
        option target 'ACCEPT'
        option family 'ipv4'

config rule
        option name 'Allow-Ping'
        option src 'wan'
        option proto 'icmp'
        option icmp_type 'echo-request'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-IGMP'
        option src 'wan'
        option proto 'igmp'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-DHCPv6'
        option src 'wan'
        option proto 'udp'
        option dest_port '546'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-MLD'
        option src 'wan'
        option proto 'icmp'
        option src_ip 'fe80::/10'
        list icmp_type '130/0'
        list icmp_type '131/0'
        list icmp_type '132/0'
        list icmp_type '143/0'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Input'
        option src 'wan'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        list icmp_type 'router-solicitation'
        list icmp_type 'neighbour-solicitation'
        list icmp_type 'router-advertisement'
        list icmp_type 'neighbour-advertisement'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Forward'
        option src 'wan'
        option dest '*'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-IPSec-ESP'
        option src 'wan'
        option dest 'lan'
        option proto 'esp'
        option target 'ACCEPT'

config rule
        option name 'Allow-ISAKMP'
        option src 'wan'
        option dest 'lan'
        option dest_port '500'
        option proto 'udp'
        option target 'ACCEPT'

config redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'SSH_ROUTER'
        option src 'wan'
        option src_dport '9999'
        option dest_ip '192.168.234.1'
        option dest_port '9999'

config rule 'Allow_OpenVPN_Inbound'
        option target 'ACCEPT'
        option src '*'
        option proto 'udp'
        option dest_port '6994'

root@OpenWrt:~# cat /etc/config/openvpn

config openvpn 'myvpn'
        option enabled '1'
        option verb '3'
        option proto 'udp'
        option port '6994'
        option dev 'tap0'
        option mode 'server'
        option tls_server '1'
        option keepalive '10 120'
        option ca '/etc/openvpn/ca.crt'
        option cert '/etc/openvpn/my-server.crt'
        option key '/etc/openvpn/my-server.key'
        option dh '/etc/openvpn/dh.pem'
        option client_config_dir '/etc/openvpn/ccd'
        list route '192.168.234.0 255.255.255.0'
        list route '192.168.231.0 255.255.255.0'
        option cipher 'none'
        option auth 'none'
        list data_ciphers 'AES-128-GCM'
        list data_ciphers 'AES-128-GCM'

root@OpenWrt:~# lsmod |grep dco
ip6_udp_tunnel         12288  1 ovpn_dco_v2
ovpn_dco_v2            53248  0
udp_tunnel             20480  1 ovpn_dco_v2
root@OpenWrt:~# logread -e openvpn |grep DCO
Tue Nov 25 19:56:45 2025 daemon.notice openvpn(myvpn)[15978]: OpenVPN 2.6.14 mips-openwrt-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [MH/PKTINFO] [AEAD] [DCO]
Tue Nov 25 19:56:45 2025 daemon.notice openvpn(myvpn)[15978]: DCO version: N/A
Tue Nov 25 20:17:57 2025 daemon.notice openvpn(myvpn)[22743]: OpenVPN 2.6.14 mips-openwrt-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [MH/PKTINFO] [AEAD] [DCO]
Tue Nov 25 20:17:57 2025 daemon.notice openvpn(myvpn)[22743]: DCO version: N/A
root@OpenWrt:~#

does the other end support DCO ?

swap to WireGuard and/or get a new(er) device.

Use WireGuard which is more performant than openvpn even with dco

I do not think tap is compatible with dco

The vlan tagging without offload on 2 cpu ports consumes 200% of CPU just routing flat....

ip -d link show | grep -i dco

Have no idea how to get Wireguard working as L2 bridge.

Tun has same problem. But on client side on Ubuntu openvpn with DCO and TAP interface looks like workable :))

2025-11-19 16:16:39 us=153939 OpenVPN 2.6.16 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
2025-11-19 16:16:39 us=154238 DCO version: 0.2.20251017
root@OpenWrt:~# ip -d link show |grep -i dco
BusyBox v1.36.1 (2025-09-19 21:19:38 UTC) multi-call binary.

Usage: ip [OPTIONS] address|route|link|neigh|rule [ARGS]

OPTIONS := -f[amily] inet|inet6|link | -o[neline]

ip addr add|del IFADDR dev IFACE | show|flush [dev IFACE] [to PREFIX]
ip route list|flush|add|del|change|append|replace|test ROUTE
ip link set IFACE [up|down] [arp on|off] [multicast on|off]
        [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]
        [master IFACE | nomaster] [netns PID]
ip neigh show|flush [to PREFIX] [dev DEV] [nud STATE]
ip rule [list] | add|del SELECTOR ACTION

Option -d not support.

Without -d empty output:

root@OpenWrt:~# ip  link show |grep -i dco
root@OpenWrt:~#

https://forum.openwrt.org/t/vpn-eoip-over-nat/174920/#4-by-vgaetera

Do you have anything HW accelerated in cat /proc/crypto output? If not... then you're stuck with least heavy SW encryption. Kernel-side encryption like WG will be the best because context switching (e.g. OpenVPN which works in userspace) will eat even more. If answer is 'yes' then you have to try to employ it somehow.

Absolutely not on ath79 :wink:

Well, in this case he should proceed with plan A, as it was already suggested )))

1 Like

cat /proc/crypto output:

name         : sha224
driver       : sha224-generic
module       : sha256_generic
priority     : 100
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 64
digestsize   : 28

name         : sha256
driver       : sha256-generic
module       : sha256_generic
priority     : 100
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 64
digestsize   : 32

name         : ccm(aes)
driver       : ccm_base(ctr(aes-generic),cbcmac(aes-generic))
module       : kernel
priority     : 100
refcnt       : 7
selftest     : passed
internal     : no
type         : aead
async        : no
blocksize    : 1
ivsize       : 16
maxauthsize  : 16
geniv        : <none>

name         : ctr(aes)
driver       : ctr(aes-generic)
module       : kernel
priority     : 100
refcnt       : 7
selftest     : passed
internal     : no
type         : skcipher
async        : no
blocksize    : 1
min keysize  : 16
max keysize  : 32
ivsize       : 16
chunksize    : 16
walksize     : 16

name         : cbcmac(aes)
driver       : cbcmac(aes-generic)
module       : kernel
priority     : 100
refcnt       : 13
selftest     : passed
internal     : no
type         : shash
blocksize    : 1
digestsize   : 16

name         : lzo
driver       : lzo-scomp
module       : lzo
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : scomp

name         : lzo
driver       : lzo-generic
module       : lzo
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : compression

name         : lzo-rle
driver       : lzo-rle-scomp
module       : lzo_rle
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : scomp

name         : lzo-rle
driver       : lzo-rle-generic
module       : lzo_rle
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : compression

name         : sha384
driver       : sha384-generic
module       : sha512_generic
priority     : 100
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 128
digestsize   : 48

name         : sha512
driver       : sha512-generic
module       : sha512_generic
priority     : 100
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 128
digestsize   : 64

name         : jitterentropy_rng
driver       : jitterentropy_rng
module       : jitterentropy_rng
priority     : 100
refcnt       : 1
selftest     : passed
internal     : no
type         : rng
seedsize     : 0

name         : sha3-512
driver       : sha3-512-generic
module       : sha3_generic
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 72
digestsize   : 64

name         : sha3-384
driver       : sha3-384-generic
module       : sha3_generic
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 104
digestsize   : 48

name         : sha3-256
driver       : sha3-256-generic
module       : sha3_generic
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 136
digestsize   : 32

name         : sha3-224
driver       : sha3-224-generic
module       : sha3_generic
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 144
digestsize   : 28

name         : stdrng
driver       : drbg_nopr_hmac_sha512
module       : drbg
priority     : 207
refcnt       : 1
selftest     : passed
internal     : no
type         : rng
seedsize     : 0

name         : stdrng
driver       : drbg_nopr_hmac_sha256
module       : drbg
priority     : 206
refcnt       : 1
selftest     : passed
internal     : no
type         : rng
seedsize     : 0

name         : stdrng
driver       : drbg_nopr_hmac_sha384
module       : drbg
priority     : 205
refcnt       : 1
selftest     : passed
internal     : no
type         : rng
seedsize     : 0

name         : stdrng
driver       : drbg_nopr_hmac_sha1
module       : drbg
priority     : 204
refcnt       : 1
selftest     : passed
internal     : no
type         : rng
seedsize     : 0

name         : stdrng
driver       : drbg_pr_hmac_sha512
module       : drbg
priority     : 203
refcnt       : 1
selftest     : passed
internal     : no
type         : rng
seedsize     : 0

name         : stdrng
driver       : drbg_pr_hmac_sha256
module       : drbg
priority     : 202
refcnt       : 1
selftest     : passed
internal     : no
type         : rng
seedsize     : 0

name         : stdrng
driver       : drbg_pr_hmac_sha384
module       : drbg
priority     : 201
refcnt       : 1
selftest     : passed
internal     : no
type         : rng
seedsize     : 0

name         : stdrng
driver       : drbg_pr_hmac_sha1
module       : drbg
priority     : 200
refcnt       : 1
selftest     : passed
internal     : no
type         : rng
seedsize     : 0

name         : crc32c
driver       : crc32c-generic
module       : crc32c_generic
priority     : 100
refcnt       : 4
selftest     : passed
internal     : no
type         : shash
blocksize    : 1
digestsize   : 4

name         : ghash
driver       : ghash-generic
module       : kernel
priority     : 100
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 16
digestsize   : 16

name         : aes
driver       : aes-generic
module       : kernel
priority     : 100
refcnt       : 13
selftest     : passed
internal     : no
type         : cipher
blocksize    : 16
min keysize  : 16
max keysize  : 32

name         : ecb(cipher_null)
driver       : ecb-cipher_null
module       : kernel
priority     : 100
refcnt       : 1
selftest     : passed
internal     : no
type         : skcipher
async        : no
blocksize    : 1
min keysize  : 0
max keysize  : 0
ivsize       : 0
chunksize    : 1
walksize     : 1

name         : digest_null
driver       : digest_null-generic
module       : kernel
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : shash
blocksize    : 1
digestsize   : 0

name         : compress_null
driver       : compress_null-generic
module       : kernel
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : compression

name         : cipher_null
driver       : cipher_null-generic
module       : kernel
priority     : 0
refcnt       : 1
selftest     : passed
internal     : no
type         : cipher
blocksize    : 1
min keysize  : 0
max keysize  : 0

What means plan A?

If not... then you're stuck with least heavy SW encryption. Kernel-side encryption like WG will be the best because context switching (e.g. OpenVPN which works in userspace) will eat even more.

Wg is routed only. There is no option for an l2 bridge with wireguard.

Why do you need to operate at l2 (vs L3)? What is the goal?

You can run gretap over wg with increased MTU, it will be even slower on your hardware/
gretap is yet another memory copy, half speed from it on top of all you (dont) have.