Applies To:
Show VersionsBIG-IP LTM
- 15.0.1, 15.0.0, 14.1.3, 14.1.2, 14.1.0, 14.0.1, 14.0.0, 13.1.3, 13.1.1, 13.1.0
How to Use Generic Message - iRules
Generic message is a framework to allow implementation of new protocols via iRule scripts. Most of the work done will be done via iRule scripting.
Overview
An iRule is a powerful and flexible feature within the BIG-IP® local traffic management system that you can use to manage your network traffic. It allows operators to implement custom behavior beyond the native capabilities of the BIG IP system.
The Generic Message Protocol filter can be configured to divide the input stream (from the transport filter) into messages when it finds an instance of its message terminating string ("\n"). Each message will initially be treated as a response message. If a destination-address is added to the message, it will be changed to a request message.
The first message received after a new connection will be used as the peer name for the connection. A dynamic route for the peer will be added to the peer table using the peer name. The peer name may be set using the GENERICMESSAGE::peer name <name> command. If the peer name has already been set, the first message will be routed as any other message.
The Generic Message Protocol filter maintains a list of pending request messages. When a request message egresses through the filter, the last hop of the originator of the request is added to the pending request list (unless the message has been flagged as a no-response message).
Any message containing a destination address is treated as a request message. If a message does not contain a destination address and a pending request exists, that message is processed as the answer to the pending request. The message's nexthop attribute will be set to the lasthop of the oldest pending message and the pending message will be removed from the pending message list, and forwarded. An iRule command, GENERICMESSAGE::message request_sequence_number, can be used to associate a response to any pending request.
If a message does not contain a destination address and a pending request does not exist, that message will be processed as a request and forwarded for routing.
New Connections
When a new connection is created, the iRule will need to set the peer name for the connection.
Setting Peer Name
Each message will automatically have the source-address field populated with this peer name. A dynamic route will be entered for this connection with the assigned peer name used as the destination-address of the route. If a route already exists with the peer name, the earlier route will take precedence.
Peer Name Options
Junk Data
This will meet the requirement that a peer name be set and will keep multiple dynamic route entries from being created.
rule gm_rules { when CLIENT_ACCEPTED { GENERICMESSAGE::peer name "." TCP::collect } when SERVER_CONNECTED { GENERICMESSAGE::peer name "." TCP::collect }
Connection Based Value
rule gm_rules { when CLIENT_ACCEPTED { GENERICMESSAGE::peer name [IP::remote_addr] TCP::collect } when SERVER_CONNECTED { GENERICMESSAGE::peer name [IP::remote_addr] TCP::collect }
Negotiated Value from Peer
tm rule gm_rule { when CLIENT_ACCEPTED { TCP::respond "What is your name\n" TCP::collect set capture_name 1 } when SERVER_CONNECTED { TCP::respond "What do you wish to be called\n" TCP::collect set capture_name 1 } when CLIENT_DATA { set lines [split [TCP::payload] "\n"] TCP::payload 0 0 foreach line $lines { set line [string trim $line] if { [string length $line] > 0 } { if { $capture_name == 1 } { GENERICMESSAGE::peer name $line set capture_name 0 TCP::respond "Welcome [GENERICMESSAGE::peer name]\n" } else { ... } } } TCP::release TCP::collect } when SERVER_DATA { set lines [split [TCP::payload] "\n"] TCP::payload 0 0 foreach line $lines { set line [string trim $line] if { [string length $line] > 0 } { if { $capture_name == 1 } { GENERICMESSAGE::peer name $line set capture_name 0 TCP::respond "Welcome [GENERICMESSAGE::peer name]\n" } else { ... } } } TCP::release TCP::collect }
Message Creation
The data stream will need to be parsed during CLIENT_DATA and SERVER_DATA iRule events for messages. Once the bytes of a message has been collected, a message object will need to be created and populated.
The GENERICMESSAGE::message create command is used to create and populate a message.
Once a message is created, the GENERICMESSAGE_INGRESS event will be raised and the script author may modify and the message.
Upon completion of the GENERMESSAGE_INGRESS event, the message will be forwarded to the router for routing.
An example script that parses the input stream to create message follows. This example identifies a request message as having the destination address specified at the start of the message separated from the data of the message by a ':'.
when CLIENT_DATA { set lines [split [TCP::payload] "\n"] TCP::payload 0 0 foreach line $lines { set line [string trim $line] if { [string length $line] > 0 } { if { $capture_name == 1 } { ... } else { set tokens [split $line ":"] if {[llength $tokens] > 1} { GENERICMESSAGE::message create [join [lrange $tokens 1 end] ":"] [lindex $tokens 0] } else { GENERICMESSAGE::message create $line } } } } TCP::release TCP::collect } when SERVER_DATA { set lines [split [TCP::payload] "\n"] TCP::payload 0 0 foreach line $lines { set line [string trim $line] if { [string length $line] > 0 } { if { $capture_name == 1 } { ... } else { set tokens [split $line ":"] if {[llength $tokens] > 1} { GENERICMESSAGE::message create [join [lrange $tokens 1 end] ":"] [lindex $tokens 0] } else { GENERICMESSAGE::message create $line } } } } TCP::release TCP::collect }
Message Routing
When a message is received for routing, MRF will raise the MR_INGRESS event. The script author may set the nexthop or route attribute of the message to bypass the normal route table lookup. Response messages may already have the nexthop attribute set but the protocol if a pending request existed in the table.
Upon completion of the MR_INGRESS event, fi the message's nexthop attribute is set, the message will be forwarded to the connection specified in the nexthop attribute.
If the message's route attribute is set, route lookup will be skipped and the route value specified in the message's route attribute will be use to determine the distination host of for the message.
If the message's route attribute is not set, the route lookup will be performed using the message's source and destination address. The message's route attribute will be populated with the selected route's value.
After route selection, a peer from the route value will be selected and a pool member will be selected from the selected peer.
If available connection exists to the selected pool member, the message will be forwarded using that connection.
If an available connection does not exist, a new connection will be created.
The MR_EGRESS event will be raised as the message is leaving the router to be forwarded to the destination.
If a route could not be found or a connection could not be created, a MR_FAILED event will be raised. The script author may attempt to retry routing using the MR::retry command.
Message Delivery
When the outgoing message is received by the protocol a GENERICMESSAGE_EGRESS event will be raised. If the protocol's parser is disabled, the script author will need to output the data of the message in the script.
when GENERICMESSAGE_EGRESS { TCP::respond "[GENERICMESSAGE::message data]\n" }
MRF iRule Events and Commands
MRF Events
Event | Description |
---|---|
MR_INGRESS | This event is raised when a message is received by the message proxy and before a route lookup occurs. Setting the route for a message will bypass route lookup. |
MR_EGRESS | This event is raised after the route has been selected and processed and the message is delivered to the mr_proxy for forwarding on the new connflow. |
MR_FAILED | This event is raised when a message has been returned to the originating flow due to a routing failure. |
MRF Commands
Command | Description |
---|---|
MR::instance | Returns the name of the current mr_router instance. The instance name will be the same name as the router profile. |
MR::protocol | Returns ‘generic, ‘sip’ or ‘diameter’ |
MR::store <name> … | Stores a tcl variable with the mr_message object. This variable will be delivered with the message to the egress connflow. Adding variables does not effect the content of the message |
MR::restore [<name> …] | Returns adds the stored variables to the current context tcl variable store. If no name is provided, it will add all stored variables. |
MR::peer <name> |
Returns the content of the named peer. If a local peer has been created with the provided name (using MR::peer <name> ...), the local peer's contents will be returned. If a local peer has not been created with the provided name, the static peer from configuration will be returned. The returned value will be formatted as: (versions 11.5 - 12.1) <destination> using <transport> where: destination = <destination_type> "<destination_value>" destination_type = pool | virtual transport = <transport_type> "<transport_name>" transport_type = virtual | config for example: pool "/Common/default_pool" using config "/Common/sip_udp_tc" (version 13.0 + ) <transport> <destination> where: destination = <destination_type> <destination_value> destination_type = pool | virtual transport = <transport_type> <transport_name> transport_type = virtual | config for example: virtual /Common/sip_tcp_vs host [10.2.3.4]%0:5060 |
MR::peer <name> [[virtual <virtual_name>] OR [config <transport_config_name>]] [[host <host tuple>] OR [pool <pool name>]] | Defines a peer to use for routing a message to. The peer may either refer to a named pool or a tuple (IP address, port and route domain iD). When creating a connection to a peer, the parameters of either a virtual server or a transport config object will be used. The peer object will only exist in the current connections connflow. When adding a route (via MR::route add), it will first look for a locally created peer object then for a peer object from the configuration. Once the current connection closes, the local peer object will go away. |
MR::peer <name> [[virtual <virtual_name>] OR [config <transport_config_name>]] [[host <host tuple>] OR [pool <pool name>]] ratio <ratio_value> | Defines a peer to use for routing a message to. The peer may either refer to a named pool or a tuple (IP address, port and route domain iD). When creating a connection to a peer, the parameters of either a virtual server or a transport config object will be used. The peer object will only exist in the current connections connflow. When adding a route (via MR::route add), it will first look for a locally created peer object then for a peer object from the configuration. Once the current connection closes, the local peer object will go away. Adding the ratio keyword allows setting the ratio of the peer. |
MR::message lasthop |
Returns the message's lasthop (details of the connection that originated the message). The lasthop is presented as <TMM number>:<FlowID> for example 0:800000000005 |
MR::message nexthop |
Returns the message's nexthop (details of the connection the message is to be forwarded to). If the new_nexthop parameter is present, a nexthop may be set for the message. The nexthop is formated as <TMM number>:<FlowID> for example 0:800000000029 |
MR::message nexthop <new_nexthop> | Sets the message's nexthop (details of the connection the message is to be forwarded to). The new_nexthop parameter is present, a nexthop may be set for the message. The nexthop is formated as <TMM number>:<FlowID> |
MR::message route |
Returns a rendering of the mr_route_value selected for this message. The returned value will be formatted as: (versions 11.5 - 12.1) { <destination> using <transport> [<destination> using <transport>] } where: destination = <destination_type> "<destination_value>" destination_type = pool | virtual transport = <transport_type> "<transport_name>" transport_type = virtual | config for example: { pool "/Common/default_pool" using config "/Common/sip_udp_tc" host "[10.2.3.4]%0:5060" using virtual "/Common/sip_tcp_vs" } (version 13.0 + ) <transport> <destination> [<transport> <destination>] where: destination = <destination_type> <destination_value> destination_type = pool | host transport = <transport_type> <transport_name> transport_type = virtual | config for example: virtual /Common/sip_tcp_vs host [10.2.3.4]%0:5060 config /Common/sip_udp_tc pool /Common/default_pool |
MR::message route peer <peer_name> [peer <peer_name>] | Instructs the route table to route the message to the provided peer list. This form of the MR::message route command takes the names of configured peers or dynamic peers created via the MR::peer command. |
MR::message route mode <sequential | ratio> peer <peer_name> [peer <peer_name>] | Instructs the route table to route the message to the provided peer list. The peer list will have the peer-selection-mode set the the provided mode. This form of the MR::message route command takes the names of configured peers or dynamic peers created via the MR::peer command. |
MR::message route [[virtual <virtual_name>] OR [config <config_name>]] [[host <host tuple>] OR [pool <pool_name>]] | Instructs the route table to route the message to the provided host or pool. |
MR::message attempted |
Returns a list of hosts that the message has been routed towards. The returned value will be formatted as: <transport> <destination> [<transport> <destination>] where: destination = <destination_type> host <host_value> transport = <transport_type> <transport_name> transport_type = virtual | config for example: virtual /Common/sip_tcp_vs host [10.2.3.4]%0:5060 config /Common/sip_udp_tc host [20.3.4.5]%0:5060 |
MR::message attempted none | Clear list of attempted hosts from the message. |
MR::message attempted [[virtual <virtual_name>] OR [config <config_name>]] [host <host tuple>] | Sets the list of attempted hosts in the message. If set before routing (during MR_INGRESS or MR_FAILED), the hosts in the attempted hosts list will be avoided when performing a lb_pick. |
MR::message originator |
Returns the transport type, transport name and ip address/port/route domain ID of the originator of the message. The returned value will be formatted as: <transport> <destination> where: destination = host <host_value> transport = <transport_type> <transport_name> transport_type = virtual | config for example: virtual /Common/sip_tcp_vs host [10.2.3.4]%0:5060 |
MR::message drop <reason> | Drops the current message. |
MR::message retry_count | Returns the number of attempts to route this message that have occurred. |
MR::message status | Returns the status of the routing operation (valid only at MR_EGRESS). Possible values are: "unprocessed", "route found", "no route found", "dropped", "queue_full", "no connection", "connection closing", "internal error", "persist key in use", and "standby dropped" |
MR::flow_id | Returns the flow_id of the current connection (in hex). |
MR::transport |
Returns the transport type and name of the current connection. for example config /Common/sip_udp_tc |
MR::prime [config <config_name>] OR [virtual <virtual_name>] [host <host tuple>] OR [pool <pool name>] | Initialize a connection to the specified peer (or active poolmembers of the specified pool) using the specified transport. |
MR::retry | This command is only available during MR_FAILED event. It re-submits the current message for routing to an alternate pool member. If the previous routing attempt set the message's nexthop or route, these fields should be cleared before retrying routing (use "MR::message nexthop none" and "MR::message route none"). The message's route_status will automatically be reset by this command. If the the retry also fails and the retry_count has reached the max_retries setting in the router profile, the message will be given a "Max retries exceeded" route status. |
MR::max_retries | Returns the configured max_retries of the router instance. |
MR::connection_instance |
Returns the instance number and number of connections of the current connection within a peer. It will be formatted as "<instance_number> of <max_connections>". For incoming connections, this will return "0 of 1". for example 0 of 5 |
MR::connection_mode | Returns the connection_mode of the current connection as configured in the peer object. Valid connection_modes are "per-peer, per-blade, per-tmm and per-client". For incoming connections, this will be "per-peer". |
Route Status
Status | Description |
---|---|
unprocessed | Message has not been submitted for routing yet |
route found | Route has been found |
no route found | A route has not been found |
dropped | The message has been dropped by a MR::message drop command |
queue full | The message was returned back to the originator because one of the MRF processing queues had reached its configured limit. |
no connection | The message was routed to a connection which was no longer present. |
connection closing | The message was queued to be send on a connection which was closed. |
internal error | The message was unable to be delivered due to an internal error. For example, out of memory. |
persist key in use | Two messages routed using the same persistence key simultanously tried to create the same persistence record. |
standby dropped | The message is a mirrored message running on a standby device and was dropped as part of routing to avoid creating an outgoing connection on the standby device. |
Max retries exceeded | The message was returned to the originator because the latest attempt to retry routing exceeded the configured max retry count. |