You could certainly do this is layer 4 (TCP), but there are a few other really cool options:
HTTP payload parsing
Because XML rides on HTTP, you can use HTTP commands to capture the payload and make routing decisions. Here's an iRule to get you started:
when CLIENT_ACCEPTED {
capture the default pool (what is configured for the virtual server)
set default_pool [LB::server pool]
}
when HTTP_REQUEST {
if { [HTTP::header Content-Type] equals "text/xml" } {
HTTP::collect [HTTP::header Content-Length]
}
}
when HTTP_REQUEST_DATA {
set pool_tmp [findstr [HTTP::payload] "" 18 "<"]
set xml_pool "pool-$pool_tmp"
if { [catch { pool $xml_pool }] } {
log local0. "($xml_pool) pool doesn't exist - using default pool"
pool $default_pool
}
}
This iRule assumes that every request is an XML POST, so you'll have to work in a way to set persistence if you don't want it to use the default pool in non-POST requests.
XML Content Based Routing
XMLCBR is designed specifically for this situation, to route based on incoming XML request payload information. Review the following documents to get acquainted with XMLCBR:
Manual Chapter: Configuring XML Content-Based Routing
https://support.f5.com/kb/en-us/products/big-ip_ltm/manuals/product/ltm_implementation/sol_xml_cbr.html?sr=102037931060876
iRules WIKI: XML_CONTENT_BASED_ROUTING
https://devcentral.f5.com/wiki/iRules.XML_CONTENT_BASED_ROUTING.ashx
Once you have the XML profile properly configured to capture the numeric value in the "To" node of your XML POST data, use something like the following iRule to make the pool assignments.
when CLIENT_ACCEPTED {
capture the default pool (what is configured for the virtual server)
set default_pool [LB::server pool]
}
when HTTP_REQUEST {
initial pool selection
pool $default_pool
}
when XML_CONTENT_BASED_ROUTING {
If there is a match, the pool value will be overwritten by the returned XPath query value
set cbr_pool "pool-$XML_values(0)"
In this example, the pool is called "pool-" where is the value returned from the XPath query
Make sure the specified pool actually exists using this catch statement. If it doesn't, use the default pool.
if { [catch { pool $cbr_pool }] } {
log local0. "($cbr_pool) pool doesn't exist - using default pool"
pool $default_pool
}
}
As in the HTTP payload example, this iRule assumes that all requests are XML POST requests, so you'll have to work in a way to set persistence if you don't want it to use the default pool in non-POST requests.