aFleX Optimization

aFleX is a powerful and flexible scripting language that you can use to manage your traffic and provide enhanced benefits and services. aFleX is optimized to run very fast and is highly scalable; however, depending on how you build your script, aFleX may use more AX/Thunder CPU and RAM resources.

This section will help you build optimal aFleX scripts.

Rule #0: What about application templates?
AX/Thunder Series offers multiple templates to do advanced functions such as:
  • URL/Host switching
  • Cookie persistence
  • HTTP header insert/delete/replace
  • HTTP redirect/rewrite
  • Filter or process traffic based on class lists Templates are simple to use (no script to do) and are optimized for efficiency.

So it's always recommended to use application templates when possible.

Rule #1: Limit variables
Variables use resources:
  • CPU to create/assign and destroy
  • Memory to store the variable


Both examples below do the same thing, but the first one is more efficient:
Example 1:
log “Client address=[IP::client_addr]”
Example 2:
set ip_addr [IP::client_addr]
log “Client address=$ip_addr"


Rule #2: Brace your expressions
aFleX uses the TCL scripting language, which is string based. Using braces {} to encapsulate commands helps TCL analyze the function. Both examples below do the same thing, but the first one is more efficient:
Example1:
set octet [expr {3 + [getfield [IP::client_addr] "." 4]}]
Example2:
set octet [expr 3 + [getfield [IP::client_addr] "." 4]]

Rule #3a: Use if-elseif instead of if
When you have multiple tests, use if-elseif to limit aFleX to go through all the tests. Both examples below do the same thing, but the second one is more efficient:
Example1:
if {[IP::client_addr] equals “20.20.125.1" } {
pool sg1
}
if {[IP::client_addr] equals “20.20.125.2" } {
pool sg2
}
if {[IP::client_addr] equals “20.20.125.3" } {
pool sg3
}

Example2:
if {[IP::client_addr] equals “20.20.125.1" } {
pool sg1
} elseif {[IP::client_addr] equals “20.20.125.2" } {
pool sg2
} elseif {[IP::client_addr] equals “20.20.125.3" } {
pool sg3
} else {
pool default
}


Rule #3b: Use switch instead of if-elseif
When you have multiple tests, a single switch statement is more efficient than many if-elseif statements for evaluating all the tests. (Switch statements are simpler to code too.)

Both examples below do the same thing, but the first one is more efficient:
Example 1:
switch [IP::client_addr] {
20.20.125.1  { pool pool1 }
20.20.125.2  { pool pool2 }
20.20.125.3  { pool pool3 }
default { pool default_pool }
}

Example 2:
if {[IP::client_addr] equals “20.20.125.1" } {
pool sg1
} elseif {[IP::client_addr] equals “20.20.125.2" } {
pool sg2
} elseif {[IP::client_addr] equals “20.20.125.3" } {
pool sg3
} else {
pool default
}


Rule #4: Use arrays instead of lists for lookups in data groups
When you have a data group and you look for an entry in that list, an array is more efficient than lists for finding an entry.

Both examples below do the same thing, but the first one is more efficient:
Example 1:
when RULE_INIT {
array set ::ARRAY1 [list "/url1" "sg1" "/url2" "sg2"  ... ] }
}
when HTTP_REQUEST {
if { info exists ::ARRAY1([HTTP::uri]) } {
pool $::ARRAY1([HTTP::uri])
....
}
}

Example 2:
when RULE_INIT {
set ::CACHEURLS [list "/url1" "/url2" …]
set ::URLS2SG [list "sg1" "sg2" …]
}
when HTTP_REQUEST {
set SEARCH_INDEX [lsearch -exact $::CACHEURLS [HTTP::uri]]
if { $SEARCH_INDEX != -1 } {
pool [lindex $::URLS2SG $SEARCH_INDEX]
}
}


Rule #5: Use the correct operator

For numbers, use the following operators: ==, !=, >, <
For strings, use “eq”, “ne”, so on.
Both examples below do the same thing, but the first one is more efficient:
Example 1:
set url_length [string length [HTTP::uri]]
if { [string length [HTTP::uri]] == 10 } {

}

Example 2:
set url_length [string length [HTTP::uri]]
if { [string length [HTTP::uri]] eq 10 } {

}


Rule #6: Avoid regex and regsub
Regex and regsub are powerful TCL commands, but use a lot of CPU. Instead, use the following commands when possible:
  • contains, ends_with, starts_with, equals, matches, instead of regexp
  • string map instead of regsub

Both examples below do the same thing, but the first one is more efficient:
Example 1:
if { [HTTP::uri] starts_with “/docs”} {

}

Example 2:
if { [regex {^/docs} [HTTP::uri] } {

}

Both examples below do the same thing, but the first one is more efficient:
Example 3:
when HTTP_RESPONSE_DATA {
if { [HTTP::header "Content-Type"] contains "text" } {
set payload_length [HTTP::payload length]
HTTP::payload replace 0 $payload_length [string map {"http://intranet.abc.com"
"https://intranet.abc.com"} [HTTP::payload]]
HTTP::release
}
}

Example 4:
when HTTP_RESPONSE_DATA {
if { [HTTP::header "Content-Type"] contains "text" } {
set payload_length [HTTP::payload length]
regsub -all "http://intranet.abc.com" [HTTP::payload] "https://intranet.abc.com"
new_payload
HTTP::payload replace 0 $payload_length $new_payload
HTTP::release
}
}
Tags:

Add new comment