BGP FlowSpec for DDoS Mitigation: Rules, Actions, Safety
BGP FlowSpec for DDoS mitigation lets you distribute packet-filter rules (destination, protocol, ports, packet length, TCP flags) to your routers through BGP, so you can drop or rate-limit only the attack traffic instead of blackholing the whole victim IP. Use discard when the attack signature has no legitimate traffic, use rate-limit when legitimate traffic shares the same protocol or port, and always put strict guardrails around any automation that announces rules.
This guide covers the rule structure, the two main actions, vendor support, example configurations, and the mistakes that cause FlowSpec outages.
How a FlowSpec rule is built
FlowSpec is defined in RFC 8955 (IPv4) and RFC 8956 (IPv6). A rule is a BGP NLRI in the flow address family (AFI/SAFI 1/133 for IPv4, 2/133 for IPv6). It has two parts: match components and actions carried as extended communities.
| Type | Match component | Typical DDoS use |
|---|---|---|
| 1 | Destination prefix | The victim, usually a /32 or /128 |
| 2 | Source prefix | Rarely useful against spoofed floods |
| 3 | IP protocol | UDP, TCP, ICMP, GRE |
| 4/5/6 | Port / destination port / source port | Source port 123, 53, 11211, 1900 for reflection |
| 7/8 | ICMP type / code | Echo flood filtering |
| 9 | TCP flags | SYN-only or RST floods |
| 10 | Packet length | Reflection responses with consistent sizes |
| 11 | DSCP | Occasionally for marked traffic |
| 12 | Fragment | Dropping non-initial fragments |
All components in a rule are ANDed. A rule that says destination 203.0.113.10/32, UDP, source port 123, length 400-500 matches only NTP monlist-style responses to that host. Everything else to that IP keeps flowing, which is the main advantage over RTBH.
Actions: rate-limit vs discard
The standard actions are extended communities:
- traffic-rate (0x8006): rate in bytes per second. A rate of 0 means discard.
- traffic-action (0x8007): sample/terminal bits.
- redirect (0x8008): redirect to a VRF via route target. Redirect-to-IP is vendor-specific or draft-based, so check your platform.
- traffic-marking (0x8009): rewrite DSCP.
When to discard
Discard when the signature has effectively zero legitimate traffic to the victim:
- UDP source port 11211 (memcached) toward a host that doesn't run a memcached client
- UDP source port 1900 (SSDP) or 389 (CLDAP) toward web servers
- Non-initial fragments toward a service that doesn't need them
- Protocols you don't serve (for example GRE or ESP to a web server)
When to rate-limit
Rate-limit when legitimate traffic uses the same protocol and port:
- UDP source port 53 toward a recursive resolver
- UDP source port 123 toward an NTP client
- ICMP echo reply or echo request
Know the limits of rate-limiting. The policer is an aggregate bucket, so legitimate and attack packets compete for the same budget. On most platforms the policer is applied per router or per line card, not globally across your network. The rate is in bytes per second, so convert carefully from Mbps (10 Mbps is 1,250,000 bytes/s).
The saturated-link caveat
FlowSpec on your edge router filters traffic after it has crossed your transit link. If the attack is larger than the link, the link is already full and the drop happens too late. Options are to get FlowSpec accepted by your upstream (many transit providers don't offer it, so ask), to use RTBH with a provider community as a last resort, or to move the traffic to a scrubbing service. NixGuard Edge does the last one: your prefixes are announced from the scrubbing edge and clean traffic returns over a GRE tunnel with a BGP session inside.
Vendor support overview
Support varies by platform, line card, and software release. Always check the hardware match and action limits before depending on it.
| Platform | FlowSpec client | Notes |
|---|---|---|
| Juniper MX / PTX | Yes | family inet flow, rules land in inetflow.0 |
| Cisco IOS XR (ASR 9000, NCS) | Yes | Needs local-install under flowspec |
| Cisco IOS XE | Platform-dependent | Check your model and release |
| Nokia SR OS, Huawei, Arista | Yes, on supported platforms | Check TCAM and action limits |
| MikroTik RouterOS | Not a FlowSpec client in versions we're aware of | Verify your version; use RTBH plus firewall rules |
| Linux | No native kernel support | Use ExaBGP or GoBGP as a controller and push nftables rules |
Router configuration examples
Documentation addresses are used throughout. AS64496 is your AS, 192.0.2.10 is the controller or detector, 203.0.113.0/24 is your customer space.
Juniper
set protocols bgp group FLOWSPEC type internal
set protocols bgp group FLOWSPEC local-address 192.0.2.1
set protocols bgp group FLOWSPEC family inet flow no-validate FS-IMPORT
set protocols bgp group FLOWSPEC import FS-IMPORT
set protocols bgp group FLOWSPEC neighbor 192.0.2.10
set policy-options policy-statement FS-IMPORT term OURS from rib inetflow.0
set policy-options policy-statement FS-IMPORT term OURS from route-filter 203.0.113.0/24 prefix-length-range /32-/32
set policy-options policy-statement FS-IMPORT term OURS then accept
set policy-options policy-statement FS-IMPORT term DEFAULT then reject
The no-validate knob is needed when the controller is an iBGP speaker that doesn't originate your unicast routes (more on validation below). The import policy then becomes your safety net.
Cisco IOS XR
flowspec
address-family ipv4
local-install interface-all
!
route-policy FS-IN
if destination in (203.0.113.0/24 ge 32 le 32) then
pass
else
drop
endif
end-policy
!
router bgp 64496
address-family ipv4 flowspec
neighbor 192.0.2.10
remote-as 64496
address-family ipv4 flowspec
route-policy FS-IN in
Verify the route-policy match syntax on your release, since flow routes can be matched differently from unicast prefixes on some versions.
Linux with ExaBGP
Linux can't enforce FlowSpec by itself, but ExaBGP is a convenient way to originate rules for your routers:
announce flow route {
match {
destination 203.0.113.10/32;
protocol udp;
source-port =123;
packet-length >=400&<=500;
}
then {
rate-limit 1250000;
}
}
GoBGP equivalent:
gobgp global rib -a ipv4-flowspec add \
match destination 203.0.113.10/32 protocol udp source-port '=123' \
then rate-limit 1250000
To discard, use discard in ExaBGP or rate-limit 0.
MikroTik fallback
If your edge is RouterOS and can't take FlowSpec, use RTBH for emergencies and a static raw rule for known signatures:
/ip firewall raw add chain=prerouting action=drop \
protocol=udp src-port=11211 dst-address=203.0.113.10 \
comment="memcached reflection"
Validation: why your rule may be ignored
RFC 8955 section 6 defines a validation procedure. A FlowSpec route with a destination prefix is only accepted if it was announced by the same peer that announced the best unicast route for that destination, and no more-specific unicast route comes from a different peer. In a typical deployment, where a collector or detector injects rules into your edge routers, this check fails by design and the routes go inactive.
Fix it by either making the validating router learn the rules from the same session as the unicast route, or by disabling validation on that session and replacing it with a strict import policy. Don't disable validation without the policy.
Safe automation guardrails
FlowSpec is powerful and can discard your own traffic across the whole network in seconds. Automation should enforce these limits:
- Destination must be inside your prefixes, and for automatic rules, only /32 or /128. Enforce this on the router, not just in the controller.
- Never allow a rule without a destination component. A rule that matches only on protocol and port affects the whole network.
- Protect legitimate ports. Block automatic discards that match TCP source port 443 or 80, UDP/TCP 53 toward resolvers, and your BGP and management ports.
- Start with rate-limit for ambiguous signatures. Promote to discard after confirming counters.
- Cap rule count per session with
maximum-prefixor equivalent, and know your hardware filter limit. - Add automatic expiry. Withdraw rules after the attack ends plus a cool-down. Stale rules are a common source of mystery outages.
- Log every announcement with the triggering threshold, flow sample, and operator.
- Test the whole chain in a lab or with a single test /32 before enabling production automation.
- Keep RTBH as the fallback when FlowSpec resources are exhausted or the attack saturates the link.
Public postmortems exist in which a single malformed FlowSpec rule caused router crashes across a network. Keep your platforms patched and validate rule syntax before announcement.
Common mistakes
- Assuming the policer is global. It's usually per router or per line card.
- Rate-limiting a reflection attack that is larger than the link.
- Matching source prefixes on spoofed traffic.
- Forgetting IPv6, which needs its own address family and rules.
- Leaving validation on and wondering why rules show as inactive.
- Using FlowSpec to hide a capacity problem instead of upgrading or moving to scrubbing.
Where NixMon fits
FlowSpec works best when a detector decides what to announce. NixMon analyzes NetFlow v5/v9, IPFIX, and sFlow with sub-second analytics, applies per-IP and per-prefix bps/pps thresholds, and can respond with BGP FlowSpec announcements or RTBH, or it can hand off to the NixGuard on-prem firewall. For attacks that exceed your upstream capacity, NixGuard Edge is available for networks with their own ASN and at least one /24. You can try the platform with the 15-day free trial, no credit card needed.
Frequently asked questions
What is the difference between BGP FlowSpec and RTBH?
RTBH drops all traffic to a victim IP, which finishes the attack but also makes the target unreachable. FlowSpec matches on protocol, ports, packet length and other fields, so you can drop only the attack traffic and keep the service online.
Should I use rate-limit or discard in FlowSpec?
Use discard when the signature has no legitimate traffic, such as memcached reflection toward a host that doesn't use memcached. Use rate-limit when legitimate traffic shares the protocol or port, such as DNS responses toward a resolver.
Why is my FlowSpec route installed but inactive?
The most common cause is RFC 8955 validation. The rule must come from the same peer as the best unicast route for the destination. Either fix the session design or disable validation on that session and use a strict import policy.
Will FlowSpec protect me if the attack fills my transit link?
Not if the rules are applied only on your edge router, because the traffic has already used the link. You need your upstream to accept FlowSpec, use an upstream RTBH community, or route traffic through a scrubbing service.