Forum Discussion
Simple irule for novice
Hi I am a novice. Could you tell me if the following irule would work to load balance to specified pools based on source ip of dns request?
When dns request {ip::address [ip::client_addr] equals 10.10.10.5/24}{pool pool1}
When dns request {ip::address [ip::client_addr] equals 10.10.20.5/24}{pool pool2}
When dns request {ip::address [ip::client_addr] equals 10.10.30.5/24}{pool pool3}
Thanks
1 Reply
- VernonWells
Employee
Unfortunately not. I'll start by providing an iRule that will work, then provide some commentary.
I assume that you want to match on individual IP addresses, rather than all IP addresses in netblocks. That is, a query from 10.10.10.5 should go to pool1, but it is not necessarily the case that all IPs in 10.10.10.0/24 should. If that is so, this iRule achieves that:
when DNS_REQUEST { switch [IP::client_addr] { "10.10.10.5" { pool pool1 } "10.10.20.5" { pool pool2 } "10.10.30.5" { pool pool3 } } }Generally speaking, a when clause for a specific event (DNS_REQUEST in this example) occurs only once in a particular iRule. As with most general purpose programming languages, iRules (a Tcl dialect) supports conditionals (both if/elseif/else and switch, as above), which is where the decision making happens.
iRule commands broadly come in two forms: inquisitive and imperative. An inquisitive command returns a value, while an imperative command instructs the system to do something. Inquisitive commands should always be wrapped in the square brackets ([]), while imperative commands usually are not. In Tcl, the square brackets force inline evaluation of the statement contained within the brackets. Inquisitive commands are expected to evaluate to a value which you subsequently use (e.g., as the conditional for the switch above); thus, the reason why square brackets are needed. Notice that the pool command -- which is imperative -- is not wrapped in square brackets. We don't expect it to evaluate to a value, and even if it did, we don't need the return value.
I mention this because there is a form of IP::addr which can be used for netblock comparison, as in:
if { [IP::addr [IP::client_addr] equals "10.10.10.0/24"] } { pool1 }Notice that both IP::client_addr and IP::addr are wrapped in square brackets. We want them both to evaluate to something (an IP address and a boolean, respectively).
For completeness, you can use a slight variant of the IP::addr statements you have above in an if conditional:
when DNS_REQUEST { if { [IP::addr [IP::client_addr] equals "10.10.10.5"] } { pool pool1 } elseif { [IP::addr [IP::client_addr] equals "10.10.20.5"] } { pool pool2 } elseif { [IP::addr [IP::client_addr] equals "10.10.30.5"] } { pool pool3 } }but I consider that to be less readable. And, strictly speaking, the IP::addr is not needed. The following would suffice:
when DNS_REQUEST { if { [IP::client_addr] equals "10.10.10.5" } { pool pool1 } ... etc ... }Since, in this context, IP::client_addr produces a string.
A few things to keep in mind:
- Usually, with this type of rule, it's a good idea to have a default pool defined. You could do this via the iRule, or better yet, attach a pool to the virtual server on which this iRule is defined;
- This will only work on the LTM module if GTM is licensed as well, or with a DNS Services add-on license. If neither of those are true, the DNS_REQUEST event is not defined and will never fire.
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com