The Mumbai dabbawala β a routing problem you already understand
Every weekday morning, 5,000 dabbawalas pick up 200,000 home-cooked lunches from Mumbai suburbs and deliver each one to the right office desk by 12:30 PM β with an error rate Forbes once measured at one mistake per 16 million deliveries. The secret is a coloured-and-lettered tag on every tiffin. At Dadar station, a sorter reads the tag, looks at three things (zone, building, floor), and tosses each tiffin into the right cart in under two seconds. No central database. No barcode scanner. Just rules in the sorter's head.
An F5 iRule is that sorter. The BIG-IP is Dadar station. Every TCP connection and every HTTP request is a tiffin. The iRule reads the headers (the tag), checks a few rules, and decides where the request goes. That's it. The whole thing rests on a 30-year-old scripting language called TCL, embedded in F5's Traffic Management Microkernel (TMM).
Why this matters β and what an interviewer will ask
If you are interviewing for an F5 admin or NetOps engineer role, the question is almost guaranteed: "write an iRule that redirects all HTTP traffic to HTTPS, except for the /healthcheck path." It's a 4-line answer. Get it wrong and the panel knows you've never logged into an F5 in production. Get it right and you've separated yourself from the candidates who only memorised what an iRule "is."
The bigger reason it matters: real applications grow weird requirements that the GUI can't express. "Send users from Bengaluru DC to pool-A, except in business hours, except if their User-Agent says they're on iOS, except if the URI contains /api/v2." The GUI runs out of checkboxes; the iRule never does. iRules are how F5 admins ship business logic at the load balancer instead of waiting six weeks for the application team to release.
iRules are powerful, which is exactly why teams overuse them. A 200-line iRule that no one but the original author understands becomes the load-balancer equivalent of legacy stored procedures β every change risks an outage. F5 has been steering customers toward LTM Policies (GUI-driven, declarative) and AS3 (Application Services 3.0 β JSON-defined, version-controlled) since 2022. Treat iRules as a sharp tool: use them when nothing else fits, document them like production code, and migrate to AS3 when the use case matures. The 2026 F5 official guidance is clear β legacy iApps templates are deprecated and AS3 is the replacement.
What an iRule actually is β the structure
Every iRule is event-driven. It does nothing until a specified network event fires on a Virtual Server, and then it runs a small TCL block. The basic shape is always the same:
when EVENT_NAME {
# TCL code that runs when EVENT_NAME fires on this Virtual Server
if { [HTTP::host] equals "shop.infosys.local" } {
pool pool_shop_app
} else {
pool pool_default
}
}
There are over 50 events, but six of them cover ~90% of real production iRules. Memorise these β they show up on F5 301a, F5 301b, and every F5 admin interview.
| Event | When it fires | Most common use |
|---|---|---|
RULE_INIT | Once, when the iRule is loaded or modified | Initialise global variables / static tables |
CLIENT_ACCEPTED | TCP connection established from client to VIP | Source-IP allowlist, geo-block |
HTTP_REQUEST | Every HTTP request received | Pool selection, redirect, header rewrite |
LB_SELECTED | After the load balancer picks a pool member | Persistence override, member logging |
HTTP_RESPONSE | Every HTTP response from pool member | Response header rewrite, body inspection |
ASM_REQUEST_BLOCKING | ASM is about to block a request | Override block for trusted partner, custom log |
Each event is a hook where your iRule can run. You don't need to handle every event β only the ones where you want to change behaviour.
Sneha's app team says "users on the shop site get 502 errors but only between 2-4pm." The dev team blames the LB. Sneha drops a one-line iRule in HTTP_REQUEST that logs [HTTP::host], [IP::client_addr], and the chosen pool member to a remote syslog. Within 30 minutes the data tells her one pool member is brown-listed by an upstream API gateway. The fix takes 5 minutes. The iRule was the diagnosis tool, not the fix.
The 5 iRule patterns you'll write in your first F5 job
Pattern 1 β HTTP-to-HTTPS redirect (with healthcheck exception)
when HTTP_REQUEST {
if { [HTTP::uri] starts_with "/healthcheck" } {
return
}
HTTP::redirect "https://[HTTP::host][HTTP::uri]"
}
Attach this to an HTTP (port 80) Virtual Server. Every request gets a 302 to the HTTPS equivalent, except /healthcheck which the upstream load balancer or monitoring system needs to hit on HTTP.
Pattern 2 β Header-based pool selection
when HTTP_REQUEST {
switch -glob [string tolower [HTTP::host]] {
"shop.infosys.local" { pool pool_shop_app }
"api.infosys.local" { pool pool_api_v2 }
"internal.*.infosys.local" { pool pool_internal_apps }
default { pool pool_default }
}
}
One Virtual Server hosts many internal hostnames. The iRule reads the Host header and routes to the right pool. string tolower protects against case-mismatch bugs.
Pattern 3 β Rate-limit by client IP (sideband-free version)
when RULE_INIT {
set ::RATE_LIMIT 60 ;# requests per minute
set ::WINDOW 60 ;# seconds
}
when HTTP_REQUEST {
set client [IP::client_addr]
set key "rl_$client"
set count [table incr -subtable rate_limit $key]
if { $count == 1 } {
table lifetime -subtable rate_limit $key $::WINDOW
}
if { $count > $::RATE_LIMIT } {
HTTP::respond 429 content "Slow down" "Retry-After" "60"
return
}
}
Uses BIG-IP's built-in table command (per-TMM, in-memory). Sneha's L1 mistake would be storing rate counts in a TCL variable β those don't survive between requests. table does.
Pattern 4 β ASM block override for a trusted partner
when ASM_REQUEST_BLOCKING {
set src [IP::client_addr]
if { [class match $src equals trusted_partner_ips] } {
ASM::unblock
log local0. "ASM block overridden for trusted partner $src on [HTTP::uri]"
}
}
Real production case from F5 DevCentral: a business partner's automated scraper triggers ASM signatures with malformed-but-benign requests. Whitelisting the policy is risky; an iRule that overrides ONLY for the partner's source IPs (defined in an LTM Data Group called trusted_partner_ips) is the surgical answer.
Pattern 5 β Maintenance page during deploy windows
when HTTP_REQUEST {
if { [class match [IP::client_addr] equals admin_bypass_ips] } { return }
if { [active_members pool_app] < 1 } {
HTTP::respond 503 \
content "<h1>Maintenance β back in 15 minutes</h1>" \
"Content-Type" "text/html" "Retry-After" "900"
}
}
If every pool member is down (deploy in progress), serve a branded maintenance page. Admins on bypass IPs skip the check and see the real (broken) app for troubleshooting.
# From BIG-IP tmsh
tmsh list ltm virtual vs_shop rules
# Expected: rules { irule_pool_by_host }
# Live trace what's firing per request
tmsh modify ltm virtual vs_shop ip-protocol tcp rules { irule_pool_by_host }
tcpdump -nni 0.0:nnnp -s0 -w /shared/tmp/vs.pcap host 10.42.10.55 &
# Then check the log:
tail -f /var/log/ltm | grep -i iruleASM integration β when iRules meet WAF
BIG-IP ASM (now branded "BIG-IP Advanced WAF") inspects requests for OWASP-style attacks. ASM has its own iRule events that fire at the WAF decision points β useful when the policy alone is too coarse.
| ASM event | When it fires | You'd use it to⦠|
|---|---|---|
ASM_REQUEST_BLOCKING | ASM has decided to block and is generating the reject response | Override block for trusted source (Pattern 4) |
ASM_REQUEST_DONE | ASM has finished processing the request | Log the violation set for SIEM |
ASM_REQUEST_VIOLATION | ASM detected a policy violation (but may not block) | Increment custom risk counter |
ASM_RESPONSE_VIOLATION | ASM detected a response-side violation (data leakage) | Mask sensitive fields in response body |
Always override at ASM_REQUEST_BLOCKING β that's the last point before ASM rejects the request. Earlier events run before ASM has decided.
Rahul's WAF blocks a Flipkart partner's price-feed scraper every hour because the scraper sends a malformed Content-Length header. Removing the ASM signature is too broad β it would let real attackers through too. Rahul writes a Pattern-4-style iRule that calls ASM::unblock only when source IP is in data_group flipkart_partner_ips. Partner unblocked; everyone else still protected.
The 3 security pitfalls that get iRules onto CVE feeds
- Double substitution. If user input ends up inside
[expr]or[eval]without quoting, you've handed the attacker TCL command execution on the BIG-IP. F-Secure published a famous 2019 paper called "Crash, Reboot, Exploit" on this exact pattern. Always wrap dynamic strings in{ β¦ }braces β braces suppress substitution. - Unsanitised
nodeorsidebandcommands.node $user_input_ip 8080lets an attacker steer load-balancing toward any IP they want, bypassing the pool entirely. Sanitise β or use a Data Group allowlist. - Logging client input to local syslog. A 200-character User-Agent string Γ 50,000 RPS Γ
log local0.= local TMM disk full in minutes. Ship logs to a dedicated remote syslog (HSL β High-Speed Logging) instead.
- Variable not persisting between requests. Symptom: rate-limit counters always show 1. Cause: TCL
set x β¦resets every request. Fix: use thetablecommand (Pattern 3). - iRule appears not to fire. Symptom: log never shows expected line. First check: is the iRule attached to the right Virtual Server?
tmsh list ltm virtual vs_name rules. Second check: does the VS have the right profile (HTTP profile required for HTTP_* events)? HTTP::respondfollowed by code that tries to also pick a pool.respondends the request β anything after it doesn't run. Usereturnto be explicit.- Slow iRule causing P99 latency spike. Cause: a
regexpagainst a large response body insideHTTP_RESPONSE. Fix: enabletiming on, find the cycle hog, replace withHTTP::collect+ targeted match. - iRule works in test, fails in HA pair after failover. Cause:
RULE_INITglobals are per-TMM, per-blade. Don't assume cross-blade consistency for stateful counters. Use a shared external store (data group sync, external DB).
- Always pseudo-code before you write TCL. Top F5 engineers all say the same thing on DevCentral β bugs come from rushing past the design step.
- Use Data Groups for any list of IPs / hosts / paths. Changing the list is a GUI edit; changing the iRule is a code review. Decouple them.
- Test with TesTcl. Yes, you can unit-test iRules.
testcl.comis the framework. If your iRule is critical-path, write the test. - Migrate to AS3 when stable. An iRule pattern that you copy-paste into 12 Virtual Servers should be an AS3 declaration with a parameter. Easier to version, easier to audit, easier to ship via CI/CD.
Aditya's iRule rate-limit (Pattern 3) works perfectly in his lab F5 β but on the HA pair in production, half the requests get through the limit because each TMM blade keeps its own counter. The fix is either using a single-blade-aware approach (CMP β Clustered Multi-Processing demotion via CMP::disable on that iRule, but at a performance cost), or moving the rate-limit to an upstream layer (CDN, AS3 WAF policy). Senior move: tell the app team and move the control. Junior move: add a comment in the iRule saying "limits are approximate per-TMM" and walk away.
When to use iRule vs LTM Policy vs AS3
Rule of thumb: if you'd repeat the same iRule across 5+ Virtual Servers, it belongs in AS3. If it's a one-off business hack, an iRule is correct.
Priya's team has 32 Virtual Servers that all share the same HTTP-to-HTTPS redirect iRule (Pattern 1). Every patch window someone forgets to attach the iRule on a new VS and gets a P1. She rewrites the rule as an AS3 declaration with a reusable redirect-pointer; now 32 VSes inherit it from one JSON file in Git. The iRule's last commit becomes "deprecated β see AS3-redirect.json."
Mapping to the F5 301a / 301b exam
- F5 301a (Architect, Set-Up & Deploy) β asks "given this app requirement, which iRule events would you use?" Expect HTTP_REQUEST + LB_SELECTED + ASM_REQUEST_BLOCKING combinations.
- F5 301b (Maintain & Troubleshoot) β asks "users report symptom X; you see Y in the log; what's the iRule bug?" Expect double-substitution traps, stale-cache pitfalls, and "iRule not attached to VS" red herrings.
- Both exams give you scenarios β never definitions. Practice writing iRules on paper without an IDE. The cert is worth nothing if you can't read an iRule under time pressure.
π Quick reference β F5 iRules cheat sheet
| Need to⦠| Use |
|---|---|
| Redirect HTTPβHTTPS | HTTP::redirect "https://[HTTP::host][HTTP::uri]" |
| Pick a pool | pool pool_name |
| Block a request inline | HTTP::respond 403 content "Blocked" |
| Add a request header | HTTP::header insert "X-Forwarded-Real" [IP::client_addr] |
| Read source IP | [IP::client_addr] |
| Read host | [HTTP::host] |
| Stateful counters | table set / table incr / table lookup |
| Log to remote syslog | HSL::send $hsl_handle "msg" (after HSL::open in RULE_INIT) |
| Override ASM block | when ASM_REQUEST_BLOCKING { ASM::unblock } |
| Profile performance | timing on at the top of the iRule |
Sources used in this lesson
- F5 official techdocs β Introduction to iRules
- DevCentral β Top 5 iRule development practices
- DevCentral β Intermediate iRules: evaluating performance (
timing on) - DevCentral β Avoiding common iRules security pitfalls (double substitution, sideband)
- F5 Agility Labs β ASM hooks lab
- F5 K000160932 β May 2026 Quarterly Security Notification
- F5 301a study guide β iRules exam topics
- TesTcl β unit testing framework for iRules
π Check your understanding β 10 scenario questions
Bloom-tiered mix: 1 Remember + 3 Apply + 4 Analyze + 2 Evaluate. Pass: 70% (7/10).
What's next?
Now build it β spin up an F5 BIG-IP VE lab and write Patterns 1-5 hands-on. Then practice the 301a/301b style scenarios on exam.techclick.in.