A CGNAT that passes a ping and loads a web page has proved very little. The faults that generate tickets show up later: a game that reports Strict NAT, a VoIP call that goes one-way after a pause, a busy household whose new connections start failing, an abuse report you cannot trace back to a subscriber. Each can be found in a test plan before go-live, and each is much cheaper to find there.
This note is the plan we would run against any CGN, written with the commands Netavo BNG provides. It assumes you have a few test subscribers behind the CGN and somewhere outside it to generate and receive traffic. RFC 7021 is a useful companion: it assessed how real applications behave through NAT444 and is a good source of things worth testing.
First: is this line behind CGNAT at all?
Start with the check a subscriber or support agent would run, because it is also the quickest way to confirm a test line is actually going through the CGN.
- Read the WAN address the home router (CPE) was given.
- Ask a "what is my IP" service which address the internet sees.
If the two match, the line has a public address and no CGN is involved. If they differ, and especially if the WAN address falls in 100.64.0.0/10, the shared address space RFC 6598 reserves for CGNAT, the line is behind carrier-grade NAT. A WAN address in RFC 1918 space with a different public address also means a NAT upstream, though not necessarily a carrier one.
On the BNG the same answer is one command: show cgn bindings <inside-ip> shows whether the subscriber has a binding, which public address it maps to, and how full each of its port blocks is. If a test subscriber has no binding, nothing below will work; cgn-no-binding in show cgn summary counts the packets this refused.
1. Translation works for the protocols you carry
Bring a test subscriber up and generate TCP, UDP and ICMP traffic to a host outside the CGN. Capture on that host and confirm the source is an address from the IP group's public subnets. Then look at the subscriber's live translations:
show cgn translations 100.64.12.37 protocol udp
Netavo's CGN translates TCP, UDP and ICMP. Anything else is refused and counted as cgn-unsupported, along with ICMP errors that do not match a translation. If some of your subscribers rely on another protocol, find out now rather than from their first ticket. show dataplane drops lists every CGN refusal reason with a one-line meaning.
Also test the bypass path if you use one: prefixes listed in an IP group's bypass-prefixes should leave untranslated.
2. NAT behaviour: mapping, filtering and hairpinning
Most application complaints about CGNAT are really complaints about NAT behaviour, so test it directly rather than inferring it.
- Mapping. Run a STUN client (RFC 5780 describes behaviour discovery with STUN) from a test subscriber against two different servers. With endpoint-independent mapping, the same inside address and port map to the same public address and port for both.
- Filtering. From a third host the subscriber has not contacted, send to that public address and port. With endpoint-independent filtering, it gets through.
- Hairpinning. Have test subscriber A connect to test subscriber B's public address and port. With hairpinning, the CGN delivers it back inside. Failures here are counted as
cgn-hairpin.
Netavo's CGN implements endpoint-independent mapping and filtering with hairpinning, so all three should pass. Finish with a games console or a SIP client behind a test CPE, and remember that a Strict result there may come from the CPE rather than the carrier. The note on CGNAT and gaming explains how to tell them apart.
3. Port exhaustion and per-subscriber limits
This is the test most often skipped and the one that most resembles a real fault. From one test subscriber, open many simultaneous flows (a load generator, or a script opening connections and holding them) and watch show cgn bindings <inside-ip> as the subscriber's first block fills and further blocks are granted.
Keep going until the subscriber reaches the IP group's port-cap. At that point new flows should fail for that subscriber only, and cgn-capacity should rise; other test subscribers on the same public address must be unaffected. That is the fairness property the per-subscriber cap exists to provide. While you are there, check the flow-setup limiter: if setups-per-sec is set, a burst of new connections above it is counted as cgn-setup-rate.
The result tells you whether your block size and cap fit your traffic. The trade-off between them is worked through in the CGNAT port-block maths.
4. Timeouts
A mapping that ages out while an application still needs it is indistinguishable, to the subscriber, from a dropped connection. Each IP group sets its own timeouts for UDP, DNS lookups on port 53, established TCP, transitory TCP and ICMP. Test the ones your subscribers will notice:
- Hold a UDP flow open with keepalives at your target application's interval (a SIP client registering, say) and confirm it survives an idle period longer than the interval.
- Leave an established TCP session idle and confirm it is still usable after the period you expect to support.
- Confirm DNS mappings expire quickly, so lookups do not hold ports longer than they need to.
5. Pool sizing and alarms
Run show cgn groups to see each group's public subnets, block size, port cap, bindings and how many blocks are in use, and show cgn summary for active bindings against max-bindings and the refusal counters. Then fill a deliberately small test pool until the high-utilisation alarm fires, so you know it reaches whoever watches your alarms:
MAJOR cgn.pool.high public-a CG-NAT IP group 'public-a' is 94% allocated (7712 of 8192 port blocks).
An alarm you have only seen in documentation is an alarm you do not yet have.
6. Attribution: run a mock abuse request
Before any real request arrives, prove you can answer one. From a test subscriber, make a connection to a host you control and note the public address, source port and time it records. Then, using only those three values, find the subscriber in your CGN log store.
Check the logger first. Netavo creates no CGN logger until you configure one, and the syslog driver is best-effort, so it is not a durable compliance record; the Azure Service Bus logger is the one intended for compliance records. Then confirm the records arrive with their sequence numbers intact, and that a subscriber who has been granted extra blocks in test 3 has an allocation record for each one, not only the first. The design behind those records is covered in CGNAT logging with deterministic port blocks.
7. Restarts and failure
Restart the service in a maintenance window with test subscribers active, and check two things: what the subscribers experience, and what the log records. The CGN log carries generation records and restart markers, and recovered bindings are announced again with allocation events, so your log index should close the old generation cleanly rather than leaving bindings that look open forever. Netavo does not synchronise NAT bindings between appliances, so plan recovery from a failed box around subscribers reconnecting rather than around stateful failover.
The plan on one page
| Test | How | Pass when | Watch |
|---|---|---|---|
| Behind CGNAT? | CPE WAN address vs "what is my IP" | They differ; WAN in 100.64.0.0/10 | show cgn bindings |
| Translation | TCP, UDP, ICMP to an outside host | Source is a pool address | show cgn translations, cgn-unsupported |
| Mapping and filtering | STUN from two servers, inbound from a third | Same public port; inbound passes | Console NAT type |
| Hairpinning | Subscriber A to B's public address | Delivered inside | cgn-hairpin |
| Port exhaustion | Many flows from one subscriber | Only that subscriber fails at the cap | cgn-capacity, cgn-setup-rate |
| Timeouts | Idle UDP and TCP flows | Survive your target idle period | Application behaviour |
| Pool alarm | Fill a small pool | Alarm reaches your monitoring | cgn.pool.high |
| Attribution | Mock request: IP, port, time | One subscriber found, all blocks logged | Logger stream sequence |
| Restart | Restart with test subscribers | Log generations close cleanly | Allocation events |
Test with real CPE. Most "CGNAT problems" in production are the interaction between the carrier NAT and the home router, and a lab that uses a bare Linux host as the subscriber will pass tests your customers would fail.
Run the plan on the evaluation build
The free evaluation build is the full production build with CGN enabled, licensed for up to 50 concurrent subscribers, which is plenty for every test above. Start at netavobng.com/evaluation; the CGN configuration and CLI reference is in the manual. If CGNAT is new to you, start with what CGNAT is and how NAT444 works.
FAQ
How do I test if I am behind CGNAT?
Compare the WAN address your router was given with the address a "what is my IP" service reports. If they differ, there is NAT upstream of your router, and a WAN address in 100.64.0.0/10, the shared address space RFC 6598 reserves for carrier-grade NAT, means you are behind CGNAT.
What should a CGNAT test plan cover?
At least translation for the protocols you carry, NAT behaviour (endpoint-independent mapping and filtering, and hairpinning), per-subscriber port exhaustion, mapping timeouts, pool-utilisation alarms, attribution of a public address, port and time back to a subscriber, and behaviour across a restart.
How do I test CGNAT port exhaustion?
Open many simultaneous flows from one test subscriber until it reaches the per-subscriber port cap. New flows should then fail for that subscriber only, while other subscribers on the same public address are unaffected. On Netavo BNG, show cgn bindings shows the subscriber's blocks filling, and the cgn-capacity counter records the refusals.
Can I test CGNAT without production traffic?
Yes. A handful of test subscribers with real CPE, a host outside the CGN to send and receive traffic, and a load generator for the port-exhaustion test cover every item in the plan. The Netavo BNG evaluation build is the production build licensed for up to 50 concurrent subscribers, which is enough to run all of it.