Advanced iRules: Tables

We’ve covered quite a bit of ground in the Getting Started with iRules and Intermediate iRules series. In this series, we’ll dive even deeper down the rabbit hole, starting with the table command. This article is a primer for the power of tables, but we actually have an entire 9 part series on the table command alone, so after reading this overview, I highly recommend you dig in to the meat of what tables can really do.

What is a table?

A table is somewhat similar to a data-group in that it is, at its core, a memory structure to contain lists. That’s about where the similarities end, though. Tables are stored in memory alone, which means they don’t have the config object backing that a data-group does, but that also makes them inherently more flexible.

A table is a read/write memory structure that is maintained across connections, making it a solid contender for storing data that needs to be persistent, as opposed to connection based like normal iRules variables. Tables also allow a few extremely powerful concepts, namely sub tables and a built in timeout/lifetime structure. Both of these things add possibilities to what tables are capable of.

Tables are also extremely efficient, much like data-groups, though on a slightly smaller scale given their more flexible nature. Tables make use of the session table within LTM, which is designed to handle every connection into or out of the device, and as such is very high performance. Table queries share this performance and can be a quick way to construct simple, persistent memory structures or more complex near DB like sets of sub-tables, depending on your needs.

What are the benefits of a table?

Tables are a high performance, highly scalable, persistent (non-connection bound), read/write data structure. That fact alone makes them unique within iRules and extremely powerful. There simply aren’t other things that fill that role. There are only a couple of ways to have read/write variable data across connections, and tables are by far the best option in almost every case.

The ability to create what amounts to a mini database in memory from within your iRule is massively useful in many scenarios also. This is easy to do via subtables. You can create not just a flat list, but named lists to segregate data however you’d like. By doing so you can create relations and a relatively complex schema for data storage and accounting.

Now add in the fact that there are configurable timeout and lifetime options, which means you’ll never have to worry about memory management or programmatic cleanup of a table, as things will time out as designed, and you’ve got another layer of usability and ease of use that is unique to tables.

The bottom line is that tables are one of the more powerful, flexible features to hit iRules in quite a while.

What command(s) would I use to access data in a table?

To access tables, you make use of the table command, much like the class command to access data-groups. This command can also get quite complex quite fast, so I won’t attempt to cover all the possible permutations here. I’ll list a couple of simple examples, and give you a link to the full documentation.


# Limit each client IP address to 20 concurrent connections
when CLIENT_ACCEPTED {
    # Check if the subtable has over 20 entries
    if { [table keys -subtable connlimit:[IP::client_addr] -count] >= 20 } {
        reject
    } else {
        # Add the client IP:port to the client IP-specific subtable
        # with a max lifetime of 180 seconds
        table set -subtable connlimit:[IP::client_addr] [TCP::client_port] "" 180
    }
}
when CLIENT_CLOSED {
    # When the client connection is closed, remove the table entry
    table delete -subtable connlimit:[IP::client_addr] [TCP::client_port]
}

As you can see tables are extremely powerful, and can add a powerful tool to your quiver for your future iRule endeavors. There are plenty of examples of using these powerful commands out on DevCentral, so there is no shortage of information to be found and code to be lifted for re-use if you scour Q&A and the Codeshare. In an attempt to keep this consumable I've not gone through the full list of command permutations or anywhere near the full possibilities. I'll leave discovering those things to the more advanced and/or eager iRulers, but suffice to say the possibilities are vast.

Updated Oct 02, 2023
Version 2.0
  • Hi Jason, thank you for this article on tables in iRules. I use tables in iRules to share data between virtuals. In this case I share a master key containing a service name. Just recently I discovered the tables aren't sync anymore on multi tmm instances. Perhaps you have a clue to sync tables again? Here are my logs. I add a session key into a subtable on one proxy and read it from another:

     

    Proxy 1:

     

    Aug  9 07:00:51 apmmuc01 info tmm7[14294]: Rule /way-software/WAY-AppAuthenticate-V2.3.01.iRule : REQ-A42-log: access to auth 483a86b149b2cfd5
    Aug  9 07:00:51 apmmuc01 info tmm7[14294]: Rule /way-software/WAY-AppAuthenticate-V2.3.01.iRule : REQ-A42-tbl: master key wayservices
    

    Proxy 2:

     

    Aug  9 07:00:51 apmmuc01 info tmm7[14294]: Rule /way-software/WAY-Authenticate-V2.1.03.iRule : APM-E02-log: session id is 483a86b149b2cfd5
    Aug  9 07:00:51 apmmuc01 info tmm7[14294]: Rule /way-software/WAY-Authenticate-V2.1.03.iRule : APM-I03-tab: master key wayservices
    

    By chance the two iRules share the same tmm.

     

    This is where it fails:

     

    Proxy 1:

     

    Aug  9 07:34:29 apmmuc01 info tmm4[14294]: Rule /way-software/WAY-AppAuthenticate-V2.3.02.iRule : REQ-A42-log: access to auth c6c405d09094e2ab
    Aug  9 07:34:29 apmmuc01 info tmm4[14294]: Rule /way-software/WAY-AppAuthenticate-V2.3.02.iRule : REQ-A42-tbl: master key wayservices
    

    Proxy 2:

     

    Aug  9 07:34:29 apmmuc01 info tmm1[14294]: Rule /way-software/WAY-Authenticate-V2.3.02.iRule : APM-E02-log: session id is c6c405d09094e2ab
    Aug  9 07:34:29 apmmuc01 info tmm1[14294]: Rule /way-software/WAY-Authenticate-V2.3.02.iRule : APM-I03-tab: master key
    

    The two iRules run on separate tmm. I use since 11.3 (2015) reliably, but recently I see this changed behavior. Do you have an idea what is wrong? The code itself is pretty simple:

     

    log local0. "REQ-A42-log: access to auth $JWTsessionKey"
    log local0. "REQ-A42-tbl: master key [table lookup -subtable $WayMasterTable $JWTsessionKey]"
    
    set tableKey [table lookup -subtable $WayMasterTable $sessionKey]
    log local0. "APM-E02-log: session id is $sessionKey]
    log local0. "APM-I03-tab: master key $tableKey"
    

    I would be more than happy I you could help. I assume I'm not the only one to use tables to share information between proxies.

     

    Cheers,

     

    Cay

     

  • Hi Cay, the process of sharing tables across TMM is slow relative to the flow of connection speed, so this is a somewhat expected behavior. You should definitely add some validation logic to handle the cases where no data is returned.

     

  • Hi Jason,

    I have contacted support on this issue. Finally the way it works is to use the same traffic group on all virtual ip addresses, since by default the tables are not synced across traffic groups. You may however choose to sync with

    tmsh modify sys db tmm.sessiondb.match_ha_unit value false
    tmsh save sys config
    

    Since I have not used this option no recommendation by my side. Perhaps this note helps the community.

    Thanks, Cay

  • I have an irule that's adding entries to a table called "tbltest". How do I view those entries in the session table from the CLI?