Forum Discussion
Chris_Phillips
Nimbostratus
Aug 03, 2006iRule as stored function or similar
Hi,
I have an iRule with a dozen lines or so and amd really hoping that there is some way to use this one single iRule as a stored function for instances of it. I mean, i will be using seperate instances of this iRule maybe 20 times, and would really like to be able to call the function with different parameters for each instance rather than having to copy all the code each time, e.g. "call my_iRule(param1, param2)".
I'm not that hopeful, but hoping to be amazed!
Thanks
Chris
10 Replies
- Colin_Walker_12Historic F5 AccountThere isn't currently a mechanism for calling iRules in a function-like manner as you described. The closest I've seen people come is to make the iRule read from a class to fill in the info specific to the Virtual it's assigned to, then create just that class of info for each Virtual.
You'd still be copying and pasting the iRule around, but at least you wouldn't have a seperate version of the rule for each Virtual, just a seperate class.
Colin - unRuleY_95363Historic F5 AccountActually, we've discussed this quite a bit in designing iRules.
The work-around is to use variables to pass arguments into an iRule and get returned results and then use priority assignment and multiple iRule combinations to chain the rule snippets together on various virtual servers. I've yet to encounter a situation where this doesn't provide the ability to write one rule that does common functionality and use it in various ways.
The decision to not have procedures was largely due to the impact on performance that making a procedure call has in Tcl.
This may someday be worked around... - Chris_Phillips
Nimbostratus
these sound very interesting, but do you have any examples? i generally undestand the class principle, presumably you'd need something identifiable like the virtual server address and/or port which would let you identify a single instance. As far as second suggestion, that's really gone way over my head... intersting sounding words but really wouldn't know where to start!
Cheers
Chris - JRahm
Admin
Check out this post
http://devcentral.f5.com/Default.aspx?tabid=28&view=topic&forumid=5&postid=8796 Click here - Deb_Allen_18Historic F5 AccountTo re-use the same rule with different variable values for different virtuals without creating multiple instances, I've used this approach with good results:
First set up a class. Each row will begin with the configured name of each virtual server to which the rule will be applied, and will also contain the value of the variables required by each:
Then you can include this code in your rule to extract the variable values based on the virtual upon which the traffic is processed (use in any event but RULE_INIT):class cl_VSVars { vs_VirtualServer1 valueA valueB valueC vs_VirtualServer2 valueA valueB valueC vs_VirtualServer3 valueA valueB valueC }
If you want to store the class name in a variable, you can do so like this:set myVSVars [findclass [virtual name] cl_VSVars] set myVar1 [getfield $myVSVars " " 1] set myVar2 [getfield $myVSVars " " 2] set myVar3 [getfield $myVSVars " " 3]
HTHwhen RULE_INIT { set ::variableClass ::VSVars } when CLIENT_ACCEPTED { set myVSVars [findclass [virtual name] [set $::variableClass]] ... }
/deb - Chris_Phillips
Nimbostratus
Thanks guys, this all looks great.
I'm left thinking about what impact this kind of complexity could have in terms of efficiency though. i guess i could write variables into a class on each connect event or suhc, but that would presumably be much less efficient that just writing directly to a local variable. I guess this is deviating from what i originally asked though, so i'll have a bash at the suggestions here.
Thanks
Chris - Chris_Phillips
Nimbostratus
Hi,
thanks for everything everyone's said here. I've updated my one single iRule to store data in an array using the virtual name as the array key:when RULE_INIT { number of times an ip address can be used between lookups set ::max_usage_count 3 array of resolved ip addresses array set ::server_ipaddr { } array of resolved address uses array set ::usage_count { } log local0. "Completed RULE_INIT on lookup" } when CLIENT_ACCEPTED { initialize usage count if not yet done for this VS if { [ info exists ::usage_count([virtual name]) ] == 0 } { set ::usage_count([virtual name]) 0 } use server_ipaddr if it exists, use dummy localhost if not if { [ info exists ::server_ipaddr([virtual name]) ] == 1 } { node $::server_ipaddr([virtual name]) [getfield [virtual name] "_" 3] } else { this WILL fail, but only occurs on very first usage when no IP address is known yet. node 127.0.0.1 } decrement usage_count for this virtual server incr ::usage_count([virtual name]) -1 call lookup if maximum usages has happened and reset usage counter if { $::usage_count([virtual name]) <= 0 } { set ::usage_count([virtual name]) $::max_usage_count NAME::lookup [getfield [virtual name] "_" 2] } } when NAME_RESOLVED { assign resolved name to server_ipaddr array if {[scan [NAME::response] "%d.%d.%d.%d" a b c d] == 4 } { set ::server_ipaddr([virtual name]) [NAME::response] } }
I realised that as i already wanted to put the destination server and port number in the virtual server name, i could just split on an underscore (e.g. vs_example.com_443) to get all the configuration details i needed. I can then store additional dunamic data in two global arrays as i go along.
I'm very happy with the logic here, but wonder about the optimization of it all. I've read tips that advise against intermediate local variable names (otherwise i would have been tempted to copy [virtual name] to a local variable in the CLIENT_ACCEPTED event) but if anyone has other pointers to tweak the efficieny, every little helps. i'm doing a lot of repeated array lookups and getfields... i'm lead to believe that's the best approach if anything though.
Cheers
Chris - JRahm
Admin
Remember too that you can test all your variations against the timing command to find the most efficient solution specific to your environment:
Details on how to configure it:Posted By unRuleY on 3/22/2005 4:19 PM
That is a very good point. You have obviously thought about this. Of course, it will all really depend on just how often you expect to match. If it does not match often, then you are completely correct. If it matches regularly, then you would likely want to save the result in a variable. Another factor to weigh is the number of elements in the class/datagroup.
For those that are interested and paying attention, I'm now going to mention a YASF (yet another stealth feature):
You can enable timing statistics in a rule which will allow you to see just how many cycles are spent evaluating a given rule event. The way you do this is with the "timing on" statement.
An example that enables timing for all subsequent events in a rule is:rule my_fast_rule { timing on when HTTP_REQUEST { Do some stuff } }
An example of only timing a specific event is:rule my_slow_rule { when HTTP_REQUEST timing on { Do some other stuff } }
This will then collect timing information each time the rule is evaluated and can be viewed with "b rule show all". You'll likely only want to look at the average and min numbers as max is often way, way out there due to the optimizations being performed on the first run of the rule. Additionally, enabling timing does have some overhead, though it should be negligible.
Details on how to make sense of the numbers:Click here - hoolio
Cirrostratus
Chris,
I notice that you're setting the node to 127.0.0.1 if server_ipaddr doesn't exist. TMM actually listens on several ports for this loopback address (including the management GUI).
You might want to pick another IP address that isn't used.
Aaron - Chris_Phillips
Nimbostratus
Yeah that would be fairly obvioous now wouldn't it? i only used that as that's what was added to my rule when it was converted to a wiki entry.
cheers
chris
Recent Discussions
Related Content
DevCentral Quicklinks
* 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
Discover DevCentral Connects
