Jump to: navigation, search

Difference between revisions of "Neutron/LBaaS/l7"

< Neutron‎ | LBaaS
(Model)
(CLI Example)
 
(14 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
== L7 Switching ==
 
== L7 Switching ==
 
=== Background ===
 
=== 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".
+
Layer 7 switching takes its name from the OSI model, indicating that the device
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 should service which 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.
+
switches requests based on layer 7 (application) data. Layer 7 switching is
Unlike load balancing, layer 7 switching does not require that all servers in the pool (farm/cluster) have the same content. In fact, layer 7 switching expects that servers will have different content, thus the need to more deeply inspect requests before determining where they should be directed. Layer 7 switches are capable of directing requests based on URI, host, HTTP headers, and anything in the application message.
+
also known as "request switching," "application switching," and "content based
 +
routing."
  
=== API Changes ===
+
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 L7Policy
 
* CRUD operations for L7Rule
 
* CRUD operations for L7Rule
* CRUD operations for L7VipPolicyAssociation
 
  
 
=== CLI Example ===
 
=== CLI Example ===
* '''neutron --policy policy1 lb-create-l7policy ''' (''Create  l7 policy named 'policy1' '')
+
* '''neutron lbaas-create-listener listener1 .....''' ('' Create listener'')
 
+
* '''neutron lbaas-create-pool pool1 .....''' ('' Create pool'')
* '''neutron lb-create-l7rule rule1 --attribute-type header --attribute-name "myheader" --attribute-value "transaction[1-9]{1,4}" --policy policy1''' (''Create l7 rule named 'rule1' and associate it with the policy 'policy1' '')
+
* '''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 lb-create-l7rule rule2 --attribute-type path  --attribute-value "/shopping/.*" --policy p1''' (''Create l7 rule named 'rule2' 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' '')
 
+
 
* '''neutron lb-create-pool pool1 .....''' ('' Create pool'')
+
 
 
+
The above L7 policy and rule creation should now enable the following logic:
* '''neutron lb-create-vip .vip1 ......''' ('' Create vip '')
+
 
 
+
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"
* '''neutron lb-associate-vip-pool  --vip vip1 --pool pool1 --action SELECT-POOL  --l7policy policy1''' ('' Associate the vip and the pool to 'policy1.If policy1 will return True, the traffic of vip1 will be directed to pool1 ' '')
+
 
 +
=== 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).
  
=== Model ===
+
==== Policy Position ====
 +
A few notes regarding policy position:
  
    class L7Rule {
+
* 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
      String l7policyID
+
whose action is followed.
      enum Type [Hostname, Path, File Type, Header, Cookie], // need to decide: enum or string
+
* If no policy matches a given request, then the request is routed to the listener's default pool (if it exists).
      enum Compare Type [regext],
+
* Policy position numbering starts with 1.
      String Value,
+
* 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.
      int  position // L7Rules are held by L7Policy as a list, one can set the position of the rule in the list
+
* 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.
    class L7Policy {
 
      String name
 
      collection of L7Rule
 
    }
 
    class L7VipPolicyAssociation { // holds the association between a vip and l7policy
 
      String vipID
 
      String l7policyID
 
      String action // Nedd to decide if we want to have enaum here {REDIRECT_TO_URL,REDIRECT_TO_POOL,REJECT}
 
      String pooID // optional. mandatory if action is REDIRECT_TO_POOL
 
      String url // optional. mandatory if action is REDIRECT_TO_URL
 
    }
 
  
===DB Migration===
+
'''Important note:''' At the present time, the reference implementation for LBaaSv2 uses haproxy, and haproxy enforces the following ordering regarding policy actions:
  
=== Implementation Plan ===
+
* ''block'' policies take precedence over all other policies.
* neutron-server change
+
* ''redirect_to_url'' policies take precedence over ''redirect_to_pool'' policies.
* db models and logic change
+
* ''redirect_to_pool'' policies are only evaluated after all of the above, and in the order specified by the 'position' of the policy.
* lbaas plugin change
 
* lbaas driver change
 
* python-neutronclient
 
* horizon
 
  
=== HAProxy L7 Switching===
+
(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.)
HAProxy L7 Switching is based on HAProxy ACL engine.
 
Example 1 (blocking):
 
<br/>
 
# ... some HTTP content smugling and other various things
 
        acl forbidden_hdrs hdr_cnt(host) gt 1
 
        acl forbidden_hdrs hdr_cnt(content-length) gt 1
 
        acl forbidden_hdrs hdr_val(content-length) lt 0
 
        acl forbidden_hdrs hdr_cnt(proxy-authorization) gt 0
 
        block if forbidden_hdrs
 
Example 2 (switching - switch to the pool(backend) named 'www2' if 'host_www2' is true ):
 
      acl host_www2  hdr_beg(host) -i www2.
 
      use_backend  www2  if host_www2
 
  
[http://cbonte.github.io/haproxy-dconv/configuration-1.4.html#7 Using ACL]
+
=== Useful links ===
<br/>
+
* https://github.com/openstack/neutron-specs/blob/master/specs/mitaka/lbaas-l7-rules.rst
[http://cbonte.github.io/haproxy-dconv/configuration-1.4.html#7.5.3 Matching at Layer 7]
+
* http://cbonte.github.io/haproxy-dconv/configuration-1.6.html#7
<br/>
 
[https://github.com/joewilliams/haproxy/blob/master/examples/acl-content-sw.cfg Examples]
 

Latest revision as of 17:36, 26 February 2016

L7 Switching

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:

  • 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

whose action is followed.

  • 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