Neutron/LBaaS/l7

Background
Layer 7 switching takes its name from the OSI model, indicating that the device switches requests based on layer 7 (application) data. Layer 7 switching is also known as "request switching," "application switching," and "content based routing."

A layer 7 switch presents to the outside world a "virtual server" that accepts requests on behalf of a number of servers and distributes those requests based on policies that use application data to determine which server or set of servers should service any given request. This allows for the application infrastructure to be specifically tuned/optimized to serve specific types of content. For example, one server can be tuned to serve only images, another for execution of server-side scripting languages like PHP and ASP, and another for static content such as HTML, CSS , and JavaScript.

Unlike lower-level load balancing, layer 7 switching does not require that all servers in the pool (farm/cluster) have the same content. In fact, it is generally expected that a load balancer configuration using layer 7 switching expects the back-end servers from different pools will have different content. Layer 7 switches are capable of directing requests based on URI, host, HTTP headers, and anything in the application message.

L7 switching in Neutron LBaaS
The layer 7 switching capabilities described in this document are slated to be added to Neutron LBaaS in time for the Mitaka release cycle. Note also that layer 7 switching applies to the LBaaS v2 API only. Since LBaaS v1 is being phased out, there are no plans to make L7 switching capability work with Neutron LBaaS v1.

It's also worth noting that while layer 7 switching can in theory be done for any well-defined layer 7 application interface, for the purposes of Neutron LBaaS, L7 functionality refers only to the HTTP protocol and its semantics.

It is also anticipated that initially not all load balancer vendors with Neutron LBaaS drivers will support L7 switching at first. However, we imagine the L7 switching functionality described in this document should be universal enough that all load balancer vendors capable of doing L7 functionality at all should be able to write drivers which work with Neutron LBaaS L7 switching.

API and logic changes

 * Pools can be created without necessarily being associated with a Listener
 * Pools are associated directly with exactly one loadbalancer.
 * Pools have a "loose coupling" with Listeners (ie. a pool can be effectively associated with zero or one listeners through L7policies, or default_pool assignments.)
 * CRUD operations for L7Policy
 * CRUD operations for L7Rule

CLI Example

 * neutron lbaas-create-listener listener1 ..... ( Create listener)
 * neutron lbaas-create-pool pool1 ..... ( Create pool)
 * neutron --policy policy1 lbaas-create-l7policy --name "policy1" --description "My Description" --listener "listener1" --action redirect_to_pool --pool "pool1" --position 1 (Create l7 policy named 'policy1' and insert it at the beginning of the the l7 policy list for 'listener1', with the action of this policy to redirect to pool 'pool1' )
 * neutron lbaas-create-l7rule rule1 --rule-type path --compare-type starts_with --value "/api" --policy policy (Create l7 rule named 'rule1' and associate it with the policy 'policy1' )
 * neutron lbaas-create-l7rule rule2 --rule-type header --compare-type equal_to --key "mycookie" --value "myvalue" --invert --policy policy1 (Create l7 rule named 'rule2' and associate it with the policy 'policy1' )

The above L7 policy and rule creation should now enable the following logic:

In listener1's configuration, redirect any given request to pool1 IF: The request URI path starts with "/api" AND cookie "mycookie" is NOT equal to "myvalue"

L7 Rules
An L7 Rule is a single, simple logical test which returns either true or false. It consists of a rule type, a comparison type, a value, and an optional key that gets used depending on the rule type. An L7 rule must always be associated with an L7 policy.

Rule types
L7 rules have the following types:


 * hostname: The rule does a comparison between the HTTP/1.1 hostname in the request against the value parameter in the rule.
 * path: The rule compares the path portion of the HTTP URI against the value parameter in the rule.
 * file_type: The rule compares the last portion of the URI against the value parameter in the rule. (eg. "txt", "jpg", etc.)
 * header: The rule looks for a header defined in the key parameter and compares it against the value parameter in the rule.
 * cookie: The rule looks for a cookie named by the key parameter and compares it against the value parameter in the rule.

Comparison types
L7 rules of a given type always do comparisons. The list of comparisons we support is below. Note that not all rule types support all comparison types:


 * regex: Perl type regular expression matching
 * starts_with: String start with
 * ends_with: String ends with
 * contains: String contains
 * equal_to: String equals

Invert
In order to more fully express the logic required by some policies, rules may have their result inverted. That is to say, if the invert parameter of a given rule is true, the result of its comparison will be inverted. (For example, an inverted "equal to" rule effectively becomes a "not equal to", and an inverted "regex" rule returns true only if the given regex does not match.)

L7 Policies
An L7 Policy is a collection of L7 rules associated with a Listener, and which may also have an association to a back-end pool. Policies describe actions that should be taken by the load balancing software if all of the rules in the policy return true / match.

Policy Logic
Policy logic is very simple: All the rules associated with a given policy are logically ANDed together. A request much match all the policy's rules to match the policy.

If you need to express a logical OR operation between rules, then do this by creating multiple policies with the same action (or, possibly, by making a more elaborate regular expression).

Policy Actions
If an L7 policy matches a given request, then that policy's action is executed. The following are the actions a L7 Policy may take:


 * block: The request is denied with an appropriate response code, and not forwarded on to any back-end pool.
 * redirect_to_url: The request is sent an HTTP redirect to the URL defined in the redirect_url parameter.
 * redirect_to_pool: The request is forwarded to the back-end pool associated with the L7 policy (which is usually not the default pool associated with the listener).

Policy Position
A few notes regarding policy position:

whose action is followed.
 * L7 Policies are evaluated in a specific order (as defined by the 'position' attribute), and the first policy that matches a given request will be the one
 * If no policy matches a given request, then the request is routed to the listener's default pool (if it exists).
 * Policy position numbering starts with 1.
 * If a new policy is created with a position that matches that of an existing policy, then the new policy is inserted at the given position.
 * If a new policy is created without specifying a position, or specifying a position that is greater than the number of policies already in the list, the new policy will just be appended to the list.
 * When policies are inserted, deleted, or appended to the list, the policy position values are re-ordered from 1 without skipping numbers. For example, if policy A, B, and C have position values of 1, 2 and 3 respectively, if you delete policy B from the list, policy C's position becomes 2.

Important note: At the present time, the reference implementation for LBaaSv2 uses haproxy, and haproxy enforces the following ordering regarding policy actions:


 * block policies take precedence over all other policies.
 * redirect_to_url policies take precedence over redirect_to_pool policies.
 * redirect_to_pool policies are only evaluated after all of the above, and in the order specified by the 'position' of the policy.

(It turns out that nearly all practical uses for 'block' and 'redirect_to_url' policies actually need these to happen before 'redirect_to_pool' policies anyway, so we don't expect the above impositions on policy evaluation order to cause problems for almost all users of the technology.)

Useful links

 * https://github.com/openstack/neutron-specs/blob/master/specs/mitaka/lbaas-l7-rules.rst
 * http://cbonte.github.io/haproxy-dconv/configuration-1.6.html#7