Description
Add a basic ACL/firewall engine to grout, implemented in modules/policy/. The ACL subsystem has two logical phases: matching and action. Both IPv4 and IPv6 must be supported.
Matching
ACL rules are organized in named rule sets (conceptually similar to ipsets in netfilter). Each rule set contains an ordered list of match entries. A match entry can filter on any combination of the following fields (derived from the BGP flowspec NLRI encoding defined in RFC 5575):
- Source and/or destination IP prefix (IPv4 or IPv6)
- IP protocol number
- Source and/or destination L4 port (single value or range)
- ICMP type and code
- TCP flags (with mask)
- DSCP value
- IP packet length (single value or range)
- IP fragment flags (don't-fragment, is-fragment, first-fragment, last-fragment)
- IPv6 flow label
Where possible, matching should be offloaded to hardware using DPDK rte_flow rules. When the NIC does not support the requested match pattern (or when rte_flow creation fails), fall back to software classification transparently. Hardware-offloaded flow rules should mark packets with an integer identifier (e.g. via RTE_FLOW_ACTION_TYPE_MARK) so that the software datapath can resolve the matching ACL rule in O(1) using a simple table lookup on the mark value, rather than walking the rule list.
Actions
The action phase is always performed in software. Supported actions for the initial implementation:
- Drop: discard the packet.
- Accept: let the packet continue through the graph.
- DSCP marking: rewrite the DSCP field in the IP header.
- Redirect to VRF: forward the packet through a different VRF's routing table.
- Redirect to nexthop: override the nexthop IP address for forwarding.
Each rule binds one match entry to one action. A default action (accept or drop) applies when no rule matches.
Datapath integration
The performance impact on the datapath must be minimal. If no ACL rule set is configured on an interface, the ACL graph nodes must be completely bypassed -- no per-packet check, no branch, no function call. This can be achieved by dynamically wiring or unwiring the ACL nodes in the rte_graph when ACL configuration changes (similar to how other optional features are handled during worker_graph_reload_all()).
Stateful matching
The existing conntrack infrastructure in modules/policy/ should be reusable for stateful ACL rules (e.g. "allow established/related" or connection-oriented filtering). The ticket does not require implementing stateful rules immediately, but the design must not preclude it.
API and CLI
The API is defined in modules/policy/api/gr_acl.h. It should follow the existing grout API patterns: enums for request/event codes, GR_REQ, GR_EVENT, set_attrs bitmask for updates, GR_REQ_STREAM for list operations.
The CLI (grcli) provides commands to create/delete rule sets, add/remove/reorder match entries, attach rule sets to interfaces (per-direction: ingress and/or egress), and display ACL state including hit counters.
FRR integration (future)
The ACL API is designed to map cleanly onto the FRR zebra dplane operations used by BGP flowspec. The six relevant dplane operations are:
DPLANE_OP_IPSET_ADD / DPLANE_OP_IPSET_DELETE -- create/destroy a named rule set
DPLANE_OP_IPSET_ENTRY_ADD / DPLANE_OP_IPSET_ENTRY_DELETE -- add/remove match entries in a rule set
DPLANE_OP_IPTABLE_ADD / DPLANE_OP_IPTABLE_DELETE -- bind a rule set to an action and attach it to interfaces
The FRR dplane plugin (frr/rule_grout.c) will translate these operations into grout ACL API calls. The ipset entry structure in FRR carries source/destination prefixes, protocol, port ranges, and a filter bitmask (MATCH_IP_SRC_SET, MATCH_PORT_DST_SET, MATCH_DSCP_SET, MATCH_ICMP_SET, MATCH_PROTOCOL_SET, MATCH_PKT_LEN_INVERSE_SET, MATCH_FRAGMENT_INVERSE_SET, MATCH_FLOW_LABEL_SET, etc.). The iptable structure carries the action (drop via ZEBRA_IPTABLES_DROP, or forward via ZEBRA_IPTABLES_FORWARD with a fwmark for VRF/nexthop redirect), plus additional match criteria like TCP flags, DSCP, packet length, and fragment flags. The fwmark field is used by FRR to correlate iptable rules with ip rule redirect entries.
FRR ipset types that must be supported: IPSET_NET (single prefix), IPSET_NET_PORT (prefix + port), IPSET_NET_NET (src + dst prefix), IPSET_NET_PORT_NET (src prefix + port + dst prefix).
This integration is not part of the initial implementation but drives the API design.
Context and Use Cases
The following examples illustrate how a BGP flowspec controller would program grout ACLs via FRR once the dplane integration is completed.
Discard traffic to a specific destination on a given protocol and port range:
A flowspec route for "drop all UDP traffic to 5.5.5.0/24 with destination port 50-90" results in:
- FRR creates an ipset of type
net,port (IPSET_NET_PORT) with one entry: dst=5.5.5.0/24, proto=17, dst_port=50-90.
- FRR creates an iptable referencing this ipset with action=
ZEBRA_IPTABLES_DROP.
- The grout dplane plugin translates this into: create a rule set, add one match entry (dst prefix + protocol + port range), bind with action=drop, attach to the relevant interface(s).
- Grout attempts to install a corresponding
rte_flow rule on the NIC. If that succeeds, matching packets are dropped (or marked) in hardware. Otherwise, the software datapath classifies and drops them.
Redirect traffic between VRFs:
A flowspec route with a route-target extended community (e.g. RT:192.168.1.1:100) redirects matching traffic to a different VRF:
- FRR creates an ipset of type
net,net (IPSET_NET_NET) with entry: src=10.0.0.0/8, dst=172.16.0.0/12.
- FRR creates an iptable with action=
ZEBRA_IPTABLES_FORWARD, fwmark=102.
- FRR installs an
ip rule (via DPLANE_OP_RULE_ADD) mapping fwmark 102 to routing table 102, which belongs to the target VRF.
- The grout dplane plugin maps this to: match entry (src + dst prefix), action=redirect-to-VRF(vrf_id).
DSCP remarking:
A flowspec route with ACTION_MARKING (DSCP value 46 = EF) applied to TCP traffic on port 5060 (SIP signaling):
- FRR creates an ipset of type
net,port with entry: dst=any, proto=6, dst_port=5060.
- FRR creates an iptable referencing the ipset with action=forward, and the BGP PBR layer applies DSCP marking.
- Grout translates this to: match TCP dst port 5060, action=set-dscp(46).
DDoS mitigation with remote-triggered blackhole:
An upstream provider advertises a flowspec route to drop traffic matching an attack signature, e.g. "drop all UDP fragments to 203.0.113.1/32 with packet length > 1400":
- FRR creates an ipset entry with dst=203.0.113.1/32, proto=17, fragment flags, packet length filter.
- Iptable action = drop.
- Grout installs the rule. If the NIC supports it, the offloaded
rte_flow rule drops attack traffic without consuming CPU cycles.
Selective nexthop override (redirect-to-IP):
A flowspec route with a redirect-IP extended community forces specific traffic through an alternate nexthop (e.g. a scrubbing center at 10.255.0.1):
- FRR creates the ipset/iptable pair as above.
- The action carries a redirect nexthop IP rather than a VRF.
- Grout maps this to: match entry, action=redirect-to-nexthop(10.255.0.1). The packet is forwarded using the specified nexthop instead of the FIB lookup result.
Description
Add a basic ACL/firewall engine to grout, implemented in
modules/policy/. The ACL subsystem has two logical phases: matching and action. Both IPv4 and IPv6 must be supported.Matching
ACL rules are organized in named rule sets (conceptually similar to ipsets in netfilter). Each rule set contains an ordered list of match entries. A match entry can filter on any combination of the following fields (derived from the BGP flowspec NLRI encoding defined in RFC 5575):
Where possible, matching should be offloaded to hardware using DPDK
rte_flowrules. When the NIC does not support the requested match pattern (or whenrte_flowcreation fails), fall back to software classification transparently. Hardware-offloaded flow rules should mark packets with an integer identifier (e.g. viaRTE_FLOW_ACTION_TYPE_MARK) so that the software datapath can resolve the matching ACL rule in O(1) using a simple table lookup on the mark value, rather than walking the rule list.Actions
The action phase is always performed in software. Supported actions for the initial implementation:
Each rule binds one match entry to one action. A default action (accept or drop) applies when no rule matches.
Datapath integration
The performance impact on the datapath must be minimal. If no ACL rule set is configured on an interface, the ACL graph nodes must be completely bypassed -- no per-packet check, no branch, no function call. This can be achieved by dynamically wiring or unwiring the ACL nodes in the
rte_graphwhen ACL configuration changes (similar to how other optional features are handled duringworker_graph_reload_all()).Stateful matching
The existing conntrack infrastructure in
modules/policy/should be reusable for stateful ACL rules (e.g. "allow established/related" or connection-oriented filtering). The ticket does not require implementing stateful rules immediately, but the design must not preclude it.API and CLI
The API is defined in
modules/policy/api/gr_acl.h. It should follow the existing grout API patterns: enums for request/event codes,GR_REQ,GR_EVENT,set_attrsbitmask for updates,GR_REQ_STREAMfor list operations.The CLI (
grcli) provides commands to create/delete rule sets, add/remove/reorder match entries, attach rule sets to interfaces (per-direction: ingress and/or egress), and display ACL state including hit counters.FRR integration (future)
The ACL API is designed to map cleanly onto the FRR zebra dplane operations used by BGP flowspec. The six relevant dplane operations are:
DPLANE_OP_IPSET_ADD/DPLANE_OP_IPSET_DELETE-- create/destroy a named rule setDPLANE_OP_IPSET_ENTRY_ADD/DPLANE_OP_IPSET_ENTRY_DELETE-- add/remove match entries in a rule setDPLANE_OP_IPTABLE_ADD/DPLANE_OP_IPTABLE_DELETE-- bind a rule set to an action and attach it to interfacesThe FRR dplane plugin (
frr/rule_grout.c) will translate these operations into grout ACL API calls. The ipset entry structure in FRR carries source/destination prefixes, protocol, port ranges, and a filter bitmask (MATCH_IP_SRC_SET,MATCH_PORT_DST_SET,MATCH_DSCP_SET,MATCH_ICMP_SET,MATCH_PROTOCOL_SET,MATCH_PKT_LEN_INVERSE_SET,MATCH_FRAGMENT_INVERSE_SET,MATCH_FLOW_LABEL_SET, etc.). The iptable structure carries the action (drop viaZEBRA_IPTABLES_DROP, or forward viaZEBRA_IPTABLES_FORWARDwith a fwmark for VRF/nexthop redirect), plus additional match criteria like TCP flags, DSCP, packet length, and fragment flags. Thefwmarkfield is used by FRR to correlate iptable rules withip ruleredirect entries.FRR ipset types that must be supported:
IPSET_NET(single prefix),IPSET_NET_PORT(prefix + port),IPSET_NET_NET(src + dst prefix),IPSET_NET_PORT_NET(src prefix + port + dst prefix).This integration is not part of the initial implementation but drives the API design.
Context and Use Cases
The following examples illustrate how a BGP flowspec controller would program grout ACLs via FRR once the dplane integration is completed.
Discard traffic to a specific destination on a given protocol and port range:
A flowspec route for "drop all UDP traffic to 5.5.5.0/24 with destination port 50-90" results in:
net,port(IPSET_NET_PORT) with one entry: dst=5.5.5.0/24, proto=17, dst_port=50-90.ZEBRA_IPTABLES_DROP.rte_flowrule on the NIC. If that succeeds, matching packets are dropped (or marked) in hardware. Otherwise, the software datapath classifies and drops them.Redirect traffic between VRFs:
A flowspec route with a route-target extended community (e.g. RT:192.168.1.1:100) redirects matching traffic to a different VRF:
net,net(IPSET_NET_NET) with entry: src=10.0.0.0/8, dst=172.16.0.0/12.ZEBRA_IPTABLES_FORWARD, fwmark=102.ip rule(viaDPLANE_OP_RULE_ADD) mapping fwmark 102 to routing table 102, which belongs to the target VRF.DSCP remarking:
A flowspec route with ACTION_MARKING (DSCP value 46 = EF) applied to TCP traffic on port 5060 (SIP signaling):
net,portwith entry: dst=any, proto=6, dst_port=5060.DDoS mitigation with remote-triggered blackhole:
An upstream provider advertises a flowspec route to drop traffic matching an attack signature, e.g. "drop all UDP fragments to 203.0.113.1/32 with packet length > 1400":
rte_flowrule drops attack traffic without consuming CPU cycles.Selective nexthop override (redirect-to-IP):
A flowspec route with a redirect-IP extended community forces specific traffic through an alternate nexthop (e.g. a scrubbing center at 10.255.0.1):